//
// DeBruijnGraph.cpp
//
//
//  Created by Pierre Peterlongo on 28/11/2012 (bon anniversaire Matt)
//

#include "DeBruijnGraph.h"
#include <assert.h>
#include "commons.h"
extern int size_seeds; // in commons.cpp
extern char comp['t'+1]; // in commons.cpp
extern char nuc [4]; // in commons.cpp
//////////////////// NODE /////////////////
Node_dbg::Node_dbg(char * fragment_sequence, const int number_of_read_sets, const int node_id){
    fragment = new Mapped_Fragment(fragment_sequence, number_of_read_sets);
    visited=false;
    this->node_id=node_id;
    inout[0]=-1;
    inout[1]=-1;
    inout[2]=-1;
    inout[3]=-1;
}

/**
 * creates a new node with same fragment than the "clone" one.
 * This does not clone the edges 
 * This does not clone the coverages and qualities
 */
Node_dbg::Node_dbg(Node_dbg * clone, const int node_id){
    fragment = new Mapped_Fragment(clone->fragment);
    visited=false;
    this->node_id=node_id;
    inout[0]=-1;
    inout[1]=-1;
    inout[2]=-1;
    inout[3]=-1;

}

void Node_dbg::add_child(Node_dbg * child, char label){
    edges.push_back(new Edge_dbg(child, label));
    //printf("adding edge %d from %s to %llx\n", (int)label, fragment->fragment_sequence, child);
}

void Node_dbg::alloc_coverage_quality(const int nb){
    fragment->alloc_coverage_quality(nb);                                         
}

extern char keyi2nucleotide_array ['T'+1]; // commons.cpp

/**
 * Given a read fully mapped on a node, being longer both left and right, this functions stores in the node (in the inout array) the incomming and outgoing edges.
 * This array inout, for a given in (0 for A, 1 for C, 2 for G and 3 for T) has values:
 * -2 if multiple out possibilities exist for a given "in"
 * -1 if not filled
 * i = 0 for A, 1 for C, 2 for G and 3 for T if a unique output is feasible for a in value.
 */
void Node_dbg::populate_in_and_out(const char incoming_char, const char outgoing_char){
    
    // HOW TO CALL THIS FUNCTION ?
    // We only considere edges entering in foward in the node.
    // Simple case: the node is considered as forward:
    //      ************************** Node
    //  ----------------------------------- Read
    //      ------------------------------- mapped_read (called mapped_next_fragment in the calling function)
    //     ° (in =mapped_read[-1])
    //                                ° (out=mapped_read[|node|)
    // A bit more complex case: the node is considered as reverse complement, we do the same thing considering that it was the reverse complement of the read that mapped, which generates this situation:
    //      ************************** Node
    //  ----------------------------------- Read
    //      ------------------------------- mapped_read
    //     °(reverse of out)          °(reverse of in)
    //          (=mapped_read[-1])        (=mapped_read[|node|])
    
    if(inout[keyi2nucleotide_array[incoming_char]]==-1) { // this input was never seen
        inout[keyi2nucleotide_array[incoming_char]] = keyi2nucleotide_array[outgoing_char]; // we set the new value
        return;
    }
    if(inout[keyi2nucleotide_array[incoming_char]]==-2) return; // already multiple outputs for this input
    if(inout[keyi2nucleotide_array[incoming_char]] == keyi2nucleotide_array[outgoing_char]) return; // this couple in/out was already seen
    if(inout[keyi2nucleotide_array[incoming_char]] != keyi2nucleotide_array[outgoing_char]){ // another ougoing was seen before for this incomming
        inout[keyi2nucleotide_array[incoming_char]] = -2; // multiple outputs for this input.
        return;
    }
}


//////////////////// EDGE /////////////////
void Edge_dbg::alloc_coverage(const int nb){
    
#ifdef CHARQUAL
    coverage = (char *) malloc (sizeof(char)*nb);
#else
    coverage = (int *) malloc (sizeof(int)*nb);
#endif
    for(int i=0;i<nb;i++) coverage[i]=0;
}

//////////////////// DEBRUIJNGRAPH /////////////////
/**
 * Loads a new de bruijn graph from a json file
 */
DBG::DBG(){
    seeds_count = hash_create_binarykey(100000);  	test_alloc(seeds_count);
}

void DBG::alloc_coverage_quality(const int nb){
    for(int i=0;i<all_nodes.size();i++){
        all_nodes[i]->alloc_coverage_quality(nb);
        for(int edge_id=0;edge_id<all_nodes[i]->edges.size();edge_id++)
            all_nodes[i]->edges[edge_id]->alloc_coverage(nb);
    }
}

