// text.cpp - Text's implementation of functions

// (obsolete note!)
// NOTE ABOUT TEXTMASK: + marks superscript, - marks subscript
// B marks bold, I marks italic, U marks underline

#include <QKeyEvent>

#include "render2d.h"
#include "drawable.h"
#include "text.h"
#include "defs.h"

// lastflag settings

Text::Text( Render2D * r1, QObject * parent )
    : Drawable( parent )
{
    r = r1;
    font = QFont( "Helvetica", 12 );    // CHANGE BACK TO 12
    highlighted = false;
    shiftdown = false;
    cursor = 0;
    selectMin = -1;
    selectMax = -1;
    bfont = font;
    bfont.setWeight( QFont::Bold );
    ifont = font;
    ifont.setItalic( true );
    ufont = font;
    ufont.setUnderline( true );
    molecule = 0;
    tjustify = TEXT_AUTO;
    whichside = 1;
    DataType = TEXT_DATA_NORMAL;
    shape = 0;
    shapewidth = -1;
    shapeheight = -1;
    oshapewidth = -1;
    oshapeheight = -1;
    drawBorder = false;
    drawFill = false;
    borderColor = QColor( 0, 0, 0 );
    fillColor = QColor( 0, 255, 255 );
}

QString Text::ToXML( QString xml_id )
{
    QString s, n1;
    int fsize;

    fsize = font.pointSize();
    if ( fsize < 1 )
        fsize = font.pixelSize();

    // begin text
    s.append( "<text id=" );
    s.append( xml_id );
    s.append( ">\n" );

    // write Start
    s.append( "<Start>" );
    n1.setNum( start->x );
    s.append( n1 );
    s.append( " " );
    n1.setNum( start->y );
    s.append( n1 );
    s.append( "</Start>\n" );

    // write text
    s.append( "<textstring>" );
    s.append( start->element );
    s.append( "</textstring>\n" );

    // write textmask
    s.append( "<richstring>" );
    s.append( displayText );
    s.append( "</richstring>\n" );

    // shape info
    s.append( "<shape>" );
    n1.setNum( shape );
    s.append( n1 );
    s.append( "</shape>\n" );

    // border info
    s.append( "<border>" );
    if ( drawBorder == true )
        s.append( "true" );
    else
        s.append( "false" );
    s.append( "</border>\n<bordercolor>" );
    n1.setNum( borderColor.red() );
    s.append( n1 );
    s.append( " " );
    n1.setNum( borderColor.green() );
    s.append( n1 );
    s.append( " " );
    n1.setNum( borderColor.blue() );
    s.append( n1 );
    s.append( "</bordercolor>\n" );

    // fill info
    s.append( "<fill>" );
    if ( drawFill == true )
        s.append( "true" );
    else
        s.append( "false" );
    s.append( "</fill>\n<fillcolor>" );
    n1.setNum( fillColor.red() );
    s.append( n1 );
    s.append( " " );
    n1.setNum( fillColor.green() );
    s.append( n1 );
    s.append( " " );
    n1.setNum( fillColor.blue() );
    s.append( n1 );
    s.append( "</fillcolor>\n" );

    // shape dimensions
    s.append( "<shapegeometry>" );
    n1.setNum( shapewidth );
    s.append( n1 );
    s.append( " " );
    n1.setNum( shapeheight );
    s.append( n1 );
    s.append( " " );
    n1.setNum( oshapewidth );
    s.append( n1 );
    s.append( " " );
    n1.setNum( oshapeheight );
    s.append( n1 );
    s.append( "</shapegeometry>\n" );

    // end text
    s.append( "</text>\n" );

    return s;
}

QString Text::ToCDXML( QString xml_id )
{
    QString s, n1;

    // begin text
    s.append( "<t id=\"" );
    s.append( xml_id );
    s.append( "\" p=\"" );
    n1.setNum( start->x );
    s.append( n1 );
    s.append( " " );
    n1.setNum( start->y );
    s.append( n1 );
    s.append( "\"><s font=\"21\" size=\"10\" face=\"96\">" );
    s.append( start->element );
    s.append( "</s></t>\n" );

    return s;
}

