// [[Rcpp::depends(BH)]]
#include <Rcpp.h>
#include <boost/algorithm/string.hpp>
#include <string>
#include <vector>
#include <fstream>

using namespace Rcpp;
using namespace std;

//' Get the number of biclusters, generated by the Bi-Force algorithm.
//' @param filename Name of the Bi-Force output file.
//' @return Number of biclusters.
//' 
//' @examples
//' a <- "PathToBiForceOutput.txt"
//' # NoBFBiclusters(a)
//' 
//' @export
// [[Rcpp::export]]
int NoBFBiclusters(String filename){
  ifstream myfile (filename);
  string line; // current bicluster
  int counter = 0; 
  
  while (getline (myfile,line))
  {
    counter++;
  }
  myfile.close();
  return(counter-2);
}

//' Get a bicluster a Bi-Force output file
//' @param filename Name of the Bi-Force output file.
//' @param cluster Number of the bicluster that should be extracted.
//' @return Bicluster as list with rownames in attribute "row" 
//' and colnames in attribute "column".
//' 
//' @examples
//' a <- "PathToBiForceOutput.txt"
//' # getBFCluster(a, cluster=1)
//' 
//' @export
// [[Rcpp::export]]
S4 getBFCluster(String filename, int cluster) {
  NumericVector col (0);
  NumericVector row (0);
  bool success = false; // Was the bicluster found
  int counter = 0; // in which bicluster are we currently?
  string line; // current bicluster
  std::vector<std::string> results; // splitted string
  ifstream myfile (filename);
  
  // Helper strings
  string sep=",";
  string R="R";
  string C="C";
  
  if(cluster>NoBFBiclusters(filename)){
    Rcout << "Bicluster not available\n";
    myfile.close();
    //List l = List::create(Named("rows") = row , Named("columns") = col);
    S4 res("bicluster");
    res.slot("algorithm") = "biforce";
    res.slot("row") = row;
    res.slot("column") = col;
    return(res);
  }
  
  while (getline (myfile,line))
  {
    if (counter==cluster){
      // The boost::split function crashes if the splitting 
      //letter is not in the string
      // so this needs to be checked first.
      std::size_t found = line.find(sep);
      if (found!=std::string::npos){
        boost::split(results, line, [](char c){return c == ',';});
      }
      else{ // Otherwise the cluster consists only of one node, 
        //which can directly be used as the result
        results.push_back(line);
      }
      success=true;
      break;
    }
    counter++;
  }
  
  if(success){
    for(int i=0; i<results.size();i++){
      if(results[i].substr(0,1)==R){
        row.push_back(stoi(results[i].substr(1, string::npos)));
      }
      if(results[i].substr(0,1)==C){
        col.push_back(stoi(results[i].substr(1, string::npos)));
      }
    }
  }
  else{
    Rcout << "Cluster could not be identified.\n";
  }
  
  myfile.close();
  //List l = List::create(Named("rows") = row , Named("columns") = col);
  S4 res("bicluster");
  res.slot("algorithm") = "biforce";
  res.slot("row") = row;
  res.slot("column") = col;
  return(res);  
}

//' Get all biclusters from a Bi-Force output file.
//' @param filename Name of the Bi-Force output file.
//' @return List of biclusters in the form of \code{\link{getBFCluster}}
//' 
//' @examples
//' a <- "PathToBiForceOutput.txt"
//' # getallBFClusters(a)
//' 
//' 
//' @export
// [[Rcpp::export]]
List getallBFClusters(String filename){
  List l=List::create();
  int nc = NoBFBiclusters(filename);
  for (int c=1; c<=nc;c++){
    l.push_back(getBFCluster(filename, c));
  }
  if(l.length()>1){
    return(l);
  } else{
    return(List());
  }
}