void DBG::output_graph(FILE * out, const int nb_read_files){
    fprintf(out,"{\n\"nodes\": [\n");
    
    // NODES
    for(int i=0;i<all_nodes.size();i++){
        fprintf(out,"{ \"data\": { \"id\": %d, \"sequence\": \"%s\"",i, all_nodes[i]->fragment->fragment_sequence);
        
        for(int id_file=0;id_file<nb_read_files;id_file++) {
            fprintf(out,", \"coverage_file_%d\": \"", id_file+1);
//            for(int j=0;j<strlen(all_nodes[i]->fragment->fragment_sequence);j++)
//                fprintf(out,"%d ",all_nodes[i]->fragment->coverage[id_file][j]);
            fprintf(out,"\"");
        }
        // TEMP
        for(int j=0;j<4;j++) if(all_nodes[i]->inout[j]>-1) fprintf(out,"\n, enter %d, out %d\n", j, all_nodes[i]->inout[j]);
        // END TEMP
        if(i!=all_nodes.size()-1) fprintf(out," }},\n"); else fprintf(out," }}\n");
    }
  
    fprintf(out,"],\n\"edges\": [\n");
    
    // EDGES
    for(int i=0;i<all_nodes.size();i++){
        for(int edge_id=0;edge_id<all_nodes[i]->edges.size();edge_id++){
            fprintf(out,"{ \"data\":{ \"source\": %d,\"target\": %d,\"direction\":",i,all_nodes[i]->edges[edge_id]->to->node_id);
            switch (all_nodes[i]->edges[edge_id]->my_label) {
                case 0:
                    fprintf(out," \"ff\"");
                    break;
                    
                case 1:
                    fprintf(out," \"rr\"");
                    break;
                    
                case 2:
                    fprintf(out," \"fr\"");
                    break;
                    
                case 3:
                    fprintf(out," \"rf\"");
                    break;
                    
                default:
                    break;
            }
            // TODO: output edges coverage.
//            for(int id_file=0;id_file<nb_read_files;id_file++)
//                fprintf(out,", \"coverage_file_%d\": \"%d\"", id_file+1, all_nodes[i]->edges[edge_id]->coverage[i]);
            if(i!=all_nodes.size()-1) fprintf(out,"}},\n"); else fprintf(out,"}}\n");

        }
        
        
    }
    
    fprintf(out,"]}\n");
}

///////// DEALING WITH THE BOOLEAN VECTOR USED FOR MARKING THE NODES /////////
void DBG::init_boolean_vector(){
    long sum=0;
    for (int i=0;i<all_nodes.size();i++){
        all_nodes[i]->starting_id_in_the_boolean_vector=sum;
        sum+=strlen(all_nodes[i]->fragment->fragment_sequence);
    }
     bv = new BooleanVector(sum);
}

/**
 * test if a position has already been tested (for instance an anchoring position of a mapped read)
 */
bool DBG::position_already_tested(Node_dbg* node, int pos){
    return bv->is_boolean_vector_visited(node->starting_id_in_the_boolean_vector+pos);
}

/**
 * set a position has already been tested (for instance an anchoring position of a mapped read)
 */
void DBG::position_tested(Node_dbg* node, int pos){
    bv->set_boolean_vector_visited(node->starting_id_in_the_boolean_vector+pos);
}


///////// SEVERAL TRAVERSALS /////////
void DBG::depth_first_from(Node_dbg * current_node, bool forward, int indent){
    if(!current_node) return;
    printf("-- level %d --", indent); for(int i=0;i<indent;i++) printf("\t");
    if(forward)
        printf("%s", current_node->fragment->fragment_sequence);
    else
        print_rev_comp(current_node->fragment->fragment_sequence);
    printf("\n");
    if(current_node->visited) return;
    current_node->visited=true;
    for(int i=0;i<current_node->edges.size();i++){
        if(forward){
            if(current_node->edges[i]->my_label==0) depth_first_from(current_node->edges[i]->to, true, indent+1); // F following FF
            else if(current_node->edges[i]->my_label==2) depth_first_from(current_node->edges[i]->to, false, indent+1); // F following FR
        }
        else{
            if(current_node->edges[i]->my_label==1) depth_first_from(current_node->edges[i]->to, false, indent+1); // R following RR
            else if(current_node->edges[i]->my_label==3) depth_first_from(current_node->edges[i]->to, true, indent+1); // R following RF
        }
    }
}

void DBG::depth_first_print(){
    
    // Right extensions of the root
    printf("Right extensions\n");
    for (int i=0;i<all_nodes.size();i++)
        if(!all_nodes[i]->visited){
            depth_first_from(all_nodes[i], true, 0);
        }
    clear_visited();
    printf("Left extensions\n");
    // left extensions of the root
    for (int i=0;i<all_nodes.size();i++)
        if(!all_nodes[i]->visited){
            depth_first_from(all_nodes[i], false, 0);
        }
    clear_visited();
}




//////////////////////////////// CHECKING THE GRAPH ///////////////////////////////

