/*

    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 <FL/fl_draw.H>
#include <FL/Fl_Double_Window.H>
#include <FL/Fl_Scroll.H>


#include <interfacce.hpp>
#include <multiline_label.hpp>


#include <mol_canvas.hpp>
#include <finestra_pr.hpp>
*/


#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;


multiline_label::multiline_label()
  :etichetta(),
   _treat_as_a_whole(true),
   _pointer_to_currline(0),
   _interline_space(multiline_label::_default_interline_space),
   _layout_lines(MULTILINE_LABEL_ALIGN_LEFT_TEXT_LAYOUT)
{
  //std::cerr << "creo multiline " << __FUNCTION__ << std::endl;
  update_vec_str();
}



multiline_label::multiline_label(const multiline_label& other)
 :etichetta(other),
  _treat_as_a_whole(true),
  _pointer_to_currline(other._pointer_to_currline),
  _interline_space(other._interline_space),
  _layout_lines(other._layout_lines)
{
  //std::cerr << "ricopio multiline " << __FUNCTION__ << std::endl;
  for(unsigned int i=0;i< (other._lines_of_text.size()) ;i++){
    etichetta* tmp=new etichetta(other._lines_of_text[i]);
    _lines_of_text.push_back(tmp);
  }

  format_paragraph();

}

multiline_label::multiline_label(const multiline_label* other)
  :etichetta(other),
   _treat_as_a_whole(other->_treat_as_a_whole),
   _pointer_to_currline(other->_pointer_to_currline),
   _interline_space(other->_interline_space),
   _layout_lines(other->_layout_lines)
{

  //std::cerr << "ricopio multiline " << __FUNCTION__ << std::endl;
  for(unsigned int i=0;i< (other->_lines_of_text.size()) ;i++){
    etichetta* tmp=new etichetta(other->_lines_of_text[i]);
    _lines_of_text.push_back(tmp);
  }
  

  //update_vec_str();

  format_paragraph();

}


multiline_label& multiline_label::operator=(const multiline_label& other){
  // std::cerr << __FUNCTION__ << std::endl;
  _treat_as_a_whole=_treat_as_a_whole;
  _pointer_to_currline=other._pointer_to_currline;
  _interline_space=other._interline_space;
  _layout_lines=other._layout_lines;


  _cr=other._cr;
  _cg=other._cg;
  _cb=other._cb;
  _allineamento=other._allineamento;
  _vec_str=other._vec_str;
  _font=other._font;
  _dim=other._dim;
  _x=other._x;
  _y=other._y;
  _v_offset=other._v_offset;
  
  _cursor_pos=other._cursor_pos;
  _draw_cursor=other._draw_cursor;
  _draw_negative=other._draw_negative;
  genitore::_il_genitore=other._il_genitore;


  for(unsigned int i=0;i< (other._lines_of_text.size()) ;i++){
    etichetta* tmp=new etichetta(other._lines_of_text[i]);
    _lines_of_text.push_back(tmp);
  }

  //update_vec_str();

  format_paragraph();

  return (*this);
}

multiline_label::~multiline_label(){
  
  for(unsigned int i=0;i< _lines_of_text.size(); i++){
    //std::cerr << "eliminata " << _lines_of_text[i] << std::endl;
    delete _lines_of_text[i];
  }
}


void multiline_label::update_vec_str(){
  
  if(ptr_line_less_lines_text()){
    _vec_str=(_lines_of_text[_pointer_to_currline])->vec_str();
    
    _cr=(_lines_of_text[_pointer_to_currline])->cr();
    _cg=(_lines_of_text[_pointer_to_currline])->cg();
    _cb=(_lines_of_text[_pointer_to_currline])->cb();

    
    _font=(_lines_of_text[_pointer_to_currline])->font();
    _dim=(_lines_of_text[_pointer_to_currline])->phys_dim();

    _x=(_lines_of_text[_pointer_to_currline])->phys_x();
    _y=(_lines_of_text[_pointer_to_currline])->phys_y();


    std::pair<int,string::size_type> nw_curpos(0,0);
    _cursor_pos=nw_curpos;
    _draw_cursor=false;

  }
  
}



void multiline_label::update_lines_of_text(){
  
  if(ptr_line_less_lines_text()){
    (_lines_of_text[_pointer_to_currline])->subst_vec_str(_vec_str);
    (_lines_of_text[_pointer_to_currline])->cr(_cr);
    (_lines_of_text[_pointer_to_currline])->cr(_cg);
    (_lines_of_text[_pointer_to_currline])->cr(_cb);
    (_lines_of_text[_pointer_to_currline])->font(_font);
    (_lines_of_text[_pointer_to_currline])->dim(_dim);
    (_lines_of_text[_pointer_to_currline])->x(_x);
    (_lines_of_text[_pointer_to_currline])->y(_y);
  }

}



int multiline_label::cr(){
  int res=0;
  
  if(treat_as_a_whole()){
    res=_cr;
  }else{
    if(ptr_line_less_lines_text()){
      res=_lines_of_text[_pointer_to_currline]->cr();
    }
  }

  return res;
}

int multiline_label::cg(){
  int res=0;
  
  if(treat_as_a_whole()){
    res=_cg;
  }else{
    if(ptr_line_less_lines_text()){
      res=_lines_of_text[_pointer_to_currline]->cg();
    }
  }

  return res;
}

int multiline_label::cb(){
  int res=0;
  if(treat_as_a_whole()){
    res=_cb;
  }else{
    if(ptr_line_less_lines_text()){
      res=_lines_of_text[_pointer_to_currline]->cb();
    }
  }

  return res;
}

