/*

    Bist: a chemical drawing tool
    Copyright (C) 2008 Valerio Benfante

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

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

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

#include <cairo/cairo.h>
#include <pango/pangocairo.h>
#include <cairo_t_singleton.hpp>
#include <glib.h>


#include <wordexp.h>
#include <sys/stat.h>
#include <dirent.h>
#include <cerrno>
//portability problem?
#include <pthread.h>

#include <cstdio>


#include <FL/Fl.H>
#include <FL/Fl_Image.H>
#include <FL/Fl_Pixmap.H>
#include <FL/Fl_Double_Window.H>
#include <FL/Fl_Scroll.H>
#include <FL/fl_ask.H>
#include <FL/Fl_Menu_Bar.H>
#include <FL/Fl_Menu_Item.H>
#include <FL/Fl_Toggle_Button.H>
#include <FL/Fl_Menu_Button.H>
#include <FL/Fl_Choice.H>
#include <FL/Fl_Light_Button.H>
#include <FL/Fl_Box.H>
#include <FL/Fl_Help_Dialog.H>
#include <FL/Fl_Check_Button.H>
//#include <FL/Fl_PNG_Image.H>

#include <interfacce.hpp>
#include <legame.hpp>
#include <etichetta.hpp>
#include <multiline_label.hpp>
#include <multifont_label.hpp>
#include <paragraph_text.hpp>
#include <atomo.hpp>
#include <procedura.hpp>
#include <gruppo.hpp>
#include <immagine.hpp>
#include <bist_plugin.hpp>
#include <mol_canvas.hpp>
#include <finestra_pr.hpp>
#include <editor.hpp>

#include <prefs.hpp>

#include <set_conf.hpp>
#include <command_line.hpp>
#include <util.hpp>
#include <substructure_search.hpp>
#include <plot_window.hpp>

#include <IR_prediction.hpp>

#include <string_tokenizer.hpp>

extern finestra_pr* MainWindow;

extern Preferences  __pref;

extern bool __close;




/**
 *Un plugin deve avere :
 *
 *una funzione  bool (*need_group)()  che ritorna true  se il  plugin ha
 *bisogno di conoscre quali atomi sono selezionati;
 *
 *una funzione  bool (*need_leg)()  che ritorna true  se il  plugin ha
 *bisogno di conoscere quali legami sono selezionati;
 *
 *una funzione  bool (*act)()  che computa quello  per cui il  plugin e'
 *stato scritto
 *
 */



IR_prediction::IR_prediction(immagine* image,string libpath)
  :bist_plugin(image,libpath),
   _spectrum(spectra_plot::IR),
   _has_to_act(true)
{

  _peak_height.insert(std::pair<std::string, float>(std::string("strong"),95));
  _peak_height.insert(std::pair<std::string, float>(std::string("medium"),50));
  _peak_height.insert(std::pair<std::string, float>(std::string("weak"),20));

}


void IR_prediction::inizialize(){


  /**
   *Contiene  coppie <tipo, < gruppo, id > > selezionati, se  si e'
   *selezionato una etichetta gruppo e' uguale a NO_VALID_GROUP
   */

  vector< pair < int, pair<int,int> > >* elem=r_elem_selected();

  //vector <gruppo>* groups=r_groups();
  
  if(elem->size()>0 && 
     (((*elem)[0]).second).first!=NO_VALID_GROUP){

    gruppo selected=*(_the_image->find_group_id( ((*elem)[0].second).first ));

    get_paths(string(LIB_PATH_SHARE) + IR_dir);
    generate_plot(selected);
    _spectrum.show();

    while(_spectrum.shown()){
      Fl::wait();
    }

  }
}


void IR_prediction::get_paths(string pt){

    DIR* direc=opendir(pt.c_str());
    //std::cerr << direc << std::endl;
    if(direc==NULL){
      fl_alert(_("Can not open library directory %s"),pt.c_str());
    }else{
      dirent* acc;
      struct stat attrb;
      while((acc=readdir(direc))!=NULL){
        string file=pt+"/"+acc->d_name;
        stat(file.c_str(),&attrb);
        if(S_ISREG(attrb.st_mode)){
          if(file.rfind("bist")!=string::npos){
            _resid_paths.push_back(file);
          }
        }
      }
      
      sort(_resid_paths.begin(),_resid_paths.end());
    }
  

}