void DBG::depth_first_check_rec(Node_dbg * current_node, bool forward){
    if(!current_node) return;
    if(current_node->visited) return;
    current_node->visited=true;
    
    
    char  * last_kmonemer;
    if(forward){
        last_kmonemer= strndup(current_node->fragment->fragment_sequence+strlen(current_node->fragment->fragment_sequence)-size_seeds+1, size_seeds-1);
        //    printf("FORWARD last %d-mer of %s = %s\n", size_seeds-1, current_node->fragment->fragment_sequence, last_kmonemer);
    }
    else{
        last_kmonemer= strndup(current_node->fragment->fragment_sequence, size_seeds-1);
        revcomp(last_kmonemer, size_seeds-1);
        //    printf("REVERSE last %d-mer of ", size_seeds-1);
        //    print_rev_comp(current_node->fragment->fragment_sequence);
        //    printf(" = %s\n", last_kmonemer);
    }
    
    for(int i=0;i<current_node->edges.size();i++){
        // check.
        char  * first_kmonemer;
        char * target_sequence = current_node->edges[i]->to->fragment->fragment_sequence;
        //    printf("%c%c\n", forward?'F':'R', (current_node->edges[i]->my_label==0 || current_node->edges[i]->my_label==3)?'F':'R');
        if((forward && current_node->edges[i]->my_label==0) || (!forward && current_node->edges[i]->my_label==3)){ // (XF --FF--> || XR --RF-->)
            first_kmonemer = strndup(target_sequence, size_seeds-1);
            if(strcmp(last_kmonemer,first_kmonemer)){
                printf("Two nodes linked with k-1-mers \n\t%s and \n\t\%s\n should not be linked, exit\n", last_kmonemer,first_kmonemer);
                exit(1);
            }
            free(first_kmonemer);
        }
        if((forward && current_node->edges[i]->my_label==2) || (!forward && current_node->edges[i]->my_label==1)) {// (XF --FR--> || XR --RR-->)
            first_kmonemer = strndup(target_sequence+strlen(target_sequence)-size_seeds+1, size_seeds-1);
            revcomp(first_kmonemer, size_seeds-1);
            if(strcmp(last_kmonemer,first_kmonemer)){
                printf("Two nodes linked with k-1-mers \n\t%s and \n\t\%s\n should not be linked, exit\n", last_kmonemer,first_kmonemer);
                exit(1);
            }
            free(first_kmonemer);
        }
        // continue
        if(forward){
            if(current_node->edges[i]->my_label==0) 	depth_first_check_rec(current_node->edges[i]->to, true); // F following FF
            else if(current_node->edges[i]->my_label==2) depth_first_check_rec(current_node->edges[i]->to, false); // F following FR
        }
        else{
            if(current_node->edges[i]->my_label==1) depth_first_check_rec(current_node->edges[i]->to, false); // R following RR
            else if(current_node->edges[i]->my_label==3) depth_first_check_rec(current_node->edges[i]->to, true); // R following RF
        }
    }
    free(last_kmonemer);
    
}



void DBG::depth_first_check(){
    printf("Checking the graph integrity\n");
    
    // Right extensions of the root
    printf("Right extensions\n");
    for (int i=0;i<all_nodes.size();i++)
        if(!all_nodes[i]->visited){
            depth_first_check_rec(all_nodes[i], true);
        }
    clear_visited();
    printf("Left extensions\n");
    // left extensions of the root
    for (int i=0;i<all_nodes.size();i++)
        if(!all_nodes[i]->visited){
            depth_first_check_rec(all_nodes[i], false);
        }
    clear_visited();
    
    printf(" ... Success\n");
}

void DBG::clear_visited(){
    for (int i=0;i<all_nodes.size();i++) all_nodes[i]->visited=false;
}

////////////////////// INDEXING ////////////////////

void DBG::count_seeds(char * fragment, const int first_non_indexed){
    int size_fragment=strlen(fragment);
    //   printf("counting in %s from %d to %d\n", fragment, first_non_indexed, size_fragment);
    
    char seed [size_seeds+1];
    int stop = size_fragment-size_seeds+1;
    for (int i=first_non_indexed;i<stop;i++){ // each kmer
        int validSeed=1;
        for(int j=0;j<size_seeds;j++) {
            seed[j]=fragment[i+j];// read the seed
            if(!valid_character(seed[j])){validSeed=0; break;}
        }
        if(validSeed) {
            seed[size_seeds]='\0';
//            printf("incrementing for seed %s\n", seed);
            hash_incr_kmer_count(seeds_count,seed);
            total_seeds++;
        }
    } // end each kmer
}



void DBG::index_a_fragment(const char * fragment, const int fragment_id, const int starting_position, const int first_non_indexed){
    int size_fragment=strlen(fragment);
    char seed [size_seeds+1];
    int stop = size_fragment-size_seeds+1;
    for (int i=first_non_indexed;i<stop;i++){ // each kmer
        int validSeed=1;
        for(int j=0;j<size_seeds;j++) {
            seed[j]=fragment[i+j];// read the seed
            if(!valid_character(seed[j])){validSeed=0; break;}
        }
        if(validSeed) {
            seed[size_seeds]='\0';
//            printf("indexing seed %s fragm %s (from %d) pos %d\n", seed, fragment, fragment_id,i+starting_position); // DEB
            hash_fill_kmer_index(seeds_count,seed,seed_table, fragment_id, i+starting_position);
          
//            // DEBUG
//            uint64_t offset_seed; // DEB
//            uint64_t nb_seeds; // DEB
//            if(get_seed_info(seeds_count,seed,&offset_seed,&nb_seeds)){ // DEB
//                nb_seeds++;
//                for (int ii=offset_seed; ii<offset_seed+nb_seeds; ii++) { //DEB
//                    couple * value = &(seed_table[ii]); // DEB
//                    Node_dbg* node = all_nodes[value->a]; // DEB
//                    printf("ii=%d seed %s occurs position %d on %s\n", ii, seed, value->b, node->fragment->fragment_sequence); // DEB
//                }
//            } // DEB
//            else // DEB
//                printf("FAIL\n");
//            // ENDDEBUG
        }
    } // end each kmer
}

