//
// C++ Implementation:
//
// Description:
//
//
// Author: Faubet Pierre <pierre.faubet@e.ujf-grenoble.fr>, (C) 2007
//
// Copyright: See COPYING file that comes with this distribution
//
//
#include <QDir>
#include <QDirModel>
#include <QTableWidgetItem>
#include <QFileDialog>
#include <QFileInfo>
#include <QMessageBox>

#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <map>

#include "utils.h"

#include "uiconverter.h"

using namespace std;

UIConverter::UIConverter(QWidget* parent, Qt::WFlags fl)
    : QDialog( parent, fl ), Ui::Dialog()
{
  setupUi(this);

  lineEdit->setText(QDir::homePath());
  outputlineEdit->setText(QDir::homePath());

  completer = new QCompleter(this);
  completer->setModel(new QDirModel(completer));
  lineEdit->setCompleter(completer);
  outputlineEdit->setCompleter(completer);

  connect(inputtoolButton,SIGNAL(clicked()),this,SLOT(setGenepopFile()));
  connect(converttoolButton,SIGNAL(clicked()),this,SLOT(convert()));
}

UIConverter::~UIConverter()
{}

void UIConverter::setGenepopFile()
{
  tableWidget->clear();
  tableWidget->setRowCount(0);
  tableWidget->setColumnCount(0);
  lineEdit->setText(QFileDialog::getOpenFileName(this,tr("Genepop file"),QDir::homePath(),"All Files (*)"));
}

/*$SPECIALIZATION$*/
void UIConverter::convert()
{
  string popflag = "POP";

  QFileInfo info(lineEdit->text());
  if (!info.isFile())
    {
      QMessageBox::critical(this,tr("Input file"),tr("Genepop file must be supplied"));
      return;
    }

  QString XXXXfilename = outputlineEdit->text();
  info.setFile(XXXXfilename);
  if (info.exists() && !info.isFile())
    {
      XXXXfilename = QFileDialog::getSaveFileName(this,tr("BIMr file"),QDir::homePath(),"BIMr Files (*.gen)");
      outputlineEdit->setText(XXXXfilename);
    }
  else if (info.exists())
    if (QMessageBox::warning(this,tr("File already exists"),tr("Do you want to overwrite it?"),QMessageBox::Yes,QMessageBox::No) == QMessageBox::No)
      return;

  if (XXXXfilename.isEmpty())
    return;

  string genepop_filename = lineEdit->text().toStdString();
  ifstream fin(genepop_filename.data());
  if (!fin)
    {
      cerr << "Can not open file " << genepop_filename << endl;
      exit(0);
    }

  int nbloci = 0;
  int nbpop = 0;
  int nbindiv = 0;
  int nballeles = 0;

  map<int,int> *alleles;

  string line;
  string::size_type pos;

  /* Skip first line */
  getline(fin,line);

  /* Read names for loci */
  string str;
  do
    {
      getline(fin,line);
      istringstream buf(line);
      buf >> str;
      if (cmp_nocase(str, popflag) != 0)
        {
          pos = line.find(',');
          if (pos == string::npos)
            nbloci++;
          else
            {
              while (pos!= string::npos)
                {
                  nbloci++;
                  line.erase(0, pos+1);
                  pos = line.find(',');
                }
              nbloci++;
            }
        }
    }
  while (cmp_nocase(str,popflag));

  alleles = new map<int,int> [nbloci];
  if (!alleles)
    {
      cerr << "Memmory allocation failed" << endl;
      exit(0);
    }

  bool *missingdata;
  missingdata = new bool [nbloci];
  if (!missingdata)
    {
      cerr << "Memmory allocation failed" << endl;
      exit(0);
    }
  for (int locus=0;locus<nbloci;locus++)
    {
      alleles[locus][0] = 0;
      missingdata[locus] = false;
    }

  nbpop++;
  stringstream stout;
  while (getline(fin,line))
    {
      istringstream buf(line);
      buf >> str;
      if (cmp_nocase(str,popflag))
        {
          nbindiv++;
          pos = line.find(',');
          string idf = line.substr(0,pos+1);
          stout << idf << '\t' << nbpop;
          line.erase(0,pos+1);
          istringstream mult_geno(line);
          for (int locus=0;locus<nbloci;locus++)
            {
              int div;
              string geno;
              mult_geno >> geno;
              int l = geno.length();
              if (l == 4)
                div = 100;
              else if (l == 6)
                div = 1000;
              else
                {
                  cerr << "Something wrong with allele coding." << endl;
                  exit(0);
                }

              int a1 = atoi(geno.c_str()) / div;
              if (!alleles[locus].count(a1))
                alleles[locus][a1] = (int) alleles[locus].size() -1;

              int a2 = atoi(geno.c_str()) % div;
              if (!alleles[locus].count(a2))
                alleles[locus][a2] = (int) alleles[locus].size() -1;

              if (!a1 || !a2)
                missingdata[locus] = true;

              stout << '\t';
              stout.fill('0');
              stout.width(2);
              stout << alleles[locus][a1];
              stout.fill('0');
              stout.width(2);
              stout << alleles[locus][a2];

              if ((int) alleles[locus].size() - (missingdata[locus] ? 1 : 0) > nballeles)
                nballeles = (int) alleles[locus].size()- (missingdata[locus] ? 1 : 0);
            }
          stout << endl;
        }
      else
        nbpop++;
    }

  tableWidget->clear();
  tableWidget->setRowCount(nballeles);
  tableWidget->setColumnCount(nbloci);
  for (int a=1;a<=nballeles;a++)
    tableWidget->setVerticalHeaderItem(a-1,new QTableWidgetItem(tr("%1").arg(a)));

  clog << "Allele codes" << endl;
  clog << "GENEPOP => BIMr" << endl;
  for (int locus=0;locus<nbloci;locus++)
    {
      clog << "Locus #" << locus+1 << endl;
      tableWidget->setHorizontalHeaderItem(locus,new QTableWidgetItem(tr("Loc%1").arg(locus+1)));
      map<int,int>::iterator all;
      for (all = alleles[locus].begin();all != alleles[locus].end();all++)
        {
          clog << all->first << " => " << all->second << endl;
          if (all->first)
            tableWidget->setItem(all->second-1,locus,new QTableWidgetItem(tr("%1").arg(all->first)));
        }
    }


  ofstream fout(XXXXfilename.toStdString().data());
  if (!fout)
    {
      cerr << "Can not open file " << XXXXfilename.toStdString() << endl;
      exit(0);
    }
  fout << "[individuals]= " << nbindiv << endl;
  nlabel->setText(nlabel->text().append(tr("%1").arg(nbindiv)));

  fout << "\n[populations]= " << nbpop << endl;
  Ilabel->setText(Ilabel->text().append(tr("%1").arg(nbpop)));

  fout << "\n[loci]= " << nbloci << endl;
  Jlabel->setText(Jlabel->text().append(tr("%1").arg(nbloci)));

  fout << "\n[alleles]= " << nballeles << endl;
  Klabel->setText(Klabel->text().append(tr("%1").arg(nballeles)));

  fout << "\n[genotypes]=" << endl;
  fout << stout.str();
  
  delete [] missingdata;
  delete [] alleles;

  clog << "End of conversion" << endl;
}

