/***************************************************************************
 *   Copyright (C) 2007 by Faubet Pierre   *
 *   pierre.faubet@e.ujf-grenoble.fr   *
 *                                                                         *
 *   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 2 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, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/

#include <QMessageBox>
#include <QWhatsThis>
#include <QFile>
#include <QFileInfo>
#include <QTextStream>
#include <QCheckBox>
#include <QLineEdit>
#include <QDebug>
#include <QFileDialog>
#include <QDir>
#include <QImageWriter>
#include <QDesktopServices>
#include <QUrl>
#include <QCoreApplication>

#include <qwt_scale_engine.h>

#include "mainwindowimpl.h"
#include "uiabout.h"
#include "uiconverter.h"

#include "mcmc.h"
#include "rawdata.h"
//
MainWindowImpl::MainWindowImpl ( QWidget * parent, Qt::WFlags f )
    : QMainWindow ( parent, f )
{
  /* Create GUI */
  setupUi ( this );

  /* Init bandwidth slider (logscale) */
  BandwidthSlider->setScaleEngine ( new QwtLog10ScaleEngine );
  BandwidthSlider->setRange ( -3.0, 3.0, 0.01 );
  BandwidthSlider->setValue ( 0 );

  /* Create plot frame */
  PlotframeLayout = new QVBoxLayout ( Plotframe );
  plot = new Plot::Plot ( Plotframe );
  PlotframeLayout->addWidget ( plot );

  /* Set main commands */
  connect ( actionStart_new_analysis,SIGNAL ( activated() ),this,SLOT ( displayNewAnalysis() ) );
  connect ( actionLoad_saved_analysis,SIGNAL ( activated() ),this,SLOT ( displayLoadResults() ) );

  actionClose->setEnabled ( false );
  connect ( actionClose,SIGNAL ( activated() ),this,SLOT ( close() ) );

  connect ( actionConversion_utility,SIGNAL ( activated() ),this,SLOT ( displayConverter() ) );

  connect ( actionExit,SIGNAL ( activated() ),this,SLOT ( quit() ) );

  /* Set configuration pages */
  connect ( actionInput,SIGNAL ( activated() ),this,SLOT ( displayInputFileDialog() ) );
  connect ( actionSettings,SIGNAL ( activated() ),this,SLOT ( displaySettingsDialog() ) );
  connect ( actionOutput,SIGNAL ( activated() ),this,SLOT ( displayOutputDialog() ) );

  /* MCMC run actions */
  actionRun->setEnabled ( false );
  connect ( actionRun,SIGNAL ( activated() ),this,SLOT ( runMCMC() ) );
  RunpushButton->setEnabled ( false );
  connect ( RunpushButton,SIGNAL ( clicked() ),this,SLOT ( runMCMC() ) );
  actionStop->setEnabled ( false );
  connect ( actionStop,SIGNAL ( activated() ),this,SLOT ( killJob() ) );
  StoppushButton->setEnabled ( false );
  connect ( StoppushButton,SIGNAL ( clicked() ),this,SLOT ( killJob() ) );

  connect ( actionSave_figure,SIGNAL ( activated() ),this,SLOT ( savePlot() ) );
  connect (actionSave_results,SIGNAL (activated()), this,SLOT(saveTable()));

  /* Set help commands */
  connect(actionManual,SIGNAL(activated()),this,SLOT(displayManual()));
  connect ( actionWhat_s_this,SIGNAL ( activated() ),this,SLOT ( whatsthis() ) );

  /* About */
  connect ( actionAbout,SIGNAL ( activated() ),this,SLOT ( About() ) );
  connect ( actionAbout_gsl,SIGNAL ( activated() ),this,SLOT ( About() ) );
  connect ( actionAbout_Qt,SIGNAL ( activated() ),this,SLOT ( About() ) );
  connect ( actionAbout_Qwt,SIGNAL ( activated() ),this,SLOT ( About() ) );

  /* No mcmc job */
  runningThreads = 0;
  sampleSizes=NULL;
  rawdata=NULL;

  /* Create configuration wizard */
  wizard = new Wizard ( this );
  connect ( wizard,SIGNAL ( accepted() ),this,SLOT ( acceptSettings() ) );
  wizard->setModal ( true );
  wizard->show();


}

/* Start new analysis wizard */
void MainWindowImpl::displayNewAnalysis()
{
  wizard->page(Wizard::Page_Input)->setFinalPage(true);
  wizard->setStartId(Wizard::Page_Input);
  wizard->restart();
  wizard->show();
}

/* Load project wizard */
void MainWindowImpl::displayLoadResults()
{
  wizard->setStartId(Wizard::Page_OpenProject);
  wizard->restart();
  wizard->show();
}

/* Mcmc input file page*/
void MainWindowImpl::displayInputFileDialog()
{
  wizard->page(Wizard::Page_Input)->setFinalPage(true);
  wizard->button(Wizard::NextButton)->setDisabled(true);
  wizard->setStartId(Wizard::Page_Input);
  wizard->restart();
  wizard->show();
}

/* Mcmc setting page */
void MainWindowImpl::displaySettingsDialog()
{
  wizard->page(Wizard::Page_Settings)->setFinalPage(true);
  wizard->setStartId(Wizard::Page_Settings);
  wizard->restart();
  wizard->show();
}

/* Output page */
void MainWindowImpl::displayOutputDialog()
{
  wizard->page(Wizard::Page_Output)->setFinalPage(true);
  wizard->button(Wizard::NextButton)->setDisabled(true);
  wizard->setStartId(Wizard::Page_Output);
  wizard->restart();
  wizard->show();
}

/* Get data from wizard */
void MainWindowImpl::acceptSettings()
{
  int currentPageId = wizard->currentId();

  switch (currentPageId)
    {
    case Wizard::Page_Input:
    case Wizard::Page_Settings:
    case Wizard::Page_Output:
      actionRun->setEnabled ( true );
      RunpushButton->setEnabled ( true );
      break;
    case Wizard::Page_StartRuns:
      if (wizard->field("Start").toBool())
        runMCMC();
      else
        {
          actionRun->setEnabled ( true );
          RunpushButton->setEnabled ( true );
        }
      break;
    case Wizard::Page_OpenProject:
      projectFilename = wizard->field("bpj_filename").toString();
      loadProject();
      break;
    default:
      break;
    }
}

