
#include <assert.h>
#include <sstream>
#include <exception>


#include "kactioncollection.h"
#include "ktoggleaction.h"
#include <kapplication.h>
#include "khtml_part.h"
#include <kiconloader.h>
#include <QPrinter>
#include <kfiledialog.h>
#include <kmessagebox.h>
#include <qimage.h>
#include <qpixmap.h>
#include <q3toolbar.h>
#include <qtoolbutton.h>
#include <qfileinfo.h>
#include <q3popupmenu.h>
#include <qmenubar.h>
#include <q3textedit.h>
#include <qfile.h>
#include <q3filedialog.h>
#include <qstatusbar.h>
#include <qmessagebox.h>
#include <qprinter.h>
#include <qapplication.h>
#include <q3accel.h>
#include <q3textstream.h>
#include <qpainter.h>
#include <q3paintdevicemetrics.h>
#include <q3whatsthis.h>
#include <qtabwidget.h>
#include <qsplitter.h>
#include <qobject.h>
#include <qaction.h>
#include <qclipboard.h>
#include <q3mainwindow.h>
#include <qsignalmapper.h>

#include "kryomol.h"
#include "tokenizer.h"
#include "kryovisor.h"
#include "kryovisordyn.h"
#include "quantumfile.h"
#include "gaussianparser.h"
#include "gamessparser.h"
#include "acesparser.h"
#include "nwchemparser.h"
#include "macromodelparser.h"
#include "maestroparser.h"
#include "macromodeldynparser.h"
#include "pdbparser.h"
#include "MolParser.h"
#include "psi3parser.h"
#include "qfreqwidget.h"
#include "qhtmltabwidget.h"

#include "qconvwidget.h"
#include "qjcdrawing.h"

#include "quvwidget.h"
#include "xyzparser.h"
#include "tinkerparser.h"
#include "cpmdparser.h"
#include "qirwidget.h"
#include "qnmrwidget.h"


#include "archiveparser.h"

#include "icons.h"

// Factory code for KDE 3
//typedef KParts::GenericFactory<KryoMolPart> KryoMolPartFactory;
bool KryoMolPart::m_bcheckglsettings=0;


static KAboutData createAboutData()
{
	KAboutData aboutData( "kryomolpart", 0, ki18n("KryoMolPart"),
		"0.7", ki18n("A KPart 3D molecular viewer"),
		KAboutData::License_GPL,
		ki18n("Copyright 2009, Armando Navarro Vazquez e-mai: armando.navarro@uvigo.es"));
	return aboutData;
}

//Factory Code
K_PLUGIN_FACTORY(KryoMolPartFactory, registerPlugin< KryoMolPart >(); )
K_EXPORT_PLUGIN( KryoMolPartFactory( createAboutData() ) )

//typedef KParts::GenericFactory<KryoMolPart> KryoMolPartFactory;

//K_EXPORT_COMPONENT_FACTORY (kryomolpart, KryoMolPartFactory)

//K_EXPORT_COMPONENT_FACTORY ( libkryomol /*library name*/, KryoMolFactory );

KryoMolPart::KryoMolPart( QWidget *parentWidget, 
                  QObject *parent, const QVariantList&) : KParts::ReadOnlyPart(parent)
{


  m_bisinsidehtml = dynamic_cast<KHTMLPart*> ( parent );
  if ( m_bisinsidehtml )
  {
#warning reimplement
/*
    QStringList::const_iterator st;
    for ( st=args.begin();st!=args.end();++st )
    {
      kDebug() << ( *st );
    } */
  }
  //setInstance ( KryoMolFactory::instance() );
  setComponentData(KryoMolPartFactory::componentData());
  setXMLFile ( "kryomol/kryomolpart.rc" );
  m_tab = new QHTMLTabWidget ( parentWidget );
  m_tab->setFocusPolicy ( Qt::ClickFocus );
  m_tab->setTabPosition ( QTabWidget::Top );
  setWidget ( m_tab );
  connect ( m_tab,SIGNAL ( currentChanged ( int ) ),this,SLOT ( OnTabChanged ( int ) ) );
  
  InitToolBars();

  InitActions();
  //   setXMLFile( "kryomol_shell.rc" );
 
  
  m_extension = new KryoMolExtension ( this );

  m_qparser=NULL;
  m_parent=parentWidget;
  m_currentvisor=NULL;
  BuildPeriodicTable();


   //   kDebug() << "has open gl =" << QGLFormat::hasOpenGL() << endl;
}

KryoMolPart::~KryoMolPart()
{}

void KryoMolPart::InitActions()
{
  KAction* aboutAction = actionCollection()->addAction("about");
  aboutAction->setText(i18n("About Kryomol"));
  connect(aboutAction,SIGNAL(triggered()),this,SLOT(OnAbout()));

  KAction* exportAction = actionCollection()->addAction("export");
  exportAction->setText(i18n("Export"));
  connect(exportAction,SIGNAL(triggered()),this,SLOT(OnExport()));

  KAction* renumberAction = actionCollection()->addAction("renumber");
  renumberAction->setText(i18n("Renumber"));
  connect(renumberAction,SIGNAL(triggered()),this,SLOT(OnRenumber()));


  KAction* setdihedralAction = actionCollection()->addAction("setdihedral");
  setdihedralAction->setText(i18n("Set Dihedral"));
  connect(setdihedralAction,SIGNAL(triggered()),this,SLOT(OnSetDihedral()));



}

