#include "Loader.h"

int number_of_read_sets;
#define IDENT(value)\
for(int i=0;i<value;i++) printf("\t");\

void original(json_value *value, int ident = 0)
{
	IDENT(ident);
	if (value->name) printf("\"V1.%s\" = ", value->name);
	switch(value->type)
	{
        case JSON_NULL:
            printf("null\n");
            break;
        case JSON_OBJECT:
        case JSON_ARRAY:
            printf(value->type == JSON_OBJECT ? "{\n" : "[\n");
            for (json_value *it = value->first_child; it; it = it->next_sibling)
            {
                original(it, ident + 1);
            }
            IDENT(ident);
            printf(value->type == JSON_OBJECT ? "}\n" : "]\n");
            break;
        case JSON_STRING:
            printf("\"V2.%s\"\n", value->string_value);
            break;
        case JSON_INT:
            printf("V3.%d\n", value->int_value);
            break;
        case JSON_FLOAT:
            printf("V4.%f\n", value->float_value);
            break;
        case JSON_BOOL:
            printf(value->int_value ? "true\n" : "false\n");
            break;
	}
}

DBG * global_dbg;
bool in_nodes;
bool in_edges;
bool in_data;
bool in_id;
bool in_sequence;
bool in_source;
bool in_target;
bool in_direction;
char edge_direction;
char * sequence;
int source, target;
int node_nb;
int node_id;


//************************************************************************************************************************************************
//****************************** SINGLE GRAPHS                                            ********************************************************
//************************************************************************************************************************************************

void load_json_rec_global(json_value *value, int ident = 0)
{
    if (value->name) {
        // printf("V1.%s\n", value->name);
        if(!strcmp(value->name,"nodes"))  in_nodes=true;
        if(!strcmp(value->name,"edges"))  in_edges=true;
        if(!strcmp(value->name,"data")) in_data=true;
        if(!strcmp(value->name,"id")) in_id=true;
        if(!strcmp(value->name,"sequence")) in_sequence=true;
        if(!strcmp(value->name,"source")) in_source=true;
        if(!strcmp(value->name,"target")) in_target=true;
        if(!strcmp(value->name,"direction")) in_direction=true;
    }
    switch(value->type)
    {
        case JSON_NULL:
            // printf("null\n");
            break;
        case JSON_OBJECT:
        case JSON_ARRAY:
            // printf(value->type == JSON_OBJECT ? "{\n" : "[\n");
            for (json_value *it = value->first_child; it; it = it->next_sibling)
            {
                load_json_rec_global(it, ident + 1);
            }
            // printf(value->type == JSON_OBJECT ? "}\n" : "]\n");
            // WHAT DID WE CLOSE ?
            if(in_data){ // READING A NODE OR AN EDGE
                if(in_nodes) {
                    global_dbg->all_nodes.push_back(new Node_dbg(sequence, number_of_read_sets, node_id));
                    free(sequence);
                } // create a new sequence.
                if(in_edges) { // add a new edge
                    //                    	  printf("adding edge %d --%d--> %d\n", source, (int)edge_direction, target);
                    int source_number = global_dbg->node_id_to_node_number(source);
                    if(source_number==-1)
                        fprintf(stderr, "cannot find node with id %d in the graph; exit\n", source);
                    int target_number = global_dbg->node_id_to_node_number(target);
                    if(target_number==-1)
                        fprintf(stderr, "cannot find node with id %d in the graph; exit\n", target);
                    
                    
                    global_dbg->all_nodes[source_number]->add_child(global_dbg->all_nodes[target_number],edge_direction);
                    //                    printf("node %s has %d soons \n", global_dbg->all_nodes[source]->fragment->fragment_sequence, global_dbg->all_nodes[source]->edges.size());
                }
                in_data=false;
            }
            else if(value->type == JSON_ARRAY && in_nodes){in_nodes=false;}
            else if(value->type == JSON_ARRAY && in_edges){in_edges=false;}
            break;
        case JSON_STRING:
            //      printf("\"V2.%s\"\n", value->string_value);
            if(in_sequence){
                	printf("adding node %s = %ld\n", value->string_value, global_dbg->all_nodes.size());
                sequence = (char *) malloc(sizeof(char)*strlen(value->string_value)+1);
                strcpy(sequence, value->string_value);
                //                global_dbg->all_nodes.push_back(new Node_dbg(value->string_value, number_of_read_sets, node_nb++));
                in_sequence=false;
            }
            else if(in_direction){
                if(!strcmp(value->string_value,"ff") || !strcmp(value->string_value,"FF")) edge_direction=(char)0;
                else if(!strcmp(value->string_value,"rr") || !strcmp(value->string_value,"RR")) edge_direction=(char)1;
                else if(!strcmp(value->string_value,"fr") || !strcmp(value->string_value,"FR")) edge_direction=(char)2;
                else if(!strcmp(value->string_value,"rf") || !strcmp(value->string_value,"RF")) edge_direction=(char)3;
                else {
                    fprintf(stderr,"Unrecognized direction %s\n", value->string_value);
                    exit(0);
                }
                in_direction=false;}
            break;
        case JSON_INT:
            // printf("V3.%d\n", value->int_value);
            if(in_id) {node_id=value->int_value; in_id=false;}
            else if(in_source) {source=value->int_value;in_source=false;} // do nothing
            else if(in_target) {target=value->int_value;in_target=false;} // do nothing
            break;
        case JSON_FLOAT:
            // printf("V4.%f\n", value->float_value);
            break;
        case JSON_BOOL:
            // printf(value->int_value ? "true\n" : "false\n");
            break;
    }
}