void multiline_label::cr(int nw){
  if(treat_as_a_whole()){
    _cr=nw;
    for(unsigned int i=0;i<_lines_of_text.size();i++){
      _lines_of_text[i]->cr(nw);
    }
  }else{
    if(ptr_line_less_lines_text()){
      _lines_of_text[_pointer_to_currline]->cr(nw);
    }
  }
}

void multiline_label::cg(int nw){
  if(treat_as_a_whole()){
    _cg=nw;
    for(unsigned int i=0;i<_lines_of_text.size();i++){
      _lines_of_text[i]->cg(nw);
    }
  }else{
    if(ptr_line_less_lines_text()){
      _lines_of_text[_pointer_to_currline]->cg(nw);
    }
  }
}

void multiline_label::cb(int nw){
  if(treat_as_a_whole()){
    _cb=nw;
    for(unsigned int i=0;i<_lines_of_text.size();i++){
      _lines_of_text[i]->cb(nw);
    }
  }else{
    if(ptr_line_less_lines_text()){
      _lines_of_text[_pointer_to_currline]->cb(nw);
    }
  }
}


int multiline_label::font(){
  int res=_font;

  if(!treat_as_a_whole()){
    if(ptr_line_less_lines_text()){
      res=_lines_of_text[_pointer_to_currline]->font();
    }
  }
  
  return res;
}



int multiline_label::dim(){
  int res=5;

  if(cairo_t_singleton::can_export()){
    res=phys_dim();
  }else{
    res=visual_dim();
  }

  return res;

}


int multiline_label::phys_dim(){
  int res=_dim;

  if(!treat_as_a_whole()){
    if(ptr_line_less_lines_text()){
      res=_lines_of_text[_pointer_to_currline]->phys_dim();
    }else{
      res=0;
    }
  }

  return res;

}

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

  return res;

}


void multiline_label::dim(int nw){
  if(treat_as_a_whole()){
    _dim=nw;
    for(unsigned int i=0;i<_lines_of_text.size();i++){
      _lines_of_text[i]->dim(nw);
    }
  }else{
    if(ptr_line_less_lines_text()){
      _lines_of_text[_pointer_to_currline]->dim(nw);
    }
  }  
  
}



float multiline_label::x(){
  float res=0;

  if( cairo_t_singleton::can_export()){
    res=phys_x();
  }else{
    res=visual_x();
  }

  return res;
}

float multiline_label::visual_x(){

  //int res=static_cast<int>(rintf(phys_x()*__pref.getZoom()));
  float res=phys_x()*__pref.getZoom();
  return res;

}

float multiline_label::phys_x(){ 

  float res=_x;

  if(!treat_as_a_whole()){
    if(ptr_line_less_lines_text()){
      res=_lines_of_text[_pointer_to_currline]->phys_x();
    }else{
      res=0;
    }
  }

  return res;

}



float multiline_label::y(){
  float res=0;

  if(cairo_t_singleton::can_export()){
    res=phys_y();
  }else{
    res=visual_y();
  }

  return res;
}

float multiline_label::visual_y(){

  //  int res=static_cast<int>(rintf(phys_y()*__pref.getZoom()));
  float res=phys_y()*__pref.getZoom();
  return res;

}

float multiline_label::phys_y(){ 

  float res=_y;

  if(!treat_as_a_whole()){
    if(ptr_line_less_lines_text()){
      res=_lines_of_text[_pointer_to_currline]->phys_y();
    }else{
      res=0;
    }
  }

  return res;

}



void multiline_label::font(int nw){

  if(treat_as_a_whole()){
    _font=nw;
    for(unsigned int i=0;i<_lines_of_text.size();i++){
      _lines_of_text[i]->font(nw);
    }
  }else{
    if(ptr_line_less_lines_text()){
      _lines_of_text[_pointer_to_currline]->font(nw);
    }
  }
  
}

void multiline_label::x(float nw){
  
  if(treat_as_a_whole()){
    _x=nw;
  }else{
    if(ptr_line_less_lines_text()){
      _lines_of_text[_pointer_to_currline]->x(nw);
    }
  }

}



void multiline_label::y(float nw){
  
  if(treat_as_a_whole()){
    _y=nw;
  }else{
    if(ptr_line_less_lines_text()){
      _lines_of_text[_pointer_to_currline]->y(nw);
    }
  }

}


void multiline_label::misura(float& altris,float& larris ){
  
  if(cairo_t_singleton::can_export()){
    phys_misura(altris,larris);
  }else{
    visual_misura(altris,larris);
  }

}


  
/**
 *Misura l'altezza e la larghezza di questa etichetta tenendo conto dello zoom
 *\param altris l'altezza dell'etichetta
 *\param larris la larghezza dell'etichetta
 */

void multiline_label::visual_misura(float& altris,float& larris ){

  if(treat_as_a_whole()){
    
    phys_misura_as_a_whole(altris,larris);
    
    altris*=__pref.getZoom();
    larris*=__pref.getZoom();
  }else{
    if(ptr_line_less_lines_text()){
      _lines_of_text[_pointer_to_currline]->visual_misura(altris,larris);
    }
  }

  
}



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

  if(treat_as_a_whole()){
    if(cairo_t_singleton::can_export()){
      multiline_label cp(*this);
      cp.merge_labels_amap();
      cp.format_paragraph();
      cp.phys_misura_as_a_whole(altris,larris);
    }else{
      phys_misura_as_a_whole(altris,larris);
    }
  }else{
    if(ptr_line_less_lines_text()){
      _lines_of_text[_pointer_to_currline]->phys_misura(altris,larris);
    }
  }

}


