#include <stdlib.h>
#include <errno.h>
#include <sys/time.h>
#include <stdio.h>
#include <libncat/libncat.h>
static struct timeval start, end;
inline static void start_timer(void)
{
    gettimeofday(&start, NULL);
}
static void end_timer(int objects, int bytes)
{
    double usecs;
    gettimeofday(&end, NULL);
    usecs = (end.tv_sec * 1000000 + end.tv_usec) - (start.tv_sec * 1000000 + start.tv_usec);
    if (bytes)
        printf ("Time(secs) %f : %9.0f objects per sec %9.0f bytes per secs\n",
                usecs / 1000000.0, (1000000.0 / usecs) * objects,
                 (1000000.0 / usecs) * bytes);
    else
        printf("Time(secs) %f : %9.0f objects per sec\n",
                usecs / 1000000.0, (1000000.0 / usecs) * objects);
}
static void print_progress(lnc_catalog * cat, float percent, char *msg, void *data)
{
    printf("Progess %f %s\n", percent, msg);
}
static int search1(lnc_dataset * dset)
{
    lnc_slist *res = NULL;
    lnc_search *srch;
    int err;
    printf("Searching for high pm or RV objects\n");
    srch = lnc_search_create(dset);
    if (lnc_search_add_comparator(srch, "pmRA", LNC_COMP_LT, "0.2"))
        printf("failed to add comp pmRA\n");
    if (lnc_search_add_comparator(srch, "pmRA", LNC_COMP_GT, "0.05"))
        printf("failed to add comp pmRA\n");
    if (lnc_search_add_operator(srch, LNC_OP_AND))
        printf("failed to add op and\n");
    if (lnc_search_add_comparator(srch, "pmDE", LNC_COMP_LT, "0.2"))
        printf("failed to add comp pmDE\n");
    if (lnc_search_add_comparator(srch, "pmDE", LNC_COMP_GT, "0.05"))
        printf("failed to add comp pmDE\n");
    if (lnc_search_add_operator(srch, LNC_OP_AND))
        printf("failed to add op and\n");
    if (lnc_search_add_comparator(srch, "RV", LNC_COMP_LT, "40"))
        printf("failed to add comp RV\n");
    if (lnc_search_add_comparator(srch, "RV", LNC_COMP_GT, "25"))
        printf("failed to add comp RV\n");
    if (lnc_search_add_operator(srch, LNC_OP_AND))
        printf("failed to add op and\n");
    if (lnc_search_add_operator(srch, LNC_OP_OR))
        printf("failed to add op or\n");
    start_timer();
    if ((err = lnc_search_get_results(srch, NULL, &res, 0)) < 0) {
        printf("Search init failed %d\n", err);
        lnc_search_free(srch);
        return err;
    }
    end_timer(lnc_search_get_tests(srch), 0);
    printf("   Search got %d objects out of %d tests\n", lnc_search_get_hits(srch), lnc_search_get_tests(srch));
    lnc_search_put_results(res);
    lnc_search_free(srch);
    return 0;
}
static int search2(lnc_dataset * dset)
{
    lnc_slist *res = NULL;
    lnc_search *srch;
    int err;
    srch = lnc_search_create(dset);
    if (lnc_search_add_comparator(srch, "Sp", LNC_COMP_LT, "G5*"))
        printf("failed to add comp G5*\n");
    if (lnc_search_add_operator(srch, LNC_OP_OR))
        printf("failed to add op or\n");
    printf("Searching for G5 class objects\n");
    start_timer();
    if ((err = lnc_search_get_results(srch, NULL, &res, 0)) < 0) {
        printf("Search init failed %d\n", err);
        lnc_search_free(srch);
        return err;
    }
    end_timer(lnc_search_get_tests(srch), 0);
    printf("   Search got %d objects out of %d tests\n", lnc_search_get_hits(srch), lnc_search_get_tests(srch));
    lnc_search_put_results(res);
    lnc_search_free(srch);
    return 0;
}
struct s_data {
    int id_offset;
    int mag_offset;
    int ra_offset;
    int dec_offset;
};
void search3_print(void *object, void *data)
{
    struct s_data *s = (struct s_data *) data;
    printf("Obj: %s RA: %f DEC: %f Mag %f\n",
           (char *) (object + s->id_offset),
           *((double *) (object + s->ra_offset)),
           *((double *) (object + s->dec_offset)),
           *((float *) (object + s->mag_offset)));
}
static int search3(lnc_dataset * dset)
{
    lnc_slist *res = NULL;
    lnc_search *srch;
    int err;
    struct s_data s;
    srch = lnc_search_create(dset);
    if (lnc_search_add_comparator(srch, "Sp", LNC_COMP_LT, "M1*"))
        printf("failed to add comp M1*\n");
    if (lnc_search_add_operator(srch, LNC_OP_OR))
        printf("failed to add op or\n");
    printf("Searching for M1 class objects\n");
    start_timer();
    if ((err = lnc_search_get_results(srch, NULL, &res, 0)) < 0) {
        printf("Search init failed %d\n", err);
        lnc_search_free(srch);
        return err;
    }
    end_timer(lnc_search_get_tests(srch), 0);
    printf("   Search got %d objects out of %d tests\n", lnc_search_get_hits(srch), lnc_search_get_tests(srch));
    s.id_offset = lnc_dset_get_field_offset(dset, "ID");
    s.mag_offset = lnc_dset_get_field_offset(dset, "Vmag");
    s.ra_offset = lnc_dset_get_field_offset(dset, "RA");
    s.dec_offset = lnc_dset_get_field_offset(dset, "DEC");
    lnc_dset_for_results_do(res, search3_print, &s);
    lnc_search_put_results(res);
    lnc_search_free(srch);
    return 0;
}
static int get1(lnc_dataset * dset)
{
    int count = 0;
    lnc_slist *res = NULL;
    printf("Get all dataset objects\n");
    lnc_dset_unclip(dset);
    count = lnc_dset_get_objects(dset, NULL, &res, 0);
    printf("   Got %d objects\n", count);
    lnc_dset_put_objects(res);
    return 0;
}
static int get2(lnc_dataset * dset)
{
    int count = 0;
    lnc_slist *res = NULL;
    printf("Get all objects < mag 3\n");
    
    lnc_dset_clip_posn(dset, 0, -90, 360, 90, 3, -2);
    count = lnc_dset_get_objects(dset, NULL, &res, 0);
    printf("   Got %d objects\n", count);
    lnc_dset_put_objects(res);
    lnc_dset_unclip(dset);
    return 0;
}
int main(int argc, char *argv[])
{
    lnc_catalog *cat = NULL;
    lnc_library *lib = NULL;
    lnc_dataset *dset = NULL;
    int dset_size, object_size;
    printf("%s using libncat %s\n", argv[0], lnc_get_version());
    
    
    if ((lib = lnc_lib_init("ftp://cdsarc.u-strasbg.fr/pub/cats", "lnc-test")) == NULL) {
        printf("%s\n", lnc_get_last_err_msg());
        exit(-lnc_get_last_err());
    }
    
    
    if ((cat = lnc_cat_create(lib, "V", "109", 0.0, 360.0, -90.0, 90.0, 15.0, -2.0, LNC_PRELOAD)) == NULL) {
        printf("%s\n", lnc_get_last_err_msg());
        exit(-lnc_get_last_err());
    }
    
    if ((dset = lnc_dset_create(cat, "sky2kv4")) == NULL) {
        printf("%s\n", lnc_get_last_err_msg());
        exit(-lnc_get_last_err());
    }
#if 1
    
    if (lnc_dset_add_custom_field(dset, "pmRA"))
        printf("failed to add pmRA\n");
    if (lnc_dset_add_custom_field(dset, "pmDE"))
        printf("failed to add pmDE\n");
    if (lnc_dset_add_custom_field(dset, "RV"))
        printf("failed to add RV\n");
    if (lnc_dset_add_custom_field(dset, "Sp"))
        printf("failed to add Sp\n");
    if (lnc_dset_add_custom_field(dset, "Vder"))
        printf("failed to add Vder\n");
    
    if (lnc_dset_set_alt_index(dset, "Vmag", "Vder", 0))
        printf("failed to add alt index\n");
#else
    
    if (lnc_dset_add_custom_field(dset, "*"))
        printf("failed to add *\n");
    if (lnc_dset_set_alt_index(dset, "Vmag", "Vder", 0))
        printf("failed to add alt index\n");
#endif
    
    start_timer();
    if (lnc_dset_init(dset, NULL, 0, 0, 0, LNC_PRECACHE | LNC_PRELOAD) < 0) {
        printf("%s\n", lnc_get_last_err_msg());
        exit(-lnc_get_last_err());
    }
    dset_size = lnc_dset_get_size(dset);
    object_size = lnc_dset_get_object_size(dset);
    end_timer(dset_size, dset_size * object_size);
    
    get1(dset);
    get2(dset);
    search1(dset);
    search2(dset);
    search3(dset);
    
    lnc_dset_free(dset);
    
    lnc_cat_free(cat);
    lnc_lib_free(lib);
    return 0;
}