DBG* load_json(char * json_file, const int nb_sets){
    char *errorPos = 0;
    char *errorDesc = 0;
    int errorLine = 0;
    block_allocator allocator(1 << 10);
    in_nodes=false;
    in_edges=false;
    in_data=false;
    in_id=false;
    in_sequence=false;
    in_source=false;
    in_target=false;
    in_direction=false;
    node_nb=0;
    number_of_read_sets=nb_sets;
    global_dbg = new DBG();
    
    
    json_value *root = json_parse(populate_sources(json_file), &errorPos, &errorDesc, &errorLine, &allocator);
    if (!root){
        fprintf(stderr,"Error loading the de bruijn graph in %s at line %d: %s\n%s\n\n", json_file, errorLine, errorDesc, errorPos);
        return NULL;
    }
    load_json_rec_global(root);
    return global_dbg;
}


//************************************************************************************************************************************************
//****************************** MULTIPLE GRAPHS                                          ********************************************************
//************************************************************************************************************************************************

vector<DBG*> global_multiple_dbg;
bool in_extremGraphs;


void load_json_rec_global_multiple(json_value *value)
{
//    printf("V1.%s\n", value->name);
    if (value->name) {
        
        
        if(!strcmp(value->name,"nodes") && in_extremGraphs) in_nodes=true;
        if(!strcmp(value->name,"edges") && in_extremGraphs)
            in_edges=true;
        if(!strcmp(value->name,"data") && (in_nodes || in_edges))
            in_data=true;
        if(!strcmp(value->name,"id") && (in_nodes)) // we dont care about id of edges.
            in_id=true;
        if(!strcmp(value->name,"sequence") && in_nodes) in_sequence=true;
        if(!strcmp(value->name,"source") && in_edges) in_source=true;
        if(!strcmp(value->name,"target") && in_edges) in_target=true;
        if(!strcmp(value->name,"direction") && in_edges) in_direction=true;
        if(!strcmp(value->name,"extremGraphs")){
            in_extremGraphs=true;
            in_edges=false;
            in_data=false;
            in_id=false;
            in_sequence=false;
            in_source=false;
            in_target=false;
            in_direction=false;
        }
        if(!strcmp(value->name,"data") && in_extremGraphs && !in_nodes && !in_edges) // starts a new extreme graph
        {
            global_multiple_dbg.push_back(new DBG());
        }
//        printf("%s %s %s %s %s ", in_nodes?"in_nodes":"", in_edges?"in_edges":"", in_data?"in_data":"", in_id?"in_id":"", in_sequence?"in_sequence":"");
//        printf("%s %s %s %s\n",in_source?"in_source":"", in_target?"in_target":"", in_direction?"in_direction":"", in_extremGraphs?"in_extremGraphs":"");
    }
    switch(value->type)
    {
        case JSON_NULL:
            // printf("null\n");
            break;
        case JSON_OBJECT:
        case JSON_ARRAY:
//            printf(value->type == JSON_OBJECT ? "{\n" : "[\n");
            for (json_value *it = value->first_child; it; it = it->next_sibling)
            {
                load_json_rec_global_multiple(it);
            }
//            printf(value->type == JSON_OBJECT ? "}\n" : "]\n");
            
            // WHAT DID WE CLOSE ?
            
            // CLOSED DATA OF A NODE
            if(in_extremGraphs && in_nodes && in_data){ // READING A NODE
                global_multiple_dbg.back()->all_nodes.push_back(new Node_dbg(sequence, number_of_read_sets, node_id));
                free(sequence);
                in_data=false;
            }
            
            // CLOSED DATA OF AN EDGE
            else if (in_extremGraphs && in_edges && in_data){ // READING AN EDGE
//                printf("adding edge %d --%d--> %d\n", source, (int)edge_direction, target);
                int source_number = global_multiple_dbg.back()->node_id_to_node_number(source);
                if(source_number==-1)
                    fprintf(stderr, "cannot find node with id %d in the graph; exit\n", source);
                int target_number = global_multiple_dbg.back()->node_id_to_node_number(target);
                if(target_number==-1)
                    fprintf(stderr, "cannot find node with id %d in the graph; exit\n", target);
                global_multiple_dbg.back()->all_nodes[source_number]->add_child(global_multiple_dbg.back()->all_nodes[target_number],edge_direction);
                in_data=false;
            }
            
            // CLOSED NODES
            else if(in_extremGraphs && value->type == JSON_ARRAY && in_nodes){
                in_nodes=false;
            }
            
            // CLOSED NODES
            else if(in_extremGraphs && value->type == JSON_ARRAY && in_edges){
                in_edges=false;
            }
            
            // CLOSED AN EXTREMGRAPH
            else if (value->type == JSON_ARRAY && in_extremGraphs && ! in_edges && ! in_nodes){
                in_extremGraphs=false;
            }

//            else if(value->type == JSON_ARRAY && in_nodes){in_nodes=false;} // end in_node
//            else if(value->type == JSON_ARRAY && in_edges){in_edges=false;} // end in_edge
//            else if(value->type == JSON_ARRAY){in_extremGraphs=false;} // end extremGraph
            break;
            
            
        case JSON_STRING:
//            printf("\"V2.%s\"\n", value->string_value);
            if(in_extremGraphs && in_sequence && in_nodes){
//                printf("adding node %s = %d\n", value->string_value, global_multiple_dbg.back()->all_nodes.size());
                sequence = (char *) malloc(sizeof(char)*strlen(value->string_value)+1);
                strcpy(sequence, value->string_value);
                //                global_dbg->all_nodes.push_back(new Node_dbg(value->string_value, number_of_read_sets, node_nb++));
                in_sequence=false;
            }
            else if(in_extremGraphs && in_direction && in_edges){
                if(!strcmp(value->string_value,"ff") || !strcmp(value->string_value,"FF")) edge_direction=(char)0;
                else if(!strcmp(value->string_value,"rr") || !strcmp(value->string_value,"RR")) edge_direction=(char)1;
                else if(!strcmp(value->string_value,"fr") || !strcmp(value->string_value,"FR")) edge_direction=(char)2;
                else if(!strcmp(value->string_value,"rf") || !strcmp(value->string_value,"RF")) edge_direction=(char)3;
                else {
                    fprintf(stderr,"Unrecognized direction %s\n", value->string_value);
                    exit(0);
                }
                in_direction=false;
            }
            else if(in_extremGraphs && in_nodes && in_id)
            {
                
                node_id=atoi((value->string_value)+1); // change the string id (n4) into an int id (4)
                in_id=false;
            }
            else if(in_extremGraphs && in_source)
            {
                source=atoi((value->string_value)+1); // change the string id (n4) into an int id (4)
                in_source=false;
            }
            else if(in_extremGraphs && in_target)
            {
                target=atoi((value->string_value)+1); // change the string id (n4) into an int id (4)
                in_target=false;
            } // do nothing
            break;
        case JSON_INT:
//            printf("V3.%d\n", value->int_value);
            
            break;
        case JSON_FLOAT:
//            printf("V4.%f\n", value->float_value);
            break;
        case JSON_BOOL:
//            printf(value->int_value ? "true\n" : "false\n");
            break;
    }
}