void multiline_label::phys_misura_as_a_whole(float& altris,float& larris ){

  if(static_cast<int>(size_lines_of_text())>0){
    format_paragraph();
    float ypos_max=-1;
    float ypos_min=10000000;
    
    for(unsigned int i=0;i<_lines_of_text.size();i++){
      if(_lines_of_text[i]->phys_y()  < ypos_min){
        ypos_min=_lines_of_text[i]->phys_y();
      }
      
      if(_lines_of_text[i]->phys_y() + _lines_of_text[i]->phys_h() > ypos_max){
        ypos_max=_lines_of_text[i]->phys_y() + _lines_of_text[i]->phys_h();
      }

    }


    float xpos_max=-1;
    float xpos_min=10000000;
    
    for(unsigned int i=0;i<_lines_of_text.size();i++){
      if(_lines_of_text[i]->phys_x() < xpos_min){
        xpos_min=_lines_of_text[i]->phys_x();
      }
      
      if(_lines_of_text[i]->phys_x() + _lines_of_text[i]->phys_w() > xpos_max){
        xpos_max=_lines_of_text[i]->phys_x()+ _lines_of_text[i]->phys_w(); 
      }
      
    }

    altris=ypos_max - ypos_min;
    larris=xpos_max - xpos_min;
    if(layout_lines()!=MULTILINE_LABEL_ALIGN_SINGLE_LINE_TEXT_LAYOUT){
      altris+= phys_interline_space();
    }
 
  }else{
    altris=0;
    larris=0;
  }  
  
}


float multiline_label::h(){

  float h=0;
  float w=0;

  if( cairo_t_singleton::can_export()){
    phys_misura(h,w);
  }else{
    visual_misura(h,w);
  }

  return h;
}

float multiline_label::visual_h(){

  float h=0;
  float w=0;

  if(treat_as_a_whole()){
    visual_misura(h,w);
  }else{
    if(ptr_line_less_lines_text()){
      _lines_of_text[_pointer_to_currline]->visual_misura(h,w);
    }
  }

  return h;

}

float multiline_label::phys_h(){
  float h=0;
  float w=0;

  if(treat_as_a_whole()){
    phys_misura(h,w);
  }else{
    if(ptr_line_less_lines_text()){
      _lines_of_text[_pointer_to_currline]->phys_misura(h,w);
    }
  }

  return h;
}



float multiline_label::w(){

  float h=0;
  float w=0;

  if( cairo_t_singleton::can_export()){
    phys_misura(h,w);
  }else{
    visual_misura(h,w);

  }


  return w;
}

float multiline_label::visual_w(){

  float h=0;
  float w=0;

  if(treat_as_a_whole()){
    visual_misura(h,w);

  }else{
    if(ptr_line_less_lines_text()){
      _lines_of_text[_pointer_to_currline]->visual_misura(h,w);
    }
  }

  return w;

}

float multiline_label::phys_w(){
  float h=0;
  float w=0;

  if(treat_as_a_whole()){
    phys_misura(h,w);
  }else{
    if(ptr_line_less_lines_text()){
      _lines_of_text[_pointer_to_currline]->phys_misura(h,w);
    }
  }

  return w;
}




float multiline_label::interline_space(){
  float res=0;
  if(cairo_t_singleton::can_export()){
    res=phys_interline_space();
  }else{
    res=visual_interline_space();
  }

  return res;
}

int multiline_label::interline_space(int nw){
  int old=_interline_space;
  _interline_space=nw;
  return old;
}

float multiline_label::phys_interline_space(){
  return _interline_space;

}

float multiline_label::visual_interline_space(){
  return _interline_space * __pref.getZoom();
  
}



std::vector< std::pair<std::string,int> > multiline_label::vec_str(){
  std::vector< std::pair<std::string,int> > res=etichetta::vec_str();
  if(ptr_line_less_lines_text()){
    res=_lines_of_text[_pointer_to_currline]->vec_str();
  }
  return res;
}





void multiline_label::aggiungi(std::string nw, int tipo){
  if(ptr_line_less_lines_text()){
    _lines_of_text[_pointer_to_currline]->aggiungi(nw,tipo);
  }
}


void multiline_label::add_line(etichetta new_line){
  etichetta* tmp=new etichetta(new_line);
  add_line(tmp);
}


void multiline_label::add_line(etichetta* new_line){
  _lines_of_text.push_back(new_line);
  _pointer_to_currline=_lines_of_text.size()-1;
}



void multiline_label::add_line(etichetta new_line,int pos){
  if(pos>=0  && static_cast<unsigned int>(pos) < _lines_of_text.size()){
    etichetta* tmp=new etichetta(new_line);
    add_line(tmp,pos);
  }
}


void multiline_label::add_line(etichetta* new_line, int pos){
  if(pos>=0  && static_cast<unsigned int>(pos) < _lines_of_text.size()){
    if(static_cast<unsigned int>(pos)==_lines_of_text.size()-1){
      add_line(new_line);
    }else{
      std::vector<etichetta*>::iterator beg=_lines_of_text.begin() + pos + 1;
      _lines_of_text.insert(beg,new_line);
      _pointer_to_currline=pos+1;
    }
  }
}



void multiline_label::insert(std::string nw, int type, int pos){
  if(ptr_line_less_lines_text()){
    _lines_of_text[_pointer_to_currline]->insert(nw,type,pos);
  }
}


void multiline_label::insert_line(etichetta new_line, int pos){
  std::vector <etichetta*>::iterator pos_iter=_lines_of_text.begin()+pos;
  if(pos>=0 && pos_iter<_lines_of_text.end()){
    etichetta* tmp=new etichetta(new_line);
    insert_line(tmp,pos);
  }
}

