/* ====================================================================
 * Copyright (c) 2003-2008  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 "config.h"
#include "DoubleTextWidget.h"
#include "TextWidget.h"
#include "TextLineNrWidget.h"
#include "TextGlueWidget.h"
#include "sublib/TextModel.h"
#include "sublib/TextModelImpl.h"
#include "sublib/Line.h"
#include "util/String.h"

// qt
#include <QtCore/QVariant>
#include <QtGui/QLayout>
#include <QtGui/QScrollBar>
#include <QtGui/QLabel>
#include <QtGui/QToolTip>
#include <QtGui/QCheckBox>
#include <QtGui/QLineEdit>

// sys
#include <stdio.h>
#include <algorithm>



DoubleTextWidget::DoubleTextWidget( QWidget *parent, const char *name )
: super( parent, name )
{
#ifdef _WIN32
  // improve layout..
  QString cname = palette().window().color().name();
  setStyleSheet( "QLineEdit:read-only {background-color: "+cname+";} QCheckBox {spacing: 0px;}" );
#endif // _WIN32

  // base class layout
  QGridLayout* gl = (QGridLayout*)layout();
  {
    QWidget*     iw  = new QWidget(this);
    QGridLayout* iwl = new QGridLayout(iw);
    iwl->setContentsMargins(1,1,1,1);
    iwl->setSpacing(2);
    gl->addWidget( iw, 0, 0, 1, 1 );
    {
      // first row, left
      _lLabel = new QLineEdit(iw);
      _lLabel->setText( _q("left...") );
      _lLabel->setReadOnly(true);
      _lLabel->setFrame(false);
      QPalette lpal = _lLabel->palette();
      lpal.setColor( QPalette::Base, Qt::transparent );
      _lLabel->setPalette(lpal);
      iwl->addWidget( _lLabel, 0, 0, 1, 1 );
      iwl->setColStretch(0,1);

      QHBoxLayout* h = new QHBoxLayout;
      iwl->addLayout( h, 0, 1, 1, 1 );  // 2
      {
        h->addSpacing(1); 
        
        _checkLeft = new QCheckBox(iw);
        h->addWidget(_checkLeft);
        _checkLeft->toggle();

        _checkLong = new QCheckBox(iw);
        h->addWidget(_checkLong);

        _checkRight = new QCheckBox(iw);
        h->addWidget(_checkRight);
        _checkRight->toggle();

        h->addSpacing(1); 
      }

      connect( _checkLeft, SIGNAL(toggled(bool)), SLOT(toggleLeft(bool)) );
      connect( _checkRight, SIGNAL(toggled(bool)), SLOT(toggleRight(bool)) );
      connect( _checkLong, SIGNAL(toggled(bool)), SLOT(toggleLong(bool)) );

      // first row, right
      _rLabel = new QLineEdit(iw);
      _rLabel->setText( _q("right...") );
      _rLabel->setReadOnly(true);
      _rLabel->setFrame(false);
      QPalette rpal = _rLabel->palette();
      rpal.setColor( QPalette::Base, Qt::transparent );
      _rLabel->setPalette(rpal);
      iwl->addWidget( _rLabel, 0, 3, 1, 1 );
      iwl->setColStretch(3,1);
      
      // second, all
      QFrame* f = new QFrame(iw);
      f->setFrameStyle( QFrame::HLine | QFrame::Sunken );
      f->setLineWidth(1);
      iwl->addWidget( f, 1, 0, 1, 4 );

      // third, all
      QHBoxLayout* mltb = new QHBoxLayout;
      mltb->setMargin(0);
      mltb->setSpacing(0);
      iwl->addLayout( mltb, 2, 0, 1, 4 );
      {
        _lLines = new TextLineNrWidget(iw);
        _left   = new TextWidget(iw,TextWidget::Left);

        _glue   = new TextGlueWidget(iw);

        _right  = new TextWidget(iw,TextWidget::Right);
        _rLines = new TextLineNrWidget( iw, TextLineNrWidget::Right );

        //_left->setMouseTracking(true);
        //_right->setMouseTracking(true);

        mltb->addWidget(_lLines);
        mltb->addWidget(_left);
        mltb->addWidget(_glue);
        mltb->addWidget(_right);
        mltb->addWidget(_rLines);
      }

      // fourth, all
      _long = new QFrame(iw);
      _long->hide();
      _long->setContentsMargins(1,1,1,1);
      _long->setFrameStyle( QFrame::Box | QFrame::Plain );
      _long->setLineWidth(1);
      _long->setSizePolicy( QSizePolicy(QSizePolicy::Expanding,QSizePolicy::Fixed) );
      QVBoxLayout* ll = new QVBoxLayout(_long);
      ll->setContentsMargins(1,1,1,1);
      ll->setSpacing(1);
      iwl->addWidget( _long, 3, 0, 1, 4 );
      {
        TextModelImpl* lm = new TextModelImpl( _s("left") );
        TextModelImpl* rm = new TextModelImpl( _s("right") );

        _l = new TextWidget(_long,TextWidget::Left);
        _l->enableRightColMark(false);
        _l->setModel(lm,rm);
        _l->setModelSize( 0, 1 );
        _l->setSizePolicy( QSizePolicy(QSizePolicy::Expanding,QSizePolicy::Fixed) );
        ll->add(_l);

        _r = new TextWidget(_long,TextWidget::Right);
        _r->enableRightColMark(false);
        _r->setModel(rm,lm);
        _r->setModelSize( 0, 1 );
        _r->setSizePolicy( QSizePolicy(QSizePolicy::Expanding,QSizePolicy::Fixed) );
        ll->add(_r);
      }
    }
  }

  connect( _left, SIGNAL(xChanged(int)), SLOT(xChange(int)) );
  connect( _left, SIGNAL(yChanged(int)), SLOT(yChange(int)) );
  connect( _right, SIGNAL(xChanged(int)), SLOT(xChange(int)) );
  connect( _right, SIGNAL(yChanged(int)), SLOT(yChange(int)) );

  connect( _left, SIGNAL(mouseLine(int)), SLOT(mouseLine(int)) );
  connect( _right, SIGNAL(mouseLine(int)), SLOT(mouseLine(int)) );
}

DoubleTextWidget::~DoubleTextWidget()
{
}

void DoubleTextWidget::setModel( TextModel* left, TextModel* right )
{
  _left->setModel( left, right );
  _lLines->setModel( left );
  _lLabel->setText( left->getSourceName().getStr() );
  QToolTip::add( _lLabel, left->getSourceName().getStr() );

  _right->setModel( right, left );
  _rLines->setModel( right );
  _rLabel->setText( right->getSourceName().getStr() );
  QToolTip::add( _rLabel, right->getSourceName().getStr() );

  sc::Size cols = 0;
  if( left->getColumnCnt()  > cols ) cols = left->getColumnCnt();
  if( right->getColumnCnt() > cols ) cols = right->getColumnCnt();

  sc::Size lines = 0;
  if( left->getLineCnt()  > lines ) lines = left->getLineCnt();
  if( right->getLineCnt() > lines ) lines = right->getLineCnt();

  _left->setModelSize( cols, lines );
  _right->setModelSize( cols, lines );
  _glue->setLineCnt( lines );
  _glue->setModel( left, right );
}

void DoubleTextWidget::setModel( DiffInfoModel* info )
{
  _left->setModel(info);
  _right->setModel(info);
  _glue->setModel(info);
}

void DoubleTextWidget::setLeftLabel( const sc::String& l )
{
  if( l.getCharCnt() > 0 )
  {
    _lLabel->setText( (const char*)l );
  }
}

void DoubleTextWidget::setRightLabel( const sc::String& r )
{
  if( r.getCharCnt() > 0 )
  {
    _rLabel->setText( (const char*)r );
  }
}

void DoubleTextWidget::vsbChange(int y)
{
  _left->setScrollPosY(y);
  _lLines->setScrollPosY(y);

  _glue->setScrollPosY(y);

  _right->setScrollPosY(y);
  _rLines->setScrollPosY(y);
}

void DoubleTextWidget::hsbChange(int x)
{
  _left->setScrollPosX(x);
  _right->setScrollPosX(x);
}

void DoubleTextWidget::xChange(int x)
{
  if( _hsb->value() == x )
  {
    return;
  }

  _hsb->setValue(x);
}

void DoubleTextWidget::yChange(int y)
{
  if( _vsb->value() == y )
  {
    return;
  }

  _vsb->setValue(y);
}

void DoubleTextWidget::toggleLeft(bool show)
{
  if( ! show )
  {
    _lLines->hide();
    _left->hide();
    _checkRight->setEnabled(false);
  }
  else
  {
    _lLines->show();
    _left->show();
    _checkRight->setEnabled(true);
  }
}

void DoubleTextWidget::toggleRight(bool show)
{
  if( ! show )
  {
    _rLines->hide();
    _right->hide();
    _checkLeft->setEnabled(false);
  }
  else
  {
    _rLines->show();
    _right->show();
    _checkLeft->setEnabled(true);
  }
}

void DoubleTextWidget::toggleLong(bool show)
{
  if( ! show )
  {
    _long->hide();
  }
  else
  {
    _long->show();
  }
}

void DoubleTextWidget::mouseLine(int y)
{
  if( _long->isHidden() )
  {
    return;
  }

  Line l = _left->getModel()->getLine(y);
  Line r = _right->getModel()->getLine(y);

  TextModelImpl* lm = dynamic_cast<TextModelImpl*>(_l->getModel());
  lm->clear();
  lm->addLine(l);

  TextModelImpl* rm = dynamic_cast<TextModelImpl*>(_r->getModel());
  rm->clear();
  rm->addLine(r);

  _l->update();
  _r->update();
}

QSize DoubleTextWidget::getScrollSizeHint()
{
  // this one is used by our superclass to size the scrollbar
  // since we can hide our text widgets we have to return the
  // values from the visible one.
  if( _left->isVisible() )
  {
    return _left->sizeHint();
  }
  else
  {
    return _right->sizeHint();
  }
}

QSize DoubleTextWidget::getScrollSizeCurr()
{
  // this one is used by our superclass to size the scrollbar
  // since we can hide our text widgets we have to return the
  // values from the visible one.
  if( _left->isVisible() )
  {
    return _left->size();
  }
  else
  {
    return _right->size();
  }
}

TextWidget* DoubleTextWidget::getLeftText() const
{
  return _left;
}

TextWidget* DoubleTextWidget::getRightText() const
{
  return _right;
}

void DoubleTextWidget::jumpToLine( int line )
{
  int ypos = _left->calcLineY(line,true);
  vsbChange(ypos);
  
  // scrolling up trashes the horizontal scrollbar on MacOSX
  _hsb->update();

  return;
  
  if( _vsb->value() == ypos )
  {
    return;
  }

  _vsb->setValue(ypos);
}

void DoubleTextWidget::jumpToBlock( int block )
{
  BlockInfo li = _left->getModel()->getBlockInfo( block );
  BlockInfo ri = _right->getModel()->getBlockInfo( block );

  if( ! li.isEmpty() )
  {
    jumpToLine( li.getStart() );
    return;
  }

  if( ! ri.isEmpty() )
  {
    jumpToLine( ri.getStart() );
    return;
  }
}

void DoubleTextWidget::setActiveDiff( int num )
{
  _glue->setActiveDiff(num);
}

void DoubleTextWidget::setAcceptDrops(bool on)
{
  _left->setAcceptDrops(true);
  _right->setAcceptDrops(true);
}
