/* ====================================================================
 * Copyright (c) 2003-2006, Martin Hauner
 *                          http://subcommander.tigris.org
 *
 * Subcommander is licensed as described in the file doc/COPYING, which
 * you should have received as part of this distribution.
 * ====================================================================
 */

// sc
#include "TextGlueWidget.h"
#include "sublib/Line.h"
#include "sublib/TextModel.h"
#include "sublib/NullTextModel.h"
#include "PainterSetup.h"
#include "DiffInfoModel.h"
#include "TextPositionCalculator.h"
#include "ScrollPositionCalculator.h"
#include "Conflict.h"

// sys
#include <stdio.h>
#include <algorithm>
#include "util/max.h"

// qt
//#include <qpainter.h>
//#include <qpixmap.h>
#include <qbutton.h>

#include "ConflictMarkerWidget.h"

static const int dashLinePad = 1;

QColor TextGlueWidget::_bgDash(255,255,255);
QColor TextGlueWidget::_fgDash(150,150,150);

QColor TextGlueWidget::_bg(255,255,255);
QColor TextGlueWidget::_fg(230,230,230);

QColor TextGlueWidget::_fgMerge(160,170,195);



static NullTextModel nullModel;

TextGlueWidget::TextGlueWidget( QWidget *parent, const char *name )
: QWidget( parent, name ), _model(0), _left(&nullModel), _right(&nullModel),
  _lines(0), _flags(0), _ypos(0)
{
  _lnColumns = 3;
  _lnLeftPad  = 3;
  _lnRightPad = 3;

  setSizePolicy( QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Expanding) );
  setBackgroundMode( Qt::NoBackground );
}

TextGlueWidget::~TextGlueWidget()
{
}

void TextGlueWidget::setModel( DiffInfoModel* model )
{
  _model = model;
}

void TextGlueWidget::setModel( TextModel* left, TextModel* right )
{
  _left  = left;
  _right = right;

  updateGeometry();
  update();
}


QColor TextGlueWidget::getColor( DiffInfo& di, bool left )
{
  if( di.getDiffNumber() == _currDiff )
  {
    switch( di.getMergeType() )
    {
    case msModified:
      {
        if( left )
        {
          return _fgMerge;
        }
        return QColor(0,0,0);
      }
    case msLatest:
      {
        if( ! left )
        {
          return _fgMerge;
        }
        return QColor(0,0,0);
      }
    //case msNotMerged:
    //case msOriginal:
    default:
      {
        return QColor(0,0,0);
      }
    }
  }
  return _fg;
}