void multiline_label::insert_line(etichetta* new_line, int pos){
  std::vector <etichetta*>::iterator pos_iter=_lines_of_text.begin()+pos;
  if(pos >=0 && pos_iter<_lines_of_text.end()){
    _lines_of_text.insert(pos_iter,new_line);
  }
}


void multiline_label::delete_line(int pos, bool reset_pointer_currline){
  etichetta* to_delete=0;
  std::vector <etichetta*>::iterator pos_iter=_lines_of_text.begin()+pos;
  if(pos>=0 && static_cast<unsigned int>(pos) < _lines_of_text.size()){
    to_delete=*pos_iter;
    _lines_of_text.erase(pos_iter);
    if(reset_pointer_currline){
      reset_pointer_to_currline();
    }
  }

  delete to_delete;
}

void multiline_label::subst_line(etichetta* nw, int pos){
  delete_line(pos,false);
  if(static_cast<unsigned int>(pos)!=_lines_of_text.size()){
    insert_line(nw,pos);
  }else{
    _lines_of_text.push_back(nw);
  }
}


etichetta multiline_label::get_line_copy(int pos) throw (out_of_range){
  if(pos>=0 && pos < static_cast<int>(_lines_of_text.size())){
    etichetta rt(_lines_of_text[pos]);
    return rt;
  }else{
    string exc="Errore _pointer_to_currline out of bound: "
      + string(__FUNCTION__);
    throw out_of_range(exc);
  }
}

int multiline_label::elimina(std::string ricercata){
  int res=0;

  if(treat_as_a_whole()){
    for(unsigned int i=0;i<_lines_of_text.size();i++){
      int tmp_res=_lines_of_text[i]->elimina(ricercata);
      if(tmp_res == 1){
        res=tmp_res;
      }
    }
  }else{
    if(ptr_line_less_lines_text()){
      res=_lines_of_text[_pointer_to_currline]->elimina(ricercata);
    }
  }

  return res;
}


void multiline_label::elimina(){
  for(unsigned int i=0;i< _lines_of_text.size(); i++){
    delete _lines_of_text[i];
  }

  _lines_of_text.erase(_lines_of_text.begin(),_lines_of_text.end());
  //std::cerr << "multiline_label::elimina()" << std::endl;
}

float multiline_label::calculate_last_line_y(bool add_interline){
  
  return 0;
}

bool multiline_label::treat_as_a_whole(){
  return _treat_as_a_whole;
}

bool multiline_label::treat_as_a_whole(bool nw){
  bool old=treat_as_a_whole();
  _treat_as_a_whole=nw;
  return old;
}





void multiline_label::format_paragraph(){

  switch(layout_lines()){

  case MULTILINE_LABEL_ALIGN_LEFT_TEXT_LAYOUT:
    {
      format_lines_align_left();

    }
    break;
  case MULTILINE_LABEL_ALIGN_RIGHT_TEXT_LAYOUT:
    {
      format_lines_align_right();      
    }
    break;
  case MULTILINE_LABEL_ALIGN_CENTER_TEXT_LAYOUT:
    {
      format_lines_align_center();
    }
    break;

  case MULTILINE_LABEL_ALIGN_SINGLE_LINE_TEXT_LAYOUT:
    {

      for(unsigned int i=0;i<_lines_of_text.size();i++){
        _lines_of_text[i]->y(_y);
        
        int total_w=0;
        for(unsigned int j=0;j<i;j++){
          total_w+=_lines_of_text[j]->phys_w();
        }

        _lines_of_text[i]->x(_x+total_w);
      }  
    }
    break;

  default:
    format_lines_align_center();
    break;
  }
}


void multiline_label::draw_cursor(bool draw){
  if(treat_as_a_whole()){
    _draw_cursor=draw;
    for(unsigned int i=0;i<_lines_of_text.size();i++){
      _lines_of_text[i]->draw_cursor(draw);
    }
  }else if(pointer_to_currline()>=0 &&
           _lines_of_text.size()>0){
    
    _lines_of_text[pointer_to_currline()]->draw_cursor(draw);
  }
}


void multiline_label::disegna(){


  if(cairo_t_singleton::can_export()){
    multiline_label cp(*this);
    cp.merge_labels_amap();
    cp.format_paragraph();
    cp.draw_label_export();
  }else{
    format_paragraph();    
    bool old_t=treat_as_a_whole(true);
    if(_draw_cursor){
      draw_cursor(false);
      treat_as_a_whole(false);
      draw_cursor(true);
    }
    treat_as_a_whole(old_t);
     
    int max_desc=-1;
    int max_h=-1;
    for(unsigned int ct=0;ct<_lines_of_text.size();ct++){
      if(_lines_of_text[ct]->get_fltk_baseline() > max_desc){
        max_desc=_lines_of_text[ct]->get_fltk_baseline();
        max_h=_lines_of_text[ct]->h();
      }
    }

 
    for(unsigned int i=0;i<_lines_of_text.size();i++){
      if(_lines_of_text[i]->h() < max_h){
        //_lines_of_text[i]->trasla(0,
        //                          _lines_of_text[i]->get_fltk_baseline()-max_desc );
      }
      /*
      int dx_scroll=(MainWindow->ritorna_mol_canvas())->x();
      int dy_scroll=(MainWindow->ritorna_mol_canvas())->y();

      fl_rect(_lines_of_text[i]->x()+dx_scroll,
              _lines_of_text[i]->y()+dy_scroll,
              _lines_of_text[i]->w(), _lines_of_text[i]->h());
      */
      _lines_of_text[i]->disegna();
    }

    /*
    std::cerr << "x: " << x() <<  " y: " << y() << std::endl;
    std::cerr << "w: " << w <<  " h: " << h << std::endl;
    */
    

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


    old_t=treat_as_a_whole(true);
    
    //int h;
    //int w;
    //misura(h,w);
    
    //std::cerr << h << std::endl;

    //fl_rect(x()+dx_scroll, y()+dy_scroll,w,h);

    treat_as_a_whole(old_t);
        
  }

}