void Text::FromXML( QString xml_tag )
{
    int i1, i2;

    i1 = xml_tag.indexOf( "<Start>" );
    i2 = xml_tag.indexOf( "</Start>" ) + 8;
    SetStartFromXML( xml_tag.mid( i1, i2 - i1 ) );
    i1 = xml_tag.indexOf( "<color>" );
    if ( i1 >= 0 ) {
        i2 = xml_tag.indexOf( "</color>" ) + 8;
        SetColorFromXML( xml_tag.mid( i1, i2 - i1 ) );
    }
    i1 = xml_tag.indexOf( "<font>" );
    if ( i1 >= 0 ) {
        i2 = xml_tag.indexOf( "</font>" ) + 7;
        SetFontFromXML( xml_tag.mid( i1, i2 - i1 ) );
    }
    i1 = xml_tag.indexOf( "<textstring>" );
    i2 = xml_tag.indexOf( "</textstring>" ) + 13;
    SetTextstringFromXML( xml_tag.mid( i1, i2 - i1 ) );
    i1 = xml_tag.indexOf( "<richstring>" );
    i2 = xml_tag.indexOf( "</richstring>" ) + 13;
    SetRichstringFromXML( xml_tag.mid( i1, i2 - i1 ) );
    i1 = xml_tag.indexOf( "<textmask>" );
    i2 = xml_tag.indexOf( "</textmask>" ) + 11;
    SetTextmaskFromXML( xml_tag.mid( i1, i2 - i1 ) );
    i1 = xml_tag.indexOf( "<shape>" );
    if ( i1 > 0 ) {
        i2 = xml_tag.indexOf( "</shape>" );
        shape = xml_tag.mid( i1 + 7, i2 - i1 - 7 ).toInt();
        qDebug() << "shape:" << shape;
    }
    i1 = xml_tag.indexOf( "<border>" );
    if ( i1 > 0 ) {
        i2 = xml_tag.indexOf( "</border>" );
        qDebug() << "border:" << xml_tag.mid( i1 + 8, 4 );
        if ( xml_tag.mid( i1 + 8, 4 ) == "true" )
            drawBorder = true;
        else
            drawBorder = false;
    }
    i1 = xml_tag.indexOf( "<fill>" );
    if ( i1 > 0 ) {
        i2 = xml_tag.indexOf( "</fill>" );
        qDebug() << "fill:" << xml_tag.mid( i1 + 6, 4 );
        if ( xml_tag.mid( i1 + 6, 4 ) == "true" )
            drawFill = true;
        else
            drawFill = false;
    }
    i1 = xml_tag.indexOf( "<bordercolor>" );
    if ( i1 >= 0 ) {
        i2 = xml_tag.indexOf( "</bordercolor>" ) + 14;
        SetBorderColorFromXML( xml_tag.mid( i1, i2 - i1 ) );
    }
    i1 = xml_tag.indexOf( "<fillcolor>" );
    if ( i1 >= 0 ) {
        i2 = xml_tag.indexOf( "</fillcolor>" ) + 12;
        SetFillColorFromXML( xml_tag.mid( i1, i2 - i1 ) );
    }
    i1 = xml_tag.indexOf( "<shapegeometry>" );
    if ( i1 >= 0 ) {
        i2 = xml_tag.indexOf( "</shapegeometry>" ) + 16;
        SetShapeGeometryFromXML( xml_tag.mid( i1, i2 - i1 ) );
    }
}

void Text::SetBorderColorFromXML( QString xml_tag )
{
    qDebug() << "SetBColorFromXML:" << xml_tag;
    int i1, i2;
    int d1, d2, d3;

    i1 = xml_tag.indexOf( "<bordercolor>" );
    i2 = xml_tag.indexOf( "</bordercolor>" );
    xml_tag.remove( i2, 999 );
    xml_tag.remove( i1, 13 );

    QTextStream ts( &xml_tag, QIODevice::ReadOnly );

    ts >> d1 >> d2 >> d3;

    borderColor = QColor( d1, d2, d3 );
}

void Text::SetFillColorFromXML( QString xml_tag )
{
    qDebug() << "SetFColorFromXML:" << xml_tag;
    int i1, i2;
    int d1, d2, d3;

    i1 = xml_tag.indexOf( "<fillcolor>" );
    i2 = xml_tag.indexOf( "</fillcolor>" );
    xml_tag.remove( i2, 999 );
    xml_tag.remove( i1, 11 );

    QTextStream ts( &xml_tag, QIODevice::ReadOnly );

    ts >> d1 >> d2 >> d3;

    fillColor = QColor( d1, d2, d3 );
}

void Text::SetShapeGeometryFromXML( QString xml_tag )
{
    qDebug() << "SetSGFromXML:" << xml_tag;
    int i1, i2;
    int d1, d2, d3, d4;

    i1 = xml_tag.indexOf( "<shapegeometry>" );
    i2 = xml_tag.indexOf( "</shapegeometry>" );
    xml_tag.remove( i2, 999 );
    xml_tag.remove( i1, 15 );

    QTextStream ts( &xml_tag, QIODevice::ReadOnly );

    ts >> d1 >> d2 >> d3 >> d4;

    shapewidth = d1;
    shapeheight = d2;
    oshapewidth = d3;
    oshapeheight = d4;
}

// convert XML <font> tag to QFont and set current
void Text::SetFontFromXML( QString xml_tag )
{
    qDebug() << "SetFontFromXML:" << xml_tag;
    int i1, i2;

    //int d1, d2, d3;

    i1 = xml_tag.indexOf( "<font>" );
    i2 = xml_tag.indexOf( "</font>" );
    xml_tag.remove( i2, 999 );
    xml_tag.remove( i1, 6 );
    i1 = xml_tag.indexOf( "#" );
    qDebug() << xml_tag.mid( 0, i1 ) << "*" << xml_tag.mid( i1 + 1 );
    font = QFont( xml_tag.mid( 0, i1 ), xml_tag.mid( i1 + 1 ).toInt() );
}

// get Text::text from <textstring> tag
void Text::SetTextstringFromXML( QString xml_tag )
{
    qDebug() << "SetTextstringFromXML:" << xml_tag;
    int i1, i2;

    //int d1, d2, d3;

    i1 = xml_tag.indexOf( "<textstring>" );
    i2 = xml_tag.indexOf( "</textstring>" );
    xml_tag.remove( i2, 999 );
    xml_tag.remove( i1, 12 );
    if ( start != 0 )
        start->element = xml_tag;
}