bool KryoMolPart::openFile()
{

 while( m_tab->count() > 0 ) 
 {
   QWidget* w=m_tab->widget(0);
   if ( w )
   {
   m_tab->removePage(w);
   delete w;
   }
 }

  eSelectionMode bkmode=eNone;
  if ( m_currentvisor )
    bkmode=m_currentvisor->SelectionMode();

  QuantumFile file ( localFilePath().latin1() );
  try
  {
    m_jobtype=file.GetFileType();


    switch ( m_jobtype )
    {
      case QuantumFile::None:
        return false;
      case QuantumFile::Gaussian:
        m_qparser= new GaussianParser ( localFilePath().latin1() );
        break;
      case QuantumFile::GaussianArchive:
        m_qparser= new ArchiveParser ( localFilePath().latin1() );
        break;
      case QuantumFile::Aces:
        m_qparser= new AcesParser ( localFilePath().latin1() );
        break;
      case QuantumFile::Gamess:
        m_qparser= new GamessParser ( localFilePath().latin1() );
        break;
      case QuantumFile::MacroModel:
        m_qparser = new MacroModelParser ( localFilePath().latin1() );
        break;
      case QuantumFile::MacroModelMaestro:
        m_qparser= new MaestroParser ( localFilePath().latin1() );
        break;
      case QuantumFile::MacroModelDyn:
        m_qparser = new MacroModelDynParser ( localFilePath().latin1() );
        break;
      case QuantumFile::Mol:
        m_qparser= new MolParser ( localFilePath().latin1() );
        break;
      case QuantumFile::Psi3:
        m_qparser= new Psi3Parser ( localFilePath().latin1() );
        break;
      case QuantumFile::PDB:
        m_qparser = new PDBParser ( localFilePath().latin1() );
        break;
      case QuantumFile::XYZ:
        m_qparser = new XYZParser ( localFilePath().latin1() );
        break;
      case QuantumFile::Tinker:
        m_qparser= new TinkerParser ( localFilePath().latin1() );
        break;
      case QuantumFile::NwChem:
        m_qparser = new NwChemParser ( localFilePath().latin1() );
        break;
      case QuantumFile::CPMD:
      {
        m_qparser =  new CPMDParser ( localFilePath().latin1() );
        QFileInfo finfo ( localFilePath() );
        std::cout << finfo.dirPath ( true ).latin1() << std::endl;
        static_cast<CPMDParser*> ( m_qparser )->SetTrajectoryFile ( finfo.dirPath ( true ).toLatin1() +"/TRAJEC.xyz" );
      }
      break;
      default:
        return false;
    }
    bool b=Parse();
    if ( b )
    {
      std::vector<KryoVisor*>::iterator it;
      for ( it=m_visors.begin();it!=m_visors.end();++it )
      {
        ( *it )->SetSelectionMode ( bkmode );
      }
    }
    return b;
  }
  catch ( std::exception& e )
  {
    QString str="Sorry, unable to parse file due to the following error:\n"+QString(e.what());
    KMessageBox::error ( 0,str );
  }
  return true;
}

