/*  trinculo, Flexible tools for multinomial association
    Copyright (C) 2014  Luke Jostins

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.*/

#include <iostream>
#include <fstream>
#include <vector>
#include <sstream>
#include <string.h>
#include <stdlib.h>
#include <iterator>
#include <map>
#include <limits>


using namespace std;

class phenos {
	// class to hold phenotype data on individuals
 public:
  int Nphenos, Ninds; //the number of phenotypes and individuals stored in the object (here "phenotype" is one column in the phenotype file, we will refer to the different values this can take as "categories" here)
  vector<vector<int> > phenotypes; //vector of categories for each individual for each phenotype (represented as integers)
  vector<map<string,int> > phenomaps; //a map from category names to integers in the above variable
  vector<string> phenonames; // the name of each phenotype in the file (taken from column names)
  vector<int> phenocounts; // the number of categories each phenotype has
  void readPhenos(string infile, map<string,int> IDMap,int Ninds,  string basepheno, string missingpheno, int ordinal);
};

void phenos::readPhenos(string infile, map<string,int> IDMap, int Ninds, string basepheno = "", string missingpheno = "NA", int ordinal = 0){
	// read in phenotype data from a file
  string line;
  ifstream phenofile;
  phenofile.open(infile.c_str());
  int i, j, value;
  istringstream linestream, tempstream;
  vector<string> splitline;

  if (basepheno != "" && basepheno != "0" && ordinal){
    cout << "Warning: Cannot set base phenotype is an ordinal analysis (base phenotype is assumed to be 0)" << endl;
  }

  if (basepheno == missingpheno){
    cout << "Error: The base phenotype and missing phenotype have the same value" << endl;
    throw(3);
  }
  
  //get header
  getline(phenofile,line);
  linestream.str(line);
  copy(istream_iterator<string>(linestream), istream_iterator<string>(), back_inserter<vector<string> >(splitline));
  Nphenos = splitline.size() - 2;
  //cout << "Prestart " << Nphenos << endl;

  phenotypes.resize(Nphenos);
  phenocounts.resize(Nphenos);
  phenomaps.resize(Nphenos);
  phenonames.resize(Nphenos);
  //cout << "Precheck" << endl;
  for (i = 0; i < Nphenos; i++) {
    phenotypes[i].resize(Ninds);
    for (j = 0 ; j < Ninds; j++) phenotypes[i][j] = -1;
    phenonames[i] = splitline[i + 2];
    phenocounts[i] = 0;
    if (basepheno != ""){
      phenomaps[i][basepheno] = 0;
      phenocounts[i]++;
    }
    
  }
  
  int havebasepheno = 0;
  //cout << "Start" << endl;
  if (phenofile.is_open()){
    cout << "Reading phenotypes file" << endl;
    while (!phenofile.eof()){
      getline(phenofile,line);
      //cout << line << endl;
      if (line.length() == 0) break;
      splitline.clear();
      linestream.clear();
      linestream.str(line);
      copy(istream_iterator<string>(linestream), istream_iterator<string>(), back_inserter<vector<string> >(splitline));
      //cout << "Here1" << endl;
      //cout << splitline[0] + ":" + splitline[1] << endl;
      //cout << IDMap[splitline[0] + ":" + splitline[1]] << endl;
      if (IDMap.find(splitline[0] + ":" + splitline[1]) == IDMap.end()) continue;
      //cout << "Here2" << endl;
      for (i = 2; i < splitline.size(); i++) {
	//cout << i << endl;
	if (!ordinal){
	  if (phenomaps[i - 2].find(splitline[i]) == phenomaps[i - 2].end() && splitline[i] != missingpheno){
	    phenomaps[i - 2][splitline[i]] = phenocounts[i - 2];
	    phenocounts[i - 2]++;
	  }
	  //cout << i << endl;
	  if (splitline[i] == basepheno){
	    havebasepheno = 1;
	  }
	  //cout << i << endl;
	  if (splitline[i] == missingpheno){
	    phenotypes[i - 2][ IDMap[splitline[0] + ":" + splitline[1]] ] = -1;
	  } else{
	    phenotypes[i - 2][ IDMap[splitline[0] + ":" + splitline[1]] ] = phenomaps[i - 2][splitline[i]];
	  }
	} else {
	  tempstream.clear();         
	  tempstream.str(splitline[i]);
	  tempstream >> value;
	  if (!tempstream) value = -1;
	  if (value < 0) value = -1;
	  phenotypes[i - 2][IDMap[splitline[0] + ":" + splitline[1]] ] = value;
	  if (value + 1 > phenocounts[i - 2])  phenocounts[i - 2] = value + 1;
	  //cout << value << " " << phenotypes[i - 2][IDMap[splitline[0] + ":" + splitline[1]] ] << endl;
	}
      }
    }	
    
    phenofile.close();
  } else {
    cout << "Error: Cannot open phenotype file" << endl;
  }
  if (!havebasepheno && basepheno != "" && !ordinal){
    cout << "Error: Base phenotype value " << basepheno << " not present in phenotype file" << endl;
  }
}
  
