/*

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

#include <cstdio>

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



#include <FL/fl_draw.H>
#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 <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 <prefs.hpp>
#include <util.hpp>

extern finestra_pr* MainWindow;



extern Preferences  __pref;

/******************etichetta****************/

etichetta::etichetta()
  : _cr(0),
    _cg(0),
    _cb(0),
    _allineamento(0),
    _font(FONT_STD),
    _dim(FONT_STD_DIM),
    _x(0),
    _y(0),
    _v_offset(0),
    _draw_cursor(false),
    _draw_negative(false),
    _can_highlight(false)

{
  _cursor_pos.first=0;
  _cursor_pos.second=0;

}



etichetta::etichetta(const etichetta& altro)
  : _cr(altro._cr),
    _cg(altro._cg),
    _cb(altro._cb),
    _allineamento(altro._allineamento),
    _vec_str(altro._vec_str),
    _font(altro._font),
    _dim(altro._dim),
    _x(altro._x),
    _y(altro._y),
    _v_offset(altro._v_offset),
    _cursor_pos(altro._cursor_pos),
    _draw_cursor(altro._draw_cursor),
    _draw_negative(altro._draw_negative),
    _can_highlight(altro._can_highlight)
    
{
  genitore::_il_genitore=altro._il_genitore;
}



etichetta::etichetta(const etichetta* altro)
  : _cr(altro->_cr),
    _cg(altro->_cg),
    _cb(altro->_cb),
    _allineamento(altro->_allineamento),
    _vec_str(altro->_vec_str),
    _font(altro->_font),
    _dim(altro->_dim),
    _x(altro->_x),
    _y(altro->_y),
    _v_offset(altro->_v_offset),
    _cursor_pos(altro->_cursor_pos),
    _draw_cursor(altro->_draw_cursor),
    _draw_negative(altro->_draw_negative),
    _can_highlight(altro->_can_highlight)
    
{
  genitore::_il_genitore=altro->_il_genitore;
}



etichetta& etichetta::operator =(const etichetta& altro){
   _cr=altro._cr;
   _cg=altro._cg;
   _cb=altro._cb;
   _allineamento=altro._allineamento;
   _vec_str=altro._vec_str;
   _font=altro._font;
   _dim=altro._dim;
   _x=altro._x;
   _y=altro._y;
   _v_offset=altro._v_offset;

   _cursor_pos=altro._cursor_pos;
   _draw_cursor=altro._draw_cursor;
   _draw_negative=altro._draw_negative;
   _can_highlight=altro._can_highlight;

   genitore::_il_genitore=altro._il_genitore;

   return *this;
}


etichetta::~etichetta(){
  //TODO
}


bool etichetta::dentro_bb(float x_bb, float y_bb, float w_bb , float h_bb){
  if(x() > x_bb && x()+w()<x_bb+w_bb &&
     y() > y_bb && y()+h()<y_bb+h_bb ){
    return true;
  }else{
    return false;
  }
}
 
int etichetta::sotto_mouse(int posx_m, int posy_m){

  float ics_e=x();
  float ips_e=y();
  float w_e=w();
  float h_e=h();


  if(posx_m > ics_e && posx_m < ics_e+w_e &&
     posy_m > ips_e && posy_m < ips_e+h_e){
    return 0;
  }else{
    return -1;
  }


}



string etichetta::costruct_plot_string(){
  string risul;

  for(unsigned int i2=0;i2<_vec_str.size();i2++){
    switch(_vec_str[i2].second){
    case ET_STR:
      risul+=_vec_str[i2].first;
      break;
    case ET_APICE:
      if(i2+1<_vec_str.size()){
	switch(_vec_str[i2+1].second){
	case ET_PEDICE:
	  risul+="\\mk\\sp"+_vec_str[i2].first+"\\ep\\rt";
	  break;
	default:
	  risul+="\\sp"+_vec_str[i2].first+"\\ep";
	  break;
	}
      }else{
	risul+="\\sp"+_vec_str[i2].first+"\\ep";
      }
      break;
    case ET_PEDICE:
      if(i2+1<_vec_str.size()){
	switch(_vec_str[i2+1].second){
	case ET_APICE:
	  risul+="\\mk\\sb"+_vec_str[i2].first+"\\eb\\rt";
	  break;
	default:
	  risul+="\\sb"+_vec_str[i2].first+"\\eb";
	  break;
	}
      }else{
	risul+="\\sb"+_vec_str[i2].first+"\\eb";
      }
      break;
    }
    
  }

  return risul;

}


string etichetta::to_raw_string(){
  string result("");
  for(unsigned int i2=0;i2<_vec_str.size();i2++){
    try{
      result+=_vec_str[i2].first;
    }catch(length_error e){
      cout << "error in etichetta::to_raw_string(): " << "i: " << i2 <<endl; 
      cout << e.what() << endl;
      abort();
    }
  }  
  return result;
}



void etichetta::phys_misura(float& altris,float& larris ){

  

  if(cairo_t_singleton::can_export()){
    measure_as_pango_layout(_vec_str,larris,altris);
  }else{

    
    string font_ps;
    int tipo_font;
    
    
    int h_f=0;
    int w_f=0;
    
    get_font_handle((*this), tipo_font, font_ps);
    
    fl_font(tipo_font,phys_dim());
    fl_font(tipo_font,phys_dim());
    
    int font_dim_std=phys_dim();
    int std_desc=fl_descent();
    int xatt=0;
    float scale_font=SCALE_APICI;
    
    
    for(unsigned int i2=0;i2<_vec_str.size();i2++){
      
      h_f=0;
      w_f=0;

      switch(_vec_str[i2].second){
        
      case ET_STR:
        fl_font(tipo_font,font_dim_std);
        fl_measure(_vec_str[i2].first.c_str(), w_f, h_f);
	altris=h_f;

        xatt+=static_cast<int>(rintf(fl_width(_vec_str[i2].first.c_str())));
        break;
      case ET_APICE:
        {
          fl_font(tipo_font,font_dim_std/scale_font);
          fl_measure(_vec_str[i2].first.c_str(), w_f, h_f);
          if(i2>0){
            if(_vec_str[i2-1].second==ET_PEDICE){
              
              float max_l=max( fl_width(_vec_str[i2].first.c_str()),
                               fl_width(_vec_str[i2-1].first.c_str()));
              xatt-=fl_width(_vec_str[i2-1].first.c_str());
              
              xatt+=static_cast<int>(rintf(max_l));
            }else{
              xatt+=static_cast<int>(rintf(fl_width(_vec_str[i2].first.c_str())));
            }
          }else{
            xatt+=static_cast<int>(rintf(fl_width(_vec_str[i2].first.c_str())));
          }
        }
        break;
      case ET_PEDICE:
        {
          fl_font(tipo_font,font_dim_std/scale_font);
          
          fl_measure(_vec_str[i2].first.c_str(), w_f, h_f);
          if(i2>0){
            if(_vec_str[i2-1].second==ET_APICE){
              float max_l=max( fl_width(_vec_str[i2].first.c_str()) , 
                               fl_width(_vec_str[i2-1].first.c_str()));
              xatt-=fl_width(_vec_str[i2-1].first.c_str());
              xatt+=static_cast<int>(rintf(max_l));
            }else{
              xatt+=static_cast<int>(rintf(fl_width(_vec_str[i2].first.c_str())));
            }
          }else{
            xatt+=static_cast<int>(rintf(fl_width(_vec_str[i2].first.c_str())));
          }
        }
        break;
      }
    }
    
    altris-=std_desc;
    larris=xatt;
  }
}