bool KryoMolPart::Parse()
{

  if ( m_qparser )
  {
    std::vector<Quantum::jobheader> jobs=m_qparser->GetJobs();

    if ( jobs.empty() ) return false; //oops some error

    if ( m_jobtype == QuantumFile::GaussianArchive )
    {
      if ( dynamic_cast<ArchiveParser*> ( m_qparser )->HasHessian() )
        jobs.front().type=Quantum::freq;
      else
        jobs.front().type=Quantum::dens;
    }



    std::vector<Quantum::jobheader>::iterator it;
    for ( it=jobs.begin();it!=jobs.end();++it )
    {
      //Determine the type of job and proceed
      QSplitter* split= new QSplitter ( m_tab );
      KryoVisor* visor=NULL;//= new KryoVisor(split);


      QWidget* w=NULL;


      QString stype; //tab label

      switch ( it->type )
      {
        case Quantum::dens:
          kDebug() << "about to construct om" << split << endl;
          
          visor= KryoVisorFactory<KryoVisorDens>::BuildVisor(split);
          kDebug() << "visor is " << visor << endl;
          split->insertWidget(0,visor);
          w=NULL;
          stype="Dens.";
          break;
        case Quantum::opt:
          visor= new KryoVisorOpt ( split );
          w= new QConvWidget ( split );
          split->setResizeMode ( w,QSplitter::Auto );
          stype="Opt.";
          break;
        case Quantum::freq:
          visor= new KryoVisorFreq ( split );
#warning change to getURL?
          w= new QFreqWidget ( localFilePath(),split );
          //this is important, otherwise the spectrum gets very small
          split->setResizeMode ( w,QSplitter::FollowSizeHint );
          connect ( w,SIGNAL ( mode ( int,int ) ),visor,SLOT ( SetMode ( int,int ) ) );
          connect ( w,SIGNAL ( movie ( bool ) ),visor,SLOT ( RecordMovie ( bool ) ) );
          connect ( w,SIGNAL ( distort ( int ) ),visor,SLOT ( OnDistortion ( int ) ) );
          connect ( w,SIGNAL ( reset() ),visor,SLOT ( OnStopAnimation() ) );
          connect ( w,SIGNAL ( Type ( IRSpectrum::SpectrumType ) ),this,SLOT ( OnIRTypeChanged ( IRSpectrum::SpectrumType ) ) );
          stype="Freq.";

          break;
        case Quantum::uv:
          visor= new KryoVisor ( split );
#warning change to getURL?
          w= new QUVWidget ( localFilePath(),split );
          connect ( w,SIGNAL ( Type ( UVSpectrum::SpectrumType ) ),this,SLOT ( OnUVTypeChanged ( UVSpectrum::SpectrumType ) ) );
          split->setResizeMode ( w,QSplitter::FollowSizeHint );
          stype="UV";
          break;
        case Quantum::nmr:
          visor = new KryoVisorNMR ( split );
          w= new QNMRWidget(split);
          connect(w,SIGNAL(references(const NMRHandler* )),visor,SLOT(OnSetReferences(const NMRHandler* )));
          stype="NMR";
          break;
        case Quantum::dyn:
          visor = new KryoVisorDyn ( split );
          //w = new QDynWidget(localFilePath(),split);
          stype="Dyn.";
          break;
        default:
          w=NULL;
      }
      connect ( visor,SIGNAL ( text ( const QString& ) ),this, SIGNAL ( setStatusBarText ( const QString& ) ) );
      connect ( visor,SIGNAL ( playing ( bool ) ),this,SLOT ( OnUpdateControls ( bool ) ) );
      m_visors.push_back ( visor );
      m_qparser->SetMolecule ( visor->GetMolecule() );

      visor->setSizePolicy ( QSizePolicy::Expanding,QSizePolicy::Expanding );
      connect ( visor,SIGNAL ( text ( const QString& ) ),this,SLOT ( OnInfoText ( const QString& ) ) );
      if ( w ) w->setSizePolicy ( QSizePolicy::Preferred,QSizePolicy::Expanding );

      assert ( split );
      m_tab->addTab ( split,stype );
      // currentTab->setCurrentPage(m_kryotab->indexOf(split));

      //m_openedurls.insert ( std::make_pair ( m_url,currentTab ) );

      if ( m_qparser->ParseFile ( it->pos ) )
      {
        switch ( it->type )
        {
          case Quantum::dens:
          {
            GaussianParser* gp=dynamic_cast<GaussianParser*> ( m_qparser );
            if ( gp )
              gp->ParseAIM ( it->pos );
          }
          visor->Initialize();
          EnableNavigationActions(false);
          break;
          case Quantum::opt:
          {
            QConvWidget* cw=static_cast<QConvWidget*> ( w );
            cw->SetNData ( visor->GetMolecule()->size() );
            double* energies=cw->GetEnergies();
            double* s2= cw->GetS2();
            double *rmsforce=cw->GetRMSForces();
            double* maximumforce=cw->GetMaximumForces();
            double* rmsdisplacement=cw->GetRMSDisplacements();
            double* maximumdisplacement=cw->GetMaximumDisplacements();
            cw->SetEnergyLevel ( visor->GetMolecule()->front().EnergyLevel().c_str() );

            if ( energies )
            {
              std::vector<CMolecule>::iterator mt;
              int i=0;
              mt=visor->GetMolecule()->begin();
              cw->SetThreshold ( mt->GetThreshold() );
              for ( i=0;mt!=visor->GetMolecule()->end();mt++,i++ )
              {
                energies[i]=mt->GetEnergy();
                s2[i]=mt->GetS2();
                rmsforce[i]=mt->GetRMSForce();
                maximumforce[i]=mt->GetMaximumForce();
                rmsdisplacement[i]=mt->GetRMSDisplacement();
                maximumdisplacement[i]=mt->GetMaximumDisplacement();
              }

            }
            visor->Initialize();
            cw->SetupCurves();
            connect ( cw,SIGNAL ( selectedPoint ( int ) ),visor,SLOT ( OnSelectPoint ( int ) ) );
            connect ( visor,SIGNAL ( selectedPoint ( int ) ),cw,SLOT ( OnSelectedPoint ( int ) ) );
            cw->OnSelectedPoint ( visor->GetCurrentPoint() );
            connect ( cw,SIGNAL ( forcescale ( float ) ),visor,SLOT ( OnForceScale ( float ) ) );
	    EnableNavigationActions( visor->GetMolecule()->size() > 1 );
          }
          break;
          case Quantum::freq:
          {

            try
            {
              m_qparser->ParseFrequencies ( it->pos );
              QFreqWidget* cw=static_cast<QFreqWidget*> ( w );
              connect ( cw,SIGNAL ( showspectrum ( bool ) ),this,SLOT ( OnShowSpectrum ( bool ) ) );

              visor->Initialize();
              cw->SetFrequencies ( visor->m_molecule.GetFrequencies() );
              cw->InitTable();

            }
            catch ( ... ) //allow to get opt jobs before broken freq jobs
            {
              std::cerr << "Error parsing frequencies" << std::endl;
            }
	    EnableNavigationActions(true);
          }
          break;
          case Quantum::uv:
          {
            ( static_cast<GaussianParser*> ( m_qparser ) )->ParseUV ( it->pos );
            visor->Initialize();
            QUVWidget* cw=static_cast<QUVWidget*> ( w );
            connect ( cw,SIGNAL ( showspectrum ( bool ) ),this,SLOT ( OnShowUVSpectrum ( bool ) ) );
            cw->SetLines ( visor->m_molecule.GetSpectralLines() );
            cw->InitTable();
	    EnableNavigationActions(false);
          }
          break;
          case Quantum::nmr:
            ( static_cast<GaussianParser*> ( m_qparser ) )->ParseNMR ( it->pos );
            //QNMRWidget* cw=
            visor->Initialize();
	    EnableNavigationActions(false);
            break;
          case Quantum::dyn:
            visor->Initialize();
	    EnableNavigationActions(true);
            break;
          default:
            visor->Initialize();

        }



      }

    }
    //m_kryotab->addTab ( currentTab , m_url.fileName() );
    //m_kryotab->setTabToolTip ( currentTab, m_url.prettyUrl() );
    m_tab->setCurrentPage ( 0 );
    if ( m_bisinsidehtml )
    {
      if ( m_tab->count() == 1 )
        m_tab->hideTabBar();
    }


    QList<KryoVisor*> childlist =m_tab->currentPage()->findChildren<KryoVisor*>();

    if ( !childlist.isEmpty() )
    {
      kDebug() << "m_currentvisor=" << m_currentvisor << endl;
      m_currentvisor=dynamic_cast<KryoVisor*> ( childlist.first() );
    }


  }

  /* The m_bcheckglsettings flag is stored into the konqueror session (KPart is loaded in memory, so it wont be displayed when navigating back and forth*/
  if ( ! m_bcheckglsettings )
  {
    CheckGLSettings();
    m_bcheckglsettings=true;
  }

  return true;
}