//void DBG::last_seeds_rec(const Node_dbg * current_node,
//                         const bool forward,
//                         char * last_kmers,
//                         int size_last_kmers,
//                         const bool index,
//                         const int fragment_id,
//                         const int starting_position){
//    
//    int first_non_indexed=size_last_kmers-size_seeds+1;
//    //  printf("for non indexed in %s pos %d linked with %s %s\n", last_kmers, first_non_indexed, current_node->fragment->fragment_sequence, forward?"Forward":"Reverse");
//    int n = strlen(current_node->fragment->fragment_sequence);
//    // stores the last k-1 mer of the node
//    if(forward)
//        for(int i=size_seeds-1; size_last_kmers<(2*size_seeds)-1 && i<n;i++)
//            last_kmers[size_last_kmers++]=current_node->fragment->fragment_sequence[i];
//    else
//        for(int i=size_seeds-1; size_last_kmers<(2*size_seeds)-1 && i<n;i++)
//            last_kmers[size_last_kmers++]=current_node->fragment->fragment_sequence[n-i-1];
//    
//    
//    last_kmers[size_last_kmers]='\0';
//    if(!index)count_seeds(last_kmers, first_non_indexed);
//    else index_a_fragment(last_kmers, fragment_id, starting_position, first_non_indexed);
//    
//    if(size_last_kmers==(2*size_seeds)-1){
//        return;
//    }
//    
//    for(int i=0;i<current_node->edges.size();i++){
//        if(forward){
//            if(current_node->edges[i]->my_label==0)  last_seeds_rec(current_node->edges[i]->to, true, last_kmers, size_last_kmers, index, fragment_id, starting_position); // F following FF
//            else if(current_node->edges[i]->my_label==2)  last_seeds_rec(current_node->edges[i]->to, false, last_kmers, size_last_kmers, index, fragment_id, starting_position); // F following FR
//        }
//        else{
//            if(current_node->edges[i]->my_label==1)  last_seeds_rec(current_node->edges[i]->to, false, last_kmers, size_seeds-1, index, fragment_id, starting_position); // R following RR
//            else if(current_node->edges[i]->my_label==3)  last_seeds_rec(current_node->edges[i]->to, true, last_kmers, size_seeds-1, index, fragment_id, starting_position); // R following RF
//        }
//    }
//    
//}
//
///**
// * Given a current node (always in forward) get all possible extensions of size k-1, and index all kmers overlapping this node and its childs
// */
//void DBG::last_seeds(const Node_dbg * current_node, const bool index, const int fragment_id){
//    //  printf("Last seeds for %s\n", current_node->fragment->fragment_sequence);
//    char last_kmers [2*size_seeds]; // size of this fragment: 2k-1 (so alloc 2k for \0)
//    int n = strlen(current_node->fragment->fragment_sequence);
//    int starting_position=n-size_seeds+1; // the starting position is the position of the last k-1 mer of the fragment
//    assert(starting_position>-1);
//    int size_last_kmers=0; //
//    for(int i=starting_position;i<n;i++) {
//        //    fprintf(stderr,"%d %d i=%d (%d) \n%s\n", size_last_kmers, (2*size_seeds)-1, i, n, current_node->fragment->fragment_sequence); // DEB
//        last_kmers[size_last_kmers++]=current_node->fragment->fragment_sequence[i]; // stores the last k-1 mer of the node
//    }
//    last_kmers[size_last_kmers]='\0';
//    for(int i=0;i<current_node->edges.size();i++){
//        if(current_node->edges[i]->my_label==0)
//            last_seeds_rec(current_node->edges[i]->to, true, last_kmers, size_last_kmers, index, fragment_id, starting_position); // F following FF
//        else if(current_node->edges[i]->my_label==2)
//            last_seeds_rec(current_node->edges[i]->to, false, last_kmers, size_last_kmers, index, fragment_id, starting_position); // F following FR
//    }
//}

void DBG::index_nodes(){
    
    char * fragment;
    int size_fragment;
    total_seeds = 0 ;
    
    // FIRST COUNT THE NUMBER OF OCCURRENCES OF EACH SEED
    for( int i=0; i<all_nodes.size();i++){
        fragment = all_nodes[i]->fragment->fragment_sequence;
        count_seeds(fragment, 0);
//        last_seeds(all_nodes[i], false, i);
    } // end each fragment
    printf("total seeds in fragments %lli  size %lli MB \n",total_seeds,total_seeds*sizeof(couple)/1024LL/1024LL);
    
    seed_table = (couple *) calloc(total_seeds,sizeof(couple));    test_alloc(seed_table);
    iterate_and_fill_offsets(seeds_count);
    
    // NOW FILL THE INFORMATION ABOUT EACH SEED
    for( int i=0; i<all_nodes.size();i++){
        fragment = all_nodes[i]->fragment->fragment_sequence;
        index_a_fragment(fragment, i, 0, 0);
//        last_seeds(all_nodes[i], true, i);
    } // end each fragment
    
    
//    for(int i=0;i<total_seeds;i++) printf("%d %d_%d \n", i,seed_table[i].a, seed_table[i].b);
//    exit(0);
}

////////////////////// MAP SEQUENCES ////////////////////



/**
 *  | pwi (may be negative)
 *     --------------  dbg node
 *  *************      mapped fragment
 *
 *  Tests if the overlapping part between read and fragment do not have more than <code>subst_allowed</code> substitions
 *  returns 1 if true between read and fragment, 0 else
 */