void etichetta::misura(float& altris,float& larris ){

  //fltk says:
  //void fl_draw(const char *, int x, int y, int w, int h);
  //The string is formatted and aligned *inside* the passed box
  
  if(cairo_t_singleton::can_export()){
    phys_misura(altris,larris);
  }else{
    string font_ps;
    int tipo_font;
    int h_f=0;
    int w_f=0;


    get_font_handle((*this), tipo_font, font_ps);
    fl_font(tipo_font,dim()-3);
    fl_font(tipo_font,dim());

    int font_dim_std=dim();
    int std_desc=fl_descent();
    int xatt=0;
    float scale_font=SCALE_APICI;
 
    for(unsigned int i2=0;i2<_vec_str.size();i2++){

      h_f=0;
      w_f=0;



      switch(_vec_str[i2].second){
      
      case ET_STR:
        fl_font(tipo_font,font_dim_std);
        fl_measure(_vec_str[i2].first.c_str(), w_f, h_f);
	altris=h_f;
        xatt+=static_cast<int>(rintf(fl_width(_vec_str[i2].first.c_str())));
        break;
      case ET_APICE:
        {
          fl_font(tipo_font,font_dim_std/scale_font);
          fl_measure(_vec_str[i2].first.c_str(), w_f, h_f);
          if(i2>0){
            if(_vec_str[i2-1].second==ET_PEDICE){
            
              float max_l=max( fl_width(_vec_str[i2].first.c_str()),
                               fl_width(_vec_str[i2-1].first.c_str()));
              xatt-=fl_width(_vec_str[i2-1].first.c_str());
            
              xatt+=static_cast<int>(rintf(max_l));
            }else{
              xatt+=static_cast<int>(rintf(fl_width(_vec_str[i2].first.c_str())));
            }
          }else{
            xatt+=static_cast<int>(rintf(fl_width(_vec_str[i2].first.c_str())));
          }
        }
        break;
      case ET_PEDICE:
        {
          fl_font(tipo_font,font_dim_std/scale_font);
        
          fl_measure(_vec_str[i2].first.c_str(), w_f, h_f);
          if(i2>0){
            if(_vec_str[i2-1].second==ET_APICE){
              float max_l=max( fl_width(_vec_str[i2].first.c_str()) , 
                               fl_width(_vec_str[i2-1].first.c_str()));
              xatt-=fl_width(_vec_str[i2-1].first.c_str());
              xatt+=static_cast<int>(rintf(max_l));
            }else{
              xatt+=static_cast<int>(rintf(fl_width(_vec_str[i2].first.c_str())));
            }
          }else{
            xatt+=static_cast<int>(rintf(fl_width(_vec_str[i2].first.c_str())));
          }
        }
        break;
      }
    }

    altris-=std_desc;
    larris=xatt;
  }

}


void etichetta::visual_misura(float& altris,float& larris ){
  int old_dim=phys_dim();
  int new_dim=visual_dim();
  dim(new_dim);
  phys_misura(altris,larris);
  dim(old_dim);
}

float etichetta::w(){
  float alt;
  float lar;
  misura(alt,lar);
  return lar;
}


float etichetta::visual_w(){
  float alt;
  float lar;
  visual_misura(alt,lar);
  return lar;
}


float etichetta::phys_w(){
  float alt;
  float lar;
  phys_misura(alt,lar);
  return lar;
}



float etichetta::h(){
  float alt;
  float lar;
  misura(alt,lar);
  return alt;
}

float etichetta::visual_h(){
  float alt;
  float lar;
  visual_misura(alt,lar);
  return alt;
}

float etichetta::phys_h(){
  float alt;
  float lar;
  phys_misura(alt,lar);
  return alt;
}

void etichetta::cr(int nw){
  _cr=nw;
}
void etichetta::cb(int nw){
  _cb=nw;
}
void etichetta::cg(int nw){
  _cg=nw;
}

void etichetta::allineamento(int nw){
  _allineamento=nw;
}

void etichetta::v_offset(int nw){
  _v_offset=nw;
}

int etichetta::cr(){
  return _cr;
}
int etichetta::cg(){
  return _cg;
}
int etichetta::cb(){
  return _cb;
}

int etichetta::allineamento(){
  return _allineamento;
}

int etichetta::v_offset(){
  return _v_offset;
}

int etichetta::font(){
  return _font;
}

int etichetta::dim(){
  
  if(cairo_t_singleton::can_export()){
    return phys_dim();
  }else{
    return visual_dim();
  }
}

int etichetta::visual_dim(){
  int zoomed_dim=static_cast<int>(rintf(phys_dim()*__pref.getZoom()));
  if(zoomed_dim<5){
    zoomed_dim=5;
  }
  return zoomed_dim;
}

int etichetta::phys_dim(){
  return _dim;

}

float etichetta::x(){
  
  if(cairo_t_singleton::can_export()){
    return phys_x();
  }else{
    return visual_x();
  }
}


float etichetta::visual_x(){
  return phys_x() * __pref.getZoom();

}

float etichetta::phys_x(){
  return _x;
}


float etichetta::y(){
  if(cairo_t_singleton::can_export()){
    return phys_y();
  }else{
    return visual_y();
  }
}


float etichetta::visual_y(){
  return phys_y() * __pref.getZoom();
}

float etichetta::phys_y(){
  return _y;
}


vector < pair<string,int> > etichetta::vec_str(){
  return _vec_str;

}

/**
 *Ritorna la lunghezza del vettore contenente le stringhe
 */

int etichetta::size_str(){
  return _vec_str.size();
}

 /**
   *Aggiunge un elemento al vettore
   *
   *\param nw la nuova etichetta
   *\param tipo il tipo si stringa: puo' assumere i valori:
   *
   *<ul>
   *<li>ET_STR
   *<li>ET_APICE
   *<li>ET_PEDICE
   *</ul>
   */

void etichetta::aggiungi(string nw, int tipo){
  pair <string,int> tmp_p(nw,tipo);
  _vec_str.push_back(tmp_p);
}


void etichetta::melt_similar(int start){
  if(_vec_str.size()>1){
    if(static_cast<unsigned int>(start)<_vec_str.size()-1){
      if(_vec_str[start].second==_vec_str[start+1].second){
        std::string l=_vec_str[start].first;
        std::string r=_vec_str[start+1].first;
        string lpr=l+r;

        _vec_str[start].first=lpr;
        std::vector < std::pair<std::string,int> >::iterator it=_vec_str.begin()+start+1;
        _vec_str.erase(it);
        melt_similar(start);
      }
    }else{
      melt_similar(start+1);
    }
  }
}


void etichetta::insert(string nw, int type, int pos, bool reset_cur){
  pair <string,int> tmp_p(nw,type);

  if(pos<0){
    pos=0;
  }

  vector < pair<string,int> >::iterator beg=_vec_str.begin() + pos;
  
  if(beg< _vec_str.end()){
    _vec_str.insert(beg,tmp_p);
  }else{
    aggiungi(nw,type);
  }

  if(reset_cur){
    reset_cursor_if_outside_limits();
  }
}


void etichetta::reset_cursor_if_outside_limits(bool second_pos_not_end){

  if(vec_str().size()==0){
    _cursor_pos.first=0;
    _cursor_pos.second=0;

  }else{

    if(static_cast<unsigned int>(_cursor_pos.first)>=vec_str().size()){
      _cursor_pos.first=vec_str().size()-1;
    }else if(_cursor_pos.first < 0){ 
      _cursor_pos.first=0;              
      
    }

    std::vector < pair<std::string,int> > vec=vec_str();

    if(_cursor_pos.second >= (vec[_cursor_pos.first].first).size()){
      if(second_pos_not_end){
        _cursor_pos.second=0;
      }else{
        _cursor_pos.second=(vec[_cursor_pos.first].first).size();
      }
    }
  }
}


/**
 *Elimina la stringa in una certa posizione.
 *
 *\param where l'elemento da eliminare.
 */

void etichetta::elimina(int where, bool reset_cur) throw (out_of_range){
  if(static_cast<unsigned int>(where) < _vec_str.size()){
    vector < pair<string,int> >::iterator iniz=_vec_str.begin();
    iniz+=where;
    _vec_str.erase(iniz);

    if(reset_cur){
      reset_cursor_if_outside_limits();
    }
    
  }else{
    string exc="Errore where < _vec_str.size() nella classe etichetta. Funzione: "
      + string(__FUNCTION__);
    throw out_of_range(exc);
  }
}


/**
 *sostituisci la stringa in una certa posizione.
 *
 *\param cosa la nuova stringa
 *\param tipo il tipo si strinag (apice pedice o normale)
 *\param where l'elemento da eliminare.
 */

void etichetta::sostituisci(string cosa, int tipo, int where, bool reset_cur)
  throw (out_of_range){
  if(static_cast<unsigned int>(where) < _vec_str.size()){
    vector < pair<string,int> >::iterator iniz=_vec_str.begin();
    iniz+=where;
    (*iniz).first=cosa;
    (*iniz).second=tipo;

    if(reset_cur){
      reset_cursor_if_outside_limits();
    }

  }else{
    string exc="Errore where < _vec_str.size() nella classe etichetta. Funzione: "
      + string(__FUNCTION__);
    throw out_of_range(exc);
  }
}