void TextGlueWidget::paintEvent( QPaintEvent *e )
{
  QRect pr = e->rect(); 

  PainterSetup ps(this,pr);
  QPainter& pp = ps.getPainter();

  //pp.setPen(_fg); // grey...
  pp.setBackgroundColor(_bg);

  QFontMetrics m(font());
  TextPositionCalculator tpc( m, pr, 0, _ypos );
  int topLine = tpc.getTopLine();
  int botLine = tpc.getBottomLine();
  int lnDefWidth = sizeHint().width();

  for( int curLine = topLine; curLine <= botLine; curLine++ )
  {
    // clear line background
    pp.eraseRect( 0, tpc.getLineY(curLine), lnDefWidth, m.height() );

    if( ! _model )
    {
      continue;
    }

    // the block stuff below doesn't like an invalid line but we need
    // the clear line above..
    sc::Size maxLine = std::max(_left->getLineCnt(),_right->getLineCnt());
    if( (sc::Size)curLine >= maxLine )
    {
      continue;
    }

    Line       lline    = _left->getLine(curLine);
    DiffInfo&  linfo    = _model->getInfo( lline.getBlockNr() );
    const BlockInfo& lb = linfo.getBlockInfo();
    QColor     lcolor   = getColor( linfo, true );

    Line       rline    = _right->getLine(curLine);
    DiffInfo&  rinfo    = _model->getInfo( rline.getBlockNr() );
    const BlockInfo& rb = rinfo.getBlockInfo();
    QColor     rcolor   = getColor( rinfo, false );

    if( lb.getStart() == curLine && (lline.isDifference() || rline.isDifference()) )
    {
      if( linfo.getDiffNumber() == _currDiff || rinfo.getDiffNumber() == _currDiff )
      {
        pp.setPen(QColor(0,0,0));
      }
      else
      {
        pp.setPen(_fg);
      }

      // draw text centered
      char lnBuf[32];
      int  lnLength  = sprintf( lnBuf, "%d", linfo.getDiffNumber() );
      int  lnWidth   = m.width( lnBuf, lnLength );
      pp.drawText( (lnDefWidth/2)-(lnWidth/2), tpc.getTextY(curLine), lnBuf, lnLength );
    }

    if( lline.isDifference() )
    {
      pp.setPen( lcolor );

      if( lb.getStart() == curLine )
      {
        pp.drawRect( 2, tpc.getLineY(curLine), 2, 2 );
      }

      pp.drawRect( 4, tpc.getLineY(curLine), 2, m.height() );
    }

    if( rline.isDifference() )
    {
      pp.setPen( rcolor );

      if( rb.getStart() == curLine )
      {
        pp.drawRect( lnDefWidth-4, tpc.getLineY(curLine), 2, 2 );
      }

      pp.drawRect( lnDefWidth-6, tpc.getLineY(curLine), 2, m.height() );
    }
  }

  // left dash line
  pp.setPen( _bgDash );
  pp.drawLine( 0, pr.y(), 0, pr.y()+pr.height() );

  pp.setPen( _fgDash );
  for( int d = pr.y()+(_ypos + pr.y())%2; d < pr.y()+pr.height(); d+=2 )
  {
    pp.drawPoint( 0, d );
  }

  // right dash line
  pp.setPen( _bgDash );
  pp.drawLine( lnDefWidth-dashLinePad, pr.y(), lnDefWidth-dashLinePad, pr.y()+pr.height() );

  pp.setPen( _fgDash );
  for( int d = pr.y()+(_ypos + pr.y())%2; d < pr.y()+pr.height(); d+=2 )
  {
    pp.drawPoint( lnDefWidth-dashLinePad, d );
  }
}

void TextGlueWidget::setScrollPosY( int ypos )
{
  ScrollPositionCalculator spc;
  int oy = _ypos;
  int ny = spc.calcPos( oy, ypos, height(), sizeHint().height() );

  if( oy == ny )
  {
    return;
  }

  _ypos = ny;
  super::scroll( 0, oy - _ypos );
}

void TextGlueWidget::setLineCnt( sc::Size l )
{
  _lines = l;
}

void TextGlueWidget::setActiveDiff( int num )
{
  _currDiff = num;
  update();
}

QSize TextGlueWidget::sizeHint() const
{
  QFontMetrics m(font());
  sc::Size width  = m.width('x')*_lnColumns + _lnLeftPad + _lnRightPad + 2*dashLinePad;
  sc::Size height = m.height()  *_lines;
  return QSize( (int)width, (int)height );
}

#if 0
int TextGlueWidget::width() const
{
  return super::width();
}

int TextGlueWidget::height() const
{
  return super::height();
}
#endif

#if 0
  DiffInfos infos = _model->getInfos();
  DiffInfo  info;

  for( DiffInfos::iterator it = infos.begin(); it != infos.end(); it++ )
  {
    const DiffInfo& info = (*it);

    if( info.getBlockInfo().getStart() < topLine )
    {
      info =
    }
  }
    for( DiffInfos::iterator it = infos.begin(); it != infos.end(); it++ )
    {
      const DiffInfo& info = (*it);

      if( info.getType() != ctCommon )
      {
      }
    }
#endif


syntax highlighted by Code2HTML, v. 0.9.1