int  DBG::number_of_substitutions(const int pwi, const char * node_sequence, const char * mapped_fragment, const int max){
	int substitution_seen=0; // number of seen substitutions for now
    
	int pos_on_mapped_fragment, pos_on_node; // where to start
    
    
    
	/*
	 *  | pwi (negative)
	 *     --------------  node_sequence
	 *  *************      mapped_fragment
	 *     | we start here
	 */
	if(pwi<0) {
		pos_on_node=0;
		pos_on_mapped_fragment=-pwi;
	}
    
	/*
	 *        | pwi (positive)
	 *     --------------  node_sequence
	 *        *************      mapped_fragment
	 *        | we start here
	 */
	else{
		pos_on_node=pwi;
		pos_on_mapped_fragment=0;
        
	}
    
    
	// walk the mapped_fragment and the fragment together, detecting substitutions.
	// stop if the number of substitution is too high
	while(node_sequence[pos_on_node]!='\0' && mapped_fragment[pos_on_mapped_fragment]!='\0'){
		if(node_sequence[pos_on_node]!=mapped_fragment[pos_on_mapped_fragment] && node_sequence[pos_on_node]!='*' && node_sequence[pos_on_node]!='?' && node_sequence[pos_on_node]!='N'){ // one subsitution
			substitution_seen++;
            if(substitution_seen>max) return substitution_seen;
		}
		pos_on_node++;
		pos_on_mapped_fragment++;
	}
    
    
	return substitution_seen;
}


/*
 *  | pwi (negative)
 *     --------------  node_sequence
 *  *************      mapped_fragment
 *     | we start here
 */



/*
 *        | pwi (positive)
 *     --------------  node_sequence
 *        *************      mapped_fragment
 *        | we start here
 */

/**
 * maps a fragment to a node: check that no substitution exist while mapping the fragment to this node.
 * If the fragment is bigger (right) than the node, find a path for which the fragment may be mapped without substitution. If exist, return true, else return ... false.
 */
bool DBG::map_strictly_right_a_fragment(const int pwi, const Node_dbg * node, const char * mapped_fragment, bool forward){
    // map the fragment to the current node
    char * test_ref_sequence = node->fragment->fragment_sequence;
    if(!forward) revcomp(test_ref_sequence,strlen(test_ref_sequence)); // if the target is reverse, change the direction
    int subst_cur=number_of_substitutions(pwi,test_ref_sequence,mapped_fragment);
    if(!forward) revcomp(test_ref_sequence,strlen(test_ref_sequence)); // change back the direction to retreive the original one
    if(subst_cur>0) return false;
    
    // test if the whole fragment was mapped on the right
    if(pwi+strlen(mapped_fragment)<=strlen(node->fragment->fragment_sequence)) return true; // all the fragment was mapped
    
    // else we need to explore the right children
    const Node_dbg * current_node = node;
    const char * next_fragment = mapped_fragment+strlen(node->fragment->fragment_sequence)-pwi; // shift the mapped fragment on the right
    do {
        // find the right next node.
        bool found=false; // set to true if a valid next node exists, having the next fragment correctly mapped on it
        for(int child_id=0;child_id<current_node->edges.size();child_id++) {// try all children
            bool next_forward=false; // initialized for valgrind, but useless
            
            if(forward){
                if(current_node->edges[child_id]->my_label==0) 	next_forward = true; // F following FF
                else if(current_node->edges[child_id]->my_label==2) next_forward = false; // F following FR
                else continue; // we cannot continue one this son, path would be non valid
                
            }
            else{
                if(current_node->edges[child_id]->my_label==1) next_forward = false; // R following RR
                else if(current_node->edges[child_id]->my_label==3) next_forward = true; // R following RF
                else continue; // we cannot continue one this son, path would be non valid
            }
            
            
            test_ref_sequence = current_node->edges[child_id]->to->fragment->fragment_sequence;
            if(!next_forward) revcomp(test_ref_sequence,strlen(test_ref_sequence));
            if(number_of_substitutions(size_seeds-1,test_ref_sequence,next_fragment)==0){
                found=true; // the fragment was correctly mapped

                if(strlen(next_fragment)+size_seeds-1<=strlen(test_ref_sequence)){
                    if(!next_forward) revcomp(test_ref_sequence,strlen(test_ref_sequence)); // get back to the right direction
                    return true; // all the mapped fragment was mapped
                }
                // TODO: here populate the graph information: coverage, quality, ...
                next_fragment = next_fragment+strlen(test_ref_sequence)-size_seeds+1; // shift the mapped fragment
                current_node = current_node->edges[child_id]->to; // advance in the graph
                forward = next_forward; // are we in current node in forward ?
                if(!next_forward) revcomp(test_ref_sequence,strlen(test_ref_sequence)); // get back to the right direction
                break; // no need to explore other children
            }
            if(!next_forward) revcomp(test_ref_sequence,strlen(test_ref_sequence)); // get back to the right direction
        } // try all child. If one maps perfectly, we stop on it.
        if(!found) return false; // it was not possible to go on
    }while(true);
    
    return false;
    // FIXME: should never come here
}

/**
 * maps a fragment to a node: check that no substitution exist while mapping the fragment to this node.
 * If the fragment is bigger (left and right) than the node, find a path for which the fragment may be mapped without substitution. If exist, return true, else return ... false.
 */