void MainWindowImpl::runMCMC()
{
  /* Disable configure actions */
  actionStart_new_analysis->setEnabled ( false );
  actionLoad_saved_analysis->setEnabled ( false );
  actionClose->setEnabled ( false );
  actionInput->setEnabled ( false );
  actionSettings->setEnabled ( false );
  actionOutput->setEnabled ( false );

  actionRun->setEnabled ( false );
  RunpushButton->setEnabled ( false );

  /* Prepare runtime table widget */
  if ( wizard->field("Fst").toBool())
    {
      RuntableWidget->insertColumn ( RuntableWidget->columnCount() );
      RuntableWidget->setHorizontalHeaderItem ( RuntableWidget->columnCount()-1,new QTableWidgetItem ( tr ( "Theta (%)" ) ) );
      RuntableWidget->insertColumn ( RuntableWidget->columnCount() );
      RuntableWidget->setHorizontalHeaderItem ( RuntableWidget->columnCount()-1,new QTableWidgetItem ( tr ( "Ptilde (%)" ) ) );
    }

  if ( wizard->field("NGData").toBool())
    {
      RuntableWidget->insertColumn ( RuntableWidget->columnCount() );
      RuntableWidget->setHorizontalHeaderItem ( RuntableWidget->columnCount()-1,new QTableWidgetItem ( tr ( "psi (%)" ) ) );
    }

  if (wizard->field("NGData").toBool() && wizard->field("RJ").toBool())
    {
      RuntableWidget->insertColumn ( RuntableWidget->columnCount() );
      RuntableWidget->setHorizontalHeaderItem ( RuntableWidget->columnCount()-1,new QTableWidgetItem ( tr ( "RJ (%)" ) ) );
    }

  RuntableWidget->insertColumn ( RuntableWidget->columnCount() );
  RuntableWidget->setHorizontalHeaderItem ( RuntableWidget->columnCount()-1,new QTableWidgetItem ( tr ( "D_assign" ) ) );

  RuntableWidget->resizeColumnsToContents();

  nbreplicates=wizard->field("nrep").toInt();
  saveSettings();
  MCMC::readMCMCSettings(projectFilename.toStdString());
  MCMC::setMCMCData();
  if (wizard->field("NGData").toBool())
    R=MCMC::getR();

  /* Create mcmc runs */
  mcmcThread = new MCMCThread *[nbreplicates];
  if ( !mcmcThread )
    {
      QMessageBox::critical ( this,tr ( "Memory error" ),tr ( "MCMC thread creation failed, exit" ) );
      close();
    }
  sampleSizes = new int [nbreplicates];
  if ( !sampleSizes )
    {
      QMessageBox::critical ( this,tr ( "Memory error" ),tr ( "Sample size array creation failed, exit" ) );
      close();
    }

  /* Edit combo boxes */
  fillComboBoxes_and_Tables();

  /* Start MCMC runs */
  progressBar->setMaximum ( 100*nbreplicates );
  progressBar->setValue ( 0 );

  for ( int rep=0;rep<nbreplicates;rep++ )
    {
      /* Sample size */
      sampleSizes[rep] = 0;

      /* Create of gui items for this run */
      RuntableWidget->insertRow ( rep );
      RuntableWidget->setItem ( rep,0,new QTableWidgetItem ( tr ( "run%1" ).arg ( rep+1 ) ) );
      for ( int col=1;col<RuntableWidget->columnCount();col++ )
        RuntableWidget->setItem ( rep,col,new QTableWidgetItem() );

      PlotRepcomboBox->addItem ( tr ( "run%1" ).arg ( rep+1 ) );

      StattableWidget->insertColumn ( StattableWidget->columnCount() );
      StattableWidget->setHorizontalHeaderItem ( StattableWidget->columnCount()-1,new QTableWidgetItem ( tr ( "run%1" ).arg ( rep+1 ) ) );
      StattableWidget->setItem(0,rep+1,new QTableWidgetItem(tr("%1").arg(sampleSizes[rep])));

      /* Create job */
      mcmcThread[rep] = new MCMCThread ( this );
      connect ( mcmcThread[rep],SIGNAL ( statusChanged ( int,QString ) ),this,SLOT ( updateStatus ( int,QString ) ) );
      connect ( mcmcThread[rep],SIGNAL ( acceptanceChanged ( int,int,double,double,double,double,double,double,double,double,double ) ),this,SLOT ( updateAcceptance ( int,int,double,double,double,double,double,double,double,double,double ) ) );
      connect ( mcmcThread[rep],SIGNAL ( progressChanged ( int,double ) ),this,SLOT ( updateProgress ( int,double ) ) );
      connect ( mcmcThread[rep],SIGNAL ( samplesizeChanged ( int,double ) ),this,SLOT ( updateSize ( int,double ) ) );
      connect ( mcmcThread[rep],SIGNAL ( finished() ),this,SLOT ( updateThreads() ) );
    }

  MCMC::writeMCMCParameters(projectFilename.toStdString());

  QMessageBox::information ( this,tr ( "Ready to start analyses" ),tr ( "Launch MCMC runs" ) );
  for ( int rep=0;rep<nbreplicates;rep++ )
    {
      runningThreads++;
      mcmcThread[rep]->start();
    }

  tabWidget->setTabEnabled(1,false);
  tabWidget->setTabEnabled(2,false);
  tabWidget->setTabEnabled(3,false);

  writeParameterNames();
  rawdata = NULL;

  actionStop->setEnabled ( true );
  StoppushButton->setEnabled ( true );

  setPlotStatConnections();
}

void MainWindowImpl::fillComboBoxes_and_Tables()
{
  PlotParamcomboBox->clear();
  StatParamcomboBox->clear();
  if ( wizard->field("printlglik").toBool())
    {
      PlotParamcomboBox->addItem ( tr ( "lglik" ) );
      StatParamcomboBox->addItem ( tr ( "lglik" ) );
    }
  if ( wizard->field("printm").toBool())
    {
      PlotParamcomboBox->addItem ( tr ( "mig" ) );
      StatParamcomboBox->addItem ( tr ( "mig" ) );
    }
  if ( wizard->field("printmig").toBool())
    {
      PlotParamcomboBox->addItem ( tr ( "mtild" ) );
      StatParamcomboBox->addItem ( tr ( "mtild" ) );
    }
  if ( wizard->field("printp").toBool())
    {
      PlotParamcomboBox->addItem ( tr ( "popfrq" ) );
      StatParamcomboBox->addItem ( tr ( "popfrq" ) );
    }
  if (wizard->field("Fst").toBool() && wizard->field("printptild").toBool())
    {
      PlotParamcomboBox->addItem ( tr ( "ancfrq" ) );
      StatParamcomboBox->addItem ( tr ( "ancfrq" ) );
    }
  if (wizard->field("printF").toBool())
    {
      PlotParamcomboBox->addItem ( tr ( "F" ) );
      StatParamcomboBox->addItem ( tr ( "F" ) );
    }
  if (wizard->field("Fst").toBool() && wizard->field("printFst").toBool())
    {
      PlotParamcomboBox->addItem ( tr ( "Fst" ) );
      StatParamcomboBox->addItem ( tr ( "Fst" ) );
    }
  if (wizard->field("NGData").toBool() && wizard->field("printpsi").toBool())
    {
      PlotParamcomboBox->addItem ( tr ( "psi" ) );
      StatParamcomboBox->addItem ( tr ( "psi" ) );
    }
  if (wizard->field("NGData").toBool() && wizard->field("printreg").toBool())
    {
      PlotParamcomboBox->addItem ( tr ( "reg" ) );
      StatParamcomboBox->addItem ( tr ( "reg" ) );
    }

  StattableWidget->insertRow(0);
  StattableWidget->setItem(0,0,new QTableWidgetItem(tr("Sample size")));

  if (wizard->field("NGData").toBool() && wizard->field("RJ").toBool())
    {
      for (int rep=0;rep<nbreplicates;rep++)
        {
          ModeltableWidget->insertColumn(ModeltableWidget->columnCount());
          ModeltableWidget->setHorizontalHeaderItem(ModeltableWidget->columnCount()-1,new QTableWidgetItem(tr("run%1").arg(rep+1)));

          RegtableWidget->insertColumn(RegtableWidget->columnCount());
          RegtableWidget->setHorizontalHeaderItem(RegtableWidget->columnCount()-1,new QTableWidgetItem(tr("run%1").arg(rep+1)));
        }


      ModeltableWidget->insertRow(0);
      ModeltableWidget->setItem(0,0,new QTableWidgetItem(tr("%1").arg(0)));
      ModeltableWidget->setItem(0,1,new QTableWidgetItem(tr("none")));
      ModelcomboBox->addItem(tr("%1").arg(0));

      int size = 1 + R + (wizard->field("inter").toBool() ? R*(R-1)/2 : 0);
      int nb_model = 1 << ( size - 1 );
      /* Print alternative models */
      for (int model = 1; model < nb_model; model++ )
        if ( is_a_valid_model(model) )
          {
            /* Add a row for the model */
            ModeltableWidget->insertRow(ModeltableWidget->rowCount());
            ModeltableWidget->setItem(ModeltableWidget->rowCount()-1,0,new QTableWidgetItem(tr("%1").arg(model)));
            ModelcomboBox->addItem(tr("%1").arg(model));

            /* Factors included */
            ModeltableWidget->setItem(ModeltableWidget->rowCount()-1,1,new QTableWidgetItem(tr("")));
            for ( int r = 1; r <= R; r++ )
              if ( ( model >> ( r - 1 ) ) % 2 )
                {
                  QString str = ModeltableWidget->item(ModeltableWidget->rowCount()-1,1)->text().append(tr("G%1 ").arg(r));
                  ModeltableWidget->item(ModeltableWidget->rowCount()-1,1)->setText(str);
                }
            /* Interactions */
            if (wizard->field("inter").toBool())
              {
                int r1=1;
                int r2=r1+1;
                for (int r=R+1;r<size;r++)
                  {
                    if ( ( model >> ( r - 1 ) ) % 2 )
                      {
                        QString str = ModeltableWidget->item(ModeltableWidget->rowCount()-1,1)->text().append(tr("G%1*G%2 ").arg(r1).arg(r2));
                        ModeltableWidget->item(ModeltableWidget->rowCount()-1,1)->setText(str);
                      }
                    if (r2 == R)
                      r2 = ++r1 + 1;
                    else
                      r2++;
                  }
              }

          }

      /* Print regression parameters */
      for (int r=0;r<size;r++)
        {
          RegtableWidget->insertRow(r);
          RegtableWidget->setItem(r,0,new QTableWidgetItem(tr("Alpha%1").arg(r)));
        }

      ModeltableWidget->resizeColumnsToContents();
      RegtableWidget->resizeColumnsToContents();
    }
}

void MainWindowImpl::print_model_estimates()
{
  int nb_model = ModeltableWidget->rowCount();
  double *prob = new double [nb_model];
  if (!prob)
    {
      qDebug() << "Memmory error" ;
      quit();
    }

  /* Loop across replicates */
  for (int rep=0;rep<wizard->field("nrep").toInt();rep++)
    {
      for (int model=0;model<nb_model;model++)
        prob[model] = 0;

      /* Raw data file */
      int nbiter = StattableWidget->item(0,rep+1)->text().toInt();
      QString mcmcFilename = projectFilename.left(projectFilename.length()-4)+tr("_run%1_reg").arg(rep+1)+tr(".txt");
      RawData *sample = new RawData( mcmcFilename.toStdString(),1,nbiter);

      for (int iter=0;iter<nbiter;iter++)
        prob[ModelcomboBox->findText(tr("%1").arg(sample->obs[iter]))]++;

      for (int model=0;model<nb_model;model++)
        ModeltableWidget->setItem(model,rep+2,new QTableWidgetItem(tr("%1").arg(prob[model]/nbiter,0,'f',3)));

      delete sample;
      ModeltableWidget->resizeColumnToContents(rep+2);
    }
  delete [] prob;
}

void MainWindowImpl::print_regression_estimates()
{
  /* Loop across replicates */
  for (int rep=0;rep<wizard->field("nrep").toInt();rep++)
    {
      /* Raw data file */
      int nbiter = StattableWidget->item(0,rep+1)->text().toInt();
      QString mcmcFilename = projectFilename.left(projectFilename.length()-4)+tr("_run%1_reg").arg(rep+1)+tr(".txt");

      for (int alpha=0;alpha<RegtableWidget->rowCount();alpha++)
        {
          RawData *sample = new RawData( mcmcFilename.toStdString(),ModelcomboBox->currentText().toInt(),alpha+3,nbiter);

          /* Display mean; mode and HPDI */
          RegtableWidget->setItem(alpha,rep+1,new QTableWidgetItem(tr("%1\n%2\n[%3;%4]").arg(sample->mean,0,'g',3).arg(sample->mode,0,'g',3).arg(sample->hpdilo,0,'g',3).arg(sample->hpdihi,0,'g',3)));

          delete sample;
        }

      RegtableWidget->resizeColumnToContents(rep+1);
    }
  RegtableWidget->resizeRowsToContents();
}

void MainWindowImpl::print_posterior_estimates()
{
  /* Loop across replicates */
  for (int rep=0;rep<wizard->field("nrep").toInt();rep++)
    {
      if (int size = StattableWidget->item(0,rep+1)->text().toInt())
        {
          /* Raw data file */
          QString mcmcFilename = projectFilename.left( projectFilename.length()-4) + tr ( "_run%1_" ).arg(rep+1) + StatParamcomboBox->currentText() + tr ( ".txt" );

          /* Get sample */
          for (int param=1;param<StattableWidget->rowCount();param++)
            {
              RawData *sample = new RawData( mcmcFilename.toStdString(),param,size);

              /* Display mean; mode and HPDI */
              StattableWidget->item(param,rep+1)->setText(tr("%1\n%2\n[%3;%4]").arg(sample->mean,0,'g',3).arg(sample->mode,0,'g',3).arg(sample->hpdilo,0,'g',3).arg(sample->hpdihi,0,'g',3));

              delete sample;
            }
        }
      else
        QMessageBox::information( this,tr ( "Data not yet available" ),tr ( "There is no sampled iterations for replicate #%1" ).arg(rep+1) );
    }
  StattableWidget->resizeColumnsToContents();
  StattableWidget->resizeRowsToContents();
}

void MainWindowImpl::updateThreads()
{
  runningThreads--;

  /* All jobs have finished */
  if ( runningThreads == 0 )
    {
      actionStop->setEnabled ( false );
      actionRefresh->setEnabled(false);
      StoppushButton->setEnabled ( false );
      actionClose->setEnabled ( true );
      for ( int rep=0;rep<nbreplicates;rep++ )
        {
          disconnect ( mcmcThread[rep],SIGNAL ( statusChanged ( int,QString ) ),this,SLOT ( updateStatus ( int,QString ) ) );
          disconnect ( mcmcThread[rep],SIGNAL ( acceptanceChanged ( int,int,double,double,double,double,double,double,double,double,double ) ),this,SLOT ( updateAcceptance ( int,int,double,double,double,double,double,double,double,double,double ) ) );
          disconnect ( mcmcThread[rep],SIGNAL ( progressChanged ( int,double ) ),this,SLOT ( updateProgress ( int,double ) ) );
          disconnect ( mcmcThread[rep],SIGNAL ( samplesizeChanged ( int,double ) ),this,SLOT ( updateSize ( int,double ) ) );
          disconnect ( mcmcThread[rep],SIGNAL ( finished() ),this,SLOT ( updateThreads() ) );
          delete mcmcThread[rep];
        }
      delete [] mcmcThread;

      QFileInfo out ( projectFilename );
      QMessageBox::information ( this,tr ( "End of MCMC runs" ),tr ( "Results are available in " ) + out.absolutePath() );

      if (tabWidget->isTabEnabled(3))
        tabWidget->setCurrentIndex (3);
      tabWidget->setCurrentIndex (2);
      tabWidget->setCurrentIndex (1);
      tabWidget->setCurrentIndex (0);
      disconnect(tabWidget,SIGNAL(currentChanged(int)),this,SLOT(refresh()));
    }
}