// get Text::displayText from <richstring> tag
void Text::SetRichstringFromXML( QString xml_tag )
{
    qDebug() << "SetRichstringFromXML:" << xml_tag;
    int i1, i2;

    //int d1, d2, d3;

    i1 = xml_tag.indexOf( "<richstring>" );
    i2 = xml_tag.indexOf( "</richstring>" );
    xml_tag.remove( i2, 999 );
    xml_tag.remove( i1, 12 );
    if ( start != 0 )
        displayText = xml_tag;
}

// get Text::textmask from <textmask> tag
void Text::SetTextmaskFromXML( QString xml_tag )
{
    // not used!!!  either <richstring> or <elementmask> tag used to set display

    //qDebug() << "SetTextmaskFromXML:" << xml_tag ;

    // obsolete tag!  silently update...
    // note that user may need to reformat text
    //displayText = start->element;
    //displayText.replace("\n", "</p>");

    /*
       int i1, i2;
       //int d1, d2, d3;

       i1 = xml_tag.indexOf("<textmask>");
       i2 = xml_tag.indexOf("</textmask>");
       xml_tag.remove(i2, 999);
       xml_tag.remove(i1, 10);
       if (start != 0)
       start->elementmask = xml_tag;
     */
}

bool Text::isWithinRect( QRect n, bool shiftdown )
{
    if ( DPointInRect( start, n ) )
        highlighted = true;
    else
        highlighted = false;
    return highlighted;
}