void KryoMolPart::CheckGLSettings()
{
#warning no longer necessary
/*
  KConfig* config= KryoMolFactory::instance()->config();
  KMessageBox::setDontShowAskAgainConfig ( config );
  if ( KMessageBox::shouldBeShownContinue ( "CheckAtiCard" ) )
  {
    std::string vendor ( ( const char* ) glGetString ( GL_VENDOR ) );
    StringTokenizer::toupper ( vendor );
    if ( vendor.find ( "ATI" ) != std::string::npos  && vendor.find ( "INC" ) != std::string::npos )
    {
      KMessageBox::setDontShowAskAgainConfig ( config );
      KMessageBox::information ( 0, QString ( "You are using the ATI propietary display drivers.  With old propietary ATI drivers before the catalyst series KryoMol may crash unexpectedly due \
                                              to incompatibility between the standard C++ 5 and C++ 6 versions.  You may try to use open source radeon drivers or new ati catalyst drivers\
                                              instead" ) , "Check display drivers", "CheckAtiCard" );
      //KMessageBox::saveDontShowAgainContinue("CheckAtiCard");

    }
  }*/
}

void KryoMolPart::OnShowSpectrum ( bool bshow )
{
  kDebug() << "On show spectrum" << endl;
  //if already exist a irwidget object simply show it, otherwise create it
  QWidget* current= m_tab->currentPage();

 kDebug() << "tab is "  << current << endl;
  if ( ! current ) return;

  //if already exist a irwidget object simply show it, otherwise create it
  if ( bshow )
  {
    QList<QIRWidget*> childlist= current->findChildren<QIRWidget*>(); ;
    kDebug() << "chidlist size is" << childlist.size() << endl;
    if ( !childlist.empty() )
    {
      QObject* child;

      for ( QList<QIRWidget*>::iterator ch=childlist.begin();ch!=childlist.end();++ch)
         (*ch)->show();
      return;
    }


    //add a vertical splitter to the current splitter
    QSplitter* vsplit =new QSplitter ( Qt::Vertical,current );

    //now get a pointer to the first element of currennt split
    KryoVisor* w= current->findChild<KryoVisor*>();


    //and now reparent this widget which should be the GLVisor
    w->reparent ( vsplit,0,QPoint ( 0,0 ) );
    
    w->setSizePolicy ( QSizePolicy::Expanding,QSizePolicy::Expanding );
    vsplit->addWidget(w);
    //add the Spectrum drawing widget
    QIRWidget* ir= new QIRWidget ( vsplit );
    vsplit->addWidget(ir);
    vsplit->setResizeMode ( ir,QSplitter::FollowSizeHint );

    QList<QFreqWidget*> chw= current->findChildren<QFreqWidget*>();
    QFreqWidget* fw= chw.first();


    QJCDrawing* jc= ir->GetSpectrum();
    //jc->SetData ( fw->GetData(),fw->Max(),fw->Min() );
    connect ( fw,SIGNAL ( data ( fidarray*,float,float ) ),jc,SLOT ( SetData ( fidarray*,float,float ) ) );
    connect ( jc,SIGNAL ( limits ( float,float ) ),fw,SLOT ( OnSetLimits ( float, float ) ) );


    //and finally move the vertical splitter to the first position
//jc->SetData ( fw->GetData(),fw->Max(),fw->Min() );
    ( static_cast<QSplitter*> ( current ) )->moveToFirst ( vsplit );
   // vsplit->show();  //we have explicitelly to request showing of the new splitter
   // current->resize(current->size() );
    jc->SetData ( fw->GetData(),fw->Max(),fw->Min() );
  }
  else
  {
    //Find a QJCDrawing and hide it

    QList<QIRWidget*> childlist=current->findChildren<QIRWidget*>();

    for ( QList<QIRWidget*>::iterator ch=childlist.begin();ch!=childlist.end();++ch)
      (*ch)->hide();
  }

kDebug() << "leaving" << endl;
}