bool DBG::map_strictly_a_fragment(const int pwi, const Node_dbg * node, char * mapped_fragment){
    
    // RIGHT PART: easy:
    if(!map_strictly_right_a_fragment(pwi,node,mapped_fragment,true)) return false;
    
    
    // LEFT PART: map the reverse complement of the mapped_fragment to the reverse complement of the node
    // in this case we change the pwi value: eg.
    //       ATCGATACCA  ref
    //    TCAATCGAT      mapped_fragment
    //    <-> pwi = -3
    // now get the reverse of both:
    //       TGGTATCGAT       /ref
    //           ATCGATTGA    /mapped_fragment
    //       <--> /pwi = -4 = 10-9-(-3) = strlen(ref)-strlen(mapped_fragment)-pwi
    
    revcomp(mapped_fragment, strlen(mapped_fragment));
    bool res_left = map_strictly_right_a_fragment(strlen(node->fragment->fragment_sequence)-strlen(mapped_fragment)-pwi,
                                                  node, mapped_fragment,false);
    revcomp(mapped_fragment, strlen(mapped_fragment)); // put back the right order
    if(res_left) return true;
    return false;
    
    
}

#ifdef CHARQUAL
#define INC(a)  ((a == 0xFF ) ? 0xFF : a++)
#else
#define INC(a) (a++)
#endif


////////////////////// Populate results ////////////////////

void DBG::populated_coverage(const int read_file_id, const int pwi, const Node_dbg * node, const bool forward, const int read_size, bool overlapped_node){
    printf("pwi = %d forward=%s overlap=%s\n", pwi, forward?"true":"false", overlapped_node?"true":"false");
    //assert(pwi>=0); // pwi must be positive

    // First case: forward=true overlapped_node=false
    // pwi >=0:
    //         -------- node
    //            ***     read_size (may be bigger than the node)
    //        +00011100
    
    // Second case: forward=true overlapped_node=true. In this case the read starts with pwi=size_seeds-1 (avoids the overlapping k-1 mer of the node). However, this overlapping part should also be incremented
    // pwi==(size_seeds-1)
    //         ---------------- node
    //              *******  read_size (may be bigger than the node)
    //         <---> size_seeds-1
    //        +1111111111110000
    
    // Cases forward=false (overlapped_node=true or false): same cases but invert sequence.
    const int stop=strlen(node->fragment->fragment_sequence);
    
    // first case
    if(forward && !overlapped_node){
        for(int i=MAX(pwi,0);i<stop && i<pwi+read_size;i++) INC(node->fragment->coverage[read_file_id][i]);
        return;
    }
    
    
    // Second case
    if(forward && overlapped_node){
        assert(pwi==size_seeds-1);
        for(int i=0;i<stop && i<pwi+read_size;i++) INC(node->fragment->coverage[read_file_id][i]);
        return;
    }
    
    // first case !forward
    if(!forward && !overlapped_node){
        for(int i=MAX(pwi,0);i<stop && i<pwi+read_size;i++) INC(node->fragment->coverage[read_file_id][stop-i-1]);
        return;
    }
    
    
    // Second case !forward
    if(!forward && overlapped_node){
        assert(pwi==size_seeds-1);
        for(int i=0;i<stop && i<pwi+read_size;i++) INC(node->fragment->coverage[read_file_id][stop-i-1]);
        return;
    }
    
    
}

/**
 * maps a fragment to a node: knowing that it maps (function map_strictly_a_fragment should have returned true before to call this function).
 * Populates the graph with coverage and quality (quality=todo)
 */
bool DBG::populate_right(const int pwi, const Node_dbg * node, const char * mapped_fragment, bool forward, int read_file_id){
    // map the fragment to the current node
    
    char * test_ref_sequence = node->fragment->fragment_sequence;
    if(!forward) revcomp(test_ref_sequence,strlen(test_ref_sequence)); // if the target is reverse, change the direction
    int subst_cur=number_of_substitutions(pwi,test_ref_sequence,mapped_fragment);
    if(!forward) revcomp(test_ref_sequence,strlen(test_ref_sequence)); // change back the direction to retreive the original one
    if(subst_cur>0) return false;
    
    
    
    
    // test if the whole fragment was mapped on the right
    if(pwi+strlen(mapped_fragment)<=strlen(node->fragment->fragment_sequence)) {
        // the populate of the starting node is done once, in the populate function
        return true; // all the fragment was mapped
    }
    // else we need to explore the right children
    const Node_dbg * current_node = node;
    const char * next_fragment = mapped_fragment+strlen(node->fragment->fragment_sequence)-pwi; // shift the mapped fragment on the right
    const char * next_mapped_fragment = next_fragment-size_seeds+1;  // for clearer code
    char inChar, outChar;
    do {
        // find the right next node.
        bool found=false; // set to true if a valid next node exists, having the next fragment correctly mapped on it
        for(int child_id=0;child_id<current_node->edges.size();child_id++) {// try all children
            bool next_forward=false; // initialized for valgrind, but useless
            
            if(forward){
                if(current_node->edges[child_id]->my_label==0) 	next_forward = true; // F following FF
                else if(current_node->edges[child_id]->my_label==2) next_forward = false; // F following FR
                else continue; // we cannot continue one this son, path would be non valid
                
            }
            else{
                if(current_node->edges[child_id]->my_label==1) next_forward = false; // R following RR
                else if(current_node->edges[child_id]->my_label==3) next_forward = true; // R following RF
                else continue; // we cannot continue one this son, path would be non valid
            }
            test_ref_sequence = current_node->edges[child_id]->to->fragment->fragment_sequence;
            
            
            if(!next_forward) revcomp(test_ref_sequence,strlen(test_ref_sequence));
            if(number_of_substitutions(size_seeds-1,test_ref_sequence,next_fragment)==0){
                found=true; // the fragment was correctly mapped
                INC(current_node->edges[child_id]->coverage[read_file_id]);
                populated_coverage(read_file_id,size_seeds-1,current_node->edges[child_id]->to,next_forward,strlen(next_fragment),true);
                if(strlen(next_mapped_fragment)>strlen(test_ref_sequence)){ // if the mapped read is longer than the sequence in the node, we populate inout
                    // generating in and out chars
                    inChar = *(next_mapped_fragment-1); // ingoing char
                    outChar = *(next_mapped_fragment+strlen(test_ref_sequence)); // outgoing char
                    current_node->edges[child_id]->to->populate_in_and_out(inChar,outChar);
                }
                
                if(strlen(next_fragment)+size_seeds-1<=strlen(test_ref_sequence)){
                    if(!next_forward) revcomp(test_ref_sequence,strlen(test_ref_sequence)); // get back to the right direction
                    return true; // all the mapped fragment was mapped
                }
                // TODO: here populate the graph information: coverage, quality, ...
                next_fragment = next_fragment+strlen(test_ref_sequence)-size_seeds+1; // shift the mapped fragment
                next_mapped_fragment = next_fragment-size_seeds+1; // for clearer code
                current_node = current_node->edges[child_id]->to; // advance in the graph
                forward = next_forward; // are we in current node in forward ?
                if(!next_forward) revcomp(test_ref_sequence,strlen(test_ref_sequence)); // get back to the right direction
                break; // no need to explore other children
            }
            if(!next_forward) revcomp(test_ref_sequence,strlen(test_ref_sequence)); // get back to the right direction
        } // try all child. If one maps perfectly, we stop on it.
        if(!found) return false; // it was not possible to go on
    }while(true);
    
    return false;
    // FIXME: should never come here
}