void Text::Render()
{
  qDebug() << "Text::Render begin";
//  r->drawString( "foobar", start->toQPoint(), QColor(0,0,0), QFont() ); return;
  qDebug() << "displayText.length():" << displayText.length();

  bool boldFlag = false, italicFlag = false, underlineFlag = false, superFlag = false, subFlag = false;
  QFont currentFont = font;
  QColor currentColor = color;

  if ( r->getFontKludge() ) {
    currentFont.setPointSize( currentFont.pointSize() * 2 );
    qDebug() << "fontkludge (top)";
  }

  QStringList parseList, renderList, lineWidths;

  int lineheight = 0, linewidth = 0, textheight = 0, textwidth = 0;
  int cp1, lp1, lp2;
  QString n1, currentElement = QString();
  bool flag1 = false;

  for ( cp1 = 0; cp1 < displayText.length(); cp1++ ) {
    flag1 = true;
    if ( displayText[cp1] == '<' ) {
      parseList.append( currentElement );
      currentElement = "<";
      flag1 = false;
    }
    if ( displayText[cp1] == '>' ) {
      currentElement.append( displayText[cp1] );
      if (!currentElement.contains("!DOCTYPE")) {
        parseList.append( currentElement );
      }
      currentElement = "";
      flag1 = false;
    }
    if ( flag1 ) {
      currentElement.append( displayText[cp1] );
    }
  }

  // just in case there were no tags...
  if ( currentElement.length() > 0 )
    parseList.append( currentElement );

  // mock render to determine width and height
  QRect b1;
  int maxfont = 0, thisfont;
  bool styletag = false;

  for ( QStringList::Iterator it = parseList.begin(); it != parseList.end(); ++it ) {
    currentElement = *it;
    qDebug() << "currentElement:" << currentElement;
    // dump the style tag!
    if ( currentElement == "</style>" ) {
      styletag = false;
      continue;
    }
    if ( styletag ) continue;
    if ( currentElement.left(6) == "<style" ) {
      styletag = true;
      continue;
    }

    if ( currentElement == "" )
      continue;
    if ( currentElement == " " )
      continue;
    if ( currentElement == "\n" )
      continue;
    if ( currentElement == "<p>" )
      continue;
    if ( currentElement == "<html>" )
      continue;
    if ( currentElement == "</html>" )
      continue;
    if ( currentElement == "<head>" )
      continue;
    if ( currentElement == "</head>" )
      continue;
    if ( currentElement == "</body>" )
      continue;
    if ( currentElement.left( 3 ) == "<p " )
      continue;
    if ( currentElement.left( 6 ) == "<body " )
      continue;
    if ( currentElement.left( 6 ) == "<meta " )
      continue;
    if ( currentElement == "</span>" ) {
      // this likely undoes a super/sub flag
      if ( superFlag == true )
	superFlag = false;
      if ( subFlag == true )
	subFlag = false;
      renderList.append( currentElement );
      continue;
    }
    currentElement.replace( "&lt;", "<" );
    currentElement.replace( "&gt;", ">" );
    renderList.append( currentElement );
    if ( currentElement == "</p>" ) {
      n1.setNum( linewidth );
      lineWidths.append( n1 );
      if ( linewidth > textwidth )
	textwidth = linewidth;
      textheight += lineheight;
      linewidth = 0;
      lineheight = 0;
      continue;
    }
    if ( currentElement.left( 6 ) == "<span " ) {
      // set font
      //qDebug() << "span: " << currentElement;
      boldFlag = false, italicFlag = false, underlineFlag = false, superFlag = false, subFlag = false;
      if ( currentElement.contains( "font-family" ) > 0 ) {
	lp2 = currentElement.indexOf( "font-family" );
	lp1 = currentElement.indexOf( ":", lp2 );
	lp2 = currentElement.indexOf( ";", lp1 );
	currentFont.setFamily( currentElement.mid( lp1 + 1, lp2 - lp1 - 1 ) );
      }
      if ( currentElement.contains( "font-size" ) > 0 ) {
	lp2 = currentElement.indexOf( "font-size" );
	lp1 = currentElement.indexOf( ":", lp2 );
	lp2 = currentElement.indexOf( "pt", lp1 );
	thisfont = currentElement.mid( lp1 + 1, lp2 - lp1 - 1 ).toInt();
	currentFont.setPointSize( thisfont );
	if ( thisfont > maxfont )
	  maxfont = thisfont;
	if ( r->getFontKludge() == true ) {
	  currentFont.setPointSize( currentFont.pointSize() * 2 );
	  qDebug() << "fontkludge";
	}
	qDebug() << "points: " << currentFont.pointSize();
      }
      currentFont.setBold( false );
      currentFont.setItalic( false );
      currentFont.setUnderline( false );
      if ( currentElement.contains( "font-weight" ) > 0 ) {
	boldFlag = true;
	currentFont.setBold( true );
      }
      if ( currentElement.contains( "italic" ) > 0 ) {
	italicFlag = true;
	currentFont.setItalic( true );
      }
      if ( currentElement.contains( "underline" ) > 0 ) {
	underlineFlag = true;
	currentFont.setUnderline( true );
      }
      if ( currentElement.contains( "super" ) > 0 ) {
	superFlag = true;
      }
      if ( currentElement.contains( "sub" ) > 0 ) {
	subFlag = true;
      }
      continue;
    }
    b1 = r->GetTextDimensions( currentElement, currentFont );
    if ( b1.height() > lineheight )
      lineheight = b1.height();
    linewidth += b1.width();
  }
  // end for?
 
  if ( lineheight > textheight )
    textheight = lineheight;
  if ( linewidth > textwidth )
    textwidth = linewidth;


  qDebug() << displayText;
  qDebug() << "Text dimensions = " << textwidth << "," << textheight;
  //qDebug() << "Text check 1 ---";

  int supersub, subx;
  QFont supersubfont;
  QColor drawcolor;

  if ( highlighted )
    drawcolor = QColor( 255, 0, 0 );
  else
    drawcolor = color;
  QRect b( 0, 0, textwidth, textheight );
  QPoint t = GetTopLeftPoint();

  b.translate( t.x(), t.y() );
  // this guarantees that the text will not overlap other objects
  // original code
  r->drawFillBox( b.topLeft(), b.bottomRight(), r->getBGColor(), false, QColor( 0, 0, 0 ), 1 );

  // draw shape, if applicable
  QPoint shapetl, shapebr, textcenter;

  oshapewidth = b.width() + maxfont;
  oshapeheight = b.height() + maxfont;
  textcenter.setX( b.left() + ( b.width() / 2 ) );
  textcenter.setY( b.top() + ( b.height() / 2 ) );
  int lsw, lsh;

  if ( shapewidth < 0 ) {
    lsw = oshapewidth;
    lsh = oshapeheight;
  } else {
    lsw = shapewidth;
    lsh = shapeheight;
  }
  if ( shape > 0 ) {
    shapetl.setX( textcenter.x() - ( lsw / 2 ) );
    shapebr.setX( textcenter.x() + ( lsw / 2 ) );
    shapetl.setY( textcenter.y() - ( lsh / 2 ) );
    shapebr.setY( textcenter.y() + ( lsh / 2 ) );
    if ( shape == TEXT_SHAPE_RECTANGLE ) {
      if ( drawFill ) {
	r->drawFillBox( shapetl, shapebr, fillColor, drawBorder, borderColor, 0 );
      } else {
	r->drawBox( shapetl, shapebr, borderColor );
      }
    }
    if ( shape == TEXT_SHAPE_SQUARE ) {
      if ( drawFill ) {
	r->drawFillBox( shapetl, shapebr, fillColor, drawBorder, borderColor, 0 );
      } else {
	r->drawBox( shapetl, shapebr, borderColor );
      }
    }
    if ( shape == TEXT_SHAPE_ELLIPSE ) {
      r->drawEllipse( shapetl, shapebr, drawBorder, borderColor, drawFill, fillColor );
    }
    if ( shape == TEXT_SHAPE_CIRCLE ) {
      r->drawEllipse( shapetl, shapebr, drawBorder, borderColor, drawFill, fillColor );
    }
  }
  // right-align behavior is different for stand-alone text
  QTextStream dts( &displayTextMask, QIODevice::ReadOnly );
  QString displayLine;
  int in1 = 0;

  //displayLine = dts.readLine();
  //in1 = r->GetStringWidth(displayLine, font);
  //qDebug() << b.width() << ":" << in1 ;
  //in1 = lineWidths[0].toInt();
  in1 = b.width() - in1;
  //bool switchpos = false;
  QPoint curpos( t.x(), t.y() + r->GetTextHeight( font ) );

  if ( ( tjustify == TEXT_RALIGN ) && ( justify == JUSTIFY_TOPLEFT ) )
    curpos.setX( curpos.x() + in1 + 2 );
  if ( ( tjustify == TEXT_CALIGN ) && ( justify == JUSTIFY_TOPLEFT ) )
    curpos.setX( curpos.x() + ( in1 / 2 ) + 2 );
  bool smaller_font = false;
  QPoint startpos = curpos;

  // actual rendering section
  //qDebug() << "Text check 2 ---";

  int lw1 = 1;

  r->resetTextOrigin();
  foreach ( currentElement, renderList ) {
    if ( currentElement == "</span>" ) {
      boldFlag = false, italicFlag = false, underlineFlag = false, superFlag = false, subFlag = false;
      continue;
    }
    if ( currentElement == "</p>" ) {
      boldFlag = false, italicFlag = false, underlineFlag = false, superFlag = false, subFlag = false;
      currentFont.setBold( false );
      currentFont.setItalic( false );
      currentFont.setUnderline( false );
      if ( justify == JUSTIFY_CENTER )
	continue;
      r->resetTextOrigin();
      //displayLine = dts.readLine();
      //in1 = r->GetStringWidth(displayLine, font);
      //qDebug() << b.width() << ":" << in1 ;
      if ( lw1 < lineWidths.size() ) {
	in1 = lineWidths[lw1].toInt();
	lw1++;
	in1 = b.width() - in1;
	curpos.setX( t.x() );
	if ( ( tjustify == TEXT_RALIGN ) && ( justify == JUSTIFY_TOPLEFT ) )
	  curpos.setX( curpos.x() + in1 + 2 );
	if ( ( tjustify == TEXT_CALIGN ) && ( justify == JUSTIFY_TOPLEFT ) )
	  curpos.setX( curpos.x() + ( in1 / 2 ) + 2 );
	curpos.setY( curpos.y() + r->GetTextFullHeight( font ) );
      }
      continue;
    }

    if ( currentElement.left( 6 ) == "<span " ) {
      // set font
      //qDebug() << "span: " << currentElement;
      boldFlag = false, italicFlag = false, underlineFlag = false, superFlag = false, subFlag = false;
      if ( currentElement.contains( "font-family" ) > 0 ) {
	lp2 = currentElement.indexOf( "font-family" );
	lp1 = currentElement.indexOf( ":", lp2 );
	lp2 = currentElement.indexOf( ";", lp1 );
	currentFont.setFamily( currentElement.mid( lp1 + 1, lp2 - lp1 - 1 ) );
      }
      if ( currentElement.contains( "font-size" ) > 0 ) {
	lp2 = currentElement.indexOf( "font-size" );
	lp1 = currentElement.indexOf( ":", lp2 );
	lp2 = currentElement.indexOf( "pt", lp1 );
	currentFont.setPointSize( currentElement.mid( lp1 + 1, lp2 - lp1 - 1 ).toInt() );
	if ( r->getFontKludge() == true ) {
	  currentFont.setPointSize( currentFont.pointSize() * 2 );
	  qDebug() << "fontkludge";
	}
      }
      currentFont.setBold( false );
      currentFont.setItalic( false );
      currentFont.setUnderline( false );
      if ( currentElement.contains( "font-weight" ) > 0 ) {
	boldFlag = true;
	currentFont.setBold( true );
      }
      if ( currentElement.contains( "italic" ) > 0 ) {
	italicFlag = true;
	currentFont.setItalic( true );
      }
      if ( currentElement.contains( "underline" ) > 0 ) {
	underlineFlag = true;
	currentFont.setUnderline( true );
      }
      if ( currentElement.contains( "super" ) > 0 ) {
	superFlag = true;
      }
      if ( currentElement.contains( "sub" ) > 0 ) {
	subFlag = true;
      }
      currentColor = QColor( 0, 0, 0 );
      if ( currentElement.contains( "color" ) > 0 ) {
	lp2 = currentElement.indexOf( "color" );
	lp1 = currentElement.indexOf( ":", lp2 );
	currentColor.setNamedColor( currentElement.mid( lp1 + 1, 7 ) );
      }
      continue;
    }

    supersub = r->GetTextHeight( currentFont ) / 2;
    supersubfont = subscriptFont( currentFont );
    subx = r->GetTextHeight( supersubfont ) / 2;

    if ( highlighted )
      currentColor = QColor( 255, 0, 0 );

    if ( superFlag == true ) {
      r->drawString( currentElement, QPoint( curpos.x(), curpos.y() - supersub ), currentColor, supersubfont );
      smaller_font = true;
    }
    if ( subFlag == true ) {
      r->drawString( currentElement, QPoint( curpos.x(), curpos.y() + subx ), currentColor, supersubfont );
      smaller_font = true;
    }
    if ( smaller_font == true ) {
      curpos.setX( curpos.x() + r->GetStringWidth( currentElement, supersubfont ) );
    } else {
      r->drawString( currentElement, curpos, currentColor, currentFont );
      curpos.setX( curpos.x() + r->GetStringWidth( currentElement, currentFont ) );
    }
    smaller_font = false;
  }
  qDebug() << "Text::Render end";
}