void MainWindowImpl::killJob()
{
  if ( QMessageBox::question ( this,tr ( "Abort all MCMC runs" ),tr ( "Do you want to stop running jobs?" ),QMessageBox::Yes,QMessageBox::No,QMessageBox::Cancel ) ==QMessageBox::Yes )
    {
      for ( int rep=0;rep<nbreplicates;rep++ )
        if ( mcmcThread[rep]->isRunning() )
          {
            disconnect ( mcmcThread[rep],SIGNAL ( statusChanged ( int,QString ) ),this,SLOT ( updateStatus ( int,QString ) ) );
            disconnect ( mcmcThread[rep],SIGNAL ( acceptanceChanged ( int,int,double,double,double,double,double,double,double,double,double ) ),this,SLOT ( updateAcceptance ( int,int,double,double,double,double,double,double,double,double,double ) ) );
            disconnect ( mcmcThread[rep],SIGNAL ( progressChanged ( int,double ) ),this,SLOT ( updateProgress ( int,double ) ) );
            disconnect ( mcmcThread[rep],SIGNAL ( samplesizeChanged ( int,double ) ),this,SLOT ( updateSize ( int,double ) ) );
            disconnect ( mcmcThread[rep],SIGNAL ( finished() ),this,SLOT ( updateThreads() ) );
            qDebug() << "Terminate replicate #" << rep;
            mcmcThread[rep]->terminate();
            mcmcThread[rep]->wait();
            delete mcmcThread[rep];
            runningThreads--;
            qDebug() << "Terminate replicate #" << rep << " ... (done)";
          }
      delete [] mcmcThread;
//       delete [] sampleSizes;

      StoppushButton->setEnabled ( false );
      actionStop->setEnabled ( false );
      actionClose->setEnabled ( true );
      QFile::remove ( projectFilename );


    }
  QMessageBox::information(this,tr("Abort all MCMC runs"),tr("Done"));
}

void MainWindowImpl::writeParameterNames()
{
  QString mcmcFilename;

  if (tabWidget->currentIndex() <= 1)
    {
      mcmcFilename = projectFilename.left ( projectFilename.length()-4 ) + tr ( "_" ) + PlotRepcomboBox->currentText() + tr ( "_" ) + PlotParamcomboBox->currentText() + tr ( ".txt" );
      PlotParamnamecomboBox->clear();
    }
  else if (tabWidget->currentIndex() == 2)
    {
      mcmcFilename = projectFilename.left ( projectFilename.length()-4 ) + tr ( "_run1_" ) + StatParamcomboBox->currentText() + tr ( ".txt" );
      for (int row=StattableWidget->rowCount()-1;row>0;row--)
        StattableWidget->removeRow(row);
    }

  // Read file header for comboBox
  QFile f( mcmcFilename );
  if ( !f.open ( QIODevice::ReadOnly ) )
    return;
  QTextStream data(&f );
  QString qline = data.readLine();
  QTextStream headerline ( &qline );
  QString header;
  while ( !headerline.atEnd() )
    {
      headerline >> header;

      if (tabWidget->currentIndex() == 1)
        PlotParamnamecomboBox->addItem ( header );
      else if ((tabWidget->currentIndex() == 2) && (header != tr("iter")))
        {
          StattableWidget->insertRow (StattableWidget->rowCount());
          StattableWidget->setItem ( StattableWidget->rowCount()-1,0,new QTableWidgetItem ( header ) );
          for (int col=1;col<StattableWidget->columnCount();col++)
            StattableWidget->setItem(StattableWidget->rowCount()-1,col,new QTableWidgetItem () );
        }
      else
        {
          PlotParamnamecomboBox->addItem ( header );
          if (header != tr("iter"))
            {
              StattableWidget->insertRow (StattableWidget->rowCount());
              StattableWidget->setItem ( StattableWidget->rowCount()-1,0,new QTableWidgetItem ( header ) );
              for (int col=1;col<StattableWidget->columnCount();col++)
                StattableWidget->setItem(StattableWidget->rowCount()-1,col,new QTableWidgetItem () );
            }
        }
    }

  f.close();

  if (( sampleSizes[PlotRepcomboBox->currentIndex() ] >= 2 ) && (tabWidget->currentIndex() == 1))
    setRawData();
  else if ((tabWidget->currentIndex() == 2))
    print_posterior_estimates();

}

void MainWindowImpl::setRawData()
{
  if ( sampleSizes[PlotRepcomboBox->currentIndex() ] < 2 )
    {
      QMessageBox::information ( this,tr ( "Data not yet available" ),tr ( "Sampling has not begun for replicate #%1" ).arg(PlotRepcomboBox->currentIndex()) );
      return;
    }

  QString mcmcFilename = projectFilename.left ( projectFilename.length()-4 ) + tr ( "_" ) + PlotRepcomboBox->currentText() + tr ( "_" ) + PlotParamcomboBox->currentText() + tr ( ".txt" );
  if ( rawdata != NULL )
    delete rawdata;

  rawdata = new RawData ( mcmcFilename.toStdString(),PlotParamnamecomboBox->currentIndex(),sampleSizes[PlotRepcomboBox->currentIndex() ] );
  resetSliders();
  setStatistics();
  makePlot();
}

void MainWindowImpl::setBurnin()
{
  BurninhorizontalSlider->setRange ( 0,BurnouthorizontalSlider->value()-1 );
  reloadRawData();
}

void MainWindowImpl::setBurnout()
{
  BurnouthorizontalSlider->setRange ( BurninhorizontalSlider->value() +1,rawdata->n-1 );
  reloadRawData();
}

void MainWindowImpl::reloadRawData()
{
  rawdata->getStatistics ( BurninhorizontalSlider->value(),rawdata->n-1-BurnouthorizontalSlider->value() );
  MinValuelabel->setText ( tr ( "%1" ).arg ( rawdata->min,0,'g',3 ) );
  MaxValuelabel->setText ( tr ( "%1" ).arg ( rawdata->max,0,'g',3  ) );
  MeanValuelabel->setText ( tr ( "%1" ).arg ( rawdata->mean,0,'g',3  ) );
  SdValuelabel->setText ( tr ( "%1" ).arg ( rawdata->sd,0,'g',3  ) );
  updateDensity();
  makePlot();
}