/**
 *Elimina la prima stringa uguale a ricercata.
 *
 *\param ricercata l'elemento da eliminare.
 */

int etichetta::elimina(string ricercata, bool reset_cur){
  vector < pair<string,int> >::iterator iniz=_vec_str.begin();
  vector < pair<string,int> >::iterator fin=_vec_str.end();
  int risul=0;
  while(iniz!=fin){
    if((*iniz).first!=ricercata){
      iniz++;
    }else{
      risul++;
      _vec_str.erase(iniz);
      iniz=fin;
    }

  }

  if(reset_cur){
    reset_cursor_if_outside_limits();
  }
  return risul;
}


/**
 *Elimina tutti gli apici.
 */
void etichetta::elimina_apici(bool reset_cur){

// #define ET_STR   0
// #define ET_APICE 1
// #define ET_PEDICE 2


  vector < pair<string,int> >::iterator iniz=_vec_str.begin();
  vector < pair<string,int> >::iterator fin=_vec_str.end();

  while(iniz!=fin){
    if((*iniz).second==ET_APICE){
      _vec_str.erase(iniz);
    }
    iniz++;
  }

  if(reset_cur){
    reset_cursor_if_outside_limits();
  }

}


/**
 *Elimina tutti i pedici
 */
void etichetta::elimina_pedici(bool reset_cur){

  vector < pair<string,int> >::iterator iniz=_vec_str.begin();
  vector < pair<string,int> >::iterator fin=_vec_str.end();

  while(iniz!=fin){
    if((*iniz).second==ET_PEDICE){
      _vec_str.erase(iniz);
    }
    iniz++;
  }

  if(reset_cur){
    reset_cursor_if_outside_limits();
  }

}


/**
 *Elimina tutta l'etichetta
 */
void etichetta::elimina(bool reset_cur){
  _vec_str.erase(_vec_str.begin(),_vec_str.end());

  if(reset_cur){
    reset_cursor_if_outside_limits();
  }

}



void etichetta::subst_vec_str(std::vector < std::pair<std::string,int> > nw){
  elimina();
  _vec_str=nw;
}


void etichetta::font(int nw){
  _font=nw;
}

void etichetta::dim(int nw){
  _dim=nw;
}

void etichetta::x(float nw){
  _x=nw;
}

void etichetta::y(float nw){
  _y=nw;
}



void etichetta::disegna(){
  string font_ps;
  int tipo_font;

  get_font_handle((*this), tipo_font, font_ps);

  if(cairo_t_singleton::can_export()){
    draw_label_export();
  }else{
    draw_label_onscreen();

    int dx_scroll=(MainWindow->ritorna_mol_canvas())->x();
    int dy_scroll=(MainWindow->ritorna_mol_canvas())->y();

    if(_draw_cursor){
      int x=-1;
      int y=-1;
      if(cursor_to_coordinate(x,y)){
	draw_shadowed_point(x+dx_scroll,y+dy_scroll,255,0,0);
      }

    }

  }
}



void etichetta::measure_as_pango_layout(std::vector < std::pair<std::string,int> > vec,
                                        float &w, float &h, int until){
  std::vector<float> ws;
  float hmax=-1;

  unsigned int limit_measure_pos=vec.size()-1;
  if(until>=0 && static_cast<unsigned int>(until)<vec.size() ){
    limit_measure_pos=static_cast<unsigned int>(until);
  }

  for(unsigned int i=0;i<=limit_measure_pos;i++){
   
     switch(vec[i].second){
     case ET_STR:
       {
         float wlocal=0;
         float hlocal=0;
         float lbearing;
	 float ascent;
	 float descent;
         get_pango_logical_sizes(vec[i].first, vec[i].second,wlocal, hlocal,lbearing,ascent,descent);

         if(hlocal>=hmax){
           hmax=hlocal;
         }
         ws.push_back(wlocal);
       }
       break;
     case ET_APICE:
     case ET_PEDICE:
       {

         float w=0;
         float h_discard=0;
         float lbearing;
	 float ascent;
	 float descent;

         get_pango_logical_sizes(vec[i].first, vec[i].second,w, h_discard, lbearing,ascent,descent);
         float wlocal=check_pango_max_between_sub_sup(vec,i);


	 if(wlocal>0 && 
	    wlocal==w && 
	    wlocal!=ws.back()){
	   ws.push_back(wlocal);
	 }
         
       }
       break;
     }

  }

  w=accumulate(ws.begin(),ws.end(),0);
  h=hmax;
}


float etichetta::check_pango_max_between_sub_sup(std::vector < std::pair<std::string,int> > vec, 
                                                 unsigned int pos){
  float res=0;
  if(pos< vec.size()){
    std::vector<int> sizes;
    unsigned int limit_left=pos;
    if(pos>0){
      limit_left--;
    }

    unsigned int limit_right=pos;
    if(pos+1<vec.size()){
      limit_right++;
    }
    
    while(limit_left<=limit_right){
      if(vec[limit_left].second==ET_APICE ||
         vec[limit_left].second==ET_PEDICE ){
        float w_logical;
        float h_logical;
        float lbearing;
	float ascent;
	float descent;

        get_pango_logical_sizes(vec[limit_left].first,vec[limit_left].second,
                                w_logical,h_logical,lbearing,ascent,descent);
        sizes.push_back(w_logical);
      }
      limit_left++;
    }
    std::vector<int>::iterator max_val=std::max_element(sizes.begin(), sizes.end());
    res=*max_val;

  }
  return res;
}



float etichetta::get_fltk_baseline(){
  string font_ps;
  int tipo_font;
  get_font_handle((*this), tipo_font, font_ps);
    
  fl_font(tipo_font,dim());
  
  return fl_descent();
}




float etichetta::get_fltk_phys_baseline(){
  string font_ps;
  int tipo_font;
  get_font_handle((*this), tipo_font, font_ps);
    
  fl_font(tipo_font,phys_dim());
  
  return fl_descent();
}


float etichetta::get_pango_baseline(int type){
  int res=-1;
  float scale_font=SCALE_APICI;
  if(_vec_str.size()>0){
    cairo_t* cn=cairo_t_singleton::get_context();
    float font_dim_std=phys_dim();

    if(type==ET_APICE || type==ET_PEDICE){
      font_dim_std/=scale_font;
    }

    int font_fltk;
    std::string font_pango;
    get_font_handle((*this), font_fltk,font_pango);
    
    cairo_save(cn);
    
    PangoFontDescription* desc=pango_font_description_new();
    pango_font_description_set_family(desc, font_pango.c_str() );
    pango_font_description_set_absolute_size(desc,
                                             font_dim_std*PANGO_SCALE);
    PangoLayout *layout = pango_cairo_create_layout(cn);
    pango_layout_set_text(layout, (_vec_str[0].first).c_str(), -1);
    pango_layout_set_font_description(layout, desc);
    pango_cairo_update_layout(cn, layout);
    
    PangoLayoutIter* itr=pango_layout_get_iter(layout);
    double d_res=pango_units_to_double(pango_layout_iter_get_baseline(itr));
    

    //i do know why but fltk  seems to make ceiling for baseline (i.e.
    //fl_descent())  of fonts...so  i have  to make  the  same here...
    //this hack below  is inelegant and maybe i have  to check the new
    //api in fltk 1.3 for fl_text_extents
    res=static_cast<int>(ceil(d_res));

    cairo_stroke(cn);
    cairo_restore(cn);
    
    g_object_unref(layout);
    pango_font_description_free(desc);
    
  }
  return res;
    
}


float etichetta::get_pango_logical_y(){
  int res=-1;
  if(_vec_str.size()>0){
    res=get_pango_logical_y(_vec_str[0].first, _vec_str[0].second);
  }

  return res;
}

float etichetta::get_pango_logical_y(std::string st, int type){

  PangoRectangle rect;
  get_pango_logical_rectangle(st,type,&rect);
  return rect.y;

}


float etichetta::get_pango_ink_y(){
  int res=-1;
  if(_vec_str.size()>0){
    res=get_pango_logical_y(_vec_str[0].first, _vec_str[0].second);
  }

  return res;
}

float etichetta::get_pango_ink_y(std::string st, int type){

  PangoRectangle rect;
  get_pango_ink_rectangle(st,type,&rect);
  return rect.y;

}