vector<DBG*> load_mapsembler_json(char * json_file, const int nb_sets){
    char *errorPos = 0; 
    char *errorDesc = 0;
    int errorLine = 0;
    block_allocator allocator(1 << 10);
    in_nodes=false;
    in_edges=false;
    in_data=false;
    in_id=false;
    in_sequence=false;
    in_source=false;
    in_target=false;
    in_direction=false;
    in_extremGraphs=false;
    node_nb=0;
    number_of_read_sets=nb_sets;
    
    
    json_value *root = json_parse(populate_sources(json_file), &errorPos, &errorDesc, &errorLine, &allocator);
    

    if (!root){
//        fprintf(stderr,"Error loading the de bruijn graph in %s at line %d: %s\n%s\n\n", json_file, errorLine, errorDesc, errorPos);
        fprintf(stderr,"Error loading the de bruijn graph in %s at line %d: %s\n", json_file, errorLine, errorDesc);

        exit(1);
    }
    
    
    
    load_json_rec_global_multiple(root);
    
    printf("DONE, read %d graphs \n", (int)global_multiple_dbg.size());
    return global_multiple_dbg;
}

//
//extern int size_seeds;
//
//int main(int argc, char **argv)
//{
//    DBG * dbg = load_json(argv[1]);
//    size_seeds=23;
////    dbg->depth_first_print();
//    dbg->depth_first_check();
//    dbg->index_nodes();
//    // node 0 linked with 1: GAGGGATCTGTTATAGATCAAACTGCCATGACTCTTTTCCAGGGAGTATGGGTCTCCGCGTTAGTCTCGCTGAATAACTTTCGGTAAGACGCAAGCGGCCAGTATGCCAAATGCATAAGTGTCATAGCTGAGTT
//    char * sequence = (char *)malloc(sizeof(char)*4048);
//    sprintf(sequence, "GAGGGATCTGTTATAGATCAAACTGCCATGACTCTTTTCCA");
//    bool mapped = dbg->map_strictly_a_fragment(0, dbg->all_nodes[0], sequence);
//    printf("%s %s mapped on graph\n", sequence, mapped?"":"dit not");
//
//    dbg->depth_first_check();
//
//    sprintf(sequence, "GGGATCTGTTATAGATCAAACTGCCATGACTCTTTTCCA");
//    mapped = dbg->map_strictly_a_fragment(2, dbg->all_nodes[0], sequence);
//    printf("%s %s mapped on graph\n", sequence, mapped?"":"dit not");
//
//
//    dbg->depth_first_check();
//
//    sprintf(sequence, "GAGGGATCTGTTATAGATCAAACTGCCATGACTCTTTTCCAGGGAGTATGGGTCTCCGCGTTAGTCTCGCTGAATAACTTTCGGTAAGACGCAAGCGGCCAGTATGCCAAATGCATAAGTGTCATAGCTGAGTT");
//    mapped = dbg->map_strictly_a_fragment(0, dbg->all_nodes[0], sequence);
//    printf("%s %s mapped on graph\n", sequence, mapped?"":"dit not");
//    
//    
//    dbg->depth_first_check();
//    
//	return 0;
//}