void MainWindowImpl::resetSliders()
{
  disconnect ( BandwidthSlider,SIGNAL ( valueChanged ( double ) ),this,SLOT ( updateDensity() ) );
  disconnect ( BurninhorizontalSlider,SIGNAL ( valueChanged ( int ) ),this,SLOT ( setBurnout() ) );
  disconnect ( BurnouthorizontalSlider,SIGNAL ( valueChanged ( int ) ),this,SLOT ( setBurnin() ) );

  BandwidthSlider->setValue ( 0 );
  BurninhorizontalSlider->setRange ( 0,rawdata->n-2 );
  BurninhorizontalSlider->setValue ( 0 );
  BurnouthorizontalSlider->setRange ( 1,rawdata->n-1 );
  BurnouthorizontalSlider->setValue ( rawdata->n-1 );

  connect ( BandwidthSlider,SIGNAL ( valueChanged ( double ) ),this,SLOT ( updateDensity() ) );
  connect ( BurninhorizontalSlider,SIGNAL ( valueChanged ( int ) ),this,SLOT ( setBurnout() ) );
  connect ( BurnouthorizontalSlider,SIGNAL ( valueChanged ( int ) ),this,SLOT ( setBurnin() ) );
}

void MainWindowImpl::updateDensity()
{
  RawData::kernel_t kernel = RawData::Null;
  switch ( KernelcomboBox->currentIndex() )
    {
    case 0:
      kernel = RawData::Epanechnikov;
      break;
    case 1:
      kernel = RawData::Triangular;
      break;
    case 2:
      kernel = RawData::Gaussian;
      break;
    case 3:
      kernel = RawData::Boxcar;
      break;
    default:
      break;
    }
  rawdata->getKde ( kernel,exp ( BandwidthSlider->value() ),BurninhorizontalSlider->value(),rawdata->n-1-BurnouthorizontalSlider->value() );
  ModeValuelabel->setText ( tr ( "%1" ).arg ( rawdata->mode,0,'g',3  ) );
  updateHPDI ( AlphaspinBox->value() );
  if ( DensityradioButton->isChecked() )
    {
      plot->clear();
      plot->DensityPlot ( rawdata->x_kde,rawdata->y_kde,rawdata->N,PlotParamnamecomboBox->currentText() );
    }
}

void MainWindowImpl::updateHist()
{
  if ( HistogramradioButton->isChecked() )
    {
      int offset = BurninhorizontalSlider->value();
      int length = BurnouthorizontalSlider->value() - BurninhorizontalSlider->value() +1;
      plot->clear();
      plot->HistogramPlot ( rawdata->obs+offset,length,PlotParamnamecomboBox->currentText(),BinspinBox->value(),rawdata->min,rawdata->max );
    }
}

void MainWindowImpl::updateHPDI ( int conf )
{
  rawdata->getHpdi ( ( 100.0-conf ) /100.0 );
  InfValuelabel->setText ( tr ( "%1" ).arg ( rawdata->hpdilo,0,'g',3  ) );
  SupValuelabel->setText ( tr ( "%1" ).arg ( rawdata->hpdihi,0,'g',3  ) );
  WidthValuelabel->setText ( tr ( "%1" ).arg ( rawdata->hpdihi-rawdata->hpdilo,0,'g',3  ) );
}

void MainWindowImpl::makePlot()
{
  int offset = BurninhorizontalSlider->value();
  int length = BurnouthorizontalSlider->value() - BurninhorizontalSlider->value() +1;
  plot->clear();
  if ( TraceradioButton->isChecked() )
    plot->TracePlot ( rawdata->iter+offset,rawdata->obs+offset,length,PlotParamnamecomboBox->currentText() );
  if ( RunningmeanradioButton->isChecked() )
    plot->RunningmeanPlot ( rawdata->iter+offset,rawdata->obs+offset,length,PlotParamnamecomboBox->currentText() );
  if ( DensityradioButton->isChecked() )
    plot->DensityPlot ( rawdata->x_kde,rawdata->y_kde,rawdata->N,PlotParamnamecomboBox->currentText() );
  if ( HistogramradioButton->isChecked() )
    plot->HistogramPlot ( rawdata->obs+offset,length,PlotParamnamecomboBox->currentText(),BinspinBox->value(),rawdata->min,rawdata->max );
}

void MainWindowImpl::setStatistics()
{
  MinValuelabel->setText ( tr ( "%1" ).arg ( rawdata->min,0,'g',3  ) );
  MaxValuelabel->setText ( tr ( "%1" ).arg ( rawdata->max,0,'g',3  ) );
  MeanValuelabel->setText ( tr ( "%1" ).arg ( rawdata->mean,0,'g',3  ) );
  SdValuelabel->setText ( tr ( "%1" ).arg ( rawdata->sd,0,'g',3  ) );
  ModeValuelabel->setText ( tr ( "%1" ).arg ( rawdata->mode,0,'g',3  ) );
  InfValuelabel->setText ( tr ( "%1" ).arg ( rawdata->hpdilo,0,'g',3  ) );
  SupValuelabel->setText ( tr ( "%1" ).arg ( rawdata->hpdihi,0,'g',3  ) );
  WidthValuelabel->setText ( tr ( "%1" ).arg ( rawdata->hpdihi-rawdata->hpdilo,0,'g',3  ) );
}

void MainWindowImpl::updateSize ( int run ,double dev)
{
  sampleSizes[run-1]++;
  RuntableWidget->item(run-1,RuntableWidget->columnCount()-1)->setText(tr("%1").arg( dev/sampleSizes[run-1],0,'f',1));
}

void MainWindowImpl::updateAcceptance ( int run,int length,double nm_acc,double m_acc, double Mt_acc,double F_acc,double p_acc,double theta_acc,double pglob_acc,double psi_acc,double Rj_acc )
{
  int k=3;
  if (MCMC::getI() > 2)
    RuntableWidget->item ( run-1,k++ )->setText ( tr ( "%1" ).arg ( nm_acc*100/ ( length*MCMC::getI() ),0,'f',1  ) );

  RuntableWidget->item ( run-1,k++ )->setText ( tr ( "%1" ).arg ( m_acc*100/ ( length*MCMC::getI() ),0,'f',1  ) );
  RuntableWidget->item ( run-1,k++ )->setText ( tr ( "%1" ).arg ( Mt_acc*100/ ( length*MCMC::getn() ),0,'f',1  ) );
  RuntableWidget->item ( run-1,k++ )->setText ( tr ( "%1" ).arg ( F_acc*100/ ( length*MCMC::getI() ) ,0,'f',1 ) );
  RuntableWidget->item ( run-1,k++ )->setText ( tr ( "%1" ).arg ( p_acc*100/ ( length*MCMC::getI() *MCMC::getJ() ),0,'f',1  ) );
  if (wizard->field("Fst").toBool())
    {
      RuntableWidget->item ( run-1,k++ )->setText ( tr ( "%1" ).arg ( theta_acc*100/ ( length*MCMC::getI() ),0,'f',1 ) );
      RuntableWidget->item ( run-1,k++ )->setText ( tr ( "%1" ).arg ( pglob_acc*100/ ( length*MCMC::getJ() ) ,0,'f',1 ) );
    }
  if (wizard->field("NGData").toBool())
    {
      RuntableWidget->item ( run-1,k++)->setText ( tr ( "%1" ).arg ( psi_acc*100/ ( length* ( MCMC::getI()-1 ) *MCMC::getI() ),0,'f',1  ) );
    }

  if (wizard->field("NGData").toBool() && wizard->field("RJ").toBool())
    RuntableWidget->item ( run-1,k++)->setText ( tr ( "%1" ).arg ( Rj_acc*100/length ,0,'f',1 ) );

  RuntableWidget->resizeColumnsToContents();
}