void KryoMolPart::OnShowUVSpectrum ( bool bshow )
{
  QTabWidget* current=static_cast<QTabWidget*> ( m_tab->currentPage() );
  if ( ! current ) return;

  //if already exist a irwidget object simply show it, otherwise create it
  if ( bshow )
  {
    QList<QIRWidget*> childlist= current->currentPage()->findChildren<QIRWidget*>();  

    if ( !childlist.isEmpty() )
    {

      for ( QList<QIRWidget*>::iterator ch=childlist.begin();ch!=childlist.end();++ch)
        (*ch)->show();
      return;
    }


    //add a vertical splitter to the current splitter
    QSplitter* vsplit =new QSplitter ( Qt::Vertical,current->currentPage() );

    //now get a pointer to the first element of currennt split
    QWidget* w= static_cast<QWidget*> ( current->currentPage()->children().first() );


    //and now reparent this widget which should be the GLVisor
    w->reparent ( vsplit,0,QPoint ( 0,0 ) );
    w->setSizePolicy ( QSizePolicy::Expanding,QSizePolicy::Expanding );
    //add the Spectrum drawing widget
    QIRWidget* ir= new QIRWidget ( vsplit );

    vsplit->setResizeMode ( ir,QSplitter::FollowSizeHint );

    QList<QUVWidget*> chwlist= current->currentPage()->findChildren<QUVWidget*>();
    QUVWidget* fw= chwlist.first();

    QJCDrawing* jc= ir->GetSpectrum();
    //jc->SetOrientation ( QJCDrawing::LeftRight );
    connect ( fw,SIGNAL ( data ( fidarray*,float,float ) ),jc,SLOT ( SetData ( fidarray*,float,float ) ) );
    connect ( jc,SIGNAL ( limits ( float,float ) ),fw,SLOT ( OnSetLimits ( float, float ) ) );


    //and finally move the vertical splitter to the first position

    ( static_cast<QSplitter*> ( current->currentPage() ) )->moveToFirst ( vsplit );
    vsplit->show();  //we have explicitelly to request showing of the new splitter
    jc->show();
    jc->SetData ( fw->GetData(),fw->Max(),fw->Min() );
  }
  else
  {
    //Find a QJCDrawing and delete it

    QList<QIRWidget*> childlist=current->currentPage()->findChildren<QIRWidget*>();


    for ( QList<QIRWidget*>::iterator child=childlist.begin();child!=childlist.end();++child)
      (*child)->hide();
  }
}

void KryoMolPart::InitToolBars()
{

  KActionCollection* ac= actionCollection();
  m_distanceAction= ac->add<KToggleAction>("distance");
  m_distanceAction->setToolTip(i18n("Measure distance"));
  m_distanceAction->setIcon(QPixmap(icons::distance));

  m_angleAction= ac->add<KToggleAction>("angle");
  m_angleAction->setToolTip(i18n("Measure angle"));
  m_angleAction->setIcon(QPixmap(icons::angle));

  m_dihedralAction= ac->add<KToggleAction>("dihedral");
  m_dihedralAction->setToolTip(i18n("Measure dihedral"));
  m_dihedralAction->setIcon(QPixmap(icons::dihedral));

  m_angleplanesAction= ac->add<KToggleAction>("angleplanes");
  m_angleplanesAction->setToolTip(i18n("Measure angle between two planes"));
  m_angleplanesAction->setIcon(QPixmap(icons::angleplanes));

  m_rotbondAction= ac->add<KToggleAction>("rotatebond");
  m_rotbondAction->setToolTip(i18n("Rotate bond between atoms"));
  m_rotbondAction->setIcon(QPixmap(icons::rotatebond));

  m_createbondAction= ac->add<KToggleAction>("createbond");
  m_createbondAction->setToolTip(i18n("Create bond between atoms"));
  m_createbondAction->setIcon(QPixmap(icons::createbond));

  m_createbondAction= ac->add<KToggleAction>("createbond");
  m_createbondAction->setToolTip(i18n("Create bond between atoms"));
  m_createbondAction->setIcon(QPixmap(icons::createbond));

  m_deletebondAction= ac->add<KToggleAction>("deletebond");
  m_deletebondAction->setToolTip(i18n("Delete bond between atoms"));
  m_deletebondAction->setIcon(QPixmap(icons::deletebond));


 /* m_distanceAction->setExclusiveGroup ( "tools" );
  m_angleAction->setExclusiveGroup ( "tools" );
  m_angleplanesAction->setExclusiveGroup ( "tools" );
  m_dihedralAction->setExclusiveGroup ( "tools" );

  m_rotbondAction->setExclusiveGroup ( "tools" );
  m_createbondAction->setExclusiveGroup ( "tools" );
  m_deletebondAction->setExclusiveGroup ( "tools" );*/



  QList<QAction*> actions=actionCollection()->actions();

  QSignalMapper* mapper= new QSignalMapper ( this );
  for ( QList<QAction*>::iterator kit=actions.begin();kit!=actions.end();++kit )
  {
    connect ( *kit, SIGNAL ( triggered(bool ) ), mapper, SLOT ( map() ) );
    mapper->setMapping ( *kit, ( *kit )->name() );
    connect ( *kit,SIGNAL ( triggered ( bool ) ),this,SLOT ( OnActionToggled ( bool ) ) );
  }

  connect ( mapper,SIGNAL ( mapped ( const QString& ) ),this,SLOT ( OnActionSelected ( const QString& ) ) );

  KIconLoader* loader = KIconLoader::global();

  m_firstaction = actionCollection()->addAction("first",this, SLOT( OnFirstFrame() ) );
  m_firstaction->setIcon(loader->loadIcon( "go-first",KIconLoader::Toolbar ));
  m_firstaction->setToolTip(i18n("First Structure" ));

  m_lastaction = actionCollection()->addAction("last",this, SLOT(OnLastFrame() ) );
  m_lastaction->setIcon(loader->loadIcon ( "go-last",KIconLoader::Toolbar ) );
  m_lastaction->setToolTip(i18n("Last structure" ));

  m_previousaction = actionCollection()->addAction("previous",this, SLOT(OnPreviousFrame() ) );
  m_previousaction->setIcon(loader->loadIcon ( "go-previous",KIconLoader::Toolbar ) );
  m_previousaction->setToolTip(i18n("Previous structure"));

  m_nextaction = actionCollection()->addAction( "next" ,this,SLOT( OnNextFrame() ) );
  m_nextaction->setIcon(  loader->loadIcon ( "go-next",KIconLoader::Toolbar ) );
  m_nextaction->setToolTip(i18n("Next structure" ));

  m_stopaction = actionCollection()->addAction( "stop" ,this,SLOT( OnStopAnimation() ) );
  m_stopaction->setIcon(  loader->loadIcon ( "process-stop",KIconLoader::Toolbar ) );
  m_stopaction->setToolTip( i18n ( "Stop Animation" ) );

  m_startaction = actionCollection()->addAction( "start" ,this,SLOT( OnStartAnimation() ) );

  m_startaction->setIcon(loader->loadIcon ( "media-playback-start",KIconLoader::Toolbar ) );
  m_startaction->setToolTip("Start animation" );
  m_stopaction->setEnabled(false);

}


