/*

    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 <iostream>
#include <FL/x.H>
#include <FL/Fl.H>
#include <FL/fl_draw.H>
#include <FL/fl_ask.H>
#include <FL/Fl_Double_Window.H>
#include <FL/Fl_Scroll.H>
#include <FL/Fl_Image.H>
#include <FL/Fl_Pixmap.H>
#include <global.hpp>

#include <2D_vector.hpp>
#include <regex.h>

#include <cstdio>


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


#include <matr.hpp>

#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 <util.hpp>

#include <immagine.hpp>
#include <bist_plugin.hpp>
#include <mol_canvas.hpp>
#include <finestra_pr.hpp>

#include <prefs.hpp>

#include <font_factory.hpp>

#include <logo.xpm>

#if HAVE_NCURSES_H
#include <ncurses.h>
#endif

using namespace std;

extern Preferences  __pref;



extern finestra_pr* MainWindow;


gruppo create_ring(float side_lenght, float numsides, 
                   bool aromatic) throw (out_of_range){
  if(numsides <3){
    throw out_of_range("numsides < 3");

  }else{

    float alpha=2*M_PI/numsides;
    float radius=side_lenght/(sqrt(2*(1-cos(alpha))));
    gruppo nw;
    
    for(float ang=0, i=0; i<numsides ; ang+=alpha , i++){
      atomo tmp;
      tmp.etich_punt()->aggiungi(NO_ETIC, ET_STR);
      tmp.pos_x(radius*cos(ang));
      tmp.pos_y(radius*sin(ang));
      nw.add_atomo_id(tmp);

    }

    //link atoms
    vector<atomo>::iterator beg=nw.iniz_atom();
    vector<atomo>::iterator end=nw.fin_atom();

    int odd_ct=0;

    while(beg < end){
      int the_id=(*beg).id();;
    
      int the_id2=-1;

      if(beg==end-1){
        the_id2=(*nw.iniz_atom()).id();
      }else{
        the_id2=(*(beg+1)).id();
      }


      atomo* a=nw.find_atomo_id(the_id);
      atomo* b=nw.find_atomo_id(the_id2);

      int type_bd=LEGAME_SINGOLO;

      if(aromatic){
        if(odd_ct%2==1){
          type_bd=LEGAME_DOPPIO;
        }

      }

      a->aggiungi_legame(the_id2,
                         type_bd,0,
                         0 ,0);
      a->costruisci_arrivati();
      b->aggiungi_legame(the_id,
                         type_bd,0,
                         0 ,0);
      b->costruisci_arrivati();
      beg++;
      odd_ct++;

    }

  

    return nw;
  }
}



int remap_color_48(int trentadue){

  return static_cast<int>(trentadue*65535/255);

}


float remap_color_1(int byte){
  return static_cast<float>(byte)/255.0;
}


string remap_ps_font(int fltkfont){
  string font_ps;
  switch(fltkfont){
  case 0:
    font_ps=__pref.get_sans_font().c_str();
    break;
  case 1:
    font_ps=__pref.get_sans_font_bold().c_str();
    break;
  case 2:

    font_ps=__pref.get_sans_font_italic().c_str();
    break;
  case 3:

    font_ps=__pref.get_sans_font_bold_italic().c_str();
    break;
  case 4:

    font_ps=__pref.get_mono_font().c_str();
    break;
  case 5:

    font_ps=__pref.get_mono_font_bold().c_str();
    break;
  case 6:

    font_ps=__pref.get_mono_font_italic().c_str();
    break;
  case 7:

    font_ps=__pref.get_mono_font_bold_italic().c_str();
    break;
  case 8:

    font_ps=__pref.get_serif_font().c_str();
    break;
  case 9:

    font_ps=__pref.get_serif_font_bold().c_str();
    break;
  case 10:

    font_ps=__pref.get_serif_font_italic().c_str();
    break;
  case 11:

    font_ps=__pref.get_serif_font_bold_italic().c_str();
    break;
  case 12:

    font_ps=__pref.get_symbol_font().c_str();
    break;
  case 13:

    font_ps=__pref.get_mono_font().c_str();
    break;
  case 14:

    font_ps=__pref.get_mono_font_bold().c_str();
    break;
  case 15:

    font_ps=__pref.get_dingbats_font().c_str();
  break;

 default:

   font_ps=__pref.get_serif_font().c_str();
   break;

  }
  return font_ps;
}



void draw_pango_string(std::string st,int x, int y, std::string font,int dim,
                       int cr, int cg, int cb){
  int font_dim_std=dim;
  cairo_t* cn=cairo_t_singleton::get_context();
  cairo_save(cn);
  
  cairo_set_source_rgb(cn,
                       remap_color_1(cr),
                       remap_color_1(cg),
                       remap_color_1(cb));

  PangoFontDescription* desc=pango_font_description_from_string(font.c_str());

  pango_font_description_set_absolute_size(desc,font_dim_std*PANGO_SCALE);
  cairo_move_to(cn, x, y);
  PangoLayout *layout = pango_cairo_create_layout(cn);
  pango_layout_set_text(layout, st.c_str(), -1);
  pango_layout_set_font_description(layout, desc);
  pango_cairo_update_layout(cn, layout);
  pango_cairo_show_layout(cn, layout);
  
  g_object_unref(layout);
  pango_font_description_free(desc);

  cairo_restore(cn);
}



float remap_y_ps(float vx){
  return __pref.getPageHeight() - vx;
  
}


bool rett_eqn(float x1, float y1, 
	      float x2, float y2, 
	      float& m, float& q){
  bool result=true;
  const static float limit_similar=0.1;
  
  if(!similar_to<float>(x1, x2, limit_similar)){
    m=(y1-y2)/(x1-x2);
    q=y2-m*x2;
  }else{
    m=0;
    q=0;
    result=false;
  }

  return result;

}



void is_perpendicular(float dax, float day, 
			  float ax, float ay, 
			  bool verso,float gap,
			  float& resx, float &resy){

  float m;
  float q;
  
  float trposx=0; 
  float trposy=0; 
  float treposx=ax-dax; 
  float treposy=ay-day;
  
  bool result=rett_eqn(trposx,trposy,
			  treposx,treposy,
			  m,q);
  
  float alfafr;
  
  if(result){
    alfafr=atan(-1/m);
  }else{
    alfafr=0;
  }
    
  if(verso){
    gap=-gap;
  }
  
  resx=gap*cos(alfafr);
  resy=gap*sin(alfafr);

  
}



void draw_parallel(float dax, float day, 
                       float ax, float ay,
                       int cr, int cg, int cb,
                       bool verso,float gap,bool tratt, bool noaccorc){

  float m;
  float q;
  float trposx=0; 
  float trposy=0; 
  float treposx=ax-dax; 
  float treposy=ay-day;
  float lung_princ=sqrt( pow(treposx,2) + pow(treposy,2) );
  float lung_accorc= noaccorc ? 0 : lung_princ - gap * lung_princ;
  float gap_par=lung_princ - lung_accorc;
  
  
  bool risultato=rett_eqn(trposx,trposy,
			  treposx,treposy,
			  m,q);
  
  
  float alfa=atan2(treposy,treposx);
  float scompy=gap_par*sin(alfa); 
  float scompx=gap_par*cos(alfa);
  
  alfa=M_PI+alfa;                 //ehm... ^_^;  
  float ecompy=gap_par*sin(alfa); 
  float ecompx=gap_par*cos(alfa);
  float lung=static_cast<float>(__pref.getDoubleBondOffset()); //SPACE_BOND;
  
  float alfafr;
  if(risultato){
    alfafr=atan(-1/m);
  }else{
    alfafr=0;
  }

    bool semip= return_half_plane(lung*cos(alfafr)+dax+scompx, 
				      lung*sin(alfafr)+day+scompy, 
				      dax, day,
				      ax, ay );


    if(!(semip==verso)){
	lung=-lung;
    }
    

    if(cairo_t_singleton::can_export()){
      
      cairo_t* cn=cairo_t_singleton::get_context();
      cairo_save(cn);
      if(tratt){
        const double dash_gap[1]={__pref.get_tratteggio_legame()};
        cairo_set_dash(cn,dash_gap,1,0);
      }
      
      cairo_set_source_rgb(cn,
                           remap_color_1(cr),
                           remap_color_1(cg),
                           remap_color_1(cb));
      cairo_move_to(cn,lung*cos(alfafr)+ax+ecompx, 
                    lung*sin(alfafr)+ay+ecompy);
      cairo_line_to(cn,lung*cos(alfafr)+dax+scompx,
                    lung*sin(alfafr)+day+scompy);

      cairo_stroke(cn);
      
      cairo_restore(cn);
      
      
    
    }else{
      if(tratt){
	char dash[2]={__pref.get_tratteggio_legame(),0};
	fl_line_style(FL_SOLID,static_cast<int>(rintf(__pref.getZoom())),dash);
      }else{
	fl_line_style(FL_SOLID,static_cast<int>(rintf(__pref.getZoom())),0);
      }    
       
      lung*=__pref.getZoom();
      
      fl_color(cr,cg,cb);
      fl_begin_line();
      fl_vertex(lung*cos(alfafr)+ax+ecompx, lung*sin(alfafr)+ay+ecompy);
      fl_vertex(lung*cos(alfafr)+dax+scompx, lung*sin(alfafr)+day+scompy);
      fl_end_line();
      fl_line_style(0);
    }
}

void draw_arrow(float dax, float day, 
		     float ax, float ay, 
		     float thickness,float arr_w, 
		     float arr_h, float arr_gap,
                     int cr, int cg, int cb,
		     bool verso){

  float the_zoom=__pref.getZoom();
  float m;
  float q;
  float trposx=0; 
  float trposy=0; 
  float treposx=dax-ax; 
  float treposy=day-ay;

  bool risultato=rett_eqn(trposx,trposy,
			  treposx,treposy,
			  m,q);
  if(risultato){
    float alfa=atan2(treposy,treposx);
    float ecompy=arr_w*sin(alfa);
    float ecompx=arr_w*cos(alfa);
    
    float ecompy_fin=(arr_w-arr_gap*arr_w)*sin(alfa);
    float ecompx_fin=(arr_w-arr_gap*arr_w)*cos(alfa);
    float alfafr=atan(-1/m);

    if(m==0){ //mah?
      alfafr=M_PI/2;
    }

    float lung=arr_h+thickness;
    float lungspess=static_cast<float>(thickness)/2.;
    	
    if(verso){
      lung=-lung;
      lungspess=-lungspess;
    }
    

    float lato1[4]={
      lungspess*cos(alfafr)+ax,lungspess*sin(alfafr)+ay,
      lung*cos(alfafr)+ax+ecompx,lung*sin(alfafr)+ay+ecompy
    };
    float lato2[4]={
      dax,day,
      ax,ay
    };
	  
    float risx=0, risy=0;
	
    is_intersection(lato1,lato2, risx, risy);

    if(cairo_t_singleton::can_export()){
      
      float back_point_x=lung*cos(alfafr)+ax+ecompx;
      float back_point_y=lung*sin(alfafr)+ay+ecompy;
      float back_point_x_w_gap=ecompx_fin+ax;
      float back_point_y_w_gap=ecompy_fin+ay;
      
      cairo_t* cn=cairo_t_singleton::get_context();
      cairo_save(cn);
      cairo_set_line_width(cn,UTILS_ARROW_PLOTTER_LINE_WIDTH);
      
      cairo_set_source_rgb(cn,
                              remap_color_1(cr),
                              remap_color_1(cg),
                              remap_color_1(cb)
                              );
      cairo_move_to(cn,risx,risy);
      cairo_line_to(cn,back_point_x,back_point_y);
      cairo_line_to(cn,back_point_x_w_gap,back_point_y_w_gap);
      cairo_close_path(cn);
      cairo_fill(cn);
      cairo_restore(cn);

    
    }else{

      fl_line_style(FL_SOLID,static_cast<int>(rintf(thickness)));
      int dx_scroll=(MainWindow->ritorna_mol_canvas())->x();
      int dy_scroll=(MainWindow->ritorna_mol_canvas())->y();

      float dx_sc=risx;//lu.first+w_sc/2;
      float dy_sc=risy;//lu.second+h_sc/2;

      float p1x=scale_center_point(risx,dx_sc, the_zoom);
      float p1y=scale_center_point(risy,dy_sc, the_zoom);

      float p2x=scale_center_point(lung*cos(alfafr)+ax+ecompx,dx_sc, the_zoom);
      float p2y=scale_center_point(lung*sin(alfafr)+ay+ecompy,dy_sc, the_zoom);

      float p3x=scale_center_point(ecompx_fin-arr_gap*ecompx_fin+ax,dx_sc, the_zoom);
      float p3y=scale_center_point(ecompy_fin+ay,dy_sc, the_zoom);
	  
      fl_begin_complex_polygon();

      fl_vertex(p1x+dx_scroll, 
		p1y+dy_scroll);

      fl_vertex(p2x+dx_scroll,
		p2y+dy_scroll);

      fl_vertex(p3x+dx_scroll, 
		p3y+dy_scroll);

      fl_end_complex_polygon();
	  
    }
  }else{

    float spy=arr_w; //displ on y
    float spx=arr_h+thickness; //displ on x
    float lungspess=thickness/2.;
	
    if(verso){// revert displ 
      spx=-spx;  
      lungspess=-lungspess;
      
    }

    if(day>ay){
      spy=-spy;
    }
    
    float lato1[4]={
      lungspess+ax,ay,
      lungspess+ax+spx,ay-spy
    };
    float lato2[4]={
      dax,day,
      ax,ay
    };
	  
    float risx=0, risy=0;
    is_intersection(lato1,lato2, risx, risy);

    if(cairo_t_singleton::get_context()){
      cairo_t* cn=cairo_t_singleton::get_context();
      cairo_save(cn);
      cairo_set_line_width(cn,UTILS_ARROW_PLOTTER_LINE_WIDTH);
      cairo_set_source_rgb(cn,
                           remap_color_1(cr),
                           remap_color_1(cg),
                           remap_color_1(cb)
                           );
      cairo_move_to(cn,risx,risy);
      cairo_line_to(cn,ax+spx,ay-spy);
      cairo_line_to(cn,ax,ay-spy+(spy*arr_gap));
      cairo_close_path(cn);
      cairo_fill(cn);
      cairo_restore(cn);

    }else{

      fl_line_style(FL_SOLID,static_cast<int>(rintf(thickness)));
      int dx_scroll=(MainWindow->ritorna_mol_canvas())->x();
      int dy_scroll=(MainWindow->ritorna_mol_canvas())->y();

      float dx_sc=risx;//lu.first+w_sc/2.0;
      float dy_sc=risy;//lu.second+h_sc/2.0;
      
      float p1x=scale_center_point(risx,dx_sc, the_zoom);
      float p1y=scale_center_point(risy,dy_sc, the_zoom);

      float p2x=scale_center_point(ax+spx,dx_sc, the_zoom);
      float p2y=scale_center_point(ay-spy,dy_sc, the_zoom);

      float p3x=scale_center_point(ax, dx_sc,the_zoom);
      float p3y=scale_center_point(ay-spy+(spy*arr_gap),dy_sc, the_zoom);
      
      fl_begin_complex_polygon();
      fl_vertex(p1x+dx_scroll, p1y+dy_scroll);
      fl_vertex(p2x+dx_scroll,p2y+dy_scroll);
      fl_vertex(p3x+dx_scroll,p3y+dy_scroll);
      fl_end_complex_polygon();
      
    }
  }
}

//////

void calculate_arrow_points(float dax, float day, 
                            float ax, float ay, 
                            float thick,float arr_w, 
                            float arr_h, float arr_gap,
                            int cr, int cg, int cb,
                            std::vector<float>& results_x,
                            std::vector<float>& results_y,
                            bool to){

  float the_zoom=__pref.getZoom();
  float m;
  float q;
  float trposx=0; 
  float trposy=0; 
  float treposx=dax-ax; 
  float treposy=day-ay;

  bool result=rett_eqn(trposx,trposy,
			  treposx,treposy,
			  m,q);
  if(result){

    float alfa=atan2(treposy,treposx);
    float ecompy=arr_w*sin(alfa);
    float ecompx=arr_w*cos(alfa);
    
    float ecompy_fin=(arr_w-arr_gap*arr_w)*sin(alfa);
    float ecompx_fin=(arr_w-arr_gap*arr_w)*cos(alfa);
    float alfafr=atan(-1/m);

    if(m==0){ //mah?
      alfafr=M_PI/2;
    }

    float lung=arr_h+thick;
    float lungspess=static_cast<float>(thick)/2.;
    	
    if(to){
      lung=-lung;
      lungspess=-lungspess;
    }
    

    float lato1[4]={
      lungspess*cos(alfafr)+ax,lungspess*sin(alfafr)+ay,
      lung*cos(alfafr)+ax+ecompx,lung*sin(alfafr)+ay+ecompy
    };
    float lato2[4]={
      dax,day,
      ax,ay
    };
	  
    float resx=0, resy=0;
	
    is_intersection(lato1,lato2, resx, resy);



    if(cairo_t_singleton::can_export()){
      float back_point_x=lung*cos(alfafr)+ax+ecompx;
      float back_point_y=lung*sin(alfafr)+ay+ecompy;
      float back_point_x_w_gap=ecompx_fin+ax;
      float back_point_y_w_gap=ecompy_fin+ay;
      

      results_x.push_back(resx);
      results_y.push_back(resy);

      results_x.push_back(back_point_x);
      results_y.push_back(back_point_y);

      results_x.push_back(back_point_x_w_gap);
      results_y.push_back(back_point_y_w_gap);

    }else{

      float dx_sc=resx;//lu.first+w_sc/2;
      float dy_sc=resy;//lu.second+h_sc/2;

      float p1x=scale_center_point(resx,dx_sc, the_zoom);
      float p1y=scale_center_point(resy,dy_sc, the_zoom);

      float p2x=scale_center_point(lung*cos(alfafr)+ax+ecompx,dx_sc, the_zoom);
      float p2y=scale_center_point(lung*sin(alfafr)+ay+ecompy,dy_sc, the_zoom);

      float p3x=scale_center_point(ecompx_fin-arr_gap*ecompx_fin+ax,dx_sc, the_zoom);
      float p3y=scale_center_point(ecompy_fin+ay,dy_sc, the_zoom);
	  


      results_x.push_back(p1x);//+dx_scroll);
      results_y.push_back(p1y);//+dy_scroll);


      results_x.push_back(p2x);//+dx_scroll);
      results_y.push_back(p2y);//+dy_scroll);


      results_x.push_back(p3x);//+dx_scroll);
      results_y.push_back(p3y);//+dy_scroll);
	  
    }
  }else{

    float spy=arr_w; //displ on y
    float spx=arr_h+thick; //displ on x
    float lungspess=thick/2.;
	
    if(to){// revert displ 
      spx=-spx;  
      lungspess=-lungspess;
    }
    


    if(day>ay){
      spy=-spy;
    }
    
    float lato1[4]={
      lungspess+ax,ay,
      lungspess+ax+spx,ay-spy
    };
    float lato2[4]={
      dax,day,
      ax,ay
    };
	  
    float resx=0, resy=0;
    is_intersection(lato1,lato2, resx, resy);

    if(cairo_t_singleton::get_context()){

      results_x.push_back(resx);
      results_y.push_back(resy);


      results_x.push_back(ax+spx);
      results_y.push_back(ay-spy);


      results_x.push_back(ax);
      results_y.push_back(ay-spy+(spy*arr_gap));

    }else{

      float dx_sc=resx;//lu.first+w_sc/2.0;
      float dy_sc=resy;//lu.second+h_sc/2.0;
      
      float p1x=scale_center_point(resx,dx_sc, the_zoom);
      float p1y=scale_center_point(resy,dy_sc, the_zoom);

      float p2x=scale_center_point(ax+spx,dx_sc, the_zoom);
      float p2y=scale_center_point(ay-spy,dy_sc, the_zoom);

      float p3x=scale_center_point(ax, dx_sc,the_zoom);
      float p3y=scale_center_point(ay-spy+(spy*arr_gap),dy_sc, the_zoom);

      results_x.push_back(p1x);//+dx_scroll);
      results_y.push_back(p1y);//+dy_scroll);


      results_x.push_back(p2x);//+dx_scroll);
      results_y.push_back(p2y);//+dy_scroll);


      results_x.push_back(p3x);//+dx_scroll);
      results_y.push_back(p3y);//+dy_scroll);

      
    }
  }
}





bool return_half_plane(float x, float y, 
			   float xrt, float yrt,
			   float xrt2, float yrt2 ){

  float m;
  float q;
  bool rest=rett_eqn(xrt,yrt,xrt2,yrt2,m,q);
  bool res;
  if(rest){
    res = y >= m*x + q;
  }else{
    res = x > xrt;
  }
  return res;

}



float b_clip_v(float da_x, float da_y, float end_x, float end_y, float x_edge){
  float xpiv=min(da_x,end_x);
  float x1=min(da_x,end_x);
  float x2=max(da_x,end_x);
  float y1= x1==da_x ? da_y : end_y;
  float y2= x2==da_x ? da_y : end_y;

  float m ,q;

  bool risul=rett_eqn(x1,y1, 
		      x2, y2, 
		      m, q); 
  if(risul){

    while(abs(xpiv-x_edge)>0.001){
      xpiv=(x2+x1)/2;

      if(xpiv<x_edge){
	x1=xpiv;
      }else{
	x2=xpiv;
      }
    }

    return xpiv*m+q;

  }else{
    //non  dovrebbe arrivarci  mai visto  che il  segmento non  sara mai
    //parallelo alla y
    cout << "b_clip_v: unexpected value returned by \'rett_eqn\' function\n" << endl;
    return -1;
  }

}


float b_clip_h(float da_x, float da_y, float end_x, float end_y, float y_edge){

  float ypiv=min(da_y,end_y);
  float y1=min(da_y,end_y);
  float y2=max(da_y,end_y);

  float x1= y1==da_y ? da_x : end_x;
  float x2= y2==da_y ? da_x : end_x;

  float m ,q;

  bool risul=rett_eqn(x1,y1, 
		      x2, y2, 
		      m, q); 

  if(risul){

    while(abs(ypiv-y_edge)>0.001){
      ypiv=(y2+y1)/2;

      if(ypiv<y_edge){
	y1=ypiv;
      }else{
	y2=ypiv;
      }
    }
    return (ypiv-q)/m;
  }else{
    return da_x;
  }

}



bool line_belongs(int x_m, int y_m, 
		     float st_x, float st_y,
		     float e_x, float e_y,
		     int thickness){

  float m;
  float q;

  if(abs(st_x-e_x) < thickness){
    e_x=st_x;
  }

  bool result=rett_eqn(st_x,st_y,
			  e_x,e_y,
			  m,q);

  if(result){

    float yprev=m * x_m + q;
    bool similar=similar_to(yprev, static_cast<float>(y_m), static_cast<float>(thickness));

    if(similar){
      if(e_x - st_x >0){
	return (x_m >=st_x && x_m <=e_x);
      }else{
	return (x_m >=e_x && x_m <=st_x);
      }
    }else{
      return false;
    }

  }else{
    if(abs(x_m - static_cast<int>(rintf(st_x))) < thickness &&
       y_m<max(st_y,e_y) &&
       y_m>min(st_y,e_y)){
      return true;
    }else{
      return 0;
    }
  }

}


void draw_point(float x, float y){
  int raggioatt=static_cast<int>(rintf(RAGGIO_EL*1.5));
  int xint=static_cast<int>(rintf(x));
  int yint=static_cast<int>(rintf(y));

  fl_color(0,0,0);
  fl_pie(xint-(raggioatt+1)/2, yint-(raggioatt+1)/2,  raggioatt+1, raggioatt+1, 0, 360);
  fl_color(198,133,149);
  fl_pie(xint-(raggioatt+1)/2, yint-(raggioatt+1)/2,  raggioatt, raggioatt, 0, 360);
}


void draw_shadowed_point(float x, float y, int r, int g, int b){
  int raggioatt=static_cast<int>(rintf(RAGGIO_EL*1.5)*__pref.getZoom());
  int xint=static_cast<int>(rintf(x));
  int yint=static_cast<int>(rintf(y));
  fl_color(0,0,0);
  fl_pie(xint-(raggioatt+1)/2, yint-(raggioatt+1)/2,  raggioatt+1, raggioatt+1, 0, 360);
  fl_color(r,g,b);
  fl_pie(xint-(raggioatt+1)/2, yint-(raggioatt+1)/2,  raggioatt, raggioatt, 0, 360);
}


void draw_frame(int x, int y , int w ,int h){

  draw_point(x,y);
  draw_point(x+w,y);
  draw_point(x+w,y+h);
  draw_point(x,y+h);
}


void get_visual_bb_etic(etichetta& et, float& x, float& y){
  float st_xpos=et.visual_x();
  float st_ypos=et.visual_y();
  int half_w=0;
  int h=0;
  string car;
  vector < pair<string,int> > stringhevec=et.vec_str();
  

  switch(et.allineamento()){

  case ETIC_ALLINEA_CT:
    st_xpos-=et.visual_w()/2;
    st_ypos-=et.visual_h()/2;
    break;
  case ETIC_ALLINEA_DX:
    if(stringhevec.size()>0){
      car=stringhevec[(stringhevec.size()-1)].first;
    }
    

    if(car.size()>0){
      car=car[car.size()-1];
      fl_measure(car.c_str(), half_w, h);
    }


    st_xpos-=et.visual_w();
    st_xpos+=half_w/2;
    st_ypos-=et.visual_h()/2;
    break;
  case ETIC_ALLINEA_SX:
  default:
    car+=((et.vec_str())[0].first)[0];
    fl_measure(car.c_str(), half_w, h);
    st_ypos-=et.visual_h()/2;
    st_xpos-=half_w/2;
    break;
  }

  x=static_cast<int>(rintf(st_xpos));
  y=static_cast<int>(rintf(st_ypos));


}


void get_bb_etic(etichetta& et, int& x, int& y){

  float st_xpos=et.x();
  float st_ypos=et.y();

  int half_w=0;
  int h=0;
  string car;
  vector < pair<string,int> > stringhevec=et.vec_str();
  

  switch(et.allineamento()){

  case ETIC_ALLINEA_CT:
    st_xpos-=et.w()/2;
    st_ypos-=et.h()/2;
    break;
  case ETIC_ALLINEA_DX:
    if(stringhevec.size()>0){
      car=stringhevec[(stringhevec.size()-1)].first;
    }
    

    if(car.size()>0){
      car=car[car.size()-1];
      fl_measure(car.c_str(), half_w, h);
    }


    st_xpos-=et.w();
    st_xpos+=half_w/2;
    st_ypos-=et.h()/2;
    break;
  case ETIC_ALLINEA_SX:
  default:
    car+=((et.vec_str())[0].first)[0];
    fl_measure(car.c_str(), half_w, h);
    st_ypos-=et.h()/2;
    st_xpos-=half_w/2;
    break;
  }

  x=static_cast<int>(rintf(st_xpos));
  y=static_cast<int>(rintf(st_ypos));

}

void get_bb_etic(etichetta& et, float& x, float& y){
  string font_ps;
  int tipo_font;


  get_font_handle(et, tipo_font, font_ps);

  fl_font(tipo_font,et.phys_dim());



  float st_xpos=et.phys_x();
  float st_ypos=et.phys_y();
  string car;
  vector < pair<string,int> > stringhevec=et.vec_str();
  

  switch(et.allineamento()){

  case ETIC_ALLINEA_CT:
    st_xpos-=et.phys_w()/2;
    st_ypos-=et.phys_h()/2;
    break;
  case ETIC_ALLINEA_DX:
    if(stringhevec.size()>0){
      car=stringhevec[(stringhevec.size()-1)].first;
      int tp_str=(stringhevec[0]).second;
      car=car[car.size()-1];
      etichetta cp(et);
      cp.elimina();
      cp.aggiungi(car, tp_str);  
      st_xpos-=et.phys_w();
      st_xpos+=cp.phys_w()/2;
      st_ypos-=et.phys_h()/2;
    }
    break;
  case ETIC_ALLINEA_SX:
  default:
    {
    if(stringhevec.size()>0){
      car=((stringhevec[0]).first)[0];
      int tp_str=(stringhevec[0]).second;
      etichetta cp(et);
      cp.elimina();
      cp.aggiungi(car, tp_str);
      st_ypos-=cp.phys_h()/2;
      st_xpos-=cp.phys_w()/2;
    }
  }
    break;
  }

  x=st_xpos;
  y=st_ypos+et.v_offset();

}



void get_font_handle(etichetta et, int &font_fltk, string &font_libplot){

  font_factory* f_factory=font_map_singleton::get_context();


  string font_ps;
  int tipo_font;
  switch(et.font()){

  case 0:
    tipo_font=f_factory->get_actual_font(FL_HELVETICA);
    font_ps=__pref.get_sans_font().c_str();
    break;
  case 1:
    tipo_font=f_factory->get_actual_font(FL_HELVETICA_BOLD);
    font_ps=__pref.get_sans_font_bold().c_str();
    break;
  case 2:
    tipo_font=f_factory->get_actual_font(FL_HELVETICA_ITALIC);
    font_ps=__pref.get_sans_font_italic().c_str();
    break;
  case 3:
    tipo_font=f_factory->get_actual_font(FL_HELVETICA_BOLD_ITALIC);
    font_ps=__pref.get_sans_font_bold_italic().c_str();
    break;
  case 4:
    tipo_font=f_factory->get_actual_font(FL_COURIER);
    font_ps=__pref.get_mono_font().c_str();
    break;
    case 5:
      tipo_font=f_factory->get_actual_font(FL_COURIER_BOLD);
    font_ps=__pref.get_mono_font_bold().c_str();
    break;
  case 6:
    tipo_font=f_factory->get_actual_font(FL_COURIER_ITALIC);
    font_ps=__pref.get_mono_font_italic().c_str();
    break;
  case 7:
    tipo_font=f_factory->get_actual_font(FL_COURIER_BOLD_ITALIC);
    font_ps=__pref.get_mono_font_bold_italic().c_str();
    break;
  case 8:
    tipo_font=f_factory->get_actual_font(FL_TIMES);
    font_ps=__pref.get_serif_font().c_str();
    break;
  case 9:
    tipo_font=f_factory->get_actual_font(FL_TIMES_BOLD);
    font_ps=__pref.get_serif_font_bold().c_str();
    break;
  case 10:
    tipo_font=f_factory->get_actual_font(FL_TIMES_ITALIC);
    font_ps=__pref.get_serif_font_italic().c_str();
    break;
  case 11:
    tipo_font=f_factory->get_actual_font(FL_TIMES_BOLD_ITALIC);
    font_ps=__pref.get_serif_font_bold_italic().c_str();
    break;
  case 12:
    tipo_font=f_factory->get_actual_font(FL_SYMBOL);
    font_ps=__pref.get_symbol_font().c_str();
    break;
  case 13:
    tipo_font=f_factory->get_actual_font(FL_SCREEN);
    font_ps=__pref.get_mono_font().c_str();
    break;
  case 14:
    tipo_font=f_factory->get_actual_font(FL_SCREEN_BOLD);
    font_ps=__pref.get_mono_font_bold().c_str();
    break;
  case 15:
    tipo_font=f_factory->get_actual_font(FL_ZAPF_DINGBATS);
    font_ps=__pref.get_dingbats_font().c_str();
  break;

 default:
   tipo_font=f_factory->get_actual_font(FL_TIMES);
   font_ps=__pref.get_serif_font().c_str();
   break;

  }

  font_fltk=tipo_font;
  font_libplot=font_ps;

}


void not_impl(){
  fl_alert(_("Sorry, not yet implemented"));
}

bool format_supported(string format){
  static const unsigned int num_format=3;
  const char* valid_format[num_format]={EXPORT_FORMAT_PS,
                                        EXPORT_FORMAT_SVG,
                                        EXPORT_FORMAT_PNG};
  bool risul=false;
  for(unsigned int i=0;i<num_format;i++){
    if(format==valid_format[i]){
      risul=true;
      break;
    }
  }

  return risul;
}




unsigned int create_hash(string value){
  static const int q = 33554393;
  unsigned int risul=0;
  int M= value.size()-1;
  for(unsigned int i=0; i<value.size(); i++){
    risul+=value[i] * static_cast<unsigned int>(pow(255.0,M)) %  q; 
    M--;
  }
  return risul;

}



bool is_intersection(float* xy1,float* xy2, float& risx, float& risy){
  float m1=-220, q1=-20;
  bool prima_retta=rett_eqn(xy1[0], xy1[1], 
			    xy1[2], xy1[3], 
			    m1,  q1);
  float m2=0, q2=0;
  bool seconda_retta=rett_eqn(xy2[0], xy2[1], 
			      xy2[2], xy2[3], 
			      m2,  q2);

  bool risul =true;
  if(prima_retta){
    if(seconda_retta){
      risy=( ( (q2-q1)/(m1-m2) ) * m1 ) + q1;
      risx=(q2-q1)/(m1-m2);
    }else{
      risx=xy2[0];
      risy=risx*m1+q1;
    }
  }else{
    if(seconda_retta){
      risx=xy1[0];
      risy=risx*m2+q2;
    }else{
      risul=false;
    }

  }
  return risul;
}



Splash_Window::Splash_Window()
  :Fl_Window(Splash_Window::splash_w,Splash_Window::splash_h),
   _logo(0,0,Splash_Window::splash_w,Splash_Window::splash_h)
{
  clear_border();
  resize(Fl::w()/2 - w()/2,Fl::h()/2 - h()/2,Splash_Window::splash_w,Splash_Window::splash_h);
  box(FL_FLAT_BOX);
  color(FL_BLACK);
  add(_logo);
  Fl::add_timeout(Splash_Window::splash_persistence, Splash_Window::hide_win_timeout, reinterpret_cast<void*>(this));
}
  
Splash_Window::~Splash_Window() { 
  Fl::remove_timeout(Splash_Window::hide_win_timeout, reinterpret_cast<void*>(this));
}
  
int Splash_Window::handle(int e){
  switch(e){
  case FL_ENTER:
    hide();
    return 1;
  }
  return 0;
}



void Splash_Window::hide_win_timeout(void* win){
  Fl_Window* w=reinterpret_cast<Fl_Window*>(win);
  w->hide();
}


const double Splash_Window::splash_persistence=5;

const int Splash_Window::splash_w=452;
const int Splash_Window::splash_h=348;

Splash_Widget::Splash_Widget(int x,int y,int w, int h)
  :Fl_Widget(x, y, w, h)
{

}

Splash_Widget::~Splash_Widget(){

}

void Splash_Widget::draw(){
  fl_draw_pixmap(logo, 2, 2);
}



void merge_groups(gruppo* g_st , gruppo* g_arr,atomo* st, atomo* arr, int tipo){

  //fare il join di due gruppi diversi
  int id_atom_arr_bk=arr->id();

  int id_atom_st_bk=st->id();

  int id_nuovo_arr=arr->id();;
  
  //the largest id in the st group
  int id_st_max=(*(g_st->fin_atom()-1)).id();
  
  //cerchiamo se nel gruppo di arr esiste id_st_max
  bool exist_in_arr=false;
  
  vector<atomo>::iterator inatm=g_arr->iniz_atom();
  vector<atomo>::iterator finatm=g_arr->fin_atom();

  while(inatm!=finatm){
    if((*inatm).id()==id_st_max){
      exist_in_arr=true;
      break;
    }
    inatm++;
  }



  if(exist_in_arr){
    
  }else{
    if(id_nuovo_arr==-1){
      id_nuovo_arr=id_atom_arr_bk;
    }
  }
  
  id_st_max++;

  
  
  int id_legato=g_arr->rimappa_da(id_st_max,id_nuovo_arr);
  
  vector<atomo>::iterator inatm2=g_arr->iniz_atom();
  vector<atomo>::iterator finatm2=g_arr->fin_atom();

  while(inatm2!=finatm2){
    (*inatm2).aggiungi_genitore(g_st);
    g_st->add_atomo((*inatm2));
    inatm2++;
  }


  vector<atomo>::iterator inatm4=g_st->iniz_atom();
  vector<atomo>::iterator finatm4=g_st->fin_atom();

  atomo* nuovoarr=0;
  atomo* nuovost=0;
  while(inatm4!=finatm4){

    if((*inatm4).id()==id_legato){
      nuovoarr=&(*inatm4);
    }
    
    if((*inatm4).id()==id_atom_st_bk){
      nuovost=&(*inatm4);
    }
    inatm4++;
  }

  nuovost->aggiungi_legame(nuovoarr->id(),tipo,0,0,0);
  nuovost->costruisci_arrivati();
  
  if(tipo==LEGAME_INTERNO || tipo== LEGAME_ESTERNO ||
     tipo==LEGAME_INTERNO_OPP || tipo==LEGAME_ESTERNO_OPP){
    tipo=-tipo;
  }
  
  nuovoarr->aggiungi_legame(nuovost->id(),tipo,0,0,0);
  nuovoarr->costruisci_arrivati();




  vector<atomo>::iterator inatm3=g_st->iniz_atom();
  vector<atomo>::iterator finatm3=g_st->fin_atom();
  
  while(inatm3!=finatm3){
    (*inatm3).costruisci_arrivati();
    inatm3++;
  }

}

bool calc_bb_gen_intersect(pair<float,float>& lu1,
                           pair<float,float>& rd1,
                           pair<float,float>& lu2,
                           pair<float,float>& rd2
                           ){
  
  bool res=true;

  
  if(lu1.first >  rd2.first) { //OK
    res=false;
  }

  if(rd1.first <  lu2.first ){
    res=false;
  }

  if(lu1.second >  rd2.second ){
    res=false;
  }


  if(rd1.second <  lu2.second ){ //OK
    res=false;
  } 
  return res;
}

void calc_bb_gen(vector<float> x, vector<float> y, 
		 pair<float,float>& ld,
		 pair<float,float>& ru){
  float min_xbb=1E20;
  float min_ybb=1E20;
  float max_xbb=1E-20;
  float max_ybb=1E-20;



  for(unsigned int i=0;i<x.size();i++){
    if(x[i]< min_xbb){
      min_xbb=x[i];
    }
    
    if(x[i]> max_xbb){
      max_xbb=x[i];
    }
    
    if(y[i]< min_ybb){
      min_ybb=y[i];
    }
    
    if(y[i]> max_ybb){
      max_ybb=y[i];
    }
    
  }

  ld.first=min_xbb;
  ld.second=min_ybb;
  
  ru.first=max_xbb;
  ru.second=max_ybb;

}


float scale_center_point(double point,double trasl, double zoom){
  return static_cast<float>( (point-trasl)*zoom+trasl );
}


float descale(float scaled){
  return scaled/__pref.getZoom();
}

float scale_z(float scaled){
  return scaled * __pref.getZoom();
}

vector<float> correct_arrow(float xtan_st, float ytan_st, 
			    float xtan_end, float ytan_end, 
			    float entity){
  vector<float> result;
  float pt_x=xtan_end;
  float pt_y=ytan_end;
  float x_c_diff=xtan_end-xtan_st;
  float y_c_diff=ytan_end-ytan_st;
  //module
  float mgn_diff=sqrt(pow(x_c_diff,2)+pow(y_c_diff,2));
  //angle
  float angl_diff=atan2f(y_c_diff,x_c_diff);
  if(mgn_diff<20){
    pt_x=xtan_st+( (mgn_diff*5/8) * cos(angl_diff));
    pt_y=ytan_st+( (mgn_diff*5/8) * sin(angl_diff));
  }
  
  result.push_back(pt_x);
  result.push_back(pt_y);
  return result;
}




int ask_overwrite_file(string the_file){
  string the_choice=string(_("File with name")) + 
    string(" ") + string(the_file) + string(" ") +
    string(_("already exist.\nDo you want to overwrite it?"));
  return fl_choice("%s",_("No"),_("Yes"),NULL,the_choice.c_str());
    
}

int ask_overwrite_file_console(string the_file){
  string the_choice=string(_("File with name")) + 
    string(" ") + string(the_file) + string(" ") +
    string(_("already exist.\nDo you want to overwrite it?[y/N] "));

  std::string ans;
  std::cout << the_choice << std::ends;
  getline(cin,ans,'\n');
  int res=1;
  if(ans!=_("y")){
    res=0;
  }

  return res;
    
}



std::pair<float, float> poly_bezier(float x0, float y0,
				    float x1, float y1,
				    float x2, float y2,
				    float x3, float y3,
				    float t) throw (out_of_range) {
  if(t >=0 && t<=1){
    std::pair<float, float> res;
    float one_minus_t=(1-t);
    float one_minus_t_square=pow(one_minus_t,2);
    float one_minus_t_cube=pow(one_minus_t,3);
    float t_square=pow(t,2);
    float t_cube=pow(t,3);
    
    res.first=x0 * one_minus_t_cube + 3 * x1 *  t * one_minus_t_square + 3 * x2 * t_square * one_minus_t + x3 * t_cube;
    res.second=y0 * one_minus_t_cube + 3 * y1 * t * one_minus_t_square + 3 * y2 * t_square * one_minus_t + y3 * t_cube;
    
    return res;
  }else{
    throw out_of_range("poly_bezier:  t <0 || t >1");
  }
}


std::pair<float, float> rotate_point(float x, float y, float angle){
  matrix<float> the_vec(2,1);
  matrix<float> transformation(2,2);
  std::pair<float, float> res(0,0);
  try{
    the_vec(0,0)=x;
    the_vec(1,0)=y;
    transformation(0,0)=cos(angle);
    transformation(0,1)=sin(angle);
    transformation(1,0)=-sin(angle);
    transformation(1,1)=cos(angle);

    matrix<float> mat_res=  transformation * the_vec;
    res.first=mat_res(0,0);
    res.second=mat_res(1,0);
  }catch (matrix_error ex){
    cerr << "exception in " <<  __LINE__ << " "
	 << __FILE__        <<  ex.what() << endl;
  }

  return res;

}

void print_redfog_wisdom(){
  const static char* wisdom_of_redfog[]={
    "                       __@                ", //0
    "                     _`\\< _              ",//1
    "                  --(|)/ (|)              ",//2
    "                 -- (/)/ (/)              ",//3
    "                --  (-)/ (-)              ",//4
    "              --    (\\)/ (\\)            ",//5
    "           --       (|)/ (|)              ",//6
    "        -           (/)/ (/)              ",//7
    "     -              (-)/ (-)              ",//8
    "                    (\\)/ (\\)            ",//9
    "...\"Caso mai passo\"...                  ", //10
    "...\"Hai martello e scarpe da tennis?\"...",//11
    "...\"Hai mollica?\"...                    ",//12
    "...\"Qualcuno sa perche' l'installazione di Debian sull'amiga 2000 mi si fermi al 2%\"...",//13
    "...\"Motoguzzi\"...                                                                    ",//14
    "\"ma sei pazzo?\nDove cazzo sei?\nMi risponde una voce in inglese!\"\n-- sms spedito a cage mentre questi e' in vacanza",//15
    "...\"nelle moderne CPU il bus della cialda di silicio e' ormai cosi'\npiccolo da essere diventato puntiforme\"..."//16
  };
  const static int start_wisdom=10;
  const static int end_wisdom=16;
  srand(time(NULL));

  unsigned int perl=( rand()%(end_wisdom - start_wisdom + 1 ) ) + start_wisdom;

#if HAVE_NCURSES_H
  unsigned int wheel_start=2;
  unsigned int wheel_size=8;
  unsigned int wheel_ptr=0;
  char ch='a';
  char st_ch='q';

  initscr();
  start_color();
  init_pair(1,COLOR_WHITE,COLOR_BLACK);
  init_pair(2,COLOR_RED,COLOR_BLACK);
  init_pair(3,COLOR_GREEN,COLOR_BLACK);

  while(ch!=st_ch){
    timeout(200);
    attron(COLOR_PAIR(1)); 
    mvprintw(0, 0,wisdom_of_redfog[0]); 
    mvprintw(1, 0,wisdom_of_redfog[1]); 
    attron(COLOR_PAIR(2)); 
    mvprintw(2, 0,wisdom_of_redfog[wheel_start + (wheel_ptr% wheel_size)]); 
    attron(COLOR_PAIR(3));
    mvprintw(3, 0,wisdom_of_redfog[perl]); 
#ifdef DEBUG
    mvprintw(4, 0,"%i",wheel_start + (wheel_ptr% wheel_size)); 
#endif
    refresh();
    wheel_ptr++;
    ch=getch();
  }  

  endwin();
#else
  std::cout << wisdom_of_redfog[0] << std::endl;
  std::cout << wisdom_of_redfog[1] << std::endl;
  std::cout << wisdom_of_redfog[2] << std::endl;
  std::cout << wisdom_of_redfog[perl] << std::endl;
#endif

  exit(EXIT_SUCCESS);


}


float rad2deg(float angle){
  return 180.0*angle/M_PI;
}

float deg2rad(float angle){
  return (angle*M_PI)/180.0;
}


void attract_mouse_to_magnetic_point(int* x_m, int* y_m){

  double mag_gap=__pref.getMagnetic_point_gap() * __pref.getZoom();
  if(mag_gap>0){
    int dx_scroll=(MainWindow->ritorna_mol_canvas())->x();
    int dy_scroll=(MainWindow->ritorna_mol_canvas())->y();
    *x_m-=dx_scroll;
    *y_m-=dy_scroll;
    
    int floor_x=static_cast<int>(floor((*x_m)/mag_gap));
    int floor_y=static_cast<int>(floor((*y_m)/mag_gap));
    
    int ceil_x=static_cast<int>(ceil((*x_m)/mag_gap));
    int ceil_y=static_cast<int>(ceil((*y_m)/mag_gap));
    if(abs(*x_m - (ceil_x * mag_gap)) <
       abs(*x_m - (floor_x * mag_gap))){
      (*x_m)=static_cast<int>(rintf(ceil_x * mag_gap));
    }else{
      (*x_m)=static_cast<int>(rintf(floor_x* mag_gap));
    }

    *x_m+=dx_scroll;

    if(abs(*y_m - (ceil_y * mag_gap)) <
       abs(*y_m - (floor_y * mag_gap))){
      (*y_m)=static_cast<int>(rintf(ceil_y* mag_gap));
    }else{
      (*y_m)=static_cast<int>(rintf(floor_y* mag_gap));
    }
    *y_m+=dy_scroll;

  }
}


std::string trim(std::string s,const std::string drop){
 std::string r=s.erase(s.find_last_not_of(drop)+1);
 return r.erase(0,r.find_first_not_of(drop));
}



void search_for_font(const char* desidered, Fl_Font destination, int num_fonts){
  for (int i = 0; i < num_fonts; i++) {
    const char *name = Fl::get_font_name((Fl_Font)i,NULL);
    if(strcasecmp (desidered,name)==0){
      Fl::set_font(destination, (Fl_Font)i);
      break;
    }
  }
}


void set_actual_font_from_prefs(){
  int n=Fl::set_fonts(NULL);
  search_for_font(__pref.get_sans_font().c_str(),FL_HELVETICA,n);
  search_for_font(__pref.get_sans_font().c_str(),FL_HELVETICA,n);
  search_for_font(__pref.get_sans_font_bold().c_str(),FL_HELVETICA_BOLD,n);
  search_for_font(__pref.get_sans_font_italic().c_str(),FL_HELVETICA_ITALIC,n);
  search_for_font(__pref.get_sans_font_bold_italic().c_str(),FL_HELVETICA_BOLD_ITALIC,n);
  search_for_font(__pref.get_mono_font().c_str(),FL_COURIER,n);
  search_for_font(__pref.get_mono_font_bold().c_str(),FL_COURIER_BOLD,n);
  search_for_font(__pref.get_mono_font_italic().c_str(),FL_COURIER_ITALIC,n);
  search_for_font(__pref.get_mono_font_bold_italic().c_str(),FL_COURIER_BOLD_ITALIC,n);
  search_for_font(__pref.get_serif_font().c_str(),FL_TIMES,n);
  search_for_font(__pref.get_serif_font_bold().c_str(),FL_TIMES_BOLD,n);
  search_for_font(__pref.get_serif_font_italic().c_str(),FL_TIMES_ITALIC,n);
  search_for_font(__pref.get_serif_font_bold_italic().c_str(),FL_TIMES_BOLD_ITALIC,n);
  search_for_font(__pref.get_symbol_font().c_str(),FL_SYMBOL,n);
  search_for_font(__pref.get_mono_font().c_str(),FL_SCREEN,n);
  search_for_font(__pref.get_mono_font_bold().c_str(),FL_SCREEN_BOLD,n);
  search_for_font(__pref.get_dingbats_font().c_str(),FL_ZAPF_DINGBATS,n);

}


bond_type shift_bond_type(bond_type curr){

  int curr_int=static_cast<int>(curr);
  int res=LEGAME_SINGOLO;

  if(curr_int==LEGAME_INTERNO ||
     curr_int==LEGAME_ESTERNO){
    res=-curr_int;
  }else{
    if(curr_int<0){
      curr_int=abs(curr_int);
    }

    res = ( curr_int+1 ) % (LAST_BOND+1);
  }

  return static_cast<bond_type>(res);

}





bool guess_is_mdl_file(std::string f){
  static const std::string signature="M  END";
  bool res=false;
  ifstream inf(f.c_str(),ios::in);

  if(inf){
    while(!inf.eof()){
      string line;
      getline(inf,line,'\n');
      if(line.size()>=signature.size()){
        std::string substr=line.substr(0,signature.size());
        if(substr==signature){
          res=true;
        }
      }
    }
  }

  inf.close();
  return res;

}

bool guess_is_cml_file(std::string f){
  static const std::string signature="<?xml";
  bool res=false;
  ifstream inf(f.c_str(),ios::in);

  if(inf){
    string line;
    getline(inf,line,'\n');
    if(line.size()>=signature.size()){
      std::string substr=line.substr(0,signature.size());
      if(substr==signature){
        res=true;
      }
    }
  }

  inf.close();
  return res;

}

bool is_ELF_shared_object(std::string file){
  std::string sub=file.substr(file.size()-2,2);
  if(sub=="so"){
    return true;
  }else{
    return false;
  }

}

proc_bezier* add_bezier_along_circle(gruppo* grp, float center_x, float center_y, float radius , float t1, float t2){
  //from http://www.tinaja.com/glib/bezcirc2.pdf

  std::pair<float, float> v1(0,0);
  std::pair<float, float> v2(0,0);
  std::pair<float, float> v1_tg(0,0);
  std::pair<float, float> v2_tg(0,0);

  float theta=t2-t1;
  v1.first = cos(theta/2.0);
  v1.second = sin(theta/2.0);

  v2.first  = v1.first;
  v2.second = -v1.second;

  v1_tg.first = (4.0-v1.first)/3.0;
  v1_tg.second = ( ((1.0-v1.first)*(3.0-v1.first))/(3.0*v1.second) );

  v2_tg.first  = v1_tg.first;
  v2_tg.second = - v1_tg.second; 

  float bezAng = -(t1 + theta/2.0);

  v1=bidimensional_vector::rotate(v1,bezAng);
  v2=bidimensional_vector::rotate(v2,bezAng);
  v1_tg=bidimensional_vector::rotate(v1_tg,bezAng);
  v2_tg=bidimensional_vector::rotate(v2_tg,bezAng);

  v1=bidimensional_vector::scale(v1,radius);
  v2=bidimensional_vector::scale(v2,radius);
  v1_tg=bidimensional_vector::scale(v1_tg,radius);
  v2_tg=bidimensional_vector::scale(v2_tg,radius);


  v1=bidimensional_vector::translate(v1,center_x,center_y);
  v2=bidimensional_vector::translate(v2,center_x,center_y);
  v1_tg=bidimensional_vector::translate(v1_tg,center_x,center_y);
  v2_tg=bidimensional_vector::translate(v2_tg,center_x,center_y);

  proc_bezier* bz=new proc_bezier();
  bz->ix(v1.first);
  bz->iy(v1.second);
  bz->ex(v2.first);
  bz->ey(v2.second);
  bz->tan1x(v1_tg.first);
  bz->tan1y(v1_tg.second);
  bz->dash(0);
  bz->tan2x(v2_tg.first);
  bz->tan2y(v2_tg.second);
  bz->spessore(1);

  int nwid=grp->aggiungi_procedura(bz);
  return dynamic_cast<proc_bezier*>(grp->find_proc_id(nwid));

}

void s_regmatch(std::string regex,std::string st,
                std::vector<std::string>& vec_res,
                bool case_ins){
  regex_t rex;
  if(case_ins){
    regcomp(&rex,regex.c_str(),REG_ICASE);
  }else{
    regcomp(&rex,regex.c_str(),REG_ICASE);
  }

  regmatch_t res_match;

  int res=regexec (&rex, st.c_str(), 
                   1, &res_match, 0);

  if(res==0){
    std::string match=st.substr(res_match.rm_so,res_match.rm_eo-res_match.rm_so);
    vec_res.push_back(match);
    regfree (&rex);
    if(res_match.rm_eo< static_cast<int>(st.size())){
      s_regmatch(regex,st.substr(res_match.rm_eo),vec_res,case_ins);
    }
  }else{
    char err[255];
    regerror (res, &rex, err, 255);
    regfree (&rex);
  }

}

std::string s_replace(std::string regex, std::string where,
		      std::string what,
		      bool case_ins){
  regex_t rex;
  if(case_ins){
    regcomp(&rex,regex.c_str(),REG_ICASE);
  }else{
    regcomp(&rex,regex.c_str(),REG_ICASE);
  }

  regmatch_t res_match;

  int res=regexec (&rex, where.c_str(), 
                   1, &res_match, 0);

  std::string result;
  if(res==0){
    std::string match=where.substr(res_match.rm_so,res_match.rm_eo-res_match.rm_so);
    std::string lft=where.substr(0,res_match.rm_so);
    std::string rght=where.substr(res_match.rm_eo);
    result= lft + what + rght;
    regfree (&rex);
  }else{
    char err[255];
    regerror (res, &rex, err, 255);
    regfree (&rex);
  }
  return result;
}


void dialog_position(Fl_Window* win, int offset){

  int x;
  int y;
  int w;
  int h;
  int mx=Fl::event_x_root();
  int my=Fl::event_y_root();
  Fl::screen_xywh(x, y, w, h);

  if(mx + offset + win->w() > w){
    mx = mx -win->w()-offset;  
  }else{
    mx = mx + offset;  
  }

  if(my + offset + win->h() > h){
    my = my - win->h() -offset;  
  }else{
    my = my + offset;  
  }
  
  win->position(mx,my);

}