void etichetta::get_pango_logical_rectangle(std::string st, int type, 
                                            PangoRectangle* rect){

  cairo_t* cn=cairo_t_singleton::get_context();
  float font_dim_std=phys_dim();
  float font_dim_sub=phys_dim()/SCALE_APICI;

  int font_fltk;
  std::string font_pango;
  get_font_handle((*this), font_fltk,font_pango);

  PangoFontDescription* desc=pango_font_description_new();

  pango_font_description_set_family(desc, font_pango.c_str() );

  switch(type){
  case ET_STR:
  pango_font_description_set_absolute_size(desc,
                                  font_dim_std*PANGO_SCALE);
  break;
  case ET_APICE:
  case ET_PEDICE:
    pango_font_description_set_absolute_size(desc,
                                  font_dim_sub*PANGO_SCALE);
    break;

  }

  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_layout_get_extents(layout,NULL,rect);
  
  pango_extents_to_pixels(rect,NULL);
  


}


void etichetta::get_pango_ink_rectangle(std::string st, int type, 
					PangoRectangle* rect){

  cairo_t* cn=cairo_t_singleton::get_context();
  float font_dim_std=phys_dim();
  float font_dim_sub=phys_dim()/SCALE_APICI;

  int font_fltk;
  std::string font_pango;
  get_font_handle((*this), font_fltk,font_pango);

  PangoFontDescription* desc=pango_font_description_new();

  pango_font_description_set_family(desc, font_pango.c_str() );

  switch(type){
  case ET_STR:
  pango_font_description_set_absolute_size(desc,
                                  font_dim_std*PANGO_SCALE);
  break;
  case ET_APICE:
  case ET_PEDICE:
    pango_font_description_set_absolute_size(desc,
                                  font_dim_sub*PANGO_SCALE);
    break;

  }

  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_layout_get_extents(layout,rect,NULL);
  pango_extents_to_pixels(rect,NULL);

}


void etichetta::get_pango_logical_sizes(std::string st, int type, 
                                        float& w_logical, float& h_logical, 
                                        float& lbearing, float& ascent, float& descent){
  cairo_t* cn=cairo_t_singleton::get_context();
  cairo_save(cn);
  float font_dim_std=phys_dim();
  float font_dim_sub=phys_dim()/SCALE_APICI;



  int font_fltk;
  std::string font_pango;
  get_font_handle((*this), font_fltk,font_pango);

  PangoFontDescription* desc=pango_font_description_new();

  pango_font_description_set_family(desc, font_pango.c_str());

  switch(type){
  case ET_STR:
    pango_font_description_set_absolute_size(desc,
					     font_dim_std*PANGO_SCALE);

    break;
  case ET_APICE:
  case ET_PEDICE:
    pango_font_description_set_absolute_size(desc,
					     font_dim_sub*PANGO_SCALE);

    break;
    
  }

  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);
  PangoRectangle logc_r;
  pango_layout_get_extents(layout,NULL,&logc_r);
  pango_extents_to_pixels(&logc_r,NULL);

  

  w_logical=PANGO_RBEARING(logc_r);
  h_logical=get_pango_baseline(type);
  descent=PANGO_DESCENT(logc_r);
  ascent=PANGO_ASCENT(logc_r);

  lbearing=PANGO_LBEARING(logc_r);



  //manage with ending withespaces
  

  PangoContext* p_cn=pango_layout_get_context(layout);
  PangoFont* p_fnt=pango_context_load_font(p_cn,desc);
  PangoLanguage* def_locale=pango_language_get_default();
  PangoFontMetrics* p_fnt_metrics=pango_font_get_metrics(p_fnt, def_locale);
  float  char_width=pango_font_metrics_get_approximate_char_width(p_fnt_metrics) / PANGO_SCALE;

  
  for(int i=st.size()-1; i>=0  && isblank(st[i]);i--){
    w_logical+=char_width;
  }
  
  g_object_unref(layout);
  pango_font_description_free(desc);

  cairo_restore(cn);

}


void etichetta::get_pango_ink_sizes(std::string st, int type, 
				    float& w_ink, float& h_ink, 
				    float& lbearing, float& ascent, float& descent){
  cairo_t* cn=cairo_t_singleton::get_context();
  cairo_save(cn);
  float font_dim_std=phys_dim();
  float font_dim_sub=phys_dim()/SCALE_APICI;

  int font_fltk;
  std::string font_pango;
  get_font_handle((*this), font_fltk,font_pango);

  PangoFontDescription* desc=pango_font_description_new();

  pango_font_description_set_family(desc, font_pango.c_str());

  switch(type){
  case ET_STR:
    pango_font_description_set_absolute_size(desc,
                                             font_dim_std*PANGO_SCALE);

    break;
  case ET_APICE:
  case ET_PEDICE:
    pango_font_description_set_absolute_size(desc,
                                             font_dim_sub*PANGO_SCALE);

    break;
    
  }

  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);
  PangoRectangle ink_r;
  
  pango_layout_get_extents(layout,&ink_r,NULL);
  pango_extents_to_pixels(&ink_r,NULL);

  w_ink=PANGO_RBEARING(ink_r);
  h_ink=get_pango_baseline(type);
  descent=PANGO_DESCENT(ink_r);
  ascent=PANGO_ASCENT(ink_r);

  lbearing=PANGO_LBEARING(ink_r);

  //manage with ending withespaces
  

  PangoContext* p_cn=pango_layout_get_context(layout);
  PangoFont* p_fnt=pango_context_load_font(p_cn,desc);
  PangoLanguage* def_locale=pango_language_get_default();
  PangoFontMetrics* p_fnt_metrics=pango_font_get_metrics(p_fnt, def_locale);
  float  char_width=pango_font_metrics_get_approximate_char_width(p_fnt_metrics) / PANGO_SCALE;

  
  for(int i=st.size()-1; i>=0  && isblank(st[i]);i--){
    w_ink+=char_width;
  }
  
  g_object_unref(layout);
  pango_font_description_free(desc);

  cairo_restore(cn);

}



void etichetta::draw_pango_sub_superscript(std::string st, int hparent,
                                           int x ,int y, int type){

  bool typeok=false;
  int nwy=y;
  float w_logical;
  float h_logical;
  float lbearing;
  float ascent;
  float descent;


  if(type==ET_APICE){
    typeok=true;
    get_pango_logical_sizes(st, type, w_logical,  h_logical, lbearing,ascent, descent);
    nwy-=hparent/2.0;
    nwy+=h_logical;
  }else if(type==ET_PEDICE){
    typeok=true;
    get_pango_logical_sizes(st, type, w_logical,  h_logical, lbearing,ascent, descent);
    nwy+=hparent;
    nwy+=- h_logical/2.0;
  }
 
  if(typeok){

    draw_pango_string(st, x, nwy, type);
  }

}


void etichetta::draw_pango_string(std::string st,int x, int y, int type){
  cairo_t* cn=cairo_t_singleton::get_context();
  int font_dim_std=phys_dim();
  float font_dim_sub=phys_dim()/SCALE_APICI;


  int font_fltk=0;
  std::string font_pango="";

  get_font_handle((*this), font_fltk,font_pango);
  /*
  PangoFontDescription* desc=pango_font_description_new();
  pango_font_description_set_family(desc,"courier 10 pitch bold");
  */
  
  PangoFontDescription* desc=pango_font_description_from_string(font_pango.c_str());


  switch(type){
  case ET_STR:
  pango_font_description_set_absolute_size(desc,
                                           font_dim_std*PANGO_SCALE);
  break;
  case ET_APICE:
  case ET_PEDICE:
    pango_font_description_set_absolute_size(desc,
                                             font_dim_sub*PANGO_SCALE);
    break;

  }

  cairo_move_to(cn, x, y);
  PangoLayout *layout = pango_cairo_create_layout(cn);
  pango_layout_set_width(layout,-1);
  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);

  
}