/**
 * maps a fragment to a node: knowing that it maps (function map_strictly_a_fragment should have returned true before to call this function).
 * Populates the graph with coverage and quality (quality=todo)
 */
bool DBG::populate(const int pwi, const Node_dbg * node, char * mapped_fragment, int read_file_id){
    
    // RIGHT PART: easy:
    assert(populate_right(pwi,node,mapped_fragment,true, read_file_id));
    
    
    // LEFT PART: map the reverse complement of the mapped_fragment to the reverse complement of the node
    // in this case we change the pwi value: eg.
    //       ATCGATACCA  ref
    //    TCAATCGAT      mapped_fragment
    //    <-> pwi = -3
    // now get the reverse of both:
    //       TGGTATCGAT       /ref
    //           ATCGATTGA    /mapped_fragment
    //       <--> /pwi = -4 = 10-9-(-3) = strlen(ref)-strlen(mapped_fragment)-pwi
    
    revcomp(mapped_fragment, strlen(mapped_fragment));
    bool res_left = populate_right(strlen(node->fragment->fragment_sequence)-strlen(mapped_fragment)-pwi,
                                                  node, mapped_fragment,false, read_file_id);
    revcomp(mapped_fragment, strlen(mapped_fragment)); // put back the right order
    assert(res_left);
    
    // populate the starting node, once
    populated_coverage(read_file_id,pwi,node,true,strlen(mapped_fragment),false);
    return true;
    
    
}

