/***************************************************************************
 *   Copyright (C) 2005 by Joachim Friedrich                               *
 *   joachim.friedrich@biozentrum.uni-wuerzburg.de                         *
 *                                                                         *
 *   This file is part of profdist and cbcanalyzer                         *
 *                                                                         *
 *   Both profdist and cbcanalyzer are 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.                       *
 *                                                                         *
 *   Profdist and cbcanalyzer are 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 <iostream>
#include <iterator>
#include <sstream>
#include "cbcAnalyser.h"
#include "temp_files.h"
#include "parser.h"
#include "wx_streambuf.h"
#include "wx_colorbuf.h"
#include "ct_transform.h"
#include "cbcs.h"
#include "concepts.h"
#include "distance.h"
#include "bionj_clean.h"
#include "progress_dialog.h"

#ifdef DARWIN_SYSTEM
#include <Carbon/Carbon.h>
#endif

void MyFrame::startTrans()
{
  if ( doTrans() > 0 )
  {
    wxMessageDialog dialog( this, "File successfull transformed!", _T( "Message" ) );
    dialog.ShowModal();
  }
  txtTransOutput->SetFocusFromKbd();
  txtTransOutput->SetInsertionPoint( 0 );
}


void MyFrame::startDetect()
{
  txtDetectOutput->Clear();
  if ( doDetect() > 0 )
  {
    wxMessageDialog dialog( this, "CBCs sucessfull detected!" );
    dialog.ShowModal();
  }
  txtDetectOutput->SetFocusFromKbd();
  txtDetectOutput->SetInsertionPoint( 0 );
}

void MyFrame::startTree()
{
  txtTreeOutput->Clear();
  if ( doTree() > 0 )
  {
    wxMessageDialog dialog( this, "Tree sucessfull created!" );
    dialog.ShowModal();
  }
  txtTreeOutput->SetFocusFromKbd();
  txtTreeOutput->SetInsertionPoint(0);
}

void MyFrame::display_file( wxString const& tempfile )
{
if( ( mTreeViewType == 0 && mFileTreeViewer1.Length() == 0 ) 
      || ( mTreeViewType == 1 && mFileTreeViewer2.Length() == 0 )
    )
    return;

#ifdef DARWIN_SYSTEM
  switch(mTreeViewType) {
    case 0: 
    case 1: 
      {
        LSLaunchFSRefSpec launcher_spec;
        FSRef application;
        FSRef file;
        wxString app = (mTreeViewType==0)?mFileTreeViewer1:mFileTreeViewer2;
        FSPathMakeRef( reinterpret_cast<UInt8 const*>(tempfile.c_str()), &file, 0 );
        FSPathMakeRef( reinterpret_cast<UInt8 const*>(app.c_str()), &application, 0 );

        launcher_spec.appRef = &application;
        launcher_spec.numDocs = 1;
        launcher_spec.itemRefs = &file;
        launcher_spec.passThruParams = 0;
        launcher_spec.launchFlags = kLSLaunchDefaults;
        launcher_spec.asyncRefCon = 0;
        LSOpenFromRefSpec( &launcher_spec, 0 );
        break;
      }
    default: 
      wxExecute( "java -jar htnewick.jar " + tempfile);
      break;
  }


#else
  wxString execute;
  if ( mTreeViewType == 0 ) // Classic Tree Viewer1
    execute = mFileTreeViewer1 + " \"" + tempfile + "\"";
  else if ( mTreeViewType == 1 ) // Classic Tree Viewer2
    execute = mFileTreeViewer2 + " \"" + tempfile + "\"";
  else // hypertree
    execute = "java -jar htnewick.jar " + tempfile;

  wxExecute( execute );
#endif

}

void MyFrame::onMnuTree( wxCommandEvent & WXUNUSED( event ) )
{
  if ( mTreeViewType < 2 )
  {
    TempFile temp( "cbcTree" );
    txtTreeOutput->SaveFile( temp.file_name );
    display_file( temp.file_name );
  }
}

void MyFrame::onMnuStart( wxCommandEvent & WXUNUSED( event ) )
{
  int idxCurrent = ntbAll->GetSelection();

  switch ( idxCurrent )
  {
    case 0: // Bootstrap
      {
        if ( txtTransInput->GetLastPosition() > 0 )
          startTrans();
      }
    break;
    case 1: // Distance
      {
        if ( txtDetectInput->GetLastPosition() > 0 )
          startDetect();
      }
    break;
    case 2: // Nj
      {
        if ( txtTreeInput->GetLastPosition() > 0 )
          startTree();
      }
    break;
  }
}

void MyFrame::onMnuSave( wxCommandEvent & WXUNUSED( event ) )
{
  int idxCurrent = ntbAll->GetSelection();

  switch ( idxCurrent )
  {
    case 0: // Bootstrap
      {
        if ( txtTransOutput->GetLastPosition() > 0 )
          saveTrans();
      }
    break;
    case 1: // Distance
      {
        if ( txtDetectOutput->GetLastPosition() > 0 )
          saveDetect();
      }
    break;
    case 2: // Nj
      {
        if ( txtTreeOutput->GetLastPosition() > 0 )
          saveTree();
      }
    break;
  }
}

void MyFrame::onMnuExit( wxCommandEvent & WXUNUSED( event ) )
{
  Close( true );
}



void MyFrame::onMnuPref( wxCommandEvent & WXUNUSED( event ) )
{
  MyDialogPref dialog( this, -1, "" );

#if defined(UNIX_SYSTEM) || defined(DARWIN_SYSTEM)
  dialog.setPreferences( mEvoModel, mTreeViewType, mFileTreeViewer1, mFileTreeViewer2, mFileBrowser);
#else
  dialog.setPreferences( mEvoModel, mTreeViewType, mFileTreeViewer1, mFileTreeViewer2 );
#endif

  if ( dialog.ShowModal() == idBtnPrefOk )
  {
#if defined(UNIX_SYSTEM) || defined(DARWIN_SYSTEM)
    dialog.getPreferences( mEvoModel, mTreeViewType, mFileTreeViewer1, mFileTreeViewer2, mFileBrowser);
    mHyperRNA->SetBrowserPath( mFileBrowser );
    mHyperMarna->SetBrowserPath( mFileBrowser );
#else
    dialog.getPreferences( mEvoModel, mTreeViewType, mFileTreeViewer1, mFileTreeViewer2 );
#endif

    saveXmlFile();
  }

}


void MyFrame::onMnuOpen( wxCommandEvent & WXUNUSED( event ) )
{
  int idxCurrent = ntbAll->GetSelection();

  switch ( idxCurrent )
  {
    case 0: // Bootstrap
      openFileTrans();
    break;
    case 1: // Distance
      openFileDetect();
    break;
    case 2: // Nj
      openFileTree();
    break;
  }
}

//---------------------------------------------------------------------------
//
//  name          : onCloseEvent
//
//  description   : read the Parameters stored in Xml File
//
//  input         : *this
//
//  return value  : void
//
//---------------------------------------------------------------------------
void MyFrame::onCloseEvent( wxCloseEvent & event)
{
  // Close the help frame; this will cause the config data to
  // get written.
  if ( help.GetFrame() ) // returns NULL if no help frame active
    help.GetFrame()->Close( TRUE );
  // now we can safely delete the config pointer
  event.Skip();
  delete wxConfig::Set( NULL );

  saveXmlFile();
  Destroy();
}

//---------------------------------------------------------------------------
//
//  name          : onMnuAbout
//
//  description   : Load a text file in Input Window from Bootstrap
//
//  input         : *this
//
//  return value  : void
//
//---------------------------------------------------------------------------
void MyFrame::onMnuAbout( wxCommandEvent & WXUNUSED( event ) )
{
  MyDialogAbout dialog( this, -1, "" );

  dialog.ShowModal();
}

void MyFrame::onMnuUndo( wxCommandEvent & WXUNUSED( event ) )
{
  wxTextCtrl * tempTextCtrl = getFocusedText();

  if ( tempTextCtrl->CanUndo() )
    tempTextCtrl->Undo();
}


bool MyFrame::doTree()
{
  using namespace std;
  vector<string> seq_names;

  TempFile file( "cbcTree");
  txtTreeInput->SaveFile( file.file_name );

  ifstream in( file.file_name.c_str() );

  profdist::distance_matrix mat;
  
  if(! profdist::read_distance_matrix( in, mat, back_insert_iterator<vector<string> >(seq_names) ) )
  {
    std::ostringstream msg;
    wxMessageDialog dialog( this, "Failure while parsing matrix",  "Error", wxICON_ERROR );
    dialog.ShowModal();
    return false;
  }

  if( mat.nRows() < 3 )
  {
    ///Message Error if not the siez of the matrix is
    wxMessageDialog dialog( this, "BIONJ need at least 3 nodes!", "Error", wxICON_ERROR );
    dialog.ShowModal();
    return false;
  }

  int num_steps = mat.nRows() - 3;

  ProgressDialog dialog( _T( "Progress dialog" ), _T( "Duration of step: 1" ),
      num_steps, this, wxPD_CAN_ABORT | wxPD_APP_MODAL | wxPD_AUTO_HIDE | wxPD_ELAPSED_TIME | wxPD_REMAINING_TIME );


  txtTreeOutput->Clear();
  {
    wx_streambuf strbuf( *txtTreeOutput);
    std::ostream out( &strbuf );

    profdist::bionj( mat, seq_names, out, dialog );
  }
  txtDetectOutput->SetInsertionPoint( 0 );

  wxMessageDialog dialog2( this, "Tree successful created!", "Info", wxICON_INFORMATION );
  return true;

}

void MyFrame::onNotebook( wxNotebookEvent & event )
{

  //wxEventType eventType = event.GetEventType();

  int idxOld = event.GetOldSelection();
  int idxNew = event.GetSelection();

  //if ( idxOld != -1 && ntbAll->GetPageText( idxNew ) == "cbcTree" )
  if ( idxOld != -1 && idxNew == 2 )
  {
    wxString temp = txtDetectOutput->GetValue();
    wxString temp2 = txtTreeInput->GetValue();

    if ( temp.Len() > 0 && temp2 != temp ) // && event. == idNtbTree)
    {
      wxMessageDialog dialog( this, "cbcDetect has a new output.\nWould you like to copy the data?", "question",
           wxYES_NO | wxICON_QUESTION );
      if ( dialog.ShowModal() == wxID_YES )
        txtTreeInput->SetValue( temp );
    }
  }
}

wxTextCtrl * MyFrame::getFocusedText()
{
  wxWindow * win = FindFocus();

  wxTextCtrl * text = win ? wxDynamicCast( win, wxTextCtrl ) : NULL;
  return text; // ? text : textDef;
}


bool MyFrame::doDetect()
{
  std::list<file_sequence> sequences;

  TempFile file( "cbcDetect");
  txtDetectInput->SaveFile( file.file_name );


  bool parse_as_marna = false;
  std::ostringstream msg;
  msg << "Error while parsing!\n";
  try {
      parse_forester( file.file_name.c_str(), sequences );
  } catch( std::runtime_error const& e ) {
    parse_as_marna = true;
    msg << "Forester parser: " << e.what() << endl; 
  }

  if( parse_as_marna )
    try {
      parse_marna( file.file_name.c_str(), sequences );
    } catch( std::runtime_error const& e ) {
      msg << "Marna parser: " << e.what() << endl;
      wxMessageDialog dialog( this, wxString( msg.str().c_str()), _T( "Message" ) );
      dialog.ShowModal();
      return false;
    }


  CbcDetector detector;

  profdist::distance_matrix distances;

  typedef sequence_data< brace_fold_data< num_sequences<base_adaptor<file_sequence::iterator> > > > fold_type;

  profdist::compute_distance( fold_type( sequences ), distances, detector );

  name_data<base_adaptor<file_sequence::iterator> > name_data( sequences ); 

  {
    txtDetectOutput->Clear();
    wx_streambuf strbuf( *txtDetectOutput );
    std::ostream out( &strbuf );

    profdist::print_distance_matrix( out, distances, name_data.name_begin(), name_data.name_end(), true );
    out.flush();
  }
  txtDetectOutput->SetInsertionPoint( 0 );

  return true;
}

bool MyFrame::doTrans()
{
  bool is_ct = false;
  TempFile temp( "cbcTransformer" );
  txtTransInput->SaveFile( temp.file_name );

  std::list<file_sequence> sequences;
  try {
    parse_ct( temp.file_name.c_str(), sequences );
    is_ct = true;
  }
  catch( std::runtime_error const& e ) 
  {
    if( sequences.size() ) {
      std::ostringstream msg;
      msg << "Continue to Transform?\n" 
        << "CT-Parser: " << e.what() 
        << " but " << sequences.size() 
        << " Sequences found." << endl; 

      if( wxMessageBox( wxString( msg.str().c_str() ), _T( "Continue to Transform?" ), // caption
            wxYES_NO | wxICON_QUESTION ) != wxYES )
        return false;
    }
    else 
    {
      std::ostringstream msg;
      msg << "Failure while parsing!\n"
        << "CT-Parser: " << e.what() << endl;

      try{ 
        sequences.clear();
        parse_bdb( temp.file_name.c_str(), sequences );
        is_ct = false;
      }
      catch( std::runtime_error const& e ) {
        msg << e.what() << endl;

        wxMessageDialog dialog( this, wxString( msg.str().c_str()), _T( "Message" ) );
        dialog.ShowModal();
        return false;
      }
    }
  }
  { 
    txtTransOutput->Clear();
    wx_streambuf strbuf( *txtTransOutput );
    std::ostream out( &strbuf );

    if( is_ct )
      to_mixed_fasta( sequences, out );
    else 
    {
      typedef sequence_data< brace_fold_data< num_nuc<name_data< base_adaptor<file_sequence::iterator> > > > > fold_type;
      to_ct( fold_type( sequences ), out );
    }
    out.flush();
  }

  txtTransOutput->SetInsertionPoint( 0 );
  return true;
}

void MyFrame::openFileTrans()
{
  wxString strFileFormat;
  strFileFormat = "ct Files (*.ct)|*.ct|";
  strFileFormat += "text Files (*.txt)|*.txt|";
  strFileFormat += "All files (*)|*";

  wxFileDialog dialog( this, _T( "Open File Dialog" ), _T( "" ), _T( "" ), strFileFormat, wxMULTIPLE );


  if ( dialog.ShowModal() == wxID_OK )
  {
    wxArrayString fileList;
    dialog.GetPaths( fileList );
    txtTransInput->Clear();
    wxString temp;
    for ( unsigned int i = 0; i < fileList.GetCount(); ++i )
    {
      txtTransInput->LoadFile( fileList.Item( i ).c_str() );
      temp += txtTransInput->GetValue() + "\n";
    }
    txtTransInput->SetValue( temp );
  }
}


void MyFrame::openFileTree()
{
  wxString strFileFormat;
  strFileFormat = "text Files (*.txt)|*.txt|";
  strFileFormat += "All files (*)|*";

  wxFileDialog dialog( this, _T( "Open File Dialog" ), _T( "" ), _T( "" ), strFileFormat );

  if ( dialog.ShowModal() == wxID_OK )
    txtTreeInput->LoadFile( dialog.GetPath().c_str() );
}


void MyFrame::saveTrans()
{
  wxFileDialog dialog( this, _T( "Save File Dialog" ), _T( "" ), _T( "" ),
  _T( "All files (*)|*" )
  , wxSAVE | wxOVERWRITE_PROMPT );
  //_T("Text files (*.txt)|*.txt|Document files (*.doc)|*.doc"),

  if ( dialog.ShowModal() == wxID_OK )
    txtTransOutput->SaveFile( dialog.GetPath() );
}


void MyFrame::saveDetect()
{
  wxFileDialog dialog( this, _T( "Save File Dialog" ), _T( "" ), _T( "" ),
      "Phylip(*.phy)|*.phy|Comma separated values(*.csv)|*.csv|Tab separated values(*.tsv)|*.tsv|"
  , wxSAVE | wxOVERWRITE_PROMPT );

  if ( dialog.ShowModal() == wxID_OK )
  {
    std::string path(dialog.GetPath().c_str());
    if(path.length() > 4 && path.substr( path.length() - 4 ) == ".csv" || path.substr( path.length() - 4 ) == ".tsv" )
    {
      std::string data( txtDetectOutput->GetValue().c_str() );
      std::istringstream in(data);

      profdist::distance_matrix matrx; 
      std::vector<std::string> names;

      ofstream out( path.c_str() );

      if( out && in && profdist::read_distance_matrix(in, matrx, back_insert_iterator<vector<string> >(names) ) ) 
        profdist::print_distance_matrix_tsv( out, matrx, names.begin(), names.end(), path.substr( path.length() - 4 ) == ".csv"?',':'\t', true );
      else
      {
        wxMessageDialog dialog( this, "Failure while parsing matrix or writing to file",  "Error", wxICON_ERROR );
        dialog.ShowModal();
      }
    }
    else 
    {
      txtDetectOutput->SaveFile( dialog.GetPath() );
    }
  }
}

void MyFrame::saveTree()
{
  wxFileDialog dialog( this, _T( "Save File Dialog" ), _T( "" ), _T( "" ),
  _T( "All files (*)|*" )
  , wxSAVE | wxOVERWRITE_PROMPT );
  //_T("Text files (*.txt)|*.txt|Document files (*.doc)|*.doc"),

  if ( dialog.ShowModal() == wxID_OK )
    txtTreeOutput->SaveFile( dialog.GetPath() );
}

void MyFrame::openFileDetect()
{
  wxString strFileFormat;
  strFileFormat = "text Files (*.txt)|*.txt|";
  strFileFormat += "All files (*)|*";

  wxFileDialog dialog( this, _T( "Open File Dialog" ), _T( "" ), _T( "" ), strFileFormat );

  if ( dialog.ShowModal() == wxID_OK )
    txtDetectInput->LoadFile( dialog.GetPath().c_str() );
}

bool MyFrame::loadXmlFile()
{
  wxConfigBase* config = wxConfigBase::Get( true );
  
  config->Read("/cbc/treeviewer/view_type", &mTreeViewType, 0);
  config->Read("/cbc/treeviewer/binary_path_1", &mFileTreeViewer1, wxString(""));
  config->Read("/cbc/treeviewer/binary_path_2", &mFileTreeViewer2, wxString(""));
  config->Read("/cbc/gui/notebook_selection", &mNtbSelection, 0);
#if defined(UNIX_SYSTEM) || defined(DARWIN_SYSTEM)
  config->Read("/cbc/gui/browser_path", &mFileBrowser, wxString(""));
  mHyperRNA->SetBrowserPath( mFileBrowser );
  mHyperMarna->SetBrowserPath( mFileBrowser );
#endif
  return true;
}

void MyFrame::onMnuSelectAll( wxCommandEvent & WXUNUSED( event ) )
{
  wxTextCtrl * tempTextCtrl = getFocusedText();
  if( tempTextCtrl )
    tempTextCtrl->SetSelection( -1, -1 );
}

void MyFrame::onMnuCopy( wxCommandEvent & WXUNUSED( event ) )
{
  wxTextCtrl * tempTextCtrl = getFocusedText();

  if( tempTextCtrl && tempTextCtrl->CanCopy() )
    tempTextCtrl->Copy();
}

void MyFrame::onMnuCut( wxCommandEvent & WXUNUSED( event ) )
{
  wxTextCtrl * tempTextCtrl = getFocusedText();

  if( tempTextCtrl && tempTextCtrl->CanCut() )
    tempTextCtrl->Cut();
}


void MyFrame::onMnuPaste( wxCommandEvent & WXUNUSED( event ) )
{
  wxTextCtrl * tempTextCtrl = getFocusedText();

  if( tempTextCtrl && tempTextCtrl->CanPaste() )
    tempTextCtrl->Paste();
}


void MyFrame::onMnuHelp( wxCommandEvent & WXUNUSED( event ) )
{
  help.Display( wxT( "cbcAnalyzer Helpfile" ) );
}

void MyFrame::saveXmlFile()
{
  wxConfigBase* config = wxConfigBase::Get( true );
  config->Write("/cbc/treeviewer/view_type", mTreeViewType );
  config->Write("/cbc/treeviewer/binary_path_1", mFileTreeViewer1 );
  config->Write("/cbc/treeviewer/binary_path_2", mFileTreeViewer2 );
  config->Write("/cbc/gui/notebook_selection", ntbAll->GetSelection() );
#if defined(UNIX_SYSTEM) || defined(DARWIN_SYSTEM)
  config->Write("/cbc/gui/browser_path", mFileBrowser );
#endif


}

void MyFrame::setSelection()
{
  ntbAll->SetSelection( mNtbSelection );
  //rdoDetectInput->SetSelection( mRdoDetectInput );
}