void etichetta::draw_label_export(){
  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()));
  
  int x_att=phys_x();
  int y_att=phys_y();

  for(unsigned int i=0;i<_vec_str.size();i++){
    if(_vec_str[i].second==ET_STR){
      draw_pango_string(_vec_str[i].first,x_att,y_att,_vec_str[i].second);
      float wlocal=0;
      float hlocal=0;
      measure_as_pango_layout(_vec_str,
                              wlocal,hlocal,i);

      cairo_set_source_rgb(cn,remap_color_1(cr()),
                           remap_color_1(cg()),
                           remap_color_1(cb()));
      

      int threshold=0;
      if( (i+1) < _vec_str.size()){
        draw_pango_sub_superscript(_vec_str[i+1].first, hlocal,
                                   phys_x()+wlocal,y_att,_vec_str[i+1].second);
        
        if(_vec_str[i+1].second==ET_APICE ||
           _vec_str[i+1].second==ET_PEDICE){
          threshold++;
        }
      }
      
      if( (i+2) < _vec_str.size()){
        draw_pango_sub_superscript(_vec_str[i+2].first, hlocal,
                                   phys_x()+wlocal,y_att, _vec_str[i+2].second);
        if(_vec_str[i+2].second==ET_APICE ||
           _vec_str[i+2].second==ET_PEDICE){
          threshold++;
        }
      }

      measure_as_pango_layout(_vec_str,
                              wlocal,hlocal,i+threshold);

      x_att=phys_x()+wlocal;
    }
  }
  
  cairo_stroke(cn);
  cairo_restore(cn);
}


void etichetta::draw_label_onscreen(){
  int tipo_font;
  string font_ps;
  get_font_handle((*this), tipo_font, font_ps);

  int font_dim_std=visual_dim();
    
  float xatt=visual_x();
  float scale_font=SCALE_APICI;

  int dx_scroll=(MainWindow->ritorna_mol_canvas())->x();
  int dy_scroll=(MainWindow->ritorna_mol_canvas())->y();
  float h_f_parent=0;  

  if(draw_negative()){
    fl_color(FL_BLACK);
    float h=0;
    float w=0;
    visual_misura(h,w);
    int x_bb=static_cast<int>(rintf(visual_x()))+dx_scroll;
    int y_bb=static_cast<int>(rintf(visual_y()))+dy_scroll;
    fl_rectf(x_bb,y_bb,w,h);
    fl_color(FL_WHITE);
  }else{
    fl_color(cr(),cg(),cb());
  }

  fl_font(tipo_font,visual_dim());
  
  
  for(unsigned int i2=0;i2<_vec_str.size();i2++){
    int w_f=0;
    int h_f=0;

    switch(_vec_str[i2].second){

    case ET_STR:
      fl_font(tipo_font,font_dim_std);
      fl_measure(_vec_str[i2].first.c_str(), w_f, h_f);
      fl_draw(_vec_str[i2].first.c_str(),
              xatt+dx_scroll,
              static_cast<int>(rintf(visual_y()+dy_scroll)),
              w_f,
              h_f, FL_ALIGN_CENTER);
      xatt+=fl_width(_vec_str[i2].first.c_str());
      h_f_parent=h_f;
      break;
    case ET_APICE:
      fl_font(tipo_font,font_dim_std/scale_font);
      fl_measure(_vec_str[i2].first.c_str(), w_f, h_f);
      fl_draw(_vec_str[i2].first.c_str(),
              xatt+dx_scroll,
              static_cast<int>(rintf(-h_f/2 + visual_y()+dy_scroll)),
              w_f,
              h_f, FL_ALIGN_CENTER);
      if((i2+1)<_vec_str.size()){
        if(_vec_str[i2+1].second==ET_STR){
          if(_vec_str[i2-1].second==ET_PEDICE){
            float max_l=max( fl_width(_vec_str[i2].first.c_str()) , 
                             fl_width(_vec_str[i2-1].first.c_str()));
            xatt+=rintf(max_l);
          }else{
            xatt+=fl_width(_vec_str[i2].first.c_str());
          }
        }
      }

      break;
    case ET_PEDICE:
      fl_font(tipo_font,font_dim_std/scale_font);

      fl_measure(_vec_str[i2].first.c_str(), w_f, h_f);
      
      fl_draw(_vec_str[i2].first.c_str(),
              xatt+dx_scroll,
              static_cast<int>(rintf(visual_y()+h_f_parent-h_f/2.0+dy_scroll)),
              w_f,
              h_f, FL_ALIGN_CENTER);
      

      if((i2+1)<_vec_str.size()){
        if(_vec_str[i2+1].second==ET_STR){
          if(_vec_str[i2-1].second==ET_APICE){
            float max_l=max( fl_width(_vec_str[i2].first.c_str()) , 
                             fl_width(_vec_str[i2-1].first.c_str()));
            xatt+=rintf(max_l);
          }else{
            xatt+=fl_width(_vec_str[i2].first.c_str());
          }
        }
	
      }
      break;
    }
  

  }
}






/**
 *Scala l'oggetto
 *
 *\param sc il fattore di scala
 */

void etichetta::scale(float sc){
  
  if(sc<1){
    if(phys_dim()>6){
      dim(phys_dim()-1);
    }
  }else{
    dim(phys_dim()+1);
  }

}

/**
 *Ruota l'oggetto in senso orario.
 *
 *\param angl l'angolo di rotazione in radianti in senso orario
 *\param xpivot ascissa relativa all'asse di rotazione
 *\param ypivot ordinata relativa all'asse di rotazione
 *
 */

void etichetta::ruota(float xpiv, float ypiv,float angl){
  not_impl();
}

/**
 *Trasla l'oggetto.
 *
 *\param dx entita' dello spostamento lungo l'ascissa
 *\param dy entita' dello spostamento lungo l'ordinata
 */

void etichetta::trasla(float dx, float dy){
   x(descale(x()+dx));
   y(descale(y()+dy));
  
}

void etichetta::phys_translate(float dx, float dy){
  x(phys_x()+dx);
  y(phys_y()+dy);
}


void etichetta::set_cursor_position( int pos_in_vec, string::size_type pos_in_string){
  _cursor_pos.first=pos_in_vec;
  _cursor_pos.second=pos_in_string;
}

  
void etichetta::set_cursor_position(std::pair<int,string::size_type> pos){
  set_cursor_position(pos.first,pos.second);
}


int etichetta::set_cursor_position(int limit){
  set_cursor_position(0,0);
  int type_res=0;
  for(int i=0;i<limit;i++){ //no  need  to care  about  lenght of  the
                            //label,   cursor_one_step_fwd()   prevent
                            //going outside its limits
    
    cursor_one_step_fwd(type_res);
    

  }

  return type_res;

}


void etichetta::go_to_end_of_label(){
  std::vector < std::pair<std::string,int> > the_vector_str=vec_str();
  if(the_vector_str.size()>0){
    _cursor_pos.second=(the_vector_str.back().first).size();
    int fst=the_vector_str.size()? the_vector_str.size()-1 : 0;
    _cursor_pos.first=fst;
  }else{
    _cursor_pos.second=0;
    _cursor_pos.first=0;
  }
}

void etichetta::go_to_end_of_line(){
  go_to_end_of_label();
}


void etichetta::go_to_start_of_label(){
  _cursor_pos.first=0;  
  _cursor_pos.second=0;
}

void etichetta::go_to_start_of_line(){
  go_to_start_of_label();
}

int etichetta::get_cursor_position(std::pair<int,string::size_type>* pos){

  ///DA CAMBIARE QUESTA FOLLIA!
  std::pair<int,string::size_type> saved_curr_pos=_cursor_pos;
  
  if(pos!=0){
    pos->first=saved_curr_pos.first;
    pos->second=saved_curr_pos.second;
  }

  int res=0;

  set_cursor_position(0,0);

  bool stop=false;
  while(!stop){

    if(_cursor_pos.first==saved_curr_pos.first){
      if(_cursor_pos.second==saved_curr_pos.second){
        stop=true;
      }
    }

    if(!stop){
      int dummy=0;
      cursor_one_step_fwd(dummy);
      res++;
    }

  }

  return res;

}

void etichetta::draw_cursor(bool draw){
  _draw_cursor=draw;
}



bool etichetta::draw_cursor(){
  return _draw_cursor;
}