void multiline_label::draw_label_export(){

    int baseline_max_h=-1;
    float y_max_h=-1;

    //find max height
    int max_h=-1;
    for(unsigned int ct=0;ct<_lines_of_text.size();ct++){
      if(_lines_of_text[ct]->phys_h() > max_h){
        max_h=_lines_of_text[ct]->phys_h();
        baseline_max_h=_lines_of_text[ct]->get_pango_baseline();
        y_max_h=_lines_of_text[ct]->y();
      }
    }


    for(unsigned int i=0;i<_lines_of_text.size();i++){
      //if(i==0){
      //int y=_lines_of_text[i]->get_pango_logical_y();
      //_lines_of_text[i]->phys_translate(0,-y);
      //y_max_h=_lines_of_text[i]->y();
      //}

      
      int baseline_curr=_lines_of_text[i]->get_pango_baseline();
      float diff=  
        (y_max_h + baseline_max_h) -(_lines_of_text[i]->y()+baseline_curr)  ;
      if(_layout_lines==MULTILINE_LABEL_ALIGN_SINGLE_LINE_TEXT_LAYOUT){
        _lines_of_text[i]->phys_translate(0,diff);
      }
      /*
       cairo_t* cn=cairo_t_singleton::get_context();
       cairo_save(cn);
       int yy=_lines_of_text[i]->y();
       
       cairo_set_source_rgb(cn,0,1,0);
       cairo_move_to(cn,_lines_of_text[i]->x(),yy);
       cairo_line_to(cn,_lines_of_text[i]->x()+500,yy);
       cairo_stroke(cn);
       
       yy=_y;

       cairo_set_source_rgb(cn,0,1,1);
       cairo_move_to(cn,_lines_of_text[0]->x(),yy);
       cairo_line_to(cn,_lines_of_text[0]->x()+100,yy);
       cairo_stroke(cn);



       cairo_restore(cn);
      */
      _lines_of_text[i]->disegna();
    }


}



void multiline_label::trasla(float dx, float dy){
  if(treat_as_a_whole()){
    x(descale(x()+dx));
    y(descale(y()+dy));
  }else{

  }

}


void multiline_label::phys_translate(float dx, float dy){
  if(treat_as_a_whole()){
    x(x()+dx);
    y(y()+dy);
  }else{

  }

}



void multiline_label::scale(float sc){
  if(sc<1){
    if(phys_dim()>6){
      for(unsigned int i=0;i<_lines_of_text.size();i++){
        _lines_of_text[i]->dim(_lines_of_text[i]->phys_dim()-1);
      }
    }
  }else{
    for(unsigned int i=0;i<_lines_of_text.size();i++){
      _lines_of_text[i]->dim(_lines_of_text[i]->phys_dim()+1);
    }
  }

  
}

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


 bool multiline_label::dentro_bb(float x_bb, float y_bb, float w_bb , float h_bb){
   //std::cerr << "ooooooo" << std::endl;
   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 multiline_label::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;
  }

}
*/

 void multiline_label::pointer_to_currline(int nw){
   if(static_cast<unsigned int>(nw)<_lines_of_text.size()){
     _pointer_to_currline=nw;
   }
 }
 
 int multiline_label::pointer_to_currline(){
   return _pointer_to_currline;
 }


 int multiline_label::pointer_to_currline_transl(int delta){
  int nw=pointer_to_currline()+delta;
   int old=pointer_to_currline();
   if(nw>=0 && static_cast<unsigned int>(nw) < _lines_of_text.size()){
    pointer_to_currline(nw);

  }

  return old;

}


bool multiline_label::cursor_one_step_back(int &curr_type){

  int ptr_line=pointer_to_currline();
  bool has_more=true;

  if(ptr_line>=0 && ptr_line_less_lines_text()){
    int currt=0;
    bool not_beg = _lines_of_text[ptr_line]->cursor_one_step_back(currt);
    
    if(!not_beg){
      pointer_to_currline_transl(-1);
      ptr_line=pointer_to_currline();
      if(ptr_line>=0 && ptr_line_less_lines_text()){
        std::vector < std::pair<std::string,int> > the_vec_str=
          _lines_of_text[ptr_line]->vec_str();

        int size_f=the_vec_str.size()-1;
        int size_s=(the_vec_str.back().first).size();
        _lines_of_text[ptr_line]->set_cursor_position(size_f,size_s);
      
      }
    }

  }else{
    has_more=false;
  }
  

  return has_more;
}



int  multiline_label::set_cursor_position(int limit){
  int res=-1;
  int ptr_line=pointer_to_currline();
  if(ptr_line>=0  && ptr_line_less_lines_text()){
    res=_lines_of_text[ptr_line]->set_cursor_position(limit);
  }

  return res;
}



  /**
   *set cursor pos
   */
  