int Text::Type()
{
    return TYPE_TEXT;
}

bool Text::Find( DPoint * target )
{
    //if (start == target) return true;
    return false;
}

DPoint *Text::FindNearestPoint( DPoint * target, double &dist )
{
    dist = 99999.0;
    return 0;
}

Drawable *Text::FindNearestObject( DPoint * target, double &dist )
{
    if ( WithinBounds( target ) )
        dist = 0.01;
    else
        dist = 99999.0;
    return this;
}

void Text::setPoint( DPoint * s )
{
    start = s;
}

bool Text::WithinBounds( DPoint * target )
{
    QRect b = r->GetTextDimensions( start->element, font );
    QPoint t = GetTopLeftPoint();

    b.translate( t.x(), t.y() );
    if ( ( target->x > b.left() ) && ( target->x < b.right() ) && ( target->y > b.top() ) && ( target->y < b.bottom() ) )
        return true;
    else
        return false;
}

QRect Text::BoundingBox()
{
    if ( highlighted == false )
        return QRect( QPoint( 999, 999 ), QPoint( 0, 0 ) );

    QTextDocument localtextdocument;
    localtextdocument.setHtml(start->element);
    QString tmpline = localtextdocument.toPlainText();

    qInfo() << "Text::BoundingBox:" << start->element << "||" << tmpline;

    //QRect b = r->GetTextDimensions( start->element, font );
    QRect b = r->GetTextDimensions( tmpline, font );
    QPoint t = GetTopLeftPoint();

    b.translate( t.x(), t.y() );
    return b;
}