void MainWindowImpl::updateStatus ( int run,QString status )
{
  RuntableWidget->item (run-1,1 )->setText ( status );
  RuntableWidget->resizeColumnToContents(1);
  if (!tabWidget->isTabEnabled(1) && status == tr("Sampling"))
    {
      tabWidget->setTabEnabled(1,true);
      tabWidget->setTabEnabled(2,true);
      tabWidget->setTabEnabled(3,wizard->field("NGData").toBool() && wizard->field("RJ").toBool());
    }
}

void MainWindowImpl::updateProgress ( int run,double progress )
{
  int old = progressBar->value();
  progressBar->setValue ( old+5 );
  RuntableWidget->item ( run-1,2 )->setText ( tr ( "%1" ).arg ( progress ) );

  RuntableWidget->resizeColumnsToContents();
  RuntableWidget->resizeRowsToContents();
}

void MainWindowImpl::setPlotStatConnections()
{
  connect ( PlotRepcomboBox,SIGNAL ( currentIndexChanged ( int ) ),this,SLOT ( setRawData() ) );
  connect ( PlotParamnamecomboBox,SIGNAL ( currentIndexChanged ( int ) ),this,SLOT ( setRawData() ) );
  connect ( PlotParamcomboBox,SIGNAL ( currentIndexChanged ( int ) ),this,SLOT ( writeParameterNames() ) );
  connect (StatParamcomboBox,SIGNAL(currentIndexChanged ( int )),this,SLOT(writeParameterNames()));

  connect ( TraceradioButton,SIGNAL ( clicked() ),this,SLOT ( makePlot() ) );
  connect ( RunningmeanradioButton,SIGNAL ( clicked() ),this,SLOT ( makePlot() ) );
  connect ( HistogramradioButton,SIGNAL ( clicked() ),this,SLOT ( makePlot() ) );
  connect ( DensityradioButton,SIGNAL ( clicked() ),this,SLOT ( makePlot() ) );

  connect ( BinspinBox,SIGNAL ( valueChanged ( int ) ),this,SLOT ( updateHist() ) );
  connect ( AlphaspinBox,SIGNAL ( valueChanged ( int ) ),this,SLOT ( updateHPDI ( int ) ) );
  connect ( KernelcomboBox,SIGNAL ( currentIndexChanged ( int ) ),this,SLOT ( updateDensity() ) );

  connect ( BandwidthSlider,SIGNAL ( valueChanged ( double ) ),this,SLOT ( updateDensity() ) );
  connect ( BurninhorizontalSlider,SIGNAL ( valueChanged ( int ) ),this,SLOT ( setBurnout() ) );
  connect ( BurnouthorizontalSlider,SIGNAL ( valueChanged ( int ) ),this,SLOT ( setBurnin() ) );

  connect(ModelcomboBox,SIGNAL(currentIndexChanged ( int )),this,SLOT(print_regression_estimates()));

  connect (actionRefresh,SIGNAL(activated()),this,SLOT(refresh()));
  connect(tabWidget,SIGNAL(currentChanged(int)),this,SLOT(refresh()));
}

void MainWindowImpl::refresh()
{
  for (int run=0;run<nbreplicates;run++)
    StattableWidget->item(0,run+1)->setText(tr("%1").arg(sampleSizes[run]));

  /* Plot */
  if ((tabWidget->currentIndex() == 1) || (tabWidget->currentIndex() == 2))
    writeParameterNames();

  /* Model estimates */
  if (tabWidget->currentIndex() == 3)
    {
      print_model_estimates();
      print_regression_estimates();
    }
}

void MainWindowImpl::saveSettings()
{
  projectFilename = wizard->field("gen_filename").toString();
  projectFilename.replace(projectFilename.length()-3,3,"bpj");

  QFile file ( projectFilename );
  if ( !file.open ( QIODevice::WriteOnly | QIODevice::Text ) )
    return;
  QTextStream out ( &file );

  out << "[genodata]=" << wizard->field("gen_filename").toString() << endl;

  if (wizard->field("NGData").toBool())
    {
      out << "[factors]=" << wizard->field("env_filename").toString() << endl;
      out << "[interaction]=" << wizard->field("inter").toBool() << endl;
    }

  /* Run settings */
  out << "[burnin]=" << wizard->field("burnin").toInt() << endl;
  out << "[samplesize]=" << wizard->field("smpSize").toInt() << endl;
  out << "[thining]=" <<   wizard->field("thining").toInt() << endl;

  /* Advanced options */
  out << "[regression]=" << wizard->field("NGData").toBool() << endl;
  out << "[RJMCMC]=" << (wizard->field("NGData").toBool() && wizard->field("RJ").toBool()) << endl;
  out << "[Fmodel]=" << wizard->field("Fst").toBool() << endl;

  /* Output options */
  out << "[lglik]=" << wizard->field("printlglik").toBool() << endl;
  out << "[psi]=" << wizard->field("printpsi").toBool() << endl;
  out << "[mig]=" << wizard->field("printm").toBool() << endl;
  out << "[mtild]=" << wizard->field("printmig").toBool() << endl;
  out << "[reg]=" << (wizard->field("NGData").toBool() && wizard->field("printreg").toBool()) << endl;
  out << "[popfrq]=" << wizard->field("printp").toBool() << endl;
  out << "[F]=" << wizard->field("printF").toBool() << endl;
  out << "[Fst]=" << (wizard->field("Fst").toBool() && wizard->field("printFst").toBool()) << endl;
  out << "[ancfrq]=" << wizard->field("printptild").toBool() << endl;
  out << "[sd]=" <<  wizard->field("printsd").toBool()<< endl;
  out << "[indivq]=" << wizard->field("printMt").toBool() << endl;
  out << "[popq]=" << wizard->field("printPop").toBool() << endl;

  /* Pilot runs */
  out << "[pilotlength]=" << wizard->field("pilotlength").toInt() << endl;
  out << "[pilotruns]=" << wizard->field("npilot").toInt() * wizard->field("usepilot").toBool() << endl;

  /* Parameters for prior distributions */
  out << "[a_tau]=" << wizard->field("a_tau").toDouble() << endl;
  out << "[b_tau]=" << wizard->field("b_tau").toDouble() << endl;
  out << "[s2_alpha]=" << wizard->field("s2_alpha").toDouble() << endl;
  out << "[Psi]=" << wizard->field("psi").toDouble() << endl;
  out << "[lambda]=" << wizard->field("lambda").toDouble() << endl;
  out << "[omega]=" << wizard->field("omega").toDouble() << endl;
  out << "[xi]=" << wizard->field("xi").toDouble() << endl;

  /* Proposal parameters */
  out << "[s2_theta]=" << wizard->field("s2_theta").toDouble() << endl;
  out << "[s2_psi]=" << wizard->field("s2_psi").toDouble() << endl;
  out << "[e_p]=" << wizard->field("e_p").toDouble() << endl;
  out << "[e_F]=" << wizard->field("e_F").toDouble() << endl;
  out << "[e_m]=" << wizard->field("e_m").toDouble() << endl;
  out << "[e_nm]=" << wizard->field("e_nm").toDouble() << endl;

  file.close();
}