void multiline_label::set_cursor_position( int pos_in_vec, string::size_type pos_in_string){
  std::pair<int,string::size_type> pos(pos_in_vec,pos_in_string);
  set_cursor_position(pos);
}

  
void multiline_label::set_cursor_position(std::pair<int,string::size_type> pos){
  
   int ptr_line=pointer_to_currline();
   if(ptr_line>=0  && ptr_line_less_lines_text()){
     _lines_of_text[ptr_line]->set_cursor_position(pos);
   }
  
}



void multiline_label::set_cursor_position_abs(int line, int pos_in_vec, 
                                              string::size_type pos_in_string){
  if(line >=0 && line < static_cast<int>(size_lines_of_text())){
    pointer_to_currline(line);
    _lines_of_text[pointer_to_currline()]->set_cursor_position(pos_in_vec,pos_in_string);
  }

}

  
void multiline_label::set_cursor_position_abs(int line,
                                              std::pair<int,string::size_type> pos){
  if(line >=0 && line < static_cast<int>(size_lines_of_text())){
    pointer_to_currline(line);
    _lines_of_text[pointer_to_currline()]->set_cursor_position(pos.first,pos.second);
  }
}

void multiline_label::go_to_end_of_label(){
  if(size_lines_of_text()>0){
    for(unsigned int i=0;i<size_lines_of_text();i++){
      _lines_of_text[i]->go_to_end_of_label();
    }
    pointer_to_currline(size_lines_of_text()-1);
  }
}

void multiline_label::go_to_end_of_line(){
  if(size_lines_of_text()>0 && 
     pointer_to_currline()>=0 &&
     ptr_line_less_lines_text()){
    _lines_of_text[pointer_to_currline()]->go_to_end_of_line();
  }
}


void multiline_label::go_to_start_of_label(){
 if(size_lines_of_text()>0){

   for(unsigned int i=0;i<size_lines_of_text();i++){
     _lines_of_text[i]->go_to_start_of_label();
   }

   pointer_to_currline(0);
 }
}

void multiline_label::go_to_start_of_line(){
  if(size_lines_of_text()>0 && 
     pointer_to_currline()>=0 &&
     ptr_line_less_lines_text()){
    _lines_of_text[pointer_to_currline()]->go_to_start_of_line();
  }
}

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

  int res=-1;
  int ptr_line=pointer_to_currline();
  if(ptr_line>=0  && ptr_line_less_lines_text()){
    res=_lines_of_text[ptr_line]->get_cursor_position(pos);
  }

  return res;

}


bool multiline_label::cursor_one_step_fwd(int &curr_type){
  int ptr_line=pointer_to_currline();
  bool has_more=true;

  if(ptr_line>=0  && ptr_line_less_lines_text()){
    int currt=0;
    bool not_end = _lines_of_text[ptr_line]->cursor_one_step_fwd(currt);

    if(!not_end){
      pointer_to_currline_transl(1);
      ptr_line=pointer_to_currline();
      if(ptr_line>0 && ptr_line_less_lines_text() //&& 
         //static_cast<unsigned int>(ptr_line) < _lines_of_text.size()-1){
         ){
        _lines_of_text[ptr_line]->set_cursor_position(0,0);
      }
    }

  }else{
    has_more=false;
  }
  

  return has_more;
}


void multiline_label::insert_string_in_curr_pos(std::string str,int type){

  int ptr_line=pointer_to_currline();

  //std::cerr << "ptr_line " << ptr_line << std::endl;
             

  if(ptr_line>=0  && ptr_line_less_lines_text()){
    _lines_of_text[ptr_line]->insert_string_in_curr_pos(str,type);
  }else if(_lines_of_text.size()==0){
    etichetta*  tmp=new etichetta();
    tmp->aggiungi(str,ET_STR);
    tmp->set_cursor_position(0,str.size());
    tmp->reset_cursor_if_outside_limits();
    add_line(tmp);

  }

}



bool multiline_label::ptr_line_less_lines_text(){
  bool res=false;
  if(static_cast<unsigned int>(pointer_to_currline()) <  
     _lines_of_text.size()){
    res=true;
  }
  return res;
}

bool multiline_label::ptr_line_is_last_line(){
  return pointer_to_currline() == static_cast<int>((_lines_of_text.size()-1));
}


void multiline_label::reset_cursor_if_outside_limits(){
  int ptr_line=pointer_to_currline();
  if(ptr_line>=0  && ptr_line_less_lines_text()){
    _lines_of_text[ptr_line]->reset_cursor_if_outside_limits();
  }

}


void multiline_label::reset_pointer_to_currline(){

  if(_lines_of_text.size() == 0){
    _pointer_to_currline=-1;
  }else if(static_cast<unsigned int>(_pointer_to_currline) >= 
           _lines_of_text.size()){
    _pointer_to_currline=_lines_of_text.size()-1;
  }

}

bool multiline_label::check_if_type_etic(int typ) throw (out_of_range){
  bool res=false;
  int ptr_line=pointer_to_currline();
  if(ptr_line>=0  && ptr_line_less_lines_text()){
    res=_lines_of_text[ptr_line]->check_if_type_etic(typ);
  }

  return res;
}


bool multiline_label::check_if_type_etic(int typ,int pos) throw (out_of_range){
  bool res=false;
  int ptr_line=pointer_to_currline();
  if(ptr_line>=0  && ptr_line_less_lines_text()){
    res=_lines_of_text[ptr_line]->check_if_type_etic(typ,pos);
  }

  return res;
}




bool multiline_label::check_if_type_etic_next_chunk(int equal,bool &res_next_exist){
  bool res=false;
  int ptr_line=pointer_to_currline();
  res_next_exist=false;
  if(ptr_line>=0  && ptr_line_less_lines_text()){
    res=_lines_of_text[ptr_line]->check_if_type_etic_next_chunk(equal,res_next_exist);
  }

  return res;
}