// return nearest center point to m (see ChemData::AutoLayout)
QPoint Text::NearestCenter( QPoint m, int di, int &ns )
{
    QRect b = r->GetTextDimensions( start->element, font );
    QPoint t = GetTopLeftPoint();

    b.translate( t.x(), t.y() );
    QPoint c1, cmin;
    double dist = 9999.0, ndist;

    if ( di == ARROW_VERTICAL ) {
        c1.setX( b.left() );
        c1.setY( b.center().y() );
        ndist = DistanceBetween( m, c1 );
        if ( ndist < dist ) {
            cmin = c1;
            dist = ndist;
            ns = TEXT_LEFT;
        }
        c1.setX( b.right() );
        c1.setY( b.center().y() );
        ndist = DistanceBetween( m, c1 );
        if ( ndist < dist ) {
            cmin = c1;
            dist = ndist;
            ns = TEXT_RIGHT;
        }
    } else {                    // ARROW_HORIZONTAL
        c1.setX( b.center().x() );
        c1.setY( b.top() );
        ndist = DistanceBetween( m, c1 );
        if ( ndist < dist ) {
            cmin = c1;
            dist = ndist;
            ns = TEXT_TOP;
        }
        c1.setX( b.center().x() );
        c1.setY( b.bottom() );
        ndist = DistanceBetween( m, c1 );
        if ( ndist < dist ) {
            cmin = c1;
            dist = ndist;
            ns = TEXT_BOTTOM;
        }
    }
    return cmin;
}

void Text::DeleteKeyPressed()
{
    qDebug() << "Delete key";
    start->element.remove( cursor, 1 );
    start->elementmask.remove( cursor, 1 );
}

void Text::InsertCharacter( QKeyEvent * k1 )
{
    // if shift pressed, start new selection
    if ( k1->modifiers() == Qt::ShiftModifier ) {
        if ( shiftdown == false ) {
            shiftdown = true;
            selectMin = cursor;
            selectMax = cursor - 1;
            qDebug() << cursor << "-" << selectMin << "-" << selectMax;
        } else {
            shiftdown = true;
        }
    } else {
        shiftdown = false;
    }

    // if return pressed, add newline only if JUSTIFY_TOPLEFT (not a label)
    if ( ( k1->key() == Qt::Key_Return ) && ( justify == JUSTIFY_CENTER ) )
        return;

    if ( k1->key() == Qt::Key_Return ) {
        qDebug() << "Return";
        start->element.insert( cursor, ( char ) 10 );
        //start->element = text;
        start->elementmask.insert( cursor, ( char ) 10 );
        cursor++;
        return;
    }
    // if left or right arrow pressed with shift, make or extend new selection
    if ( ( k1->key() == Qt::Key_Left ) && shiftdown ) {
        qDebug() << cursor << "-" << selectMin << "-" << selectMax;
        if ( selectMin > 0 ) {
            if ( cursor > selectMin )
                selectMax--;
            else
                selectMin--;
        }
        if ( cursor > 0 )
            cursor--;
        return;
    }
    if ( ( k1->key() == Qt::Key_Right ) && shiftdown ) {
        qDebug() << cursor << "-" << selectMin << "-" << selectMax;
        if ( selectMax < start->element.length() ) {
            if ( cursor <= selectMax )
                selectMin++;
            else
                selectMax++;
        }
        if ( cursor < start->element.length() )
            cursor++;
        return;
    }
    // if Home or End pressed with shift, make or extend new selection
    if ( ( k1->key() == Qt::Key_Home ) && shiftdown ) {
        qDebug() << cursor << "-" << selectMin << "-" << selectMax;
        if ( selectMin > 0 ) {
            if ( cursor > selectMin )
                selectMax--;
            else
                selectMin = 0;
        }
        if ( cursor > 0 )
            cursor = 0;
        return;
    }
    if ( ( k1->key() == Qt::Key_End ) && shiftdown ) {
        qDebug() << cursor << "-" << selectMin << "-" << selectMax;
        if ( selectMax < start->element.length() ) {
            if ( cursor <= selectMax )
                selectMin++;
            else
                selectMax = start->element.length();
        }
        if ( cursor < start->element.length() )
            cursor = start->element.length();
        return;
    }
    // if left or right arrow pressed w/o shift, clear selection
    if ( k1->key() == Qt::Key_Left ) {
        if ( cursor > 0 )
            cursor--;
        selectMin = -1;
        selectMax = -1;
        return;
    }
    if ( k1->key() == Qt::Key_Right ) {
        if ( cursor < start->element.length() )
            cursor++;
        selectMin = -1;
        selectMax = -1;
        return;
    }
    // if Home or End was pressed, go home or end
    if ( k1->key() == Qt::Key_Home ) {
        if ( cursor > 0 )
            cursor = 0;
        selectMin = -1;
        selectMax = -1;
        return;
    }
    if ( k1->key() == Qt::Key_End ) {
        if ( cursor < start->element.length() )
            cursor = start->element.length();
        selectMin = -1;
        selectMax = -1;
        return;
    }
    if ( k1->key() == Qt::Key_Backspace ) {
        if ( cursor == 0 )
            return;
        if ( ( selectMin >= 0 ) && ( selectMax >= 1 ) ) {       // something selected
            start->element.remove( selectMin, selectMax - selectMin + 1 );
            start->elementmask.remove( selectMin, selectMax - selectMin + 1 );
            //start->element = text;
            cursor = selectMin;
            selectMin = -1, selectMax = -1;
            return;
        }
        start->element.remove( cursor - 1, 1 );
        //start->element = text;
        start->elementmask.remove( cursor - 1, 1 );
        cursor--;
        return;
    }
    // if key > 96 and not already handled, ignore (letters/numbers/space < 96)
    // note that this breaks international layouts and is probably not needed
    //if (k1->key() > 96) return;
    //
    // this is a more useful test in a Unicode world
    //qDebug() << "Key text:" << k1->text() << ":";
    QChar kc1 = k1->text().at( 0 );

    if ( kc1.isPrint() == false )
        return;
    //qDebug() << kc1 << "(key accepted)";

    // regular letter/number pressed
    start->element.insert( cursor, k1->text() );
    //start->element = text;
    start->elementmask.insert( cursor, QChar( ' ' ) );
    cursor++;
}