void DBG::duplicate_one_simple_node(Node_dbg * current, char in, char out){
    if(current->edges.size()<3) return; // don't duplicate a node having only one ingoing and one outgoing edge
    // Find the node "from" that ended with the character "in" at position len-k
    //   012345
    //   ******
    //     °<-> k-1 = 3 :: 2 = len(******)-4-k = 6-4 = len-k
    // Finding the good entering edge (fromToCurrent):
    //    -------  ->   -------   fromToCurrent_edge
    //   | from  |     |current|  
    //    -------  <-   -------   currentToFrom_edge
    // From each node "from", find the edge going to "current", get the last character before the branching (position len-k),
    //   * either on the direct strand if the edge from "from" to "current" starts with "F"
    //   * or on the reverse complemented strand if it starts with "R"
    Node_dbg * from;
    Edge_dbg * fromToCurrent_edge;
    Edge_dbg * currentToFrom_edge;    bool found = false;
    int from_id;
    
    // much easier
    // Find the "to" that started with the "out" letter
    //    -------  ->   -------   currentToTo_edge
    //   |current|     |   to  |
    //    -------  <-   -------   toToCurrent_edge
    
    Node_dbg * to; // easy
    Edge_dbg * toToCurrent_edge; // must search in all "to" edges, the one targetting "current"
    Edge_dbg * currentToTo_edge; // easy
    int to_id;
    
    
    for(int current_mapped_strand=0;!found && current_mapped_strand<2;current_mapped_strand++){ // consider that the node may have been mapped once in the direct direction, and once in the reverse
        char last=-1;
        for(from_id=0;from_id<current->edges.size() && !found;from_id++){
            from = current->edges[from_id]->to;
            for(int from_child_id=0;from_child_id<from->edges.size() && !found; from_child_id++){
                if(from->edges[from_child_id]->to == current){ // this edge goes to "current"
                    // 0=FF, 1=RR, 2=FR, 3=RF
                    if(current_mapped_strand==0){ // consider that we mapped the node in forward strand
                        if(from->edges[from_child_id]->my_label==0) // leaves in forward to target the forward
                            last = from->fragment->fragment_sequence[strlen(from->fragment->fragment_sequence)-size_seeds];
                        
                        else if(from->edges[from_child_id]->my_label==3) // leaves in reverse to target the forward
                            last = comp[from->fragment->fragment_sequence[size_seeds-1]];
                    } // end consider that we mapped the node in forward strand
                    else {
                        if(from->edges[from_child_id]->my_label==2) // leaves in forward to target the reverse
                            last = from->fragment->fragment_sequence[strlen(from->fragment->fragment_sequence)-size_seeds];
                        
                        else if(from->edges[from_child_id]->my_label==1) // leaves in reverse to target the reverse
                            last = comp[from->fragment->fragment_sequence[size_seeds-1]];
                    }
                    
                    if (last == in) { // we found the right edge from the right node entering with "in" in the "current" node...
                        found=true;
                        fromToCurrent_edge=from->edges[from_child_id];
                        currentToFrom_edge=current->edges[from_id];
                        break;
                    }
                    break; // we stop with this "to" node, no other outgoing edge will target "current" node.
                } // end this edge goes to "current"
            } // end try all outgoing edges of the "to" node looking for the "current" child node
        } // end the searching all "to" reachable nodes from the "current" node
        from_id--; // removing the last ++ to conserve the good id value, used latter.
        
        
        found = false;
        char first=-1;
        for(to_id=0;to_id<current->edges.size() && !found;to_id++){ // try all leaving edges
            to = current->edges[to_id]->to;
            // 0=FF, 1=RR, 2=FR, 3=RF
            printf(" --- %d --- \n", current->edges[to_id]->my_label);
            
            if(current_mapped_strand==0){ // consider that we mapped the node in forward strand
                if(current->edges[to_id]->my_label==0) // leaves in forward to target forward
                    first = to->fragment->fragment_sequence[size_seeds-1];
                else if(current->edges[to_id]->my_label==2) // leaves in forward to target reverse
                    first = comp[to->fragment->fragment_sequence[strlen(to->fragment->fragment_sequence)-size_seeds]];
            }
            else {// end consider that we mapped the node in forward strand                
                if(current->edges[to_id]->my_label==3) // leaves in reverse to target forward
                    first = to->fragment->fragment_sequence[size_seeds-1];
                else if(current->edges[to_id]->my_label==1) // leaves in reverse to target reverse
                    first = comp[to->fragment->fragment_sequence[strlen(to->fragment->fragment_sequence)-size_seeds]];
            }
            if (first == out) { // we found the right leaving node starting with the good branching char
                currentToTo_edge = current->edges[to_id];
                // find the good toToCurrent edge:
                for(int i=0;i<to->edges.size();i++) if(to->edges[i]->to == current) {
                    toToCurrent_edge = to->edges[i];
                    found = true;
                    break;
                } // end find the good toToCurrent edge:
            } // end we found the right leaving node starting with the good branching char
        } // end try all leaving edges
        to_id--; // removing the last ++ to conserve the good id value, used latter.
    }
    assert(found);

    // Now we know from where we came, and the two couples of edges, we can duplicate the node.
    // *** quite easy: create a new node "current_bis" from "current", storing the same info about fragment sequence only (rest is useless). ***
    Node_dbg * current_bis = new Node_dbg(current, all_nodes.size());
    all_nodes.push_back(current_bis); // add this new node to the whole set of nodes
    // *** link current node using only fromToCurrent_edge, currentToFrom_edge, currentToTo_edge and toToCurrent_edge edges ***
    // modify the previous target of edges linked to current being duplicated
    fromToCurrent_edge->to = current_bis;
    toToCurrent_edge->to = current_bis;
    
    // link the new created node to the "from" and the "to" nodes
    current_bis->add_child(currentToFrom_edge->to, currentToFrom_edge->my_label); // link the new node
    current_bis->add_child(currentToTo_edge->to, currentToTo_edge->my_label);
    
    // remove currentToFrom_edge from the "current"
    fprintf(stderr, "1\n");
    current->edges.erase(current->edges.begin()+max(to_id,from_id)); // remove the edges with the biggest id (this does not change the id of the smallest (I know, it simply cleaver).
    // remove currentToTo_edge from the "current"
    fprintf(stderr, "2\n");
    current->edges.erase(current->edges.begin()+min(to_id,from_id)); // and now revome the other one.
    fprintf(stderr, "3\n");
    
    // these edges are no more used
    delete(currentToTo_edge);
    delete(currentToFrom_edge);
}

/**
 * For each node that we can duplicate, we duplicate... 
 */
void DBG::duplicate_simple_nodes(){    
    
    int initial_size = all_nodes.size(); // as we duplicate nodes, we add some that are not well initialized
    for(int i=0;i<initial_size;i++){
        for(int car=0;car<4;car++){
            if(all_nodes[i]->inout[car]>-1){
                printf("duplicate node %s entering with %c leaving with %c(%d)\n", all_nodes[i]->fragment->fragment_sequence,nuc[car], nuc[all_nodes[i]->inout[car]],all_nodes[i]->inout[car]);
                duplicate_one_simple_node(all_nodes[i], nuc[car], nuc[all_nodes[i]->inout[car]]);
            }
        }
    }
}


