/* ***************************************************************************
 *
 *                              KisSplice
 *      de-novo calling alternative splicing events from RNA-seq data.
 *
 * ***************************************************************************
 *
 * Copyright INRIA
 *  contributors :  Vincent Lacroix
 *                  Pierre Peterlongo
 *                  Gustavo Sacomoto
 *                  Vincent Miele
 *                  Alice Julien-Laferriere
 *                  David Parsons
 *
 * pierre.peterlongo@inria.fr
 * vincent.lacroix@univ-lyon1.fr
 *
 * This software is a computer program whose purpose is to detect alternative
 * splicing events from RNA-seq data.
 *
 * This software is governed by the CeCILL license under French law and
 * abiding by the rules of distribution of free software. You can  use,
 * modify and/ or redistribute the software under the terms of the CeCILL
 * license as circulated by CEA, CNRS and INRIA at the following URL
 * "http://www.cecill.info".

 * As a counterpart to the access to the source code and  rights to copy,
 * modify and redistribute granted by the license, users are provided only
 * with a limited warranty  and the software's author,  the holder of the
 * economic rights,  and the successive licensors  have only  limited
 * liability.

 * In this respect, the user's attention is drawn to the risks associated
 * with loading,  using,  modifying and/or developing or reproducing the
 * software by the user in light of its specific status of free software,
 * that may mean  that it is complicated to manipulate,  and  that  also
 * therefore means  that it is reserved for developers  and  experienced
 * professionals having in-depth computer knowledge. Users are therefore
 * encouraged to load and test the software's suitability as regards their
 * requirements in conditions enabling the security of their systems and/or
 * data to be ensured and,  more generally, to use and operate it in the
 * same conditions as regards security.
 *
 * The fact that you are presently reading this means that you have had
 * knowledge of the CeCILL license and that you accept its terms.
 */


// ===========================================================================
//                               Include Libraries
// ===========================================================================
#include <list>
#include <vector>




// ===========================================================================
//                             Include Project Files
// ===========================================================================
#include <CGraph.h>




// ===========================================================================
//                             Declare Used Namespaces
// ===========================================================================
using namespace std;




//############################################################################
//                                                                           #
//                                Class CGraph                               #
//                                                                           #
//############################################################################

// ===========================================================================
//                                  Constructors
// ===========================================================================

CGraph::CGraph(int nbNodes, vector<LabelledCEdge>& allEdges, int kValue)
{
  k_value = kValue;
  adj_list.reserve(nbNodes);
  adj_list_sz.reserve(nbNodes);

  int j = 0;
  int offset = 0;
  for ( int i = 0 ; i < nbNodes ; i++ )
  {
    // Count the number of edges (they are ordered in all_edges) of node i
    j = 0;
    while ( offset + j < (int) allEdges.size() && allEdges[offset + j].getFirst() == i )
    {
      j++;
    }
    
    // ...
    adj_list.push_back(j != 0 ? new int[j] : NULL);
    adj_list_sz.push_back(0);
    offset += j;
  }

  // ...
  for ( int i = 0 ; i < (int)allEdges.size() ; i++ )
  {
    insert_unique_edge_dir( allEdges[i].getFirst(), allEdges[i].getSecond() );
  }
}


// ===========================================================================
//                                  Destructors
// ===========================================================================
CGraph::~CGraph(void) {
}

// ===========================================================================
//                                 Public Methods
// ===========================================================================

void CGraph::insert_unique_edge_dir(int u, int v)
{
  int i;
  int* neighbours = adj_list[u];
  int  nb_neighbours = adj_list_sz[u];
  
  // Find corresponding neighbour (if it exists)
  for ( i = 0 ; i < nb_neighbours ; i++, neighbours++ )
  {
    if ( *neighbours == v )
    {
      break;
    }
  }
  
  // If not found, add the missing edge
  if ( i == nb_neighbours ) 
  {
    *neighbours = v; 
    adj_list_sz[u]++;
  }
}

void CGraph::insert_unique_edge( int u, int v )
{
  insert_unique_edge_dir(u,v);
  insert_unique_edge_dir(v,u);
}

void CGraph::destroy_adj_list(void)
{
  for (int i = 0; i < (int)adj_list.size(); i++)
    delete[] adj_list[i];
  
  vector<int *>().swap(adj_list);
}

void CGraph::destroy(void)
{
  destroy_adj_list();
  vector<int>().swap(adj_list_sz);
}



//================================================================
// 					Reading functions
//================================================================

int count_nb_lines( FILE* file )
{
  int ch, number_of_lines = 0;

  while (EOF != (ch=getc(file)))
    if ('\n' == ch)
      number_of_lines++;
  
  // Set the cursor back to the begining of the file.
  rewind(file);
  
  // Don't care if the last line has a '\n' or not. We over-estimate it.
  return number_of_lines + 1; 
}

void read_node_file( FILE* node_file, vector<char *>& seqs, int k_val )
{
  char* buffer = new char[100 * MAX];
  char* seq;
  
  seqs.reserve(count_nb_lines(node_file));
  
  while ( fgets(buffer, 100 * MAX, node_file) != NULL )
  {
    char* p;

    if (strlen(buffer) == 100 * MAX)
    {  
      p = strtok(buffer, "\t\n");
      fprintf(stdout, "ERROR: node %s with sequence larger than %d!", p, 100 * MAX);
      exit(0);
    }
      
    // Node label
    p = strtok( buffer, "\t\n" );
          
    // Node seq
    p = strtok( NULL, "\t\n"  );
    seq = new char[strlen(p) + 1];
    strcpy( seq, p );

    seqs.push_back( seq );
    //~ printf( "pushed %s (0x%x)|\n", seq, seq );
    //~ getchar();
    
    //~ delete [] seq; 
  }
  
  delete [] buffer;
}

void read_edge_file( FILE *edge_file, vector<LabelledCEdge>& edges )
{
  char* buffer = new char[100 * MAX];
  char* u = new char[MAX];
  char* v = new char[MAX];
  char* label = new char[MAX];
  
  edges.reserve(count_nb_lines(edge_file));

  while ( fgets(buffer, 100 * MAX, edge_file) != NULL )
  {
    char* p;

    // outgoing node
    p = strtok( buffer, "\t\n" );
    strcpy( u, p );

    // incoming node
    p = strtok( NULL, "\t\n" );
    strcpy( v, p );

    // edge label
    p = strtok( NULL, "\t\n" );
    strcpy(label, p);
  
    edges.push_back( LabelledCEdge( atoi(u), atoi(v), label ) );
  }
  
  sort( edges.begin(), edges.end() );
  
  delete [] buffer;
  delete [] u;
  delete [] v;
  delete [] label;
  
}
