//
// 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

//#define DEBUG_DBG

//#define DEBUG_GRAPH_SIMPLIFICATION

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



Edge_dbg * get_reverse_edge(const Node_dbg * current, const Edge_dbg * outgoing){
    Node_dbg * to = outgoing->to;
//        printf("%d node to %d \n", current->node_id, to->node_id);
//        printf("from= %s\n", outgoing->to->fragment->fragment_sequence);
//        printf("%d \n", to->edges.size());
    for(int i=0;i<to->edges.size();i++){
//                printf("to = %s \n", to->edges[i]->to->fragment->fragment_sequence);
        if(to->edges[i]->to == current){
//            printf("%d and %d\n", outgoing->my_label, to->edges[i]->my_label);
            // check if the labels are coherents:
            // 0=FF, 1=RR, 2=FR, 3=RF
            if(outgoing->my_label==0 && to->edges[i]->my_label==1) return to->edges[i];
            if(outgoing->my_label==1 && to->edges[i]->my_label==0) return to->edges[i];
            if(outgoing->my_label==2 && to->edges[i]->my_label==2) return to->edges[i];
            if(outgoing->my_label==3 && to->edges[i]->my_label==3) return to->edges[i];
        }
    }
    fprintf(stderr,"Pb... a link from %d-%s to %d-%s exists (label %d), but not the contrary...\n", current->node_id, current->fragment->fragment_sequence, outgoing->to->node_id, outgoing->to->fragment->fragment_sequence, outgoing->my_label);
    assert(1==0); // we should never come here
}
void remove_couple_edges(Node_dbg * current, Edge_dbg * outgoing){
    Node_dbg * to = outgoing->to;
    //    printf("%d nodeto %d \n", current->node_id, to->node_id);
    //    printf("from= %s\n", outgoing->to->fragment->fragment_sequence);
    //    printf("%d \n", to->edges.size());
    int remove_edge_id=-1;
    for(int i=0;i<to->edges.size();i++){
        //        printf("to = %s \n", to->edges[i]->to->fragment->fragment_sequence);
        if(to->edges[i]->to == current){
            // check if the labels are coherents:
            // 0=FF, 1=RR, 2=FR, 3=RF
            if(outgoing->my_label==0 && to->edges[i]->my_label==1) {remove_edge_id=i; break;}
            if(outgoing->my_label==1 && to->edges[i]->my_label==0) {remove_edge_id=i; break;}
            if(outgoing->my_label==2 && to->edges[i]->my_label==2) {remove_edge_id=i; break;}
            if(outgoing->my_label==3 && to->edges[i]->my_label==3) {remove_edge_id=i; break;}
        }
    }
    
    if(remove_edge_id==-1){
        fprintf(stderr,"Pb... a link from %d-%s to %d-%s exists (label %d), but not the contrary...\n", current->node_id, current->fragment->fragment_sequence, outgoing->to->node_id, outgoing->to->fragment->fragment_sequence, outgoing->my_label);
        assert(1==0); // we should never come here
    }
    
    Edge_dbg * erase_me = to->edges[remove_edge_id];
    to->edges.erase(to->edges.begin()+remove_edge_id);
    delete(erase_me);
    
    
    // now remove the outgoing node
    for(int i=0;i<current->edges.size();i++){
        if(current->edges[i] == outgoing){
            current->edges.erase(current->edges.begin()+i);
            //            current->edges.erase(current->edges.begin()+i);
            delete(outgoing);
            break;
        }
    }
    
    
}

//////////////////// 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;
    left_pwi_to_distance_and_path_mapping=NULL;
    right_pwi_to_distance_and_path_mapping=NULL;
    this->node_id=node_id;
}

/**
 * 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;
}

Node_dbg::~Node_dbg(){
    delete(fragment);
    for(int i=0;i<edges.size();i++) delete(edges[i]);
    
}

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);
}


map< int, pair<int, Edge_dbg *> >* Node_dbg::get_map(const bool right){
    if(right) return right_pwi_to_distance_and_path_mapping;
    return left_pwi_to_distance_and_path_mapping;
}

void Node_dbg::create_map(const bool right){
    if(right)
        right_pwi_to_distance_and_path_mapping = new map< int, pair<int, Edge_dbg *> > ();
    else
        left_pwi_to_distance_and_path_mapping = new map< int, pair<int, Edge_dbg *> > ();
}

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 incomming edge the outgoing edge.
 */
void DBG::populate_in_and_out(Edge_dbg * incomming_edge, Edge_dbg *  outgoing_edge){
    //#define DEBUG_PHASING
//    check_all((char *)"entering pop in and out");
    
    if(!incomming_edge->doable) return; // already multiple outputs for this input
    
//    check_all((char *)"next in pop in and out");
    // this input is still valid: never seen or seen with a unique leaving edge
    if(incomming_edge->out_edge == NULL){ // first time this "in" is seen
        // we have to check that the reverse of the out_edge edge is either linked to the reverse of the incomming edge or NULL and doable. In this last case set also the reverse.
        
        // -- incomming_edge     --> ---- --out_edge-->
        // <- routgoing_out_edge --  |  |  <-rougoing --
        // <- rincomming         --  ----
        Edge_dbg * routgoing = get_reverse_edge(incomming_edge->to, outgoing_edge);
        if(!routgoing->doable){ // the reverse of outgoing cannot be linked, thus we remove it as doable
            incomming_edge->out_edge = NULL;
            incomming_edge->doable = false;
            
#ifdef  DEBUG_PHASING
            printf("out_edge not feasible as its symetrical is not doable, node %d\n", incomming_edge->to->node_id);
#endif
            
            return;
        }
        
        
        // this node was already traversed with a read entering with the reverse of the ougoing edge
        // but not being coherent with the current couple incomming / outgoing. Such a traversal is thus impossible
        if(routgoing->out_edge!=NULL && incomming_edge != get_reverse_edge(incomming_edge->to, routgoing->out_edge)) {
            routgoing->out_edge=NULL;
            routgoing->doable = false;
            incomming_edge->out_edge = NULL;
            incomming_edge->doable = false;
            
#ifdef  DEBUG_PHASING
            printf("node %d was already phased but with another couple of coherency...\n", incomming_edge->to->node_id);
#endif
            
            return;
        }
        
        
        // we are in a case where either this is the first time this node is traversed with a read, whatever the direction,
        // or it was already traversed but being coherent with the couple incomming / outgoing.
        incomming_edge->out_edge = outgoing_edge; // we set the new value
        // we also set the same symetrical value for the corresponding symetrical situation. This is indispensable in case of latter pahsing with a third node that would be done even if the pahsing is node fully done on the current node.
        // e.g. 1 is phased with the set 0-->1-->2. If latter, 1 is phased with 2-->1-->3, we need to avoid that this phasing is done.
        if(routgoing->out_edge==NULL)
            routgoing->out_edge=incomming_edge->find_reverse_edge();
        return;
    }
//    check_all((char *)"next2 in pop in and out");
    if(incomming_edge->out_edge == outgoing_edge) return; // already seen with this outgoing edge
    
    else { // we saw already this in char with another leaving edge, no inout simplification feasible
//        check_all((char *)"next3 in pop in and out");
#ifdef  DEBUG_PHASING
        printf("node going to %s(%d), was linked to %s(%d), but now we try to link it to %s(%d), so we avoid phasin\n",
               incomming_edge->to->fragment->fragment_sequence,
               incomming_edge->to->node_id,
               incomming_edge->out_edge->to->fragment->fragment_sequence,
               incomming_edge->out_edge->to->node_id,
               outgoing_edge->to->fragment->fragment_sequence,
               outgoing_edge->to->node_id);
#endif
        incomming_edge->out_edge = NULL;
        incomming_edge->doable = false;
        // also set the symetrical as non feasible.
        Edge_dbg * routgoing = get_reverse_edge(incomming_edge->to, outgoing_edge);
        routgoing->out_edge=NULL;
        routgoing->doable = false;
        
    }
//    check_all((char *)"end in pop in and out");
    
}


//////////////////// EDGE /////////////////

Edge_dbg * Edge_dbg::find_reverse_edge(){
    // 0=FF, 1=RR, 2=FR, 3=RF
    // go to all nodes reachable with a reverse of the current label:
    // 0->1, 1->0, 2->2, 3->3
    for(int i=0;i<to->edges.size();i++){
        if(my_label==0 && to->edges[i]->my_label==1 && get_reverse_edge(to, to->edges[i]) == this) return to->edges[i];
        if(my_label==1 && to->edges[i]->my_label==0 && get_reverse_edge(to, to->edges[i]) == this) return to->edges[i];
        if(my_label==2 && to->edges[i]->my_label==2 && get_reverse_edge(to, to->edges[i]) == this) return to->edges[i];
        if(my_label==3 && to->edges[i]->my_label==3 && get_reverse_edge(to, to->edges[i]) == this) return to->edges[i];
    }
    fprintf(stderr,"edge to %d (label %d) has no reverse\n", to->node_id, my_label);
    assert(1==0);
}

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

/**
 * Increases the coverage of an edge AND of its reverse complement
 */
void Edge_dbg::increase_coverage(const int read_file_id){
    INC(coverage[read_file_id]);
    INC(find_reverse_edge()->coverage[read_file_id]);
}
//////////////////// DEBRUIJNGRAPH /////////////////
/**
 * Loads a new de bruijn graph from a json file
 */
