/***************************************************************************
 *   Copyright (C) 2003-2005 by liuspider                                  *
 *   liuspider@users.sourceforge.net                                       *
 *                                                                         *
 *   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 2 of the License, or     *
 *   (at your option) any later version.                                   *
 ***************************************************************************/
#include "scimstringrender.h"

#include <qwidget.h>

class ScimStringRenderPrivate
{
public:
    QString text;
    scim::AttributeList attrs;
    int valid_widthhint;
    QSize storedSizeHint;
    QWidget * parent;
    int cursorPos;
};

ScimStringRender::ScimStringRender(QWidget * w) 
: d(new ScimStringRenderPrivate), fm(w->fontMetrics())
{
    d->parent = w;
    d->cursorPos = -1;
}

void ScimStringRender::drawString ( QPainter * p, const QRect & cr) const
{
//     QRect cr = contentsRect();
    static const QColorGroup& cg = d->parent->colorGroup();
    p->save();
    //it seems this fillrect is not needed, as Qt normally erases the widget's area
    p->fillRect(cr, cg.background());

    if(d->attrs.size())
    {
      uint start_index, length, wlen = d->text.length();
      QRect curRect;
      std::vector<QRect> drawForegroundRect;
      std::vector<QString> drawForegroundString;
      std::vector<scim::Attribute *> drawForegroundAttribute;

      //first draw all background and save the qrect for those which 
      //need to draw customized foreground
      for(uint i=0; i<d->attrs.size (); ++i)
      {
        curRect = cr;
        start_index = d->attrs[i].get_start();
        length = d->attrs[i].get_length();
        const QString leftPart = d->text.mid(0, start_index);
        const QString curString = d->text.mid(start_index, length);
        int newLineCount = leftPart.contains('\n');
        
        if(d->text.contains('\n') > 0) {
          int newLineBegin = d->text.findRev('\n', start_index) + 1;
          curRect.setLeft(cr.x() + 
            fm.width(d->text.mid(newLineBegin , start_index - newLineBegin)));
          curRect.setTop(cr.y() + fm.height() * newLineCount + fm.leading() * newLineCount);
          curRect.setBottom(curRect.y() + fm.height());
        } else {
          curRect.setLeft(cr.x() + fm.width(leftPart));
          curRect.setRight(curRect.x() + fm.width(curString));
        }
        
        uint dtype = d->attrs[i].get_type(), dvalue = d->attrs[i].get_value();
        bool needDrawForeground = false;
        if (start_index + length <= wlen)
        {
          if(dtype == scim::SCIM_ATTR_DECORATE)
          {
            if( dvalue == scim::SCIM_ATTR_DECORATE_UNDERLINE) {
              needDrawForeground = true;
            } else if( dvalue == scim::SCIM_ATTR_DECORATE_REVERSE){
              p->fillRect(curRect, cg.text());
              needDrawForeground = true;
            } else if( dvalue == scim::SCIM_ATTR_DECORATE_HIGHLIGHT){
              p->fillRect(curRect, cg.highlight());
              needDrawForeground = true;
            } 
          } else if(dtype == scim::SCIM_ATTR_FOREGROUND){
              needDrawForeground = true;
          } else if(dtype == scim::SCIM_ATTR_BACKGROUND){
            p->fillRect(curRect, QColor(SCIM_RGB_COLOR_RED(dvalue), 
                SCIM_RGB_COLOR_GREEN(dvalue), SCIM_RGB_COLOR_BLUE(dvalue)));
          }
          if(needDrawForeground)
          {
            drawForegroundRect.push_back(curRect);
            drawForegroundString.push_back(curString);
            drawForegroundAttribute.push_back(&d->attrs[i]);
          }
        }
      }
      
      //now draw all the string in default painter
      p->drawText(cr, Qt::AlignVCenter, d->text);

      //draw customized foreground text
      for(uint rectIndex = 0; rectIndex < drawForegroundRect.size(); ++rectIndex)
      {
//       std::cout << d->attrs[i].get_start() << "ok \n";
        uint dtype = drawForegroundAttribute[rectIndex]->get_type(), 
          dvalue = drawForegroundAttribute[rectIndex]->get_value();
        p->restore();
        p->save();
          if(dtype == scim::SCIM_ATTR_DECORATE)
          {
            if( dvalue == scim::SCIM_ATTR_DECORATE_UNDERLINE) {
              QFont f = d->parent->font();
              f.setUnderline(true);
              p->setFont(f);
            } else if( dvalue == scim::SCIM_ATTR_DECORATE_REVERSE){
              p->setPen( cg.background() );
            } else if( dvalue == scim::SCIM_ATTR_DECORATE_HIGHLIGHT){
              p->setPen( cg.highlightedText() );
            } 
          } else if(dtype == scim::SCIM_ATTR_FOREGROUND){
            p->setPen( QColor(SCIM_RGB_COLOR_RED(dvalue), 
                SCIM_RGB_COLOR_GREEN(dvalue), SCIM_RGB_COLOR_BLUE(dvalue)) );
          }
          p->drawText(drawForegroundRect[rectIndex], 
            Qt::AlignVCenter, drawForegroundString[rectIndex]);
      }
    } else
      p->drawText(cr, Qt::AlignVCenter, d->text);
     
    p->restore();
     
    //draw cursor if it is visible
    //this will not modify the painter, so we do not need to save/restore the its state
    if(d->cursorPos >= 0)
    {
      int cix = fm.width(d->text, cursorPosition());
      QPoint from( cr.x() + 1 + cix, cr.top() + (cr.height() - fm.height()) / 2);
      QPoint to = from + QPoint( 0, fm.height() );
      p->drawLine( from, to );
    }
}

void ScimStringRender::setCursorPosition ( int p ) { d->cursorPos = p; }
int ScimStringRender::cursorPosition() const  { return d->cursorPos; }
    
void ScimStringRender::setText(const QString & text, const scim::AttributeList & attrlist ) 
{
    d->text = text;
    d->attrs = attrlist;
    d->valid_widthhint = -1;
}

QSize ScimStringRender::minimumSizeHint (int hextra, int vextra) const
{
    if(d->valid_widthhint == 1)
        return d->storedSizeHint;

    d->valid_widthhint = 1;
    if(d->text.length())
    {
//       int hextra = 2 * frameWidth();
//       int vextra = hextra;
      QFontMetrics fm( d->parent->fontMetrics() );
      QRect br = fm.boundingRect( 0, 0, 2000 ,2000, 
        Qt::AlignAuto | Qt::AlignVCenter | Qt::ExpandTabs, d->text );
      d->storedSizeHint.setWidth( br.width() + hextra);
      d->storedSizeHint.setHeight( br.height() + vextra );
      return d->storedSizeHint;
    }
    else
      return QSize(0, 0);
}

ScimStringRender::~ScimStringRender()
{
    delete d;
}