void Text::InsertString( QString pt )
{
    start->element.insert( cursor, pt );
    pt.fill( ' ' );
    start->elementmask.insert( cursor, pt );
    cursor += pt.length();
}

// Superscript selected text
void Text::DoSuperscript()
{
    if ( selectMin < 0 )
        return;
    for ( int i = selectMin; i < selectMax + 1; i++ ) {
        if ( start->elementmask[i] == ' ' ) {
            start->elementmask[i] = '+';
            continue;
        }
        if ( start->elementmask[i] == '+' ) {
            start->elementmask[i] = ' ';
            continue;
        }
        if ( start->elementmask[i] == '-' ) {
            start->elementmask[i] = '+';
            continue;
        }
    }
}

// Subscript selected text
void Text::DoSubscript()
{
    if ( selectMin < 0 )
        return;
    for ( int i = selectMin; i < selectMax + 1; i++ ) {
        if ( start->elementmask[i] == ' ' ) {
            start->elementmask[i] = '-';
            continue;
        }
        if ( start->elementmask[i] == '+' ) {
            start->elementmask[i] = '-';
            continue;
        }
        if ( start->elementmask[i] == '-' ) {
            start->elementmask[i] = ' ';
            continue;
        }
    }
}

// Bold selected text
void Text::DoBold()
{
    if ( selectMin < 0 )
        return;
    for ( int i = selectMin; i < selectMax + 1; i++ ) {
        if ( start->elementmask[i] == ' ' ) {
            start->elementmask[i] = 'B';
            continue;
        }
        if ( start->elementmask[i] == 'B' ) {
            start->elementmask[i] = ' ';
            continue;
        }
    }
}

// Italicize selected text
void Text::DoItalic()
{
    if ( selectMin < 0 )
        return;
    for ( int i = selectMin; i < selectMax + 1; i++ ) {
        if ( start->elementmask[i] == ' ' ) {
            start->elementmask[i] = 'I';
            continue;
        }
        if ( start->elementmask[i] == 'I' ) {
            start->elementmask[i] = ' ';
            continue;
        }
    }
}

// Underline selected text
void Text::DoUnderline()
{
    if ( selectMin < 0 )
        return;
    for ( int i = selectMin; i < selectMax + 1; i++ ) {
        if ( start->elementmask[i] == ' ' ) {
            start->elementmask[i] = 'U';
            continue;
        }
        if ( start->elementmask[i] == 'U' ) {
            start->elementmask[i] = ' ';
            continue;
        }
    }
}

// move cursor to target
void Text::MoveCursor( DPoint * target )
{
    selectMin = -1;
    selectMax = -1;
    double mindist = 99999.0, ldist;
    int newcur;
    DPoint *e = new DPoint;

    qDebug() << "Move";
    if ( WithinBounds( target ) == false )
        return;
    QPoint t = GetTopLeftPoint();
    int lx = t.x(), ly = t.y() + ( r->GetTextFullHeight( font ) / 2 );

    for ( int i = 0; i < start->element.length(); i++ ) {
        e->x = lx;
        e->y = ly;
        ldist = e->distanceTo( target );
        if ( ldist < mindist ) {
            mindist = ldist;
            newcur = i;
        }
        if ( QChar( start->element[i] ).digitValue() == 10 ) {
            lx = t.x();
            ly = ly + r->GetTextFullHeight( font );
        } else {
            lx = lx + r->GetCharWidth( start->element[i], font );
        }
    }
    cursor = newcur;
    delete e;
}