bool etichetta::cursor_to_coordinate(int& x, int& y){
  bool res=true;
  int type_str=type_etic_at_cur_pos();
  etichetta copy_et=*this;
  if(_cursor_pos.first< copy_et.size_str()){

    for(int i=_cursor_pos.first+1;i<copy_et.size_str();){
      copy_et.elimina(i);
      i=_cursor_pos.first+1;
    }

    
    if(_cursor_pos.first>0){
      if(type_etic_at_cur_pos()==ET_APICE ||
         type_etic_at_cur_pos()==ET_PEDICE ){
        bool exist=false;
        if(check_if_type_etic_previous_chunk(ET_PEDICE,exist)||
           check_if_type_etic_previous_chunk(ET_APICE,exist) ){
          copy_et.elimina(_cursor_pos.first-1);
          copy_et.set_cursor_position(_cursor_pos.first-1,_cursor_pos.second);
          copy_et.reset_cursor_if_outside_limits();
        }
      }
    }


    std::vector < std::pair<std::string,int> > the_vector_str=copy_et.vec_str();

    if(_cursor_pos.second<=(the_vector_str.back().first).size()){
      if(_cursor_pos.second==(the_vector_str.back().first).size()){
        //draw here the cursor after the last char  of the label
	//TODO
      }else{
	std::string to_update=the_vector_str.back().first;
	to_update=to_update.substr(0,_cursor_pos.second);
        
        std::pair<int,string::size_type> c_pos(0,0);
        copy_et.get_cursor_position(&c_pos);
	copy_et.sostituisci(to_update,type_str,c_pos.first);
      }

      //misuriamo il risultato
      x=copy_et.x()+copy_et.w();
      y=copy_et.y();

      int tipo_font;
      string font_ps;
      int h_f=0;
      int w_f=0;
      vector < pair<string,int> > vec_str=copy_et.vec_str();

      get_font_handle((*this), tipo_font, font_ps);
      fl_font(tipo_font,dim()/SCALE_APICI);
      fl_measure(vec_str[0].first.c_str(), w_f, h_f);
      fl_font(tipo_font,dim());

      if(the_vector_str.back().second==ET_PEDICE){
	y+=copy_et.h()+h_f;
      }else if(the_vector_str.back().second==ET_APICE){
	y+=h_f/SCALE_APICI;
      }else if(the_vector_str.back().second==ET_STR){
        if(copy_et.h()>=0){
          y+=copy_et.h();
        }else{
          y+=dim();
        }
      }
    }else{
      res=false;
    }
  }else{
    res=false;
  }
  
  return res;

}


bool etichetta::cursor_one_step_fwd(int &curr_type){
  std::vector < std::pair<std::string,int> > the_vec_str=vec_str();
  bool res=true;
  if(_cursor_pos.second<the_vec_str[_cursor_pos.first].first.size()){
    _cursor_pos.second++;
  }else if((_cursor_pos.first+1)<size_str()) {
    _cursor_pos.first++;
    _cursor_pos.second=0;
  }else{
    res=false;
  }

  curr_type=the_vec_str[_cursor_pos.first].second;

  return res;
}


bool etichetta::cursor_one_step_back(int &curr_type){
  std::vector < std::pair<std::string,int> > the_vec_str=vec_str();
  bool res=true;
  if(_cursor_pos.second>0){
    _cursor_pos.second--;
  }else if(( (static_cast<int>(_cursor_pos.first)-1) >=0)){
    _cursor_pos.first--;
    _cursor_pos.second=the_vec_str[_cursor_pos.first].first.size();
   
  }else{
    res=false;
  }
  
  curr_type=the_vec_str[_cursor_pos.first].second;
  return res;
}




bool etichetta::check_if_type_etic(int typ) throw (out_of_range){
  bool res=false;
  if(size_str()>0){

    vector < pair<string,int> > strings=vec_str();
    pair<string,int> pt= strings.back();
    
    if(pt.second==typ){
      res= true;
    }else{
      res= false;
    }
    return res;
  }else{
    std::string exc="Errore where < _vec_str.size() nella classe etichetta. " 
      + std::string(__FUNCTION__);
    throw out_of_range(exc);
  }
}



bool etichetta::check_if_type_etic(int typ,int pos) throw (out_of_range){

  vector < pair<string,int> > stringhe=vec_str();

  if(static_cast<unsigned int>(pos) < vec_str().size() &&
     pos >=0){

    vector < pair<string,int> >::iterator it= stringhe.begin();
    pair<string,int> pt= *(it+pos);

    if(pt.second==typ){
      return true;
    }else{
      return false;
    }
  }else{
    string exc="Errore where < _vec_str.size() nella classe etichetta. Funzione: "
      + std::string(__FUNCTION__);
    throw out_of_range(exc);
  }
}


bool etichetta::check_if_type_etic_previous_chunk(int equal,bool &res_prev_exist){

  vector < pair<string,int> > stringhe=vec_str();
  bool res=false;


  try{
    if(check_if_type_etic(equal,_cursor_pos.first-1)){
      res=true;
      res_prev_exist=true;
    }else{
      res=false;
      res_prev_exist=true;
    }
    return res;
  }catch(out_of_range e){
    res_prev_exist=false;
    res=false;
    return res;
  }

}


bool etichetta::check_if_type_etic_next_chunk(int equal,bool &res_next_exist){
  vector < pair<string,int> > stringhe=vec_str();

  bool res=false;
  try{
    if(check_if_type_etic(equal,_cursor_pos.first+1)){
      res=true;
      res_next_exist=true;
    }else{
      res=false;
      res_next_exist=true;
    }
    return res;
  }catch(out_of_range e){
    res_next_exist=false;
    res=false;
    return res;
  }
}



int etichetta::type_etic_at_cur_pos(){
  int res=-1;
  try{
    if(check_if_type_etic(ET_STR,_cursor_pos.first)){
      res=ET_STR;
    }else if(check_if_type_etic(ET_APICE,_cursor_pos.first)){
      res=ET_APICE;
    }else if(check_if_type_etic(ET_PEDICE,_cursor_pos.first)){
      res=ET_PEDICE;
    }
  }catch (out_of_range e){
    return res;
  }

  return res;
}

void etichetta::manage_sub_super(int check, int troublesome,std::string car){
  //poniamo sia un apice
  try{
    if(check_if_type_etic(check,_cursor_pos.first)){ //ultimo e' apice aggiungere

      for(unsigned int i=0;i<car.size();i++){
        insert_char_in_curr_pos(car[i],check);
      }

    }else if(check_if_type_etic(ET_STR,_cursor_pos.first)){

      if(manage_add_sub_super_next_normal_str(check)){
        for(unsigned int i=0;i<car.size();i++){
          insert_char_in_curr_pos(car[i],check);
        }
      }
    }else if (check_if_type_etic(troublesome,_cursor_pos.first)){
      if(manage_add_sub_next_super(check)){
        for(unsigned int i=0;i<car.size();i++){
          insert_char_in_curr_pos(car[i],check);
        }
      }
    }
  }catch (out_of_range e){

#ifdef DEBUG
    std::cerr << __FUNCTION__ 
              << " error in line "
              << __LINE__ << std::endl
              << std::endl;
    
#endif


  }
}

void etichetta::insert_string_in_curr_pos(std::string add,int type){

  if(type==ET_APICE){
    manage_sub_super(ET_APICE, ET_PEDICE,add);
  }else if(type==ET_PEDICE){//dovremmo aggiungere un pedice
    manage_sub_super(ET_PEDICE,ET_APICE,add);
  }else{ // insert normal string
    try{
      break_string_at_cur_pos(ET_STR);
      for(unsigned int i=0;i<add.size();i++){
        insert_char_in_curr_pos(add[i],ET_STR);
      }
      
    }catch (out_of_range e){ // il  vettore  e' vuoto  possiamo
      // aggiungere e inizializzarlo
      for(unsigned int i=0;i<add.size();i++){
        insert_char_in_curr_pos(add[i],ET_STR);
      }
    }
  }
}

bool etichetta::manage_add_sub_next_super(int type){
  std::vector < std::pair<std::string,int> > the_vec_str=vec_str();
  std::string str=the_vec_str[_cursor_pos.first].first;
  bool res=true;
  bool next_or_prev_exist=false;

  if((type_etic_at_cur_pos() >0  && type_etic_at_cur_pos()!=type)){
    bool exist=false;
    if(check_if_type_etic_next_chunk(type,exist)){
      _cursor_pos.first++;
      std::cerr << "+" << std::endl;
      next_or_prev_exist=true;
    }else if(check_if_type_etic_previous_chunk(type,exist)){
      std::cerr << "-" << std::endl;
      _cursor_pos.first--;
      next_or_prev_exist=true;
    }

    if(next_or_prev_exist){
      std::string tmp_str=the_vec_str[_cursor_pos.first].first;
      if(_cursor_pos.second > tmp_str.size()){
        _cursor_pos.second = tmp_str.size();
      }
    }else{ //next or previous but it is an ET_STR
      insert("",type,_cursor_pos.first);
      _cursor_pos.second = 0;
    }

  }else if(type_etic_at_cur_pos() <0){
    res=false;
#ifdef DEBUG
    std::cerr << __FUNCTION__ 
              << " error in line "
              << __LINE__ << std::endl
              << "subscript or superscript (type: "
              << type << ") "
              << "without parent" 
              << std::endl;
    
#endif

  }

  return res;

}