void MainWindowImpl::readProjectFile()
{
  qDebug() << "Read BIMr project file";

  QFileInfo info(projectFilename);
  if ( !info.exists() || !info.isFile())
    return;

  QFile file(projectFilename);
  if ( !file.open ( QIODevice::ReadOnly | QIODevice::Text ) )
    return;

  /* Read project file */
  QTextStream in ( &file );
  while ( !in.atEnd() )
    {
      QString line = in.readLine();
      QStringList list = line.split ( "=" );

      if ( list.count() > 1 )
        {
          if ( list.first() == tr ( "[genodata]" ) )
            {
              wizard->setField("gen_filename",QVariant(list.last()));
            }
          else if ( list.first() == tr ( "[factors]" ) )
            wizard->setField("env_filename",QVariant(list.last()));

          else if ( list.first() == tr ( "[nbfactors]" ) )
            R=list.last().toInt();

          else if (list.first() == tr("[interaction]"))
            {
              wizard->setField("inter",QVariant(list.last().toInt() == 1));
            }

          else if ( list.first() == tr ( "[burnin]" ) )
            wizard->setField("burnin",QVariant(list.last().toInt()));

          else if ( list.first() == tr ( "[samplesize]" ) )
            wizard->setField("smpSize",QVariant(list.last().toInt()));

          else if ( list.first() == tr ( "[thining]" ) )
            wizard->setField("thining",QVariant(list.last().toInt()));

          else if ( list.first() == tr ( "[runs]" ) )
            wizard->setField("nrep",QVariant(list.last().toInt()));

          else if ( list.first() == tr ( "[regression]" ) )
            {
              wizard->setField("NGData",QVariant(list.last().toInt() == 1 ));
            }

          else if ( list.first() == tr ( "[RJMCMC]" ) )
            {
              wizard->setField("RJ",QVariant(list.last().toInt() == 1));
            }

          else if ( list.first() == tr ( "[Fmodel]" ) )
            wizard->setField("Fst",QVariant(list.last().toInt() == 1));

          else if ( list.first() == tr ( "[pilotruns]" ) )
            {
              wizard->setField("npilot",QVariant(list.last().toInt()));
              wizard->setField("usepilot",QVariant(list.last().toInt() != 0 ));
            }

          else if ( list.first() == tr ( "[pilotlength]" ) )
            wizard->setField("pilotlength",QVariant(list.last().toInt()));

          else if ( list.first() == tr ( "[a_tau]" ) )
            wizard->setField("a_tau",QVariant(list.last().toDouble()));

          else if ( list.first() == tr ( "[b_tau]" ) )
            wizard->setField("b_tau",QVariant(list.last().toDouble()));

          else if ( list.first() == tr ( "[s2_alpha]" ) )
            wizard->setField("s2_alpha",QVariant(list.last().toDouble()));

          else if ( list.first() == tr ( "[Psi]" ) )
            wizard->setField("psi",QVariant(list.last().toDouble()));

          else if ( list.first() == tr ( "[lambda]" ) )
            wizard->setField("lambda",QVariant(list.last().toDouble()));

          else if ( list.first() == tr ( "[omega]" ) )
            wizard->setField("omega",QVariant(list.last().toDouble()));

          else if ( list.first() == tr ( "[xi]" ) )
            wizard->setField("xi",QVariant(list.last().toDouble()));

          else if ( list.first() == tr ( "[e_nm]" ) )
            wizard->setField("e_nm",QVariant(list.last().toDouble()));

          else if ( list.first() == tr ( "[e_m]" ) )
            wizard->setField("e_m",QVariant(list.last().toDouble()));

          else if ( list.first() == tr ( "[e_F]" ) )
            wizard->setField("e_F",QVariant(list.last().toDouble()));

          else if ( list.first() == tr ( "[e_p]" ) )
            wizard->setField("e_p",QVariant(list.last().toDouble()));

          else if ( list.first() == tr ( "[s2_theta]" ) )
            wizard->setField("s2_theta",QVariant(list.last().toDouble()));

          else if ( list.first() == tr ( "[s2_psi]" ) )
            wizard->setField("s2_psi",QVariant(list.last().toDouble()));

          else if ( list.first() == tr ( "[lglik]" ) )
            wizard->setField("printlglik",QVariant(list.last().toInt()==1));

          else if ( list.first() == tr ( "[F]" ) )
            wizard->setField("printF",QVariant(list.last().toInt()==1));

          else if ( list.first() == tr ( "[Fst]" ) )
            wizard->setField("printFst",QVariant(list.last().toInt()==1));

          else if ( list.first() == tr ( "[indivq]" ) )
            wizard->setField("printMt",QVariant(list.last().toInt()==1));

          else if ( list.first() == tr ( "[mig]" ) )
            wizard->setField("printm",QVariant(list.last().toInt()==1));

          else if ( list.first() == tr ( "[mtild]" ) )
            wizard->setField("printmig",QVariant(list.last().toInt()==1));

          else if ( list.first() == tr ( "[popfrq]" ) )
            wizard->setField("printp",QVariant(list.last().toInt()==1));

          else if ( list.first() == tr ( "[ancfrq]" ) )
            wizard->setField("printptild",QVariant(list.last().toInt()==1));

          else if ( list.first() == tr ( "[reg]" ) )
            wizard->setField("printreg",QVariant(list.last().toInt()==1));

          else if ( list.first() == tr ( "[sd]" ) )
            wizard->setField("printsd",QVariant(list.last().toInt()==1));

          else if ( list.first() == tr ( "[psi]" ) )
            wizard->setField("printpsi",QVariant(list.last().toInt()==1));

          else if ( list.first() == tr ( "[popq]" ) )
            wizard->setField("printPop",QVariant(list.last().toInt()==1));
        }
    }
  qDebug() << "Read BIMr project file ... (done)";
}

void MainWindowImpl::loadProject()
{
  actionStart_new_analysis->setEnabled ( false );
  actionLoad_saved_analysis->setEnabled ( false );
  actionRun->setEnabled ( false );
  actionClose->setEnabled ( true );

  disconnect ( wizard,SIGNAL ( accepted() ),this,SLOT ( acceptSettings() ) );

  readProjectFile();
  nbreplicates=wizard->field("nrep").toInt();

  sampleSizes = new int [wizard->field("nrep").toInt()];
  if ( !sampleSizes )
    {
      qDebug() << "Load data error";
      quit();
    }

  tabWidget->setTabEnabled(3,wizard->field("NGData").toBool() && wizard->field("RJ").toBool());
  fillComboBoxes_and_Tables();
  PlotRepcomboBox->clear();
  for ( int rep=0;rep<wizard->field("nrep").toInt();rep++ )
    {
      sampleSizes[rep] = wizard->field("smpSize").toInt();
      PlotRepcomboBox->addItem ( tr ( "run%1" ).arg ( rep+1 ) );
      StattableWidget->insertColumn ( StattableWidget->columnCount() );
      StattableWidget->setHorizontalHeaderItem ( StattableWidget->columnCount()-1,new QTableWidgetItem ( tr ( "run%1" ).arg ( rep+1 ) ) );
      StattableWidget->setItem(0,rep+1,new QTableWidgetItem(tr("%1").arg(sampleSizes[rep])));
    }

  actionRun->setEnabled(false);
  actionRefresh->setEnabled(false);
  rawdata = NULL;
  setPlotStatConnections();
  tabWidget->setTabEnabled ( 0,false );

  /* Fill tables */
  if (tabWidget->isTabEnabled(3))
    tabWidget->setCurrentIndex (3);
  tabWidget->setCurrentIndex (2);
  tabWidget->setCurrentIndex (1);

  disconnect(tabWidget,SIGNAL(currentChanged(int)),this,SLOT(refresh()));
}