void KryoMolPart::OnFirstFrame()
{
  if ( m_currentvisor ) m_currentvisor->OnFirstFrame();
}

void KryoMolPart::OnLastFrame()
{
  if ( m_currentvisor ) m_currentvisor->OnLastFrame();
}

void KryoMolPart::OnPreviousFrame()
{
  if ( m_currentvisor ) m_currentvisor->OnPreviousFrame();
}

void KryoMolPart::OnNextFrame()
{
  if ( m_currentvisor ) m_currentvisor->OnNextFrame();
}

void KryoMolPart::OnStopAnimation()
{
  if ( m_currentvisor) m_currentvisor->OnStopAnimation();
}

void KryoMolPart::OnStartAnimation()
{
  if ( m_currentvisor ) m_currentvisor->OnStartAnimation();
  
}

void KryoMolPart::OnUpdateControls(bool b)
{

  m_stopaction->setEnabled(b);
  m_startaction->setEnabled(!b);
  m_firstaction->setEnabled(!b);
  m_lastaction->setEnabled(!b);
  m_nextaction->setEnabled(!b); 
  m_previousaction->setEnabled(!b);
}

void KryoMolPart::OnActionSelected ( const QString& actiontext )
{

  kDebug() << "ActionSelected=" << actiontext <<  endl;
  QList<QAction*> actions=actionCollection()->actions();

  for ( QList<QAction*>::const_iterator kit=actions.begin();kit!=actions.end();++kit )
  {
    if ( ( *kit )->name() != actiontext )
    {
      KToggleAction* ta=dynamic_cast<KToggleAction*> ( ( *kit ) );
      if ( ta )
        ta->setChecked ( false );
    }
  }

  std::vector<KryoVisor*>::iterator it;
  if ( actiontext == i18n ( "distance" ) )
  {
    for ( it=m_visors.begin();it!=m_visors.end();it++ )
      ( *it )->OnMeasureDistances ( actionCollection()->action ( actiontext )->isEnabled() );
  }

  if ( actiontext == i18n ( "angle" ) )
  {
    for ( it=m_visors.begin();it!=m_visors.end();it++ )
      ( *it )->OnMeasureAngles ( actionCollection()->action ( actiontext )->isEnabled() );
  }

  if ( actiontext == i18n ( "dihedral" ) )
  {
    for ( it=m_visors.begin();it!=m_visors.end();it++ )
      ( *it )->OnMeasureDihedrals ( actionCollection()->action ( actiontext )->isEnabled() );
  }
  if ( actiontext == i18n ( "angleplanes" ) )
  {
    for ( it=m_visors.begin();it!=m_visors.end();it++ )
      ( *it )->OnMeasureAngleBetweenPlanes ( actionCollection()->action ( actiontext )->isEnabled() );
  }
  if ( actiontext == i18n ( "rotateBond" ) )
  {
    for ( it=m_visors.begin();it!=m_visors.end();it++ )
      ( *it )->OnRotateBond ( actionCollection()->action ( actiontext )->isEnabled() );
  }
  if ( actiontext == i18n ( "createBond" ) )
  {
    for ( it=m_visors.begin();it!=m_visors.end();it++ )
      ( *it )->OnCreateBond ( actionCollection()->action ( actiontext )->isEnabled() );
  }
  if ( actiontext == i18n ( "deleteBond" ) )
  {
    for ( it=m_visors.begin();it!=m_visors.end();it++ )
      ( *it )->OnDeleteBond ( actionCollection()->action ( actiontext )->isEnabled() );
  }


}