bool multiline_label::check_if_type_etic_previous_chunk(int equal,bool &res_prev_exist){
  bool res=false;
  int ptr_line=pointer_to_currline();
  res_prev_exist=false;
  if(ptr_line>=0  && ptr_line_less_lines_text()){
    res=_lines_of_text[ptr_line]->check_if_type_etic_previous_chunk(equal,res_prev_exist);
  }
  return res;
}

int multiline_label::type_etic_at_cur_pos(){
  int res=-1;
  int ptr_line=pointer_to_currline();
  if(ptr_line>=0  && ptr_line_less_lines_text()){
    res=_lines_of_text[ptr_line]->type_etic_at_cur_pos();
  }
  
  return res;
}


void multiline_label::delete_char_curr_pos(bool before){
  int ptr_line=pointer_to_currline();
  std::pair<int,string::size_type> curpos;
  get_cursor_position(&curpos);
  if(_lines_of_text.size()>0){
    std::vector < std::pair<std::string,int> > the_vec_str=
      _lines_of_text[ptr_line]->vec_str();
    
    if(curpos.first==0 && curpos.second==0 && before){
      int currtype=0;
      cursor_one_step_back(currtype);
      
    }else if(curpos.first==static_cast<int>(the_vec_str.size()-1) &&
             curpos.second==(the_vec_str[curpos.first]).first.size() &&
             !ptr_line_is_last_line() && ! before){
      
        int currtype=0;
        //i  have  to statically  set  the  function  to avoid  infinite
        //recursion    in   inerithed    classes    of   multiline_label
        //(i.e. multifont_label::cursor_one_step_fwd)
        multiline_label::cursor_one_step_fwd(currtype);
        delete_char_curr_pos(before);
            
    }else{
      if(ptr_line>=0  && ptr_line_less_lines_text()){
        _lines_of_text[ptr_line]->delete_char_curr_pos(before);
      }

      if(_lines_of_text.size()>0 && 
         _lines_of_text[ptr_line]->size_str()==0){
        delete_line(ptr_line,true);
      }
    }
  }
}






void multiline_label::manage_sub_super(int check, int troublesome,std::string car){
  int ptr_line=pointer_to_currline();
  if(ptr_line>=0  && ptr_line_less_lines_text()){
    _lines_of_text[ptr_line]->manage_sub_super(check,troublesome,car);
  }
}

bool multiline_label::manage_add_sub_super_next_normal_str(int type){
  int ptr_line=pointer_to_currline();
  bool res=false;
  if(ptr_line>=0  && ptr_line_less_lines_text()){
    res=_lines_of_text[ptr_line]->manage_add_sub_super_next_normal_str(type);
  }
  return res;
}

bool multiline_label::manage_add_sub_next_super(int type){
  int ptr_line=pointer_to_currline();
  bool res=false;
  if(ptr_line>=0  && ptr_line_less_lines_text()){
    res=_lines_of_text[ptr_line]->manage_add_sub_next_super(type);
  }
  return res;
}

void multiline_label::insert_char_in_curr_pos(char add, int type){
  int ptr_line=pointer_to_currline();
  if(ptr_line>=0  && ptr_line_less_lines_text()){
    _lines_of_text[ptr_line]->insert_char_in_curr_pos(add,type);
  }
}

void multiline_label::break_string_at_cur_pos(int breaking_type){
  
  int ptr_line=pointer_to_currline();
  if(ptr_line>=0  && ptr_line_less_lines_text()){
    _lines_of_text[ptr_line]->break_string_at_cur_pos(breaking_type);
  }

}

void multiline_label::break_sub_super(int me, int type_to_insert,bool is_after){

  int ptr_line=pointer_to_currline();
  if(ptr_line>=0  && ptr_line_less_lines_text()){
    _lines_of_text[ptr_line]->break_sub_super(me,type_to_insert,is_after);
  }
  
}

void multiline_label::break_sub_or_super(int me, int type_to_insert){
  int ptr_line=pointer_to_currline();
  if(ptr_line>=0  && ptr_line_less_lines_text()){
    _lines_of_text[ptr_line]->break_sub_or_super(me,type_to_insert);
  }
}

void multiline_label::break_normal_str(int type_to_insert){
 int ptr_line=pointer_to_currline();
  if(ptr_line>=0  && ptr_line_less_lines_text()){
    _lines_of_text[ptr_line]->break_normal_str(type_to_insert);
  }
}



bool multiline_label::break_and_split_normal_str(etichetta** left , etichetta** right){
  int ptr_line=pointer_to_currline();
  bool res=false;
  if(ptr_line>=0  && ptr_line_less_lines_text()){
    res=_lines_of_text[ptr_line]->break_and_split_normal_str(left,right);
  }
  return res;
}


std::vector<etichetta*> multiline_label::get_lines_text(){
  return _lines_of_text;
}

bool multiline_label::dump_label(){
  std::cerr << __FUNCTION__ << std::endl;
  
  std::cerr << __FUNCTION__ <<  " x() " << x() << std::endl;
  std::cerr << __FUNCTION__ <<  " y() " << y() << std::endl;
  std::cerr << __FUNCTION__ <<  " interline_space() " << interline_space() << std::endl;

  for(unsigned int i =0;i< _lines_of_text.size();i++){
    std::cerr << __FUNCTION__ << "str " << _lines_of_text[i]->to_raw_string() 
              << std::endl;
  }

  return true;
}



int multiline_label::layout_lines(){
  return _layout_lines;
}