void MainWindowImpl::saveTable()
{
  if (tabWidget->currentIndex() >= 2)
    {
      QString savefilename = QFileDialog::getSaveFileName(this,tr("Save table to text file"),QDir::homePath(),"Text Files (*.txt)");
      QFile data(savefilename);
      if (data.open(QFile::WriteOnly | QFile::Truncate))
        {
          QTextStream out(&data);

          if (tabWidget->currentIndex() == 2)
            {
              out << "Param/Run";
              for (int col=1;col<StattableWidget->columnCount();col++)
                out << '\t' << tr("run%1").arg(col);
              out << endl;

              for (int row=1;row<StattableWidget->rowCount();row++)
                {
                  out << StattableWidget->item(row,0)->text();
                  for (int i=0;i<3;i++)
                    {
                      for (int col=1;col<StattableWidget->columnCount();col++)
                        out << '\t' << StattableWidget->item(row,col)->text().split('\n').at(i);
                      out << endl;
                    }
                }
            }

          else if (tabWidget->currentIndex() == 3)
            {
              if (QMessageBox::question(this,tr("Save table"),tr("Save posterior model probabilities?"),QMessageBox::No,QMessageBox::Ok)==QMessageBox::Ok)
                {
                  out << "Model" << '\t' <<"Factors included";
                  for (int col=2;col<ModeltableWidget->columnCount();col++)
                    out << '\t' << tr("run%1").arg(col);
                  out << endl;

                  for (int row=0;row<ModeltableWidget->rowCount();row++)
                    {
                      out << ModeltableWidget->item(row,0)->text();
                      for (int col=1;col<ModeltableWidget->columnCount();col++)
                        out << '\t' << ModeltableWidget->item(row,col)->text();
                      out << endl;
                    }
                }
              else
                {
                  QMessageBox::question(this,tr("Save table"),tr("Save regression parameter estimates under current model?"));
                  out << "Param/Run";
                  for (int col=1;col<RegtableWidget->columnCount();col++)
                    out << '\t' << tr("run%1").arg(col);
                  for (int row=0;row<RegtableWidget->rowCount();row++)
                    {
                      out << RegtableWidget->item(row,0)->text();
                      for (int i=0;i<3;i++)
                        {
                          for (int col=1;col<RegtableWidget->columnCount();col++)
                            out << '\t' << RegtableWidget->item(row,col)->text().split('\n').at(i);
                          out << endl;
                        }
                    }
                }
            }
        }
    }
  else
    QMessageBox::information(this,tr("Can not save table"),tr("Choose a tab that contains tables."));
}

void MainWindowImpl::savePlot()
{
  if (tabWidget->currentIndex() == 1)
    {
      QPixmap *image = new QPixmap();

      QString format;
      // Get available image formats
      QString formats;
      int formatcount = QImageWriter::supportedImageFormats().count();
      for ( int i = 0; i < formatcount ; i++ )
        formats.append(QString(QImageWriter::supportedImageFormats().at(i))+ ( i == formatcount-1 ? "" :";;" ) );

      // Get save file name
      QString savefilename = QFileDialog::getSaveFileName ( this,tr ( "Save file as" ),QDir::homePath(),formats,&format );
      if ( !savefilename.isEmpty() )
        {
          QFile imgfile ( savefilename );
          *image = QPixmap::grabWidget ( Plotframe );
          image->save ( savefilename,format.toStdString().data() );
        }
    }
  else
    QMessageBox::information(this,tr("Save figure"),tr("Choose Plot tab"));
}

void MainWindowImpl::About()
{
  if (sender()->objectName() == "actionAbout_Qt")
    {
      QMessageBox::aboutQt ( this,tr ( "About Qt" ) );
      return;
    }

  QString pixmaprc = ":/Icons/Icons/";
  QString textrc = ":/About/About/";

  if (sender()->objectName() == "actionAbout")
    {
      pixmaprc += "BIMrIcon.png";
      textrc += "AboutBIMr.html";
    }
  else if (sender()->objectName() == "actionAbout_gsl")
    {
      pixmaprc += "gnu-head-banner.png";
      textrc += "AboutGSL.html";
    }
  else if (sender()->objectName() == "actionAbout_Qwt")
    {
      pixmaprc += "qwtplot.png";
      textrc += "AboutQWT.html";
    }

  UIAbout displayabout(this);
  displayabout.setPixmap(pixmaprc);
  displayabout.setText(textrc);
  displayabout.adjustSize();
  displayabout.exec();
}

void MainWindowImpl::whatsthis()
{
  QWhatsThis::enterWhatsThisMode();
}

void MainWindowImpl::displayManual()
{
  QUrl helpUrl(tr("http://www-leca.ujf-grenoble.fr/logiciels/BIMr/manual.html"));
  QDesktopServices::openUrl(helpUrl);
}

void MainWindowImpl::displayConverter()
{
  UIConverter converter(this);
  converter.exec();
}

/* Exit application */
void MainWindowImpl::quit()
{
  /* Check for running job */
  if ( runningThreads > 0 )
    {
      QMessageBox::information ( this,tr ( "Running jobs: %1" ).arg(runningThreads),tr ( "Stop MCMC runs" ) );
      killJob();
    }

  if (plot)
    delete plot;
  if (sampleSizes)
    delete [] sampleSizes;
  if (rawdata)
    delete rawdata;

  /* Quit */
  QCoreApplication::quit();
}

/* Close current session and open a new one */
void MainWindowImpl::close()
{
  /* Check for running job */
  if ( runningThreads > 0 )
    {
      QMessageBox::information ( this,tr ( "Running jobs: %1" ).arg(runningThreads),tr ( "Stop MCMC runs" ) );
      killJob();
    }

  if (rawdata)
    delete rawdata;
  if (plot)
    delete plot;
  if (sampleSizes)
    delete [] sampleSizes;

  /* Start a new session */
  if ( QMessageBox::question ( this,tr ( "Close" ),tr ( "Do you want to close current session?" ),QMessageBox::Yes,QMessageBox::No,QMessageBox::Cancel ) == QMessageBox::Yes )
    {
      MainWindowImpl *win = new MainWindowImpl;
      win->show();
      QWidget::close();
    }
}

bool MainWindowImpl::is_a_valid_model(int M)
{
  int r = R;
  if ( wizard->field("inter").toBool() && ( M > 1 << ( R - 1 ) ) )
    for ( int r1 = 0; r1 < R; r1++ )
      for ( int r2 = r1 + 1; r2 < R; r2++ )
        {
          if ( ( ( M >> r ) % 2 )
               && ! ( ( ( M >> r1 ) % 2 ) && ( ( M >> r2 ) % 2 ) ) )
            return false;
          r++;
        }
  return true;
}
