/*

    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 <flip_around_bond.hpp>



extern finestra_pr* MainWindow;

extern Preferences  __pref;

extern bool __close;




flip_around_bond::flip_around_bond(immagine* image,string libpath)
  :bist_plugin(image,libpath),
   _has_to_act(false),
   _has_acted(true)
  
{
  
}


void flip_around_bond::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();  

  atomo*  atm_parent=NULL;
  atomo*  atm_child=NULL;
  gruppo* the_grp=NULL;

  find_atoms(&atm_parent, &atm_child);

  if(atm_parent!=NULL && 
     atm_child!=NULL){

    for(unsigned int i=0;i<groups->size();i++){
      gruppo* tmp=&(*groups)[i];
      if(atm_child->id_gruppo()==tmp->id()){
        the_grp=tmp;
      }
    }

    float trasl_saved_x=atm_child->pos_x();
    float trasl_saved_y= atm_child->pos_y();
    the_grp->trasla(-trasl_saved_x,-trasl_saved_y);


    int chce=fl_choice("Flip molecule or fragment?", 
                       "molecule", "fragment", NULL);
    

    
    if(chce==0){
      the_grp->generic_depth_search_appl_popped(atm_child, atm_parent, atm_child ,the_grp, 
                                                trasl_depth_search_pf);
    }else{
      
      the_grp->generic_depth_search_appl_popped(atm_child, atm_parent, atm_child ,
                                                the_grp, 
                                                atm_parent,
                                                trasl_depth_search_pf,
                                                ignore_plug);
    }


    the_grp->trasla(trasl_saved_x,trasl_saved_y);

  }
}


std::pair<float, float> vec_flipped(atomo a, atomo b){
  std::pair<float, float> diff;
  diff.first =b.pos_x()   - a.pos_x();
  diff.second=b.pos_y()   - a.pos_y();
  diff.first=-diff.first;
  diff.second=-diff.second;
  return diff;
}


float angle(std::pair<float,float> a, std::pair<float,float> b){
  std::pair<float,float> a_norm=normalize_vec(a);
  std::pair<float,float> b_norm=normalize_vec(b);

  float dot_p=dot_product_vec(a_norm, b_norm);
  float angle=acos(dot_p);
  
  if(cross_product_vec(a,b)<0){
    angle=-angle;
  }

  return angle;
}


float dot_product_vec(std::pair<float,float> a, std::pair<float,float> b){
  
  return (a.first * b.first) + (a.second * b.second);

}

float cross_product_vec(std::pair<float,float> a, std::pair<float,float> b){
  return a.first * b.second - a.second * b.first;

}


float magn_vec(std::pair<float,float> a){
  
  return sqrt(a.first * a.first + a.second * a.second);

}



std::pair<float,float> normalize_vec(std::pair<float,float> a){
  static const float zero_thr=0.001;
  float mag=magn_vec(a);
  std::pair<float,float> res=a;    
  
  if(!similar_to(mag, 0.0f, zero_thr)){
    res.first/=mag;
    res.second/=mag;
  }

  return res;
  
}

void flip_around_bond::find_atoms(atomo** atm_parent, atomo** atm_child){

  *atm_parent=NULL;
  *atm_child=NULL;


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


  if(elem->size()==2){
    pair < int, pair<int,int> > atm_sel_p=(*elem)[0];
    pair < int, pair<int,int> > atm_sel_c=(*elem)[1];
    if(atm_sel_p.first==ATOMO &&
       atm_sel_c.first==ATOMO &&
       (atm_sel_p.second).first==(atm_sel_c.second).first){
      

      gruppo* g_parent=NULL;
      
      for(unsigned int i=0;i<groups->size();i++){
        gruppo* tmp=&(*groups)[i];
        if(tmp->id()==(atm_sel_p.second).first){
          g_parent=tmp;
        }
        
      }

      if(g_parent!=NULL){
        *atm_parent=g_parent->find_atomo_id((atm_sel_p.second).second);
        *atm_child=g_parent->find_atomo_id((atm_sel_c.second).second);
      }
    }
  }     

}


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

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

bool flip_around_bond::act(int e){
  return _has_to_act;
}


flip_around_bond::~flip_around_bond(){
  cout <<  __FUNCTION__ << _the_image <<endl;
}

void flip_around_bond::register_plugin(){

}

 
bool flip_around_bond::time_to_act(){
  return _has_to_act;
}
    


/**************end member functions**********************************/



/****

void gruppo::generic_depth_search(atomo* da, void* data, void* data2 ,void* data3,
				  int (*pf)(atomo* da , atomo* fino,
					    void* data, void* data2, void* data3) )


void gruppo::generic_depth_search_appl_popped(atomo* da, void* data, void* data2 ,void* data3,
					      int (*pf)(atomo* da ,void* data, 
							void* data2, void* data3) ){


***/


bool ignore_plug(atomo* atm, void* data4){
  atomo* plug=static_cast<atomo*>(data4);
  return atm->id() == plug->id();
}

int trasl_depth_search_pf(atomo* da ,
                          void* data, void* data2, void* data3){

  atomo*  root=static_cast<atomo*> (data);
  atomo*  block=static_cast<atomo*> (data2);
  //gruppo* the_grp=static_cast<gruppo*> (data3);


  std::pair<float, float> pivot = vec_flipped(*block, *root);

  if(da->id() != root->id() &&
     da->id() != block->id()){
    std::pair<float,float> arrow(da->pos_x(),da->pos_y());
    float angle_rot=angle(arrow,pivot);
    
    std::pair<float, float> rotated=rotate_point(arrow.first, arrow.second, -2*angle_rot);
    da->pos_x(rotated.first);
    da->pos_y(rotated.second);
  }

  return 1;
}


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

extern "C" void destroy_plugin(bist_plugin* j){
  delete j;
}