void KryoMolPart::OnTabChanged ( int index )
{
  QWidget* w=m_tab->widget(index);
  QList<KryoVisor*> childlist=w->findChildren<KryoVisor*>();
  if ( childlist.empty() ) return;

#warning assert should be done
  m_currentvisor=dynamic_cast<KryoVisor*>(childlist.first());
  kDebug() << "OnTabChanged" << endl;

   KryoVisorFreq* freqvisor=dynamic_cast<KryoVisorFreq*> ( m_currentvisor );
   if ( freqvisor != 0 )
   {
      OnUpdateControls( freqvisor->IsPlaying() );
      return;
   }
   
       if ( m_currentvisor->m_molecules.size() > 1 )
       OnUpdateControls(false);
         else
       EnableNavigationActions(false);
    
 
}

void KryoMolPart::OnIRTypeChanged ( IRSpectrum::SpectrumType t )
{
  QWidget* current= m_tab->currentPage();
  if ( ! current ) return;

  //QObjectList* childlist=const_cast<QObjectList*> ( current->queryList ( "QIRWidget" ) );

  QList<QIRWidget*> childlist= current->findChildren<QIRWidget*>();
  if ( childlist.empty() ) return;
  QIRWidget* w=childlist.first();
  if ( ! w ) return;
  QJCDrawing::BaseLinePosition pos;
  switch ( t )
  {
    case IRSpectrum::IR:
      pos=QJCDrawing::Bottom;
      break;
    case IRSpectrum::VCD:
      pos=QJCDrawing::Middle;
  }
  w->GetSpectrum()->SetBaseLinePosition ( pos );

}

void KryoMolPart::OnUVTypeChanged ( UVSpectrum::SpectrumType t )
{
  kDebug() << "Type changed";
  QWidget* current= m_tab->currentPage();
  if ( ! current ) return;

 // QObjectList* childlist=const_cast<QObjectList*> ( current->queryList ( "QIRWidget" ) );

 // QIRWidget* w=dynamic_cast<QIRWidget*> ( childlist->first() );
 // if ( !w ) return;

#warning should not be QUVWidget?
  QList<QIRWidget*> childlist= current->findChildren<QIRWidget*>();
  if ( childlist.empty() ) return;
  QIRWidget* w=childlist.first();
  if ( ! w ) return;
  QJCDrawing::BaseLinePosition pos;
  switch ( t )
  {
    case UVSpectrum::UV:
      pos=QJCDrawing::Bottom;
      break;
    case UVSpectrum::ECD:
      pos=QJCDrawing::Middle;
  }
  w->GetSpectrum()->SetBaseLinePosition ( pos );
}

// void KryoMolPart::OnCloseCurrent()
// {
//   QWidget* w=m_tab->currentPage();
//   if ( w )
//   {
//     m_kryotab->removePage ( w );
//     w->close ( true );
//   }
// 
//   /*if( m_kryotab->count() == 0 )
//     m_kryotoolbar->setEnabled(false);*/
// 
// }

/*void KryoMol::OnReload()
{
  OnCloseCurrent();

}*/

void KryoMolPart::OnRenumber()
{
  std::vector<KryoVisor*>::iterator it;
  for ( it=m_visors.begin();it!=m_visors.end();it++ )
    ( *it )->OnRenumbering ( true );
}

void KryoMolPart::OnSetDihedral()
{
  std::vector<KryoVisor*>::iterator it;
  for ( it=m_visors.begin();it!=m_visors.end();it++ )
    ( *it )->OnSetDihedral( true );
}



void KryoMolPart::OnExport()
{

#warning reimplement

  /*QString s = KFileDialog::getSaveFileName(
              QString::null,
                    "*.svg (SVG files)\n*.qpic (QPicture files)",
                    0,
                    "Save Vector Image" );  */

 /* if ( !m_currentvisor ) return;
  QString filter1= "*.eps (Encasulated Poscript)";
  QString filter2= "*.ps (PostScript)";
  QString filter3= "*.svg (SVG)";
  KFileDialog d ( QString::null,
                  filter1+"\n"+filter2,
                  0,
                  "Save Vector Image",true,0 );

  QString s;

  if ( d.exec() ==QDialog::Accepted )
    s=d.selectedFile();

  if ( s.isEmpty() )
    return;
  QString filter=d.currentFilter();

  StringTokenizer path ( s,"." );
  StringTokenizer::toupper ( path.back() );
  QString mode=path.back();
  if ( ( path.back() !="EPS" ) && ( path.back() !="PS" ) && ( path.back() !="SVG" ) )
  {
    //QFile file(s);
    if ( filter==filter1 )
    {
      mode="EPS";
      s+=".eps";
    }
    if ( filter==filter2 )
    {
      mode="PS";
      s+=".ps";
    }
    if ( filter==filter3 )
    {
      mode="SVG";
      s+=".svg";
      //file.setName(s);
    }
    //QFile file(s);
  }

  m_currentvisor->Export ( s,mode );
*/

}
void KryoMolPart::OnPaste()
{
#warning reimplement
/*
  QString archive=QApplication::clipboard()->text();
  if ( archive == QString::null )
  {
    QMessageBox ok;
    ok.setText ( tr ( "No data in clipboard" ) );
    ok.exec();
  }
  else
  {
    std::stringstream f;

    f << archive.latin1();

    QuantumFile file ( &f );

    m_jobtype=file.GetFileType();
    switch ( m_jobtype )
    {
      case QuantumFile::None:
      {
        QMessageBox bwar;
        bwar.setText ( tr ( "No valid data in clipboard" ) );
        bwar.exec();
      }
      return;
      break;
      case QuantumFile::Gaussian:
        m_qparser= new GaussianParser ( &f );
        break;
      case QuantumFile::GaussianArchive:
        m_qparser= new ArchiveParser ( &f );
        break;
      case QuantumFile::Aces:
        m_qparser= new AcesParser ( &f );
        break;
      case QuantumFile::Gamess:
        m_qparser= new GamessParser ( &f );
        break;
      case QuantumFile::MacroModel:
        m_qparser = new MacroModelParser ( &f );
        break;
      case QuantumFile::MacroModelMaestro:
        m_qparser = new MaestroParser ( &f );
        break;
      case QuantumFile::Mol:
        m_qparser= new MolParser ( &f );
        break;
      case QuantumFile::Psi3:
        m_qparser= new Psi3Parser ( &f );
        break;
      case QuantumFile::PDB:
        m_qparser = new PDBParser ( &f );
        break;
      case QuantumFile::NwChem:
        m_qparser= new NwChemParser ( &f );
        break;
      default:
        break;
    }
    Parse();

  }
*/
}