// Select text between endpoints e1 and e2
void Text::Select( DPoint * e1, DPoint * e2 )
{
    if ( WithinBounds( e1 ) == false )
        return;
    if ( WithinBounds( e2 ) == false )
        return;
    qDebug() << "select";
    double mindist = 99999.0, ldist;
    int newcur;
    int cr1 = 0, cr2 = 0;
    QPoint t;
    int i, lx, ly;
    DPoint *e = new DPoint;

    t = GetTopLeftPoint();
    lx = t.x();
    ly = t.y() + ( r->GetTextFullHeight( font ) / 2 );
    for ( i = 0; i < start->element.length(); i++ ) {
        e->x = lx;
        e->y = ly;
        ldist = e->distanceTo( e1 );
        if ( ldist < mindist ) {
            mindist = ldist;
            newcur = i;
        }
        if ( QChar( start->element[i] ).digitValue() == 10 ) {
            cr1++;
            lx = t.x();
            ly = ly + r->GetTextFullHeight( font );
        } else {
            lx = lx + r->GetCharWidth( start->element[i], font );
        }
    }
    selectMin = newcur;
    mindist = 99999.0;
    t = GetTopLeftPoint();
    lx = t.x();
    ly = t.y() + ( r->GetTextFullHeight( font ) / 2 );
    for ( i = 0; i < start->element.length(); i++ ) {
        e->x = lx;
        e->y = ly;
        ldist = e->distanceTo( e2 );
        if ( ldist < mindist ) {
            mindist = ldist;
            newcur = i;
        }
        if ( QChar( start->element[i] ).digitValue() == 10 ) {
            cr2++;
            lx = t.x();
            ly = ly + r->GetTextFullHeight( font );
        } else {
            lx = lx + r->GetCharWidth( start->element[i], font );
        }
    }
    selectMax = newcur;
    if ( selectMin > selectMax ) {
        int swp = selectMin;

        selectMin = selectMax;
        selectMax = swp - 1;
    }
    qDebug() << selectMin << " " << selectMax;
    delete e;
}

QPoint Text::GetTopLeftPoint()
{
    bool leftcenter = true;

    if ( justify == JUSTIFY_TOPLEFT ) {
        return start->toQPoint();
    } else {
        QPoint a;
        QRect b = r->GetTextDimensions( start->element, font );

        // center on first or last character.  Try to guess what user intended
        // (a dangerous idea at best :)
        if ( ( start->element.left( 1 ) == "H" ) && ( start->element.length() > 1 ) )
            leftcenter = false;
        if ( ( start->element.left( 1 ) == "+" ) && ( start->element.length() > 1 ) )
            leftcenter = false;
        if ( ( start->element.left( 1 ) == "-" ) && ( start->element.length() > 1 ) )
            leftcenter = false;
        if ( start->element.at( 0 ).isNumber() == true )
            leftcenter = false;
        if ( whichside == 2 )
            leftcenter = false;
        if ( tjustify == TEXT_LALIGN )
            leftcenter = true;
        if ( tjustify == TEXT_CALIGN )
            leftcenter = true;
        if ( tjustify == TEXT_RALIGN )
            leftcenter = false;
        if ( leftcenter ) {
            int lc = r->GetCharWidth( start->element.at( 0 ), font );

            a.setX( qRound( start->x - lc / 2.0 ) );
        } else {
            int rc = r->GetCharWidth( start->element.at( start->element.length() - 1 ), font );

            a.setX( qRound( start->x - b.width() + rc / 2.0 ) );
        }
        a.setY( qRound( start->y - b.height() / 2.0 ) );
        return a;
    }
}

// position atom labels according to hindrance
void Text::CheckAlignment( int alignside )
{
    // 1 = left, 2 = right
    whichside = alignside;
    qDebug() << "whichside = " << whichside;
}

void Text::ForceAlignment( int alignside )
{
    tjustify = alignside;
}

// find next smaller font for subscripts
QFont Text::subscriptFont( QFont f_in )
{
    QFont f_out = f_in;

    if ( f_out.pointSize() > 1 )
        f_out.setPointSize( f_out.pointSize() - 2 );
    else
        f_out.setPixelSize( f_out.pixelSize() - 2 );

    return f_out;
}

void Text::UpdateDisplayText()
{
    return;
    // this function doesn't do anything now that we're using RichText

    // old code follows

    // use user string if justify chosen
    if ( tjustify != TEXT_AUTO ) {
        displayText = start->element;
        displayTextMask = start->elementmask;
        return;
    }
    // validate saved text, make sure format is 'appropriate'
    if ( start->element == "MeO" )
        start->element = "OMe";

    // decide how to display the text string
    if ( whichside == 1 ) {
        //cerr << "left hindered (normal) version" ;
        displayText = start->element;
        displayTextMask = start->elementmask;
        return;
    }
    // create right-aligned version.
    //cerr << "right hindered version" ;
    if ( start->element == "OMe" ) {
        displayText = "MeO";
        displayTextMask = "   ";
        return;
    }
    displayText = start->element;
    displayTextMask = start->elementmask;
}

// kate: tab-width 4; indent-width 4; space-indent on; replace-trailing-space-save on;