bool etichetta::manage_add_sub_super_next_normal_str(int type){
  std::vector < std::pair<std::string,int> > the_vec_str=vec_str();
  std::string str=the_vec_str[_cursor_pos.first].first;
  bool res=true;
  if(str.size() == _cursor_pos.second){
    _cursor_pos.first++;
    _cursor_pos.second=0;

    if((type_etic_at_cur_pos() >0  && type_etic_at_cur_pos()!=type) || 
       (type_etic_at_cur_pos() <0)
       ){
      if(type_etic_at_cur_pos() >0){
        _cursor_pos.second=(the_vec_str[_cursor_pos.first].first).size();
        insert("",type,_cursor_pos.first,false); 
      }else{
        insert("",type,_cursor_pos.first,true); 
      }
    }
  }else if(_cursor_pos.second==0){
    _cursor_pos.first--;

    if(type_etic_at_cur_pos() >0  && type_etic_at_cur_pos()!=type){
      insert("",type,_cursor_pos.first,false); 

    }else if(type_etic_at_cur_pos() >0  && type_etic_at_cur_pos()==type){
      str=the_vec_str[_cursor_pos.first].first;      
      _cursor_pos.second=str.size();
    }else if(type_etic_at_cur_pos() <0){
      res=false;
      _cursor_pos.first++;
    }

  }else{
    break_normal_str(type);
  }

  return res;
}


void etichetta::insert_char_in_curr_pos(char add, int type){

  std::vector < std::pair<std::string,int> > the_vec_str=vec_str();
  if(the_vec_str.size()<=0){ //inizializza il vettore

    aggiungi(std::string(1,add),type);
    _cursor_pos.second=1;
    _cursor_pos.first=0;
  }else if(static_cast<unsigned int>(_cursor_pos.first)<the_vec_str.size()){ //posizione first valida

    if(_cursor_pos.second<=0){


      if( the_vec_str[_cursor_pos.first].first.size()>0){
	std::string to_update= the_vec_str[_cursor_pos.first].first;
	to_update.insert(_cursor_pos.second,std::string(1,add));
	sostituisci(to_update,type,_cursor_pos.first);
	_cursor_pos.second++;

      }else{// ma vuota
	sostituisci(std::string(1,add),type,_cursor_pos.first);
	_cursor_pos.second=1;
      }
    }else{ // non vuota inserisci
      std::string to_update= the_vec_str[_cursor_pos.first].first;

      if(_cursor_pos.second<to_update.size()){ //cursore non  alla   fine  della
					//stringa
	to_update.insert(_cursor_pos.second,std::string(1,add));
	sostituisci(to_update,type,_cursor_pos.first);
	_cursor_pos.second++;
      }else{
	to_update+=std::string(1,add);
	sostituisci(to_update,type,_cursor_pos.first);
	_cursor_pos.second=to_update.size();
      }
    }
  }
  
  
}


void etichetta::delete_char_curr_pos(bool before){

  if(size_str()>0){
    std::vector < std::pair<std::string,int> > the_vec_str=vec_str();
    try{
      check_if_type_etic(ET_STR,_cursor_pos.first);
      check_if_type_etic(ET_APICE,_cursor_pos.first);
      check_if_type_etic(ET_PEDICE,_cursor_pos.first);
      std::string to_update= the_vec_str[_cursor_pos.first].first;
      int type=the_vec_str[_cursor_pos.first].second;

      if(before){
        if(_cursor_pos.second<=to_update.size() && 
           _cursor_pos.second>0){

          to_update.erase(_cursor_pos.second-1,1);
          
          if(to_update!=""){
            sostituisci(to_update,type,_cursor_pos.first);
            if(_cursor_pos.second < to_update.size()){
              _cursor_pos.second--;
            }
          }else{
            clean_string_after_delete();
          }
      }else if(_cursor_pos.second==0 && 
               ( (static_cast<int>(_cursor_pos.first)-1) >=0)){

          if(the_vec_str[_cursor_pos.first].first.size()==0){
            elimina(_cursor_pos.first);
            _cursor_pos.second=the_vec_str[_cursor_pos.first].first.size();
          }else{
            int dummy=0;
            cursor_one_step_back(dummy);
          }
        }
      }else{
        if(_cursor_pos.second<to_update.size()){ //cursore non  alla   fine  della
                                                 //stringa
          to_update.erase(_cursor_pos.second,1);
          if(to_update!=""){
            sostituisci(to_update,type,_cursor_pos.first);
          }else{
            clean_string_after_delete();
          }
        }
      }
    }catch (out_of_range e){
      std::cerr << __FUNCTION__ << " Exception: can not delete char" << std::endl;
    }
  }
}


 void etichetta::break_string_at_cur_pos(int breaking_type){

  std::vector < std::pair<std::string,int> > the_vec_str=vec_str();
  int cur_type=type_etic_at_cur_pos();
  bool res_exist=false;
  if(cur_type==ET_APICE){
    if(check_if_type_etic_next_chunk(ET_PEDICE,res_exist) && res_exist){       
      break_sub_super(ET_APICE,breaking_type,true);
    }else if(check_if_type_etic_previous_chunk(ET_PEDICE,res_exist) && res_exist){
      break_sub_super(ET_APICE,breaking_type,false);
    }else{
      break_sub_or_super(ET_APICE,breaking_type);
    }
  }else if(cur_type==ET_PEDICE){
    if(check_if_type_etic_next_chunk(ET_APICE,res_exist)  && res_exist){       
      break_sub_super(ET_PEDICE,breaking_type,true);
    }else if(check_if_type_etic_previous_chunk(ET_APICE,res_exist) && res_exist){
      break_sub_super(ET_PEDICE,breaking_type,false);
    }else{
      break_sub_or_super(ET_PEDICE,breaking_type);
    }
  }else{
    break_normal_str(breaking_type);
  }


  
}



bool etichetta::break_and_split_normal_str(etichetta** left , etichetta** right){
  bool res=false;
  if((*left)!=0 && (*right)!=0){
    delete (*left);
    delete (*right);
  }
  
  (*left)=new etichetta();
  (*right)=new etichetta();


  etichetta copy_lab(this);

  (*(*left))=copy_lab;
  (*(*right))=copy_lab;
  (*left)->elimina();
  (*right)->elimina();

  copy_lab.break_normal_str(ET_APICE);
      
  std::vector < std::pair<std::string,int> > the_vec_str=copy_lab.vec_str();
  std::pair<int,string::size_type> c_pos(0,0);
  copy_lab.get_cursor_position(&c_pos);
  if(copy_lab.type_etic_at_cur_pos()==ET_APICE && 
     the_vec_str[c_pos.first].first==""){
    for(unsigned int i=0;i<the_vec_str.size();i++){
      if(i<static_cast<unsigned int>(c_pos.first)){
        (*left)->aggiungi(the_vec_str[i].first,the_vec_str[i].second);
      }else if(i>static_cast<unsigned int>(c_pos.first)){
        (*right)->aggiungi(the_vec_str[i].first,the_vec_str[i].second);
      }
    }
  }

  if((*left)->size_str() > 0 && (*right)->size_str() >0){
    res=true;
  }
  
  return res;
}