DBG::DBG(int size_reads){
    seeds_count = hash_create_binarykey(100000);  	test_alloc(seeds_count);
//    estimated_size_reads=50000;//size_reads;
//    printf("max read size estimated  = %d\n", estimated_size_reads);
}

DBG::~DBG(){
    for(int i=0;i<all_nodes.size();i++) delete all_nodes[i];
    // hash_free(seeds_count); // TODO
}
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::check_all(char * text){
    printf("\n testing %s ...\n", text);
    for(int i=0;i<all_nodes.size();i++){
        for(int edge_id=0;edge_id<all_nodes[i]->edges.size();edge_id++)
            get_reverse_edge(all_nodes[i], all_nodes[i]->edges[edge_id]);
        }
    return;
    for(int i=0;i<all_nodes.size();i++){
        for(int edge_id=0;edge_id<all_nodes[i]->edges.size();edge_id++)
            for(int j=0;j<strlen(all_nodes[i]->edges[edge_id]->to->fragment->fragment_sequence);j++)
                int afac=all_nodes[i]->edges[edge_id]->to->fragment->coverage[0][j];
    }
    printf("done\n");
}


/**
 * Used while loading a graph where nodes id are not consecutives.
 */
int DBG::node_id_to_node_number(int node_id){
    for(int node_number=0;node_number<all_nodes.size();node_number++)
        if(all_nodes[node_number]->node_id==node_id) return node_number;
    return -1;
}

/**
 * removes informations about all positions where a read mapped nodes
 */
void DBG::clear_mapped_nodes(){
    for(int i=0;i<current_mapped_nodes.size();i++){
        if(current_mapped_nodes[i]->left_pwi_to_distance_and_path_mapping!=NULL){
            current_mapped_nodes[i]->left_pwi_to_distance_and_path_mapping->clear();
            delete(current_mapped_nodes[i]->left_pwi_to_distance_and_path_mapping);
            current_mapped_nodes[i]->left_pwi_to_distance_and_path_mapping = NULL;
        }
        if(current_mapped_nodes[i]->right_pwi_to_distance_and_path_mapping!=NULL){
            current_mapped_nodes[i]->right_pwi_to_distance_and_path_mapping->clear();
            delete(current_mapped_nodes[i]->right_pwi_to_distance_and_path_mapping);
            current_mapped_nodes[i]->right_pwi_to_distance_and_path_mapping = NULL;
        }
    }
    current_mapped_nodes.clear();
}

void DBG::output_graph(FILE * out, const int nb_read_files, int& first_edge_id, bool consider_coverage, bool surrounded_by_braces){
    if(surrounded_by_braces)
        fprintf(out,"{\n");
    
    fprintf(out,"\"nodes\": [\n");
    // NODES
    for(int i=0;i<all_nodes.size();i++){
        fprintf(out,"{ \"data\": { \"id\": \"n%d\", \"sequence\": \"%s\"",all_nodes[i]->node_id, all_nodes[i]->fragment->fragment_sequence);
        if(consider_coverage){
            fprintf(out,", \"coverage\":[\n");
            for(int id_file=0;id_file<nb_read_files;id_file++) {
                float avg=0;
                for(int j=0;j<strlen(all_nodes[i]->fragment->fragment_sequence);j++){
                    avg+=all_nodes[i]->fragment->coverage[id_file][j];
//                                        fprintf(out,"%d ",all_nodes[i]->fragment->coverage[id_file][j]); // USELESS, TOREMOVE
                }
                avg/=(float)strlen(all_nodes[i]->fragment->fragment_sequence);
                fprintf(out,"\t\t{\n");
                fprintf(out,"\t\t\t\"id\":\"file_%d\",\n", id_file+1);
                fprintf(out,"\t\t\t\"avg_coverage\": %.2f\n", avg);
                fprintf(out,"\t\t}%s\n",id_file<nb_read_files-1?",":"");
            }
            
            fprintf(out,"]\n");
        }
        fprintf(out,", \"length\": %lu", strlen(all_nodes[i]->fragment->fragment_sequence));
        if(i!=all_nodes.size()-1) fprintf(out," }},\n"); else fprintf(out," }}\n");
    }
    
    
    
    // EDGES
    fprintf(out,"],\n\"edges\": [\n");
    //if no edge exist, should not write this, so we test...
    //    bool at_least_one_edge=false;
    //    for(int i=0;i<all_nodes.size() && !at_least_one_edge;i++){
    //        //        if(all_nodes[i]->edges.size()){
    //        fprintf(out,"],\n\"edges\": [");
    //        break;
    //        //        }
    //    }
    
    
    bool first=true;
    
    for(int i=0;i<all_nodes.size();i++){
        for(int edge_id=0;edge_id<all_nodes[i]->edges.size();edge_id++){
            
            
            if(first){
                fprintf(out,"\n");
                first=false;
            }
            else fprintf(out,",\n");
            fprintf(out,"{ \"data\":{ \"id\": \"e%d\", \"source\": \"n%d\",\"target\": \"n%d\",\"direction\":",first_edge_id++, all_nodes[i]->node_id,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;
            }
            // output edges coverage.
            if(consider_coverage){
                fprintf(out,", \"coverage\":[\n");
                for(int id_file=0;id_file<nb_read_files;id_file++) {
                    fprintf(out,"\t\t{\n");
                    fprintf(out,"\t\t\t\"id\":\"file_%d\",\n", id_file+1);
                    fprintf(out,"\t\t\t\"avg_coverage\": %d\n", all_nodes[i]->edges[edge_id]->coverage[id_file]);
                    fprintf(out,"\t\t}%s\n",id_file<nb_read_files-1?",":"");
                }
                
                fprintf(out,"]\n");
            }
            fprintf(out,"}}");
            
        }
        
        
    }
    fprintf(out,"\n]");
    if(surrounded_by_braces)
        fprintf(out,"}");
}

#define computeDepth(line)\
for(int i=0;i<strlen(line);i++) {\
if (line[i]=='[' || line[i]=='{') depth++;\
if (line[i]==']' || line[i]=='}') depth--;\
}

/**
 * Static method
 * Writes back a json comming from mapsembler.
 * basically: copy all parts not concerning the extremGraphs
 * replace previous extremGraphs by those modified by the phaser.
 */
void DBG::output_graphs(char * original_json, FILE * out, const int nb_read_files, bool consider_coverage, vector<DBG*> dbgs){
    printf("output graph coverage = %s\n", consider_coverage?"true":"false");
    char * line = NULL;
    size_t len = 0;
    ssize_t read;
    int edge_id=0;
    
    FILE  * fp;
    fp = fopen(original_json, "r");
    if (fp == NULL)
        exit(EXIT_FAILURE);
    
    bool in_extremGraphs_of_a_starter=false;
    bool in_subgraph_dont_output;
    bool in_edges;
    int depth;
    int subgraph_number=0;
    
    while ((read = getline(&line, &len, fp)) != -1) {
        //        printf("Retrieved line %s of length %zu :\n", line, read);
        
        
        
        if(strstr(line, "extremGraphs")!=NULL){
            
            depth=0;
            
            while(true){ // this loops on all extreme kmers of a starter
                fprintf(out, "%s",line);
                //                printf("printing %s", line);
                computeDepth(line);
                //                printf("%d ",depth);
                if(depth==0) { // end of the extreme graph
                    break;
                }
                bool printing_header=true; // we are printing stuffs comming before nodes or edges, i.e.:
                // data":{ ---> depth 3
                // "id":"k0",
                // "sequence":"AGTTCCAGAGTTTCTAGAGTTTCCA",
                // "direction":"RIGHT",
                // "firstNodeId":"n0",
                bool stuff_read=false; // stuffs all data of an extreme kmer  were read if depth gets bigger than 2.
                while ((read = getline(&line, &len, fp)) != -1) {
                    computeDepth(line);
                    if(strstr(line, "nodes") || strstr(line, "edges")) printing_header=false;
                    //                    printf("%sline=%s",printing_header?"HEADER":"nothing",line);
                    if(printing_header) fprintf(out, "%s",line);
                    if(depth>1) stuff_read=true;
                    
                    // in this case, we walked throw the edges and nodes of an extreme graph. We print it.
                    if(depth<=1 && stuff_read) {
//                                                fprintf(out, "end of an extreme kmer, line=%s", line);
                        dbgs[subgraph_number++]->output_graph(out, nb_read_files, edge_id, consider_coverage, false);
                        fprintf(out, "\n%s ",line);
                        break;
                    }
                }
                
                if((read = getline(&line, &len, fp)) == -1) break; // prepare next while loop
            } // end all extreme kmers of a starter
            
            
            
            
        } // end we are in a full set of xtremGraphs
        else {
            fprintf(out, "%s",line);
        }
        //        printf("%s output line:                %s",in_subgraph_dont_output?"don't":"", line);
    }
    
    if (line)
        free(line);
    
    printf("I outputed %d subgraphs\n", subgraph_number);
}


/////////// 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+estimated_size_reads; // this allows to map negative positions on the node (when a read starts before a fragment of a node)
//        sum+=strlen(all_nodes[i]->fragment->fragment_sequence)+estimated_size_reads;
//    }
//    bv = new BooleanVector(sum);
//    
//    //    for(int i=0;i<all_nodes.size();i++) printf("pos in the vector of %d = %ld\n", all_nodes[i]->node_id, all_nodes[i]->starting_id_in_the_boolean_vector);
//}

/**
 * test if a position has already been tested (for instance an anchoring position of a mapped read)
 */