bool IR_prediction::generate_plot(gruppo mol){
  bool res=true;

  for(unsigned int i=0;i<_resid_paths.size();i++){
    bool no_ok;
    gruppo r=get_residual(_resid_paths[i],no_ok);
    if(!no_ok){
      if(match(mol,r)){
        add_peak(_resid_paths[i]);
      }else{
        //std::cerr << "NO match " << _resid_paths[i] << std::endl;
      }
    }else{
      res=false;
    }


  }

  return res;
}

bool IR_prediction::add_peak(std::string file){
  std::string::size_type sl=file.rfind('/');
  std::string::size_type pt=file.rfind('.');

  std::string nm=file.substr(sl+1,pt-sl-1);

  char* start_name=NULL;
  std::string sk;
  strtof(nm.c_str(),&start_name);

  while(*start_name!='\0'){
    sk+=*start_name;
    start_name++;
  }
  bool has_error=false;

  
  if(find(_resid_excluded.begin(),
          _resid_excluded.end(),sk)==_resid_excluded.end()){

   
    immagine im=get_residual_immagine(file, has_error);
  
    if(!has_error){
      gruppo r=get_residual(file,has_error);
      float x=0;
      float y=0;

      for(int i=0;i<im.size_etich_vector();i++){
      
        switch(i){
        case 0:
          {

            etichetta* et=im.ritorna_punt_etich(0);
            std::string set=et->to_raw_string();
            x=strtof(set.c_str(),NULL);
          }
          break;
        case 1:
          {
            etichetta* et=im.ritorna_punt_etich(i);
            std::string set=et->to_raw_string();
            y=_peak_height[set];
          }
          break;
        case 2:
          {
            etichetta* et=im.ritorna_punt_etich(i);
            std::string set=et->to_raw_string();
            std::string del=" ";
            string_tokenizer tk(set, del);
            while(tk.has_more_tokens()){
              std::string nx=tk.next_token();
              if(nx!=skip_label){
                _resid_excluded.push_back(nx);
              }
            }

          }
          break;
        }

      }
      _spectrum.add_spike(x,y);
      _spectrum.add_group(r,x,y);
    }
  }
  return has_error;
}


bool IR_prediction::match(gruppo mol, gruppo r){
  return mol.substructure_match(r);
}




gruppo IR_prediction::get_residual(std::string file, bool& has_error){
  immagine im(file);
  im.start();
  gruppo res;
  if(!im.has_error()&&
     im.size_etich_vector()>1 &&
     im.size_gruppi_vector()>0){
    res=im.ritorna_gruppo(0);
    has_error=false;
  }else{
    has_error=true;
  }
  return res;
}


immagine IR_prediction::get_residual_immagine(std::string file, bool& has_error){
  immagine im(file);
  im.start();
  immagine res;
  if(!im.has_error()&&
     im.size_etich_vector()>0&&
     im.size_gruppi_vector()>0){
    res=im;
    has_error=false;
  }else{
    has_error=true;
  }

  return res;
}


bool IR_prediction::need_atom(){
  return false;
}

bool IR_prediction::need_leg(){
  return false;
}

bool IR_prediction::act(int e){
  return true;
}


IR_prediction::~IR_prediction(){
  
  cout << "IR distruzione!!! " << _the_image <<endl;
}

void IR_prediction::register_plugin(){

}

 
bool IR_prediction::time_to_act(){
  return false;
}
    

string IR_prediction::libpath(){
  return _lib;
}


std::string IR_prediction::menu_path(){
  return "calculation/";
}


const std::string IR_prediction::IR_dir="IR_prediction";

const std::string IR_prediction::skip_label="skip";
/**************fine metodi di classe**********************************/




extern "C" bist_plugin* create_plugin(immagine* imm, string libpath){
  return new IR_prediction(imm, libpath);
}

extern "C" void destroy_plugin(bist_plugin* j){
  cout << "distruzione plugin: " << j <<  endl;
  delete j;
  cout << "riuscita" << endl;
}