void KryoMolPart::OnCopy()
{
  /*       QImage image;
  m_pvisor->GetImage(image,800,640);
  image.createHeuristicMask();

   
   //  image.save( &buffer, "PNG" ); // writes image into ba in PNG format
    // QPixmap pix;
  QClipboard * cb=QApplication::clipboard();
  cb->setImage(image);*/
}


void KryoMolPart::OnPrint()
{
  //KPrinter* pP= new KPrinter(QPrinter::HighResolution);
  //pP->setOrientation(KPrinter::Landscape);
  m_currentvisor->Print ( NULL );
}

KAboutData* KryoMolPart::createAboutData()
{
#warning reimplement
  /*KAboutData* aboutData =
      new KAboutData ( "kryomol", I18N_NOOP ( "KryoMol" ),
                       "0.6.5", I18N_NOOP ( "Molecular Visor" ),
                       KAboutData::License_GPL,
                     "(c) 2003, Armando Navarro-Vazquez  <qoajnv@usc.es>" ); */ 
  return NULL;
}


KryoMolExtension::KryoMolExtension ( KryoMolPart *parent )
    : KParts::BrowserExtension ( parent )
{
  enableAction ( "paste",true );
  enableAction ( "copy",true );
  enableAction ( "print",true );
  m_parent=parent;
}

KryoMolExtension::~KryoMolExtension()
{}

void KryoMolExtension::paste()
{

  m_parent->OnPaste();
}

void KryoMolExtension::copy()
{

  m_parent->OnCopy();
}

void KryoMolExtension::print()
{

  m_parent->OnPrint();
}

void KryoMolPart::OnAbout()
{
#warning reimplement
/*
  KAboutDialog* dialog= new KAboutDialog ( 0,"aboutDialog" );
  //dialog->setLogo(QPixmap(kern_xpm));
  dialog->setAuthor ( "Authors:Armando Navarro Vazquez","qoajnv@usc.es","http://desoft03.usc.es/armando/software/kryomol.html","Santiago de Compostela" );
  dialog->setVersion ( "KryoMol 0.6.6" );
  dialog->exec();
*/
}

void KryoMolPart::OnActionToggled ( bool b )
{
  //Check if all actions are deactivated
  if ( b == false )
  {
    QList<QAction*> actions=actionCollection()->actions();
    QList<QAction*>::const_iterator kit;
    bool bck=false;
    for ( kit=actions.begin();kit!=actions.end();++kit )
    {
      KToggleAction* kt=dynamic_cast<KToggleAction*> ( *kit );
      if ( kt )
      {
        bck=kt->isChecked();
      }
      if ( bck ) break;
    }
    if ( kit == actions.end() )
    {
      //Set selection mode to none on all visors
      std::vector<KryoVisor*>::iterator it;
      for ( it=m_visors.begin();it!=m_visors.end();++it )
      {
        ( *it )->OnSelectionNone();

      }
    }

  }
}

void KryoMolPart::ParseChimeScript ( const QString& script )
{
  //by now wireframe and spacefill

  StringTokenizer token ( script.ascii()," ,\t\r" );
  StringTokenizer::iterator it;
  for ( it=token.begin();it!=token.end();++it )
  {
    StringTokenizer::toupper ( *it );
    if ( ( *it ) == "WIREFRAME" )
    {
      if ( ( it+1 ) != token.end() )
      {
        if ( * ( it+1 ) == "ON" )
        {
          m_currentvisor->SetGraphMode ( CGlVisorBase::WIREFRAME );
          m_currentvisor->update();
        }
      }
    }
    if ( ( *it ) == "SPACEFILL" )
    {
      if ( ( it+1 ) != token.end() )
      {
        if ( * ( it+1 ) == "ON" )
          m_currentvisor->SetGraphMode ( CGlVisorBase::CPK );
        m_currentvisor->update();
      }
    }
  }

}

void KryoMolPart::EnableNavigationActions(bool b)
{

  m_stopaction->setEnabled(b);
  m_startaction->setEnabled(b);
  m_firstaction->setEnabled(b);
  m_lastaction->setEnabled(b);
  m_nextaction->setEnabled(b); 
  m_previousaction->setEnabled(b);
}