void etichetta::break_normal_str(int type_to_insert){
  std::vector < std::pair<std::string,int> > the_vec_str=vec_str();
  int cur_type=type_etic_at_cur_pos();
  
  if(cur_type==ET_STR){
    if(type_to_insert==ET_APICE || 
       type_to_insert==ET_PEDICE ){
      
      std::string rem=the_vec_str[_cursor_pos.first].first;
      std::string new_chunk=the_vec_str[_cursor_pos.first].first;
      rem.erase(_cursor_pos.second);
      new_chunk=new_chunk.substr(_cursor_pos.second);

      elimina(_cursor_pos.first,false);
      
      insert(rem, ET_STR, _cursor_pos.first,false);
      
      _cursor_pos.first++;
      _cursor_pos.second=0;
      insert("", type_to_insert, _cursor_pos.first,false);

      insert(new_chunk, ET_STR, _cursor_pos.first+1,false);
      
    }
  }
}


 void etichetta::break_sub_or_super(int me, int type_to_insert){
   std::vector < std::pair<std::string,int> > the_vec_str=vec_str();



   if((me==ET_APICE || me==ET_PEDICE) &&
      type_to_insert == ET_STR ){

     std::string rem_me(the_vec_str[_cursor_pos.first].first);
     std::string new_chunk_me(the_vec_str[_cursor_pos.first].first);

     rem_me.erase(_cursor_pos.second);
     new_chunk_me=new_chunk_me.substr(_cursor_pos.second);

     elimina(_cursor_pos.first,false);

     if(rem_me!=""){
       insert(rem_me,me,_cursor_pos.first,false);
       _cursor_pos.first++;
     }

     insert("", type_to_insert, _cursor_pos.first,false);

     if(new_chunk_me!=""){
       insert(new_chunk_me,me,_cursor_pos.first+1,false);
     }



   }
 }


 void etichetta::break_sub_super(int me, int type_to_insert,bool is_after){
   std::vector < std::pair<std::string,int> > the_vec_str=vec_str();

   if((me==ET_APICE || me==ET_PEDICE) &&
      type_to_insert == ET_STR ){
     int other=-1;


     if(me==ET_APICE){
       other=ET_PEDICE;
     }else{
       other=ET_APICE;
     }

     bool res_exist=false;
     bool next_ok=false;

     if(is_after){
       next_ok=check_if_type_etic_next_chunk(other,res_exist);
     }else{
       next_ok=check_if_type_etic_previous_chunk(other,res_exist);
     }
  
     if(next_ok){
       int delta_first_pos_cur=0;
       if(is_after){
         delta_first_pos_cur=1;
       }else{
         delta_first_pos_cur=-1;
       }

       std::string rem_me(the_vec_str[_cursor_pos.first].first);
       std::string rem_other(the_vec_str[_cursor_pos.first+delta_first_pos_cur].first);
    
       std::string new_chunk_me(the_vec_str[_cursor_pos.first].first);
       std::string new_chunk_other(the_vec_str[_cursor_pos.first+delta_first_pos_cur].first);
      
      
       /**
          v 2
          1  aaaa
          S
          pppp
          3 
       */

       rem_me.erase(_cursor_pos.second);
    
       if(_cursor_pos.second<rem_other.size()){
         rem_other.erase(_cursor_pos.second);
       }



       new_chunk_me=new_chunk_me.substr(_cursor_pos.second);
    
       if(_cursor_pos.second<new_chunk_other.size()){
         new_chunk_other=new_chunk_other.substr(_cursor_pos.second);
       }else{
         new_chunk_other="";
       }

    
       elimina(_cursor_pos.first,false);


       if(is_after){
         elimina(_cursor_pos.first,false);
       }else{
         _cursor_pos.first--;
         elimina(_cursor_pos.first,false);
       }

       if(rem_me!=""){
         insert(rem_me,me,_cursor_pos.first,false);
         _cursor_pos.first++;
       }

       if(rem_other!=""){
         insert(rem_other,other,_cursor_pos.first,false);
         _cursor_pos.first++;
       }
       
       int pos_cursor_break=_cursor_pos.first;
    
       insert("", type_to_insert, pos_cursor_break);
    
       if(new_chunk_me!=""){
         insert(new_chunk_me, me, pos_cursor_break+1);
       }

       if(new_chunk_other!=""){
         insert(new_chunk_other, other, pos_cursor_break+2);
       }
       
       _cursor_pos.first=pos_cursor_break;
       _cursor_pos.second=0;
     }
   }

 }


void etichetta::draw_negative(bool nw){
  _draw_negative=nw;
}


bool etichetta::draw_negative(){
  return _draw_negative;
}



bool etichetta::can_highlight(){
  return _can_highlight;
}

bool etichetta::can_highlight(bool nw){
  bool old=_can_highlight;
  _can_highlight=nw;
  return old;
}


 int etichetta::switch_APIC_PEDIC(int what){
   int res=ET_APICE;
   
   if(what==ET_APICE){
     res=ET_PEDICE;
   }
   return res;
 }



bool etichetta::merge_with_previous_if_equal(bool reset_cur) throw (out_of_range){
  std::vector < std::pair<std::string,int> > the_vec_str=vec_str();
  vector < pair<string,int> >::iterator iniz=_vec_str.begin();
  iniz+=_cursor_pos.first;
  bool res_merged=false;
  if(_cursor_pos.first < static_cast<int>(_vec_str.size())){

    bool pre_exist=false;
    
    if(check_if_type_etic_previous_chunk((*iniz).second,pre_exist) &&
       pre_exist ){
      std::string bef=(*(iniz-1)).first;
      std::string nw=bef+(*iniz).first;
      (*(iniz-1)).first=nw;
      set_cursor_position(_cursor_pos.first-1, bef.size());
      elimina(_cursor_pos.first+1);
      res_merged=true;;
    }

    if(reset_cur){
      reset_cursor_if_outside_limits();
    }
    return res_merged;
  }else{
    string exc="Errore where < _vec_str.size() in class etichetta. Function: "
      + string(__FUNCTION__);
    throw out_of_range(exc);
  }

}


void etichetta::merge_orphan_pedic_apic(int from, int type,bool& has_merged){
  std::vector < std::pair<std::string,int> > the_vec_str=vec_str();

  if(from >=0 && from < static_cast<int>(the_vec_str.size()-1)){
    if(check_if_type_etic(type,from)){
      std::string str_to_merge=the_vec_str[from].first;
      for(int i=from+1;i< static_cast<int>(the_vec_str.size());i++){
        if(check_if_type_etic(ET_STR,i)){
          merge_orphan_pedic_apic(i,type,has_merged);
          break;
        }else if(check_if_type_etic(type,i)){
          str_to_merge+=the_vec_str[i].first;
          elimina(i, false);
          the_vec_str=vec_str();
          i--;
        }
      }
      sostituisci(str_to_merge,type,from,true); 
      has_merged=true;

    }else{
      merge_orphan_pedic_apic(from+1,type,has_merged);
    }
  }
}

void etichetta::delete_orphan_pedic_apic(int from,int type){
  std::vector < std::pair<std::string,int> > the_vec_str=vec_str();
  if(from >=0 && from < static_cast<int>(the_vec_str.size())){
    for(int i=from;i< static_cast<int>(the_vec_str.size());i++){

      if(check_if_type_etic(type,i)){
        try{
          if(!check_if_type_etic(ET_STR,i-1) &&
             !check_if_type_etic(ET_STR,i-2) ){
            elimina(i, false);
            the_vec_str=vec_str();
            i--;
          }
        }catch (out_of_range e){
          elimina(i, false);
          the_vec_str=vec_str();
          i--;
        }
      }
    }
  }
}


 void etichetta::clean_string_after_delete(){
   std::vector < std::pair<std::string,int> > the_vec_str=vec_str();
   int old_type=type_etic_at_cur_pos();

   bool old_is_last =false;
   if(_cursor_pos.first == static_cast<int>(the_vec_str.size()-1)){
     old_is_last=true;
   }

   elimina(_cursor_pos.first,true);
   bool has_merged=false;
   merge_orphan_pedic_apic(0, ET_APICE, has_merged);
   has_merged=false;
   merge_orphan_pedic_apic(0, ET_PEDICE, has_merged);
   delete_orphan_pedic_apic(0,ET_APICE);
   delete_orphan_pedic_apic(0,ET_PEDICE);
   reset_cursor_if_outside_limits(true);
   
   the_vec_str=vec_str();

   if(old_type==ET_APICE || old_type==ET_PEDICE){

     if(_cursor_pos.first<static_cast<int>(the_vec_str.size()-1)){
       _cursor_pos.first--;
     }else if(check_if_type_etic(ET_STR,_cursor_pos.first)){
       if(!old_is_last){
         _cursor_pos.first--;
       }
     }

     reset_cursor_if_outside_limits(true);
     while(_cursor_pos.first >0 &&
           !check_if_type_etic(ET_STR,_cursor_pos.first)){
       _cursor_pos.first--;
     }
   }

   
   if(the_vec_str.size()>0){
     _cursor_pos.second=(the_vec_str[_cursor_pos.first].first).size();
   }
   
 }