void multiline_label::layout_lines(int nw){
  _layout_lines=nw;
}




void multiline_label::format_lines_align_left(){

  for(unsigned int i=0;i<_lines_of_text.size();i++){
    _lines_of_text[i]->x(_x);
    
    int total_h=0;
    for(unsigned int j=0;j<i;j++){
      total_h+=_lines_of_text[j]->phys_h();
      total_h+=phys_interline_space();

    }

    _lines_of_text[i]->y(_y+total_h);
   
   
  }
}

void multiline_label::format_lines_align_right(){

  float w_max=0;

  for(unsigned int i=0;i<_lines_of_text.size();i++){
    if(_lines_of_text[i]->w() > w_max){
      w_max=_lines_of_text[i]->w();
    }
  }

  for(unsigned int i=0;i<_lines_of_text.size();i++){
    _lines_of_text[i]->x(_x + (w_max - _lines_of_text[i]->w()) );


    int total_h=0;
    for(unsigned int j=0;j<i;j++){
      total_h+=_lines_of_text[j]->phys_h();
      total_h+=phys_interline_space();
    }
    
    _lines_of_text[i]->y(_y+total_h);

  
  }
}

void multiline_label::format_lines_align_center(){

  float w_max=0;

  for(unsigned int i=0;i<_lines_of_text.size();i++){
    if(_lines_of_text[i]->w() > w_max){
      w_max=_lines_of_text[i]->w();
    }
  }

  for(unsigned int i=0;i<_lines_of_text.size();i++){
    _lines_of_text[i]->x(_x + w_max/2 - _lines_of_text[i]->w()/2 );


    int total_h=0;
    for(unsigned int j=0;j<i;j++){
      total_h+=_lines_of_text[j]->phys_h();
      total_h+=phys_interline_space();
    }

    _lines_of_text[i]->y(_y+total_h);

  }

}


void multiline_label::increase_highlighted(){
  std::vector<etichetta*>::iterator beg=_lines_of_text.begin()+pointer_to_currline();
  std::vector<etichetta*>::iterator end=_lines_of_text.end();

  if(beg<end){

    while(beg!=end && (*beg)->draw_negative()==true ){
      beg++;
    }

    if(beg!=end){
      (*beg)->draw_negative(true);
    }
  }

}

void multiline_label::decrease_highlighted(){
  int i=_lines_of_text.size()-1;
  for(;i>=0;i--){
    if(_lines_of_text[i]->draw_negative()==true){
      _lines_of_text[i]->draw_negative(false);
      break;
    }
  }

  

}

void multiline_label::de_highlight(){
  for(unsigned int i=0;i<_lines_of_text.size();i++){
    _lines_of_text[i]->draw_negative(false);
  }
}



void multiline_label::draw_negative(bool nw){
  if(treat_as_a_whole()){
    for(unsigned int i=0;i<_lines_of_text.size();i++){
      _lines_of_text[i]->draw_negative(nw);
    }
  }else{
    int ptr_line=pointer_to_currline();
    if(ptr_line>=0  && ptr_line_less_lines_text()){    
      _lines_of_text[ptr_line]->draw_negative(nw);
    }
  }
}

bool multiline_label::draw_negative(){
  bool res=_draw_negative;
  if(!treat_as_a_whole()){
    int ptr_line=pointer_to_currline();
    if(ptr_line>=0  && ptr_line_less_lines_text()){    
      res=_lines_of_text[ptr_line]->draw_negative();
    }
  }
  return res;
}


unsigned int multiline_label::size_lines_of_text(){
  return _lines_of_text.size();
}





void multiline_label::merge_labels_amap(){
  if(_lines_of_text.size()>1){
    std::vector<etichetta*> merged;
    
    for(unsigned int i=0;i< _lines_of_text.size();){
      etichetta* tmp=new etichetta(_lines_of_text[i]);
      //std::cerr << "i primo ciclo " << i  << std::endl;
      bool found_join=false;
      //DEBUG_TO_CERR(tmp->to_raw_string());
      for(unsigned int j=i+1;j< _lines_of_text.size();j++) {
        //std::cerr << "i " << i << " j " << j << std::endl;
        if(tmp->font()==_lines_of_text[j]->font() &&
           tmp->dim()==_lines_of_text[j]->dim()){
          //std::cerr << "aggiungo " << _lines_of_text[j]->to_raw_string() << std::endl;
          found_join=true;
          vector < pair<string,int> > vec=_lines_of_text[j]->vec_str();
          for(unsigned int ct=0;ct<vec.size();ct++){
            tmp->aggiungi(vec[ct].first,vec[ct].second);
          }
          i=j+1;
        }else{
          //std::cerr << "esco ma aggiungo " << _lines_of_text[j]->to_raw_string() << std::endl;
          break;
        }
        
      }
      if(!found_join){
        i++;
      }
      //std::cerr << "alla fine i=" << i << std::endl;

      merged.push_back(tmp);
    }

    for(unsigned int i=0;i<merged.size();i++){
      merged[i]->melt_similar(0);
      //std::cerr << "merged: "<< i  << " " << merged[i]->to_raw_string() << std::endl;
    }

    //delete old lines
    
    
    for(unsigned int i=0;i< _lines_of_text.size(); i++){
      //std::cerr << "eliminata merged" << _lines_of_text[i] << std::endl;
      delete _lines_of_text[i];
    }
    
    //_lines_of_text.erase(_lines_of_text.begin(),_lines_of_text.end());
    _lines_of_text=merged;
    

    reset_cursor_if_outside_limits();
    reset_pointer_to_currline();

  }
}



const int multiline_label::_default_interline_space=5;