bool Node_dbg::position_already_tested(const int pos, const bool right){
    if(right){
    if ( right_pwi_to_distance_and_path_mapping==NULL ) return false;
    if ( right_pwi_to_distance_and_path_mapping->find(pos) == right_pwi_to_distance_and_path_mapping->end() ) return false;
    return true;
    }
    else{
        if ( left_pwi_to_distance_and_path_mapping==NULL ) return false;
        if ( left_pwi_to_distance_and_path_mapping->find(pos) == left_pwi_to_distance_and_path_mapping->end() ) return false;
        return true;
    }
}
//
///**
// * set a position has already been tested (for instance an anchoring position of a mapped read)
// */
//void DBG::position_tested(const 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(){
    
    // Right 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], true);
        }
    clear_visited();
    // 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();
    
}

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
        bool validSeed=true;
        for(int j=0;j<size_seeds;j++) {
            seed[j]=fragment[i+j];// read the seed
            if(!valid_character(seed[j])){
//                printf("not valid %s\n", seed); //DEB
                validSeed=false; break;}
        }
        if(validSeed) {
            seed[size_seeds]='\0';
            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
        bool validSeed=true;
        for(int j=0;j<size_seeds;j++) {
            seed[j]=fragment[i+j];// read the seed
            if(!valid_character(seed[j])){validSeed=false; 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
}
/**This is usefull for generic graphs, without overlapping k-1mers as this is the case for de bruijn graphs
 * The indexes overlapping seeds
 */
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(int pos_on_node, int pos_on_fragment, const char * node_sequence, const char * mapped_fragment, const int max){
	int substitution_seen=0; // number of seen substitutions for now
    
    
	// 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_fragment]!='\0'){
		if(node_sequence[pos_on_node]!=mapped_fragment[pos_on_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_fragment++;
	}
    
    
	return substitution_seen;
}


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



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

/**
 * Given two paths (left and right) from an anchoring node on wich a fragment was mapped starting at position pwi, this function:
 *  - populates the used edges
 *  - populates the used edges couples
 *  - populates the used mapped positions
 */
void DBG::populate_given_paths(vector<Edge_dbg *> left_path, vector<Edge_dbg *>  right_path, const Node_dbg * anchoring_node, const int pwi, int read_file_id, char * mapped_fragment){
    //
    // 1/ determine the starting position of the fragment on the leftmost node
    // 2/ determine the ending position of the fragment on the rightmost node
    // 3/ walk the right path to popultate
    //   3.1/ the mapped positions
    //   3.2/ the edges couples
    //                     central node
    //   :==:<-l2-:==:<-l1-:==:-r1->:==:-r2->:==:
    //    edges couples: r1,r2; r2,r3; ..., l1,l2; l2,l3; ..., -l1,r1 (couple on the central node).
    //   3.3/ the edges
    // NOTE: this function was written in order to be comprensive. It may be highly faster, merging loops, and avoiding the explicit computation of intermediate variables
    
    // DEBUG:
//    printf("populate a path of length %lu+%lu nodes with %s\n", left_path.size(), right_path.size(), mapped_fragment);
    
    // 1&2
    
    //        k-1                              last_mapped  dontmap
    //        <-->          anchoring_node          <-----><--->
    //   =========        =================         ============
    //        ===============           ===============
    //       ********************************************** mapped fragment
    //       <------------> -pwi
    //   <----------------> left_length (sum of left nodes without overlaps)
    //   <-->               starting_pwi
    //                                     <-------------------> right_length
    //   <-----------------------------------------------------> total_length
    //       <--------------------------------------------> lenght mapped fragment
    int left_length=0;
//    check_all((char *)"entering populate");
    for(int i=0;i<left_path.size();i++){
        left_length+=strlen(left_path[i]->to->fragment->fragment_sequence)-size_seeds+1;
    }
    const int pwi_first = left_length+pwi;
   
    assert(pwi_first>=0);
//    check_all((char *)"entering populate");
    
    int right_length=0;
    for(int i=0;i<right_path.size();i++){
        
//        printf("adding %d to %d\n", strlen(right_path[i]->to->fragment->fragment_sequence)-size_seeds+1, right_length);
        right_length+=strlen(right_path[i]->to->fragment->fragment_sequence)-size_seeds+1;
    }
    const int total_length = left_length+strlen(anchoring_node->fragment->fragment_sequence)+right_length;
    const int dontmap = total_length-pwi_first-strlen(mapped_fragment);
    int last_mapped;
    if(right_path.size()) last_mapped = strlen(right_path[right_path.size()-1]->to->fragment->fragment_sequence) - dontmap;
    else last_mapped =  pwi+strlen(mapped_fragment);
    
    // 3.1/
//    check_all((char *)"populate 3.1 central");
    // central node:
    const int start = max(0,pwi);
    const int stop = min(pwi+strlen(mapped_fragment), strlen(anchoring_node->fragment->fragment_sequence));
    for(int i=start;i<stop; i++) INC(anchoring_node->fragment->coverage[read_file_id][i]);
    
//    check_all((char *)"populate 3.1 left");
    // left_path:
    bool forward=false; // on the left part, we start on the reverse complement of the central node.
    for(int i=0;left_path.size() && i<left_path.size()-1;i++){ // all nodes of the left path except the last one
        for(int j=0;j<strlen(left_path[i]->to->fragment->fragment_sequence);j++)
            INC(left_path[i]->to->fragment->coverage[read_file_id][j]);
        // 0=FF, 1=RR, 2=FR, 3=RF
        if(forward && left_path[i]->my_label==0) forward=true; // useless but clearer
        else if(forward && left_path[i]->my_label==2) forward=false;
        else if(!forward && left_path[i]->my_label==1) forward=false; // useless but clearer
        else if(!forward && left_path[i]->my_label==3) forward=true;
        else {
            for(int xx=0;left_path.size() && xx<left_path.size()-1;xx++)
                printf("--%c%c-->%d", left_path[xx]->my_label%2?'R':'F', (left_path[xx]->my_label==0||left_path[xx]->my_label==3)?'F':'R',left_path[xx]->to->node_id); //DEB
            fprintf(stderr,"Left: Impossible to be in %s, leaving with label %d\n", forward?"forward":"revcomp", left_path[i]->my_label);
            assert(1==0);
        }
    }
//    check_all((char *)"populate 3.1 last left");
    // last left node:
    if(left_path.size()){
        int last = left_path.size()-1;
        // 0=FF, 1=RR, 2=FR, 3=RF
        if(forward && left_path[last]->my_label==0) forward=true; // useless but clearer
        else if(forward && left_path[last]->my_label==2) forward=false;
        else if(!forward && left_path[last]->my_label==1) forward=false; // useless but clearer
        else if(!forward && left_path[last]->my_label==3) forward=true;
        else {
            fprintf(stderr,"Left: Impossible to be in %s, leaving with label %d\n", forward?"forward":"revcomp", left_path[last]->my_label);
            assert(1==0);
        }
        
        
        if(forward)
            for(int i=pwi_first;i<strlen(left_path[left_path.size()-1]->to->fragment->fragment_sequence);i++)
                INC(left_path[left_path.size()-1]->to->fragment->coverage[read_file_id][i]);
        else
            for(int i=0;i<strlen(left_path[left_path.size()-1]->to->fragment->fragment_sequence)-pwi_first-1;i++)
                INC(left_path[left_path.size()-1]->to->fragment->coverage[read_file_id][i]);
    }
//    check_all((char *)"populate 3.1 right");
    // right path:
    forward=true;
    for(int i=0;right_path.size() && i<right_path.size()-1;i++){ // all nodes of the right path except the last one
        for(int j=0;j<strlen(right_path[i]->to->fragment->fragment_sequence);j++)
        	INC(right_path[i]->to->fragment->coverage[read_file_id][j]);
        // 0=FF, 1=RR, 2=FR, 3=RF
        if(forward && right_path[i]->my_label==0) forward=true; // useless but clearer
        else if(forward && right_path[i]->my_label==2) forward=false;
        else if(!forward && right_path[i]->my_label==1) forward=false; // useless but clearer
        else if(!forward && right_path[i]->my_label==3) forward=true;
        else {

            for(int xx=0;right_path.size() && xx<right_path.size()-1;xx++)
                printf("--%c%c-->%d", right_path[xx]->my_label%2?'R':'F', (right_path[xx]->my_label==0||right_path[xx]->my_label==3)?'F':'R',right_path[xx]->to->node_id); //DEB
            fprintf(stderr,"Right: Impossible to be in %s, leaving with label %d\n", forward?"forward":"revcomp", right_path[i]->my_label);
            assert(1==0);
        }
    }
//    check_all((char *)"populate 3.1 last right");
    // last right node:
    if(right_path.size()){
        int last = right_path.size()-1;
        //get the last direction:
        // 0=FF, 1=RR, 2=FR, 3=RF
        if(forward && right_path[last]->my_label==0) forward=true; // useless but clearer
        else if(forward && right_path[last]->my_label==2) forward=false;
        else if(!forward && right_path[last]->my_label==1) forward=false; // useless but clearer
        else if(!forward && right_path[last]->my_label==3) forward=true;
        else {
            fprintf(stderr,"Right: Impossible to be in %s, leaving with label %d\n", forward?"forward":"revcomp", right_path[last]->my_label);
            assert(1==0);
        }
        
//        check_all((char *)"populate 3.1 last right1");
        // fill the last node
        if(forward){
            for(int i=0;i<last_mapped;i++){
                INC(right_path[right_path.size()-1]->to->fragment->coverage[read_file_id][i]);
//                check_all((char *)"populate 3.1 last right A --");
            }
        }
        else{
            for(int i=strlen(right_path[right_path.size()-1]->to->fragment->fragment_sequence)-last_mapped;i<strlen(right_path[right_path.size()-1]->to->fragment->fragment_sequence);i++){
                INC(right_path[right_path.size()-1]->to->fragment->coverage[read_file_id][i]);
//                check_all((char *)"populate 3.1 last right B --");
            }
        }
        
//        check_all((char *)"populate 3.1 last right2");
    }
    // 3.2
    
//    check_all((char *)"populate 3.2 left");
    // left couples:
    for(int i=0;left_path.size() && i<left_path.size()-1;i++)
        populate_in_and_out(left_path[i], left_path[i+1]);
//    check_all((char *)"populate 3.2 right");
    // right couples:
    for(int i=0;right_path.size() && i<right_path.size()-1;i++){
//        printf("populates in and out %d %d\n", right_path[i]->to->node_id, right_path[i+1]->to->node_id);
        populate_in_and_out(right_path[i], right_path[i+1]);
    }
//    check_all((char *)"populate 3.2 central");
    // central node edge couple
    if(left_path.size() && right_path.size()){
        populate_in_and_out(get_reverse_edge(anchoring_node, left_path[0]), right_path[0]);
    }
    // 3.3
//    check_all((char *)"populate 3.3 left");
    //    printf("left: %d right: %d\n", left_path.size(), right_path.size());
    for(int i=0;i<left_path.size();i++)
        left_path[i]->increase_coverage(read_file_id);
    
//    check_all((char *)"populate 3.3 right");
    for(int i=0;i<right_path.size();i++)
        right_path[i]->increase_coverage(read_file_id);
    
//    check_all((char *)"populate ends");
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////  GRAPH Mapping (recursive version)                    ///////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////

/**
 * map a fragment on a node, and checks recursivelly on depth first that there is a unique path that maps the full given \param[fragment] to a graph
 * A tricky stuff: the current_pwi is the real position of where the fragment maps on the node sequence (it may be negative).
 * While the starting_pwi simulates the position where the full initial fragment (not reduced to what has to be aligned) starts on this node. It is used to mark to couple (node (considered in direct strand), position where the fragment starts). So this couple is not used twice with another seed on the same fragment.
 * modifies:
 *      - the \param[path] : the ordered set of paths on which the fragment is mapped
 *      - the \param[distance] : the maping distance of fragment over the returned path
 * returns:
 *      - true: if a unique path is detected having less than param[threshold_substitution] substitutions
 *      - false:
 *              ° if no path have at most param[threshold_substitution] substitutions (in this case the \param[distance] is -1)
 *              ° if at least two distinct paths have exactly the same number of substitutions < param[threshold_substitution] (in this case the \param[distance] is still stored)
 */
bool DBG::map_fragment(Node_dbg * current_node, // the node on which the fragment is mapped
                       char * fragment, // the fragment we are trying to map on the graph
                       const int starting_on_fragment,
                       const int starting_on_node,
                       const bool forward, // is the forward direction of the node is mapped (true) or the reverse (false)
                       int& distance, // stores the (minimal) number of substitutitons used while mapping the fragment on the graph
                       const bool right // are we extending a right fragment?
){
    //                       -----------------
    //                       |     node      |
    //                       -----------------
    //   >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> fragment
    //   <-------------------------->        starting_on_fragment
    //                       <------> starting_on_node
    //   <--full_pwi--------> = -(starting_on_fragment - starting_on_node)
    int full_pwi =  starting_on_node-starting_on_fragment;
    
    
    // Test wether this mapping was already tested
    if(current_node->position_already_tested(full_pwi,right)){
//        printf("I was already tested with %d (distance = %d)\n", full_pwi, current_node->pwi_to_distance_and_path_mapping->find(full_pwi)->second.first);
        distance=current_node->get_map(right)->find(full_pwi)->second.first;
        return distance<=threshold_substitutions;
    }
    
    // do we have to create a new "pwi_to_distance_and_path_mapping" ?
    if(current_node->get_map(right) == NULL)
    {
        current_node->create_map(right);
        current_mapped_nodes.push_back(current_node);
    }


    // map the fragment to the current node
    char * test_ref_sequence = current_node->fragment->fragment_sequence;
//        printf("%s %s\n", fragment+starting_on_fragment, test_ref_sequence+full_pwi);
    if(!forward) revcomp(test_ref_sequence,strlen(test_ref_sequence)); // if the target is reverse, change the direction
    int subst_cur=number_of_substitutions(starting_on_node,starting_on_fragment,test_ref_sequence,fragment, threshold_substitutions);
    if(!forward) revcomp(test_ref_sequence,strlen(test_ref_sequence)); // change back the direction to retreive the original one
    
    // too much substitutions, recursion ends
    if(subst_cur>threshold_substitutions) {
        distance=subst_cur;
        current_node->get_map(right)->insert(pair<int, pair<int, Edge_dbg *> > (full_pwi,pair<int, Edge_dbg *> (distance, NULL)));
        return false;
    }
    
    // test if the whole fragment was mapped on the right (recursion ends)
    if(starting_on_fragment - starting_on_node + strlen(current_node->fragment->fragment_sequence) >= strlen(fragment)) {
        distance=subst_cur;
        current_node->get_map(right)->insert(pair<int, pair<int, Edge_dbg *> > (full_pwi,pair<int, Edge_dbg *> (distance, NULL)));
        return true; // all the fragment was mapped
    }
    
    
    /// Lets traverse the sibling of the current_node ///
    //////////////////////////////////////////////////////
    int nb_soons = current_node->edges.size();
    //    vector <Edge_dbg *> * path_soons = (vector <Edge_dbg *> *) malloc(sizeof(vector <Edge_dbg *>)*nb_soons); test_alloc(path_soons);
    
    
    int distances [nb_soons];
    bool success_soons [nb_soons];
    for(int outedge_id = 0; outedge_id<nb_soons; outedge_id++){ // each soon
        success_soons[outedge_id]=false;
        Node_dbg * out_node = current_node->edges[outedge_id]->to;
        // 0=FF, 1=RR, 2=FR, 3=RF
        if(forward && current_node->edges[outedge_id]->my_label%2) continue; // cannot leave a forward following something starting with R
        if(!forward && !(current_node->edges[outedge_id]->my_label%2)) continue; // cannot  leave a reverse following something starting with F
        
        bool next_forward;
        if(current_node->edges[outedge_id]->my_label==0 || current_node->edges[outedge_id]->my_label==3) // next is in forward
            next_forward = true;
        else // next is in revcomp
            next_forward = false;
        if(current_node->edges[outedge_id]->to->fragment->isPalindromic() && !next_forward) {
            //            printf("next node %s is palindromic, we read it only in forward\n", current_node->edges[outedge_id]->to->fragment->fragment_sequence);
            continue; // we considere only the forward part of palindromic nodes
        }
        success_soons[outedge_id] = map_fragment(current_node->edges[outedge_id]->to,
                                                 fragment, //
                                                 starting_on_fragment + strlen(current_node->fragment->fragment_sequence)-starting_on_node,
                                                 size_seeds-1, // next mapping starts after the overlap
                                                 next_forward, // inform if next node is in forward
                                                 distances[outedge_id],
                                                 right); // will store the distance
    } // end each soon
    
    /// Analyse the sibling traversals                 ///
    //////////////////////////////////////////////////////
    
    // analyse soons and keep only the unique better if exists, else return false
    int min_dist=threshold_substitutions+1;
    int min_dist_id=-1;
    bool unique=false;
    for(int outedge_id = 0; outedge_id<nb_soons; outedge_id++){ // check results on each soon.
        if(!success_soons[outedge_id]) continue; // this one didn't succeed
        if(distances[outedge_id] < min_dist){ // a new min dist found
            min_dist = distances[outedge_id];
            min_dist_id = outedge_id;
            unique=true;
            continue;
        }
        if(distances[outedge_id] == min_dist){ // this one was already found, we can't choose.
            unique=false;
        }
    }
    
    // no traversal respects the threshold
    if(!unique || min_dist_id == -1){
        distance = INT_MAX; // this permit to differenciate the case where two path have the same distance < threshold_substtutions
        current_node->get_map(right)->insert(pair<int, pair<int, Edge_dbg *> >
                                                               (full_pwi,pair<int, Edge_dbg *> (distance, NULL)));
        return false;
    }
    // a good unique path was found, we store the results in the path of the current node
    else{
        distance = subst_cur+min_dist; // store the result
        current_node->get_map(right)->insert(pair<int, pair<int, Edge_dbg *> >
                                                               (full_pwi,pair<int, Edge_dbg *> (distance, current_node->edges[min_dist_id])));
        return distance<=threshold_substitutions;
    }

}


/**
 * fully maps a fragment on a graph, anchored on a node, with a seed position \param[b] on the node fragment and position \param[i] on the framemt.
 * this function modifies the two path vectors (left path and right path used to align the framgent on the graph from the node
 * it returns true if it succesfully mapped the fragment on a unique path on the graph with less than threshold_substitutions substitutions (cumulated left and right paths), else returns false
 */
bool DBG::map_approx_a_fragment(const int b, const int i, Node_dbg * node, char * fragment, int& distance, Edge_dbg ** first_left_edge, Edge_dbg ** first_right_edge){

    
//    printf("mapping on node %d, pos %d\n", node->node_id, b-i);
    
    
    //        ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;  node sequence
    //        <---------> b        <-----------------> bbar
    //                   [--------]                     seed
    //             ******************************       fragment
    //             <----> i        <------------> ibar
    //        <---> pwi
    
//    const int pwi = b-i; // starting position of the fragment on the node.
//    position_tested(node, pwi); // set the position as tested
    //    printf("node %s is tested with position %d\n", node->fragment->fragment_sequence, pwi);
    int right_distance;
    bool right_mapped;
    // RIGHT PART: map the right part of the fragment (after the seed).
//    printf("pwi forward = %d, pwi rc = %d\n", b-i, strlen(node->fragment->fragment_sequence)-b-(strlen(fragment)-i));
    right_mapped= map_fragment(node, // the node on which the fragment is mapped
                               fragment, // the fragment we are trying to map on the graph, right after the seed
                               i+size_seeds, // where to start on fragment
                               b+size_seeds, // starting position of the fragment on the current node (may be negative)
                               // pwi+size_seeds, // starting position of the initial fragment on the graph w.r.t. the calling node
                               true, // this is always
                               right_distance, // stores the (minimal) number of substitutitons used while mapping the fragment on the graph
                               true // this is a right extension
                               );
    
    if(right_mapped)
        *first_right_edge = node->get_map(true)->at(b-i).second;
    
    
    
    // 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
    if(right_mapped && right_distance <=threshold_substitutions){
        int left_distance;
        bool left_mapped;
        revcomp(fragment, strlen(fragment));
        left_mapped= map_fragment(node, // the node on which the fragment is mapped
                                  fragment,
                                  strlen(fragment)-i, // ibar = strlen(fragment)-i-size_seeds; fragmentbar+ibar+sizeseeds = frgamentbar+strlen(fragment)-i-size_seeds+size_seeds = fragmentbar cqfd
                                  strlen(node->fragment->fragment_sequence)-b,  // we start position size-b on the reverse complement of the node
                                  // bbar = strlen(node)-b-size_seeds; bbar+size_seeds = strlen(node)-b; cqfd
                                  false, // now node is in reverse complement always
                                  left_distance, // stores the (minimal) number of substitutitons used while mapping the fragment on the graph
                                  false // this is a left extension
                                  );
        revcomp(fragment, strlen(fragment)); // put back the right order
            
        
        
        if(left_mapped && right_mapped && left_distance+right_distance <=threshold_substitutions){
            * first_left_edge = node->get_map(false)->at(strlen(node->fragment->fragment_sequence)-b-(strlen(fragment)-i)).second;
            distance = left_distance+right_distance;
//            printf("yeah, mapped, distance is %d (%d+%d)\n", distance, left_distance,right_distance);
            return true;
        }
    }
    return false;
    
    
}



//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////  GRAPH MODIFICATION (USING MAPPING INFORMATION)       ///////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
//int DBG::unpalindromize(){
//    int number_unpalindromized=0;
//    for(int node_id=0;node_id<all_nodes.size();node_id++) {
//        Node_dbg * current = all_nodes[node_id];
//        if(!current->fragment->isPalindromic()) continue;
//        printf("unpalindromize %d-%s\n", current->node_id, current->fragment->fragment_sequence);
//        number_unpalindromized++;
//        // chose an entry node.
//        Node_dbg * from = current->edges[0]->to;
//        // we consider we traverse the current node in forward while comming from node "from"
//        for(int edge_id=0;edge_id<current->edges.size();edge_id++){
//            // if the edge goes to "from" and leaving with "F", remove the couple of edges corresponding.
//            if(current->edges[edge_id]->to == from && current->edges[edge_id]->my_label%2==0){
//                remove_couple_edges(current, current->edges[edge_id]);
//                continue;
//            }
//            // if the edge goes to another node but leaves with R, remove the couple
//            if(current->edges[edge_id]->to != from && current->edges[edge_id]->my_label%2==1){
//                remove_couple_edges(current, current->edges[edge_id]);
//                continue;
//            }
//
//
//        }
//
//
//    }
//
//    return number_unpalindromized;
//}
/**
 * Duplicate deadend nodes as:
 *   A
 *     ==> C
 *   B
 * into
 *   A --> C' and B --> C
 */
int DBG::duplicate_deadend_nodes(){
    int number_duplicated=0;
    for(int node_id=0;node_id<all_nodes.size();node_id++) {
        Node_dbg * current = all_nodes[node_id];
        if(current->edges.size()<2) continue;
        // 0=FF, 1=RR, 2=FR, 3=RF
        int first = current->edges[0]->my_label%2; // 0: leaves with F (so enter with R) -- 1: leaves with R (so enter with R).
        bool doable=true;
        for(int edge_id=1;edge_id<current->edges.size();edge_id++){
            if(current->edges[edge_id]->my_label%2 != first){
                doable = false;
                break;
            }
        }
        
        // if doable: this current node is a dead end. We can duplicate it.
        if(doable){
            number_duplicated++;
            // we conserve the first edge.
            // Then we remove one by one all the others, each time adding a new node
            while(current->edges.size()>1){
                Node_dbg * current_bis = new Node_dbg(current, all_nodes[all_nodes.size()-1]->node_id+1); // duplicate the node containing current
                all_nodes.push_back(current_bis); // add this new node to the whole set of nodes
                Edge_dbg * in = get_reverse_edge(current, current->edges[1]); // find the edge incomming to "in"...
                in->to = current_bis; // ... and change its destination.
                current_bis->edges.push_back(current->edges[1]); // steal the current outgoing edge to put it in the duplicated node...
                current->edges.erase(current->edges.begin()+1); // ... remove it from the current node.
            }
        } // end duable
    }
    return number_duplicated;
}

Node_dbg * DBG::duplicate_one_simple_node(Node_dbg * current, Edge_dbg *in1, Edge_dbg * out1, Edge_dbg *in2, Edge_dbg *out2){
    //    in1       ---> ----------- -----> out1
    //                   |         |
    //    out2      <--- ----------- <----- in2
    if(current->edges.size() == 2) return current; // no need to duplicate if indeegree = 1 (corresponding to two outgoing egdes).
    // 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[all_nodes.size()-1]->node_id+1);
    //    printf("created new node with id %d \n", all_nodes[all_nodes.size()-1]->node_id+1);
    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
    in1->to = current_bis;
    in2->to = current_bis;
    
    // link the new created node to the "from" and the "to" nodes
    current_bis->edges.push_back(out2);
    current_bis->edges.push_back(out1);
    
    
    
    // remove out2 and out1 from the "current" node
    // find ids of the out1 and out2 edges
    int out1_id=-1, out2_id=-1;
    for(int i=0;i<current->edges.size();i++){
        if(current->edges[i] == out1) out1_id=i;
        if(current->edges[i] == out2) out2_id=i;
    }
    assert(out1_id!=-1);
    assert(out2_id!=-1);
    current->edges.erase(current->edges.begin()+max(out1_id,out2_id)); // remove the edges with the biggest id (this does not change the id of the smallest (I know, it simply cleaver).
    current->edges.erase(current->edges.begin()+min(out1_id,out2_id)); // and now revome the other one.
    
    return current_bis;
}

/**
 * For each node that we can duplicate, we duplicate...
 */
int DBG::duplicate_simple_nodes(){
    int number_duplicated=0;
    for(int node_id=0;node_id<all_nodes.size();node_id++) {
        Node_dbg * current = all_nodes[node_id];
        //        printf("eventually duplicate node %d %lX-%lu\n", current->node_id, all_nodes[1], all_nodes[1]->edges.size());
        
        
        //        if(current->fragment->isPalindromic()) continue;
        
        // for now we duplicate only the nodes for which ALL ingoing nodes have a unique outgoing node.
        // 1/ Get all incoming edges of the node.
        // 2/ for each incoming edge (in2): check if its out going edge (out2) is unique, or absent.
        // 2'/ in this case checks also that the information is symetrical: (that in1 corresponds to out1 or to nothing)
        //    in1       ---> ----------- -----> out1
        //                   |         |
        //    out2      <--- ----------- <----- in2
        // 3/ if this is the case, duplicate the node.
        for(int edge_id=0;edge_id<current->edges.size() && current->edges.size()>2;edge_id++){
            Edge_dbg * out1 = current->edges[edge_id];
            Edge_dbg * in2 = get_reverse_edge(current, out1);
            if(in2->doable && in2->out_edge!=NULL){ // a unique out
                Edge_dbg * out2=in2->out_edge;
                printf("try with out1 = %d et out2 = %d\n",out1->to->node_id, out2->to->node_id);
                Edge_dbg * in1 = get_reverse_edge(current, out2);
                if(in1->doable && (in1->out_edge == out1 || in1->out_edge == NULL)){ // the couple in1/out1 either does not exists (NULL) or is coherent with in2/out2
                    printf("duplicate %d-%s (out1 = %d, out2 = %d)... ", current->node_id, current->fragment->fragment_sequence, out1->to->node_id, out2->to->node_id);
                    Node_dbg * duplicated = duplicate_one_simple_node(current, in1, out1, in2, out2); // we can duplicate the node
                    //                    printf("done\n");
                    if(duplicated != current){
                        number_duplicated++;
                        edge_id--;
                    }
                    
                }
            }
        } // all outgoing edges
    }
    return number_duplicated;
}


//bool DBG::merge_node_trio(Node_dbg * central){
//    if(central->edges.size()!=2) return false;
//    Node_dbg * left, * right;
//    Edge_dbg * central_to_left, * left_to_central, * right_to_central, * central_to_right;
//    // 0=FF, 1=RR, 2=FR, 3=RF
//    //    left_to_central          ---> ----------- -----> central_to_right
//    //                                  | central |
//    //    central_to_left          <--- ----------- <----- right_to_central
//
//    // we consider that we read the central node in the forward direction.
//    // first thing is thus to find the good left and right, so the central node is foward:
//    //   left --XF--> central --FY--> right.
//    // one of the out must start with F (link from central to right) and the other with R (link from central to left).
//    if(central->edges[0]->my_label%2==0){ // 0 is the right.
//        if(central->edges[1]->my_label%2==0) // 1 is also the right, impossible to merge.
//            return false;
//        right = central->edges[0]->to;
//        left = central->edges[1]->to;
//        central_to_left = central->edges[1];
//        central_to_right = central->edges[0];
//    }
//    else if(central->edges[1]->my_label%2==0){ // 1 is the right
//        if(central->edges[0]->my_label%2==0) // 0 is also the right, impossible to merge.
//            return false;
//        right = central->edges[1]->to;
//        left = central->edges[0]->to;
//        central_to_left = central->edges[0];
//        central_to_right = central->edges[1];
//    }
//    else return false; // not any possibility to read this node in forward (as no edge leaves with F).
//
//    left_to_central = get_reverse_edge(central, central_to_left);
//    right_to_central = get_reverse_edge(central, central_to_right);
//
//
//
//
//    bool left_forward;
//    if(left_to_central->my_label%2==0) left_forward=true;
//    else left_forward=false;
//
//    bool central_forward = true;
//    bool right_forward;
//    if(central_to_right->my_label==0 || central_to_right->my_label==3) right_forward=true;
//    else right_forward=false;
//
//    // we can merge only if no other outgoing edge leave "left" with label "X".
//    if(left_forward){ // we should have only one outgoing edge from "left" leaving with F.
//        int nb=0;
//        for(int i=0;i<left->edges.size();i++)
//            if(left->edges[i]->my_label%2==0)
//                nb++;
//        if(nb!=1) return false;
//    }
//    else{ // we should have only one outgoing edge from "left" leaving with R.
//        int nb=0;
//        for(int i=0;i<left->edges.size();i++)
//            if(left->edges[i]->my_label%2!=0)
//                nb++;
//        if(nb!=1) return false;
//    }
//
//    // we can merge only if no other outgoing edge leave "right" with label "Ybar"
//    if(right_forward){ // we go from right to central with R, so only one leaving with R.
//        int nb=0;
//        for(int i=0;i<right->edges.size();i++)
//            if(right->edges[i]->my_label%2!=0)
//                nb++;
//        if(nb!=1) return false;
//    }
//    else { // we go from right to central with F, so only one leaving with F.
//        int nb=0;
//        for(int i=0;i<right->edges.size();i++)
//            if(right->edges[i]->my_label%2==0)
//                nb++;
//        if(nb!=1) return false;
//    }
//
//    ////// FROM HERE: we merge, that's sure //////
//
////    // a preliminary stuff. Here is the situation:
////    // ... --> L-1 --> L --> central --> R --> R+1 --> ...
////    // ... -> L'-1 --/                     \-> R'+1 --> ...
////    // maybe one of the left most nodes (L-1 or L'-1 for instance is phased with "central" AND so for one of the rightmost nodes R+1 or R'+1
////    // in such a case we need to remind this as after the merging, node L-1 (for instance) will be phased with node R+1 (for instance):
////    // ... --> L-1 --> merged_node --> R+1 --> ...
////    // ... -> L'-1 --/             \-> R'+1 --> ...
////    // Let's check this situation:
////
////    Edge_dbg * out_to_left_phased = NULL;
////    Edge_dbg * out_to_right_phased = NULL;
////    Node_dbg * right_out = NULL; // one of the R+1 nodes
////    Node_dbg * left_out = NULL; // one of the L-1 nodes
////
////    // this is possible only if central_to_left is doable and central_to_right is doable
////    if(central_to_left->doable && central_to_right->doable){
////        // Is L phased ?
////        // if edge from current to left is phased, it's simple,just check that the symetrical edge is also phased in the same way.
////        if(central_to_left->out_edge!= NULL){
////            left_out = central_to_left->out_edge->to;
////            out_to_left_phased = get_reverse_edge(left, central_to_left->out_edge);
////            if(out_to_left_phased->doable && out_to_left_phased->out_edge != NULL){
////                if(out_to_left_phased->out_edge->to!=central)
////                    out_to_left_phased = NULL; // not phased with central
////            }
////        }
////        else { // central_to_left->out_edge is null, but maybe one of the output edges of the L-1 nodes are phased with central. we need to check this
////            for(int id_left_edge = 0;id_left_edge<left->edges.size();id_left_edge++){
////                Edge_dbg * to_left = get_reverse_edge(left, left->edges[id_left_edge]);
////                if(to_left->doable && to_left->out_edge != NULL && to_left->out_edge->to==central){
////                    out_to_left_phased = to_left;
////                    break;
////                }
////            }
////        }
////        if(out_to_left_phased != NULL){
////            // Is R phased ?
////            // if edge from current to right is phased, it's simple,just check that the symetrical edge is also phased in the same way.
////            if(central_to_right->out_edge!= NULL){
////                right_out = central_to_right->out_edge->to;
////                out_to_right_phased = get_reverse_edge(right, central_to_right->out_edge);
////                if(out_to_right_phased->doable && out_to_right_phased->out_edge != NULL){
////                    if(out_to_right_phased->out_edge->to!=central)
////                        out_to_right_phased = NULL; // not phased with central
////                }
////            }
////            else { // central_to_right->out_edge is null, but maybe one of the output edges of the L-1 nodes are phased with central. we need to check this
////                for(int id_right_edge = 0;id_right_edge<right->edges.size();id_right_edge++){
////                    Edge_dbg * to_right = get_reverse_edge(right, right->edges[id_right_edge]);
////                    if(to_right->doable && to_right->out_edge != NULL && to_right->out_edge->to==central){
////                        out_to_right_phased = to_right;
////                        break;
////                    }
////                }
////            }
////        }
////    }
////
////    if(out_to_left_phased && out_to_right_phased){
////        Edge_dbg * right_to_out = get_reverse_edge(right_out,out_to_right_phased);
////        out_to_left_phased->doable = true;
////        out_to_left_phased->out_edge = right_to_out;
////
////        Edge_dbg * left_to_out = get_reverse_edge(left_out,out_to_left_phased);
////        out_to_right_phased->doable = true;
////        out_to_right_phased->out_edge = left_to_out;
////    }
////    else {
////        if(out_to_left_phased){
////            out_to_left_phased->doable = false;
////            out_to_left_phased->out_edge = NULL;
////        }
////        if(out_to_right_phased){
////            out_to_right_phased->doable = false;
////            out_to_right_phased->out_edge = NULL;
////        }
////    }
//
//
//    // 1a. add central sequence to left node
//    // 1b. add right sequence to left node
//    if(!left_forward) revcomp(left->fragment->fragment_sequence, strlen(left->fragment->fragment_sequence));
////    if(!central_forward) revcomp(central->fragment->fragment_sequence, strlen(central->fragment->fragment_sequence));
//    if(!right_forward) revcomp(right->fragment->fragment_sequence, strlen(right->fragment->fragment_sequence));
//
//    char * new_left_sequence = (char *) malloc(sizeof(char)*(strlen(left->fragment->fragment_sequence)+strlen(central->fragment->fragment_sequence)+strlen(right->fragment->fragment_sequence)-2*size_seeds+3));
//    strcpy(new_left_sequence, left->fragment->fragment_sequence);
//    strcat(new_left_sequence, central->fragment->fragment_sequence+size_seeds-1);
//    strcat(new_left_sequence, right->fragment->fragment_sequence+size_seeds-1);    if(!left_forward) revcomp(new_left_sequence,strlen(new_left_sequence)); // put back the good left sequence in the right direction.
//    free(left->fragment->fragment_sequence);
//    left->fragment->fragment_sequence = new_left_sequence;
//#ifdef DEBUG_DBG
//    printf("new left seq = %s\n", left->fragment->fragment_sequence);
//#endif
//
//#ifdef DEBUG_DBG
//    printf("left = %d-%s\n", left->node_id, left->fragment->fragment_sequence);
//    printf("central = %d-%s\n", central->node_id, central->fragment->fragment_sequence);
//    printf("right = %d-%s\n", right->node_id, right->fragment->fragment_sequence);
//#endif
//
//
//
//    // 2. deal with outgoing edges of node "right"
//    //      Two cases:
//    //         // left and right node are both forward or both reverse : just add nodes outgoing right and ingoing right to left
//    //         // else: for outgoing: change FF to RF, RR to FR, FR to RR, RF to FF
//    //                  for  ingoing: change RR to RF, FF to FR, FR to FF, RF to RR
//    // 0=FF, 1=RR, 2=FR, 3=RF
//    for (int i=0;i<right->edges.size();i++){
//    //for (int i=right->edges.size()-1; i>=0;i--){
//        Edge_dbg * out = right->edges[i];
//        if(out->to == central) continue;
//
//#ifdef DEBUG_DBG
//        printf("shift edge from %d-%s to %d-%s\n", right->node_id, right->fragment->fragment_sequence, out->to->node_id, out->to->fragment->fragment_sequence);
//#endif
//        Edge_dbg * in = get_reverse_edge(right, out);
//        if(left_forward!=right_forward){ // in this case we need to change the labels of the ingoing and outgoing edges of soon deleted right edge.
//            if(out->my_label==0) out->my_label=3;
//            else if(out->my_label==1) out->my_label=2;
//            else if(out->my_label==2) out->my_label=1;
//            else if(out->my_label==3) out->my_label=0;
//
//            if(in->my_label==0) in->my_label=2;
//            else if(in->my_label==1) in->my_label=3;
//            else if(in->my_label==2) in->my_label=0;
//            else if(in->my_label==3) in->my_label=1;
//        }
//        left->add_child(out->to, out->my_label);
//
//
//        in->doable = false; // the previous info stored in this node is not true anymore.
//        in->out_edge = NULL;
//
//        in->to=left;
//    }
//
//    // 3. remove outgoing edge from left to central:
//    int left_to_central_id=-1;
//    for(int i=0;i<left->edges.size() && left_to_central_id==-1;i++) if(left->edges[i]->to == central) {left_to_central_id=i; break;}
//
//#ifdef DEBUG_DBG
//    printf("remove edge from %d to %d\n", left->node_id, central->node_id);
//    if(left->node_id==47)
//        for(int z=0;z<left->edges.size();z++) printf("47 --> %d\n", left->edges[z]->to->node_id);
//
//#endif
//    assert(left_to_central_id!=-1);
//    left->edges.erase(left->edges.begin()+left_to_central_id);
//
//#ifdef DEBUG_DBG
//    printf("removed edge from %d to %d\n", left->node_id, central->node_id);
//    if(left->node_id==47)
//        for(int z=0;z<left->edges.size();z++) printf("47 --> %d\n", left->edges[z]->to->node_id);
//
//    left_to_central_id=-1;
//    for(int i=0;i<left->edges.size() && left_to_central_id==-1;i++) if(left->edges[i]->to == central) {left_to_central_id=i; break;}
//    printf("still one ? id=%d\n", left_to_central_id);
//    assert(left_to_central_id==-1);
//#endif
//
//    // 4. delete nodes central and right.
//
//
//    int central_id=-1, right_id=-1;
//    for(int i=0;i<all_nodes.size();i++){
//        if(all_nodes[i] == central) central_id=i;
//        if(all_nodes[i] == right) right_id=i;
//        if(central_id!=-1 && right_id!=-1) break;
//    }
//    assert(central_id!=-1);
//    assert(right_id!=-1);
////    printf("avant:\n"); for(int node_id=0;node_id<all_nodes.size();node_id++) printf("%d\n", all_nodes[node_id]->node_id);
//    all_nodes.erase(all_nodes.begin()+max(central_id,right_id)); // remove the edges with the biggest id (this does not change the id of the smallest (I know, it simply cleaver).
//    all_nodes.erase(all_nodes.begin()+min(central_id,right_id)); // and now revome the other one.
////    printf("apres:\n"); for(int node_id=0;node_id<all_nodes.size();node_id++) printf("%d\n", all_nodes[node_id]->node_id);
//
//#ifdef DEBUG_DBG
//
//    for(int node_id=0;node_id<all_nodes.size();node_id++){
//        if(all_nodes[node_id]->node_id == central->node_id) {
//            printf("error central node (%d-%s) still here\n", all_nodes[node_id]->node_id, all_nodes[node_id]->fragment->fragment_sequence);
//            exit(0);
//        }
//
//        if(all_nodes[node_id]->node_id == right->node_id) {
//            printf("error right node (%d-%s) still here\n", all_nodes[node_id]->node_id, all_nodes[node_id]->fragment->fragment_sequence);
//            exit(0);
//        }
//
//        for(int edge_id=0;edge_id<all_nodes[node_id]->edges.size();edge_id++){
//            if(all_nodes[node_id]->edges[edge_id]->to == central){
//                printf("error still a node (%d-%s) is linked to central == %d-%s\n", all_nodes[node_id]->node_id, all_nodes[node_id]->fragment->fragment_sequence, central->node_id, central->fragment->fragment_sequence);
//                exit(0);
//            }
//            if(all_nodes[node_id]->edges[edge_id]->to == right){
//                printf("error still a node (%d-%s) is linked to right == %d-%s\n", all_nodes[node_id]->node_id, all_nodes[node_id]->fragment->fragment_sequence, right->node_id, right->fragment->fragment_sequence);
//                exit(0);
//            }
//        }
//    }
//#endif
//
//#ifdef DEBUG_DBG
//    printf("delete %d\n", central->node_id);
//    printf("delete %d\n", right->node_id);
//#endif
//
//    delete(central);
//    delete(right);
//
//    return true;
//}

/**
 * Given an edge, this function merges the two linked nodes a and b iif
 * 1/ no other edge "leave" left node
 * 2/ no other edge "enter" right node.
 * in practice:
 * a--FF-->b implies no other edge leaving a with an F and not other edges entering b with an F (= no edge leaves b with an R, except the one going to a)
 * a--RR-->b implies no other edge leaving a with an R and not other edges entering b with an R (= no edge leaves b with an F, except the one going to a)
 * a--FR-->b implies no other edge leaving a with an F and not other edges entering b with an R (= no edge leaves b with an F, except the one going to a)
 * a--RF-->b implies no other edge leaving a with an R and not other edges entering b with an F (= no edge leaves b with an R, except the one going to a)
 */
bool DBG::merge_node_couples(Node_dbg * a, Edge_dbg * ab){
    // 0=FF, 1=RR, 2=FR, 3=RF
    Node_dbg * b = ab->to;
    // special cases:
    if(a == b) return false;
    // another very special case (for instance):
    //   --FR-->
    // a        b
    //  <--FR--
    // AND
    //   --RF-->
    // a        b
    //  <--RF--
    for(int a_edge_id=0;a_edge_id<a->edges.size(); a_edge_id++)
        if(a->edges[a_edge_id]!=ab && a->edges[a_edge_id]->to==b){
            //             printf("very special case detected\n");
            return false;
        }
    
    //
    //
    //     printf("starting merging node %s to node\n", a->fragment->fragment_sequence);
    //     printf("to node %s\n", b->fragment->fragment_sequence);
    bool a_forward, b_forward;
    // Checks a outgoing edges
    if(ab->my_label%2==0){ // starts with F
        a_forward=true;
        // check that no other edge leaves a with F
        for(int a_edge_id=0;a_edge_id<a->edges.size(); a_edge_id++)
            if(a->edges[a_edge_id]->my_label%2==0 && a->edges[a_edge_id]->to != b) return false; // an edge leaves a with F but doesn't go to b
    }
    else { // starts with R
        a_forward=false;
        // check that no other edge leaves a with R
        for(int a_edge_id=0;a_edge_id<a->edges.size(); a_edge_id++)
            if(a->edges[a_edge_id]->my_label%2!=0 && a->edges[a_edge_id]->to != b) return false; // an edge leaves a with R but doesn't go to b
    }
    
    // checks b incomming edges.
    if(ab->my_label == 0 || ab->my_label == 3) { // enter b with F
        b_forward=true;
        for(int b_edge_id=0;b_edge_id<b->edges.size(); b_edge_id++)
            if(b->edges[b_edge_id]->my_label%2!=0 && b->edges[b_edge_id]->to != a) return false; // an edge leaves b with an R not going to a. Thus another node a' is linked to b with a'--XF-->b
    }
    else { // enter b with R
        b_forward=false;
        for(int b_edge_id=0;b_edge_id<b->edges.size(); b_edge_id++)
            if(b->edges[b_edge_id]->my_label%2==0 && b->edges[b_edge_id]->to != a) return false; // an edge leaves b with an F not going to a. Thus another node a' is linked to b with a'--XR-->b
    }
    
    // we reverse nodes read in the reverse direction:
    if(!a_forward)
        revcomp(a->fragment->fragment_sequence, strlen(a->fragment->fragment_sequence));
    if(!b_forward)
        revcomp(b->fragment->fragment_sequence, strlen(b->fragment->fragment_sequence));
    
    // store the new left sequence:
    char * new_left_sequence = (char *) malloc(sizeof(char)*(strlen(a->fragment->fragment_sequence)+strlen(b->fragment->fragment_sequence)-size_seeds+2));
    strcpy(new_left_sequence, a->fragment->fragment_sequence);
    strcat(new_left_sequence, b->fragment->fragment_sequence+size_seeds-1);
    free(a->fragment->fragment_sequence);
    a->fragment->fragment_sequence = new_left_sequence;
    if(!a_forward) // put back a in its original direction.
        revcomp(a->fragment->fragment_sequence, strlen(a->fragment->fragment_sequence));
    
    
    // deal with outgoing edges of node "b" that become outgoing edges of node a
    //      Two cases:
    //         // a and b nodes are both forward or both reverse : just add a edges' to b.
    //         // else: for outgoing: change FF to RF, RR to FR, FR to RR, RF to FF
    //                  for  ingoing: change RR to RF, FF to FR, FR to FF, RF to RR
    // 0=FF, 1=RR, 2=FR, 3=RF
    for (int i=0;i<b->edges.size();i++){
        Edge_dbg * out = b->edges[i];
        if(out->to == a) continue; // this one will be removed.
        
        Edge_dbg * in = get_reverse_edge(b, out);
        if(a_forward!=b_forward){ // in this case we need to change the labels of the ingoing and outgoing edges of soon deleted right edge.
            if(out->my_label==0) out->my_label=3;
            else if(out->my_label==1) out->my_label=2;
            else if(out->my_label==2) out->my_label=1;
            else if(out->my_label==3) out->my_label=0;
            
            if(in->my_label==0) in->my_label=2;
            else if(in->my_label==1) in->my_label=3;
            else if(in->my_label==2) in->my_label=0;
            else if(in->my_label==3) in->my_label=1;
        }
        a->add_child(out->to, out->my_label);
        in->to = a;
    }
    
    // keep the smallest node id of a and b. This is useful for the jspn format where extreme kmers are immuable and are linked to a node id that is minimal.
    // if for instance extrem kmer is linked to node 0, this node 0 should not be changed to node 1.
    if(b->node_id<a->node_id) a->node_id=b->node_id;
    
    // remove edge ab
    int ab_id=-1;
    for(int i=0;i<a->edges.size();i++) if(a->edges[i] == ab) {ab_id=i; break;}
    assert(ab_id!=-1);
    a->edges.erase(a->edges.begin()+ab_id);
    delete(ab);
    
    // remove node b
    int b_id=-1;
    for(int i=0;i<all_nodes.size();i++){
        if(all_nodes[i] == b) {b_id=i; break;}
    }
    assert(b_id!=-1);
    all_nodes.erase(all_nodes.begin()+b_id);
    delete(b);
    return true;
}


int DBG::simplify_simple_paths_couples(){
    int number_simplidfied = 0;
    for(int node_id=0;node_id<all_nodes.size();node_id++) { // all nodes
        Node_dbg * current = all_nodes[node_id];
        
        //        bool changed=false;
        //        do{
        //            changed=false;
        //            printf("node %d\n", current->node_id);
        for(int edge_id=0;edge_id<current->edges.size();edge_id++){ // try all edges
            
//            printf("try merge edge %d (node %d) (%d nodes total)\n", edge_id, current->node_id, (int) all_nodes.size());
            // we try several time the same edge: at each merging it is
            if(merge_node_couples(current, current->edges[edge_id])){ // success merging
//                printf("success\n");
                //                    changed=true;
                number_simplidfied++;
                edge_id--; //stay on the same edge for the next "for" iteration
                
            } // end success merging
        } // end try all edges
        //        } while (changed);
        // as we possibly removed nodes present before current in the all_nodes vector, we need to come back to the good place in the vector:
        int test_node_id=node_id;
        while(all_nodes[test_node_id] != current && test_node_id>=0)
            test_node_id--;
        node_id=test_node_id;
    } // end all nodes
    return number_simplidfied;
}

//
//
//int DBG::simplify_simple_paths(){
//    int number_simplidfied = 0;
//    for(int node_id=0;node_id<all_nodes.size();node_id++) {
////        printf(" simplify node %d \n", all_nodes[node_id]->node_id);
//        Node_dbg * current = all_nodes[node_id];
//        // for now we duplicate only the nodes for which ALL ingoing nodes have a unique outgoing node.
//        // 1/ Get all incoming edges of the node.
//        // 2/ for each incoming edge (in2): check if its out going edge (out2) is unique, or absent.
//        // 2'/ in this case checks also that the information is symetrical: (that in1 corresponds to out1 or to nothing)
//        //    in1       ---> ----------- -----> out1
//        //                   |         |
//        //    out2      <--- ----------- <----- in2
//        // 3/ if this is the case, duplicate the node.
//        if(current->edges.size()!=2) continue;
//        if(merge_node_trio(current))
//            number_simplidfied++;
//
//        // as we possibly removed nodes present before current in the all_nodes vector, we need to come back to the good place in the vector:
//        int test_node_id=node_id;
//        while(all_nodes[test_node_id] != current && test_node_id>=0)
//            test_node_id--;
//        node_id=test_node_id;
//    }
//    return number_simplidfied;
//}



void DBG::remove_node(const int node_index){
    Node_dbg * current = all_nodes[node_index];
    
    // remove all edges comming to the current node
    for(int edge_id=0;edge_id<current->edges.size();edge_id++){
        Edge_dbg * outgoing = current->edges[edge_id];
        Node_dbg * to = outgoing->to;
        
        // deal with nodes "to" phased with "current" as output.
        for(int i=0;i<to->edges.size();i++){ // check all outgoing edges of "to"
            Edge_dbg * to_to = get_reverse_edge(to, to->edges[i]);
            if(to_to->doable && to_to->out_edge && to_to->out_edge->to==current){
                to_to->doable=false;
                to_to->out_edge=NULL;
            }
        }
        
        //TODO: pour chaque noeud liee au noeud courrant, verifier que courant n'est pas un out_edge d'une arete entrante de ce noeud. Si c'est le cas, la mettre a NULL;
        for(int i=0;i<to->edges.size();i++){ // check all outgoing edges of "to"
            if(to->edges[i]->to == current){ // find an edge entering current
                // check if the labels are coherents:
                // 0=FF, 1=RR, 2=FR, 3=RF
                if((outgoing->my_label==0 && to->edges[i]->my_label==1) || // find an edge entering current, and compatible with the outgoing edge
                   (outgoing->my_label==1 && to->edges[i]->my_label==0) ||
                   (outgoing->my_label==2 && to->edges[i]->my_label==2) ||
                   (outgoing->my_label==3 && to->edges[i]->my_label==3)){
                    Edge_dbg * to_remove = to->edges[i];
                    to->edges.erase(to->edges.begin()+i);
                    delete(to_remove);
                    i--;
                } // end find an edge entering current, and compatible with the outgoing edge
            } // end find an edge entering current
        } // end check all outgoing edges of "to"
        
    }
    all_nodes.erase(all_nodes.begin()+node_index);
    delete(current);
}

int DBG::remove_uncovered_nodes(const int threshold, const int nb_read_sets){
    int number_removed=0;
    for(int node_id=0;node_id<all_nodes.size();node_id++) {
        Node_dbg * current = all_nodes[node_id];
        bool remove =true;
        for (int id_read_set = 0;remove && id_read_set<nb_read_sets;id_read_set++){
            // at least one position covered at least threshold times
            for(int pos = 0;remove && pos<strlen(current->fragment->fragment_sequence); pos++){
#ifdef DEBUG_GRAPH_SIMPLIFICATION
                printf("node %d, pos %d, cov %d\n", all_nodes[node_id]->node_id, pos, current->fragment->coverage[id_read_set][pos]);
#endif
                
                if(current->fragment->coverage[id_read_set][pos]>=threshold){
                    remove=false;
                }
            }
            
        }
        
        if(remove) {
            number_removed++;
#ifdef DEBUG_GRAPH_SIMPLIFICATION
            printf("removed node %d\n", all_nodes[node_id]->node_id);
#endif
            remove_node(node_id);
            node_id--; // prepare the next "for" iteration
        }
    } // end all nodes
    return number_removed;
}

/**
 * When an edge is removed from a node, we have to take care it was not an out edge of a simple path in this node.
 * This function 1/ detects if it is the case, and 2/ if its the case, remove the simple path
 */
void edge_removal_checker (Node_dbg * current, Edge_dbg * to_remove){
    // for each incomming edges:
    for(int out_edge_id=0;out_edge_id<current->edges.size();out_edge_id++){
        Edge_dbg * in = get_reverse_edge(current, current->edges[out_edge_id]);
        // check if its a simple path leaving witht the edge to remove
        if(in->doable && in->out_edge == to_remove){
            // in this case, remove the simple path
            in->doable = false;
            in->out_edge=NULL;
        }
    }
    
}

int DBG::remove_uncovered_edges(const int threshold, const int nb_read_sets){
    int number_removed=0;
    for(int node_id=0;node_id<all_nodes.size();node_id++) {
        Node_dbg * current = all_nodes[node_id];
        for(int edge_id=0;edge_id<current->edges.size();edge_id++){
            Edge_dbg * out = current->edges[edge_id];
            int max_cov=0;
            for(int i=0;i<nb_read_sets;i++) if((int)out->coverage[i]>max_cov) max_cov=(int)out->coverage[i];
#ifdef DEBUG_GRAPH_SIMPLIFICATION
            printf("edge %d-->%d :: ", current->node_id, out->to->node_id); for(int i=0;i<nb_read_sets;i++) printf("find %d\n",(int)out->coverage[i]);
#endif
            if(max_cov<threshold) {
                number_removed++;
#ifdef DEBUG_GRAPH_SIMPLIFICATION
                printf("I remove edge from %s to %s (max_cov=%d, threshold=%d)\n", current->fragment->fragment_sequence, out->to->fragment->fragment_sequence, max_cov, threshold);
#endif
                edge_removal_checker(current, out);
                Edge_dbg * in = get_reverse_edge(current, out);
                edge_removal_checker(out->to, in);
                // remove the out edge:
                current->edges.erase(current->edges.begin()+edge_id);
                edge_id--; // prepare the next "for" iteration
                // remove the in edge from the node targeted by out
                Node_dbg * to = out->to;
                for (int i=0; i<to->edges.size(); i++) {
                    if(to->edges[i]==in){
                        to->edges.erase(to->edges.begin()+i);
                        break;
                    }
                } // end find the in edge from node "to"
                delete(out);
                delete(in);
            } // end remove the edge
        } // end all edges
    } // end all nodes
    return number_removed;
}
