/***************************************************************************
                          kompareconnectwidget.cpp  -  description
                             -------------------
    begin                : Tue Jun 26 2001
    copyright            : (C) 2001-2003 John Firebaugh
                           (C) 2001-2004 Otto Bruggeman
                           (C) 2004      Jeff Snyder
    email                : jfirebaugh@kde.org
                           otto.bruggeman@home.nl
                           jeff@caffeinated.me.uk
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   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 <tqapplication.h>
#include <tqpainter.h>
#include <tqpixmap.h>
#include <tqstyle.h>
#include <tqtimer.h>

#include <kdebug.h>

#include "viewsettings.h"
#include "komparemodellist.h"
#include "komparelistview.h"
#include "komparesplitter.h"

#include "kompareconnectwidget.h"

using namespace Diff2;

KompareConnectWidgetFrame::KompareConnectWidgetFrame( KompareListView* left,
                                                      KompareListView* right,
                                                      ViewSettings* settings,
                                                      KompareSplitter* parent,
                                                      const char* name ) :
	TQSplitterHandle(TQt::Horizontal, (TQSplitter *)parent, name),
	m_wid ( left, right, settings, this, name ),
	m_label ( "", this ),
	m_layout ( this )
{
	setSizePolicy ( TQSizePolicy(TQSizePolicy::Fixed, TQSizePolicy::Ignored) );
	m_wid.setSizePolicy ( TQSizePolicy(TQSizePolicy::Ignored, TQSizePolicy::Ignored) );
	m_label.setSizePolicy ( TQSizePolicy(TQSizePolicy::Ignored, TQSizePolicy::Fixed) );
	m_label.setMargin(3);
	TQFrame* bottomLine = new TQFrame(this);
	bottomLine->setFrameShape(TQFrame::HLine);
	bottomLine->setFrameShadow ( TQFrame::Plain );
	bottomLine->setSizePolicy ( TQSizePolicy(TQSizePolicy::Ignored, TQSizePolicy::Fixed) );
	bottomLine->setFixedHeight(1);
	m_layout.setSpacing(0);
	m_layout.setMargin(0);
	m_layout.addWidget(&m_label);
	m_layout.addWidget(bottomLine);
	m_layout.addWidget(&m_wid);
}

KompareConnectWidgetFrame::~KompareConnectWidgetFrame()
{
}

TQSize KompareConnectWidgetFrame::sizeHint() const
{
	return TQSize(50, style().pixelMetric( TQStyle::PM_ScrollBarExtent ) );
}

static int kMouseOffset;

void KompareConnectWidgetFrame::mouseMoveEvent( TQMouseEvent *e )
{
	if ( !(e->state()&TQt::LeftButton) )
		return;

	TQCOORD pos = s->pick( parentWidget()->mapFromGlobal(e->globalPos()) )
		- kMouseOffset;

	((KompareSplitter*)s)->moveSplitter( pos, id() );
}

void KompareConnectWidgetFrame::mousePressEvent( TQMouseEvent *e )
{
	if ( e->button() == TQt::LeftButton )
		kMouseOffset = s->pick( e->pos() );
	TQSplitterHandle::mousePressEvent(e);
}

void KompareConnectWidgetFrame::mouseReleaseEvent( TQMouseEvent *e )
{
	if ( !opaque() && e->button() == TQt::LeftButton ) {
		TQCOORD pos = s->pick( parentWidget()->mapFromGlobal(e->globalPos()) )
			- kMouseOffset;
		((KompareSplitter*)s)->moveSplitter( pos, id() );
    }
}

KompareConnectWidget::KompareConnectWidget( KompareListView* left, KompareListView* right,
      ViewSettings* settings, TQWidget* parent, const char* name )
	: TQWidget(parent, name),
	m_settings( settings ),
	m_leftView( left ),
	m_rightView( right ),
	m_selectedModel( 0 ),
	m_selectedDifference( 0 )
{
//	connect( m_settings, TQ_SIGNAL( settingsChanged() ), this, TQ_SLOT( slotDelayedRepaint() ) );
	setBackgroundMode( NoBackground );
	setSizePolicy( TQSizePolicy( TQSizePolicy::Fixed, TQSizePolicy::Minimum ) );
	setFocusProxy( parent->parentWidget() );
}

KompareConnectWidget::~KompareConnectWidget()
{
}

void KompareConnectWidget::slotSetSelection( const DiffModel* model, const Difference* diff )
{
	if( m_selectedModel == model && m_selectedDifference == diff )
		return;

	if ( m_selectedModel == model && m_selectedDifference != diff )
	{
		m_selectedDifference = diff;
		slotDelayedRepaint();
		return;
	}

	m_selectedModel = model;
	m_selectedDifference = diff;

	slotDelayedRepaint();
}

void KompareConnectWidget::slotDelayedRepaint()
{
	TQTimer::singleShot( 0, this, TQ_SLOT( repaint() ) );
}

void KompareConnectWidget::slotSetSelection( const Difference* diff )
{
	if ( m_selectedDifference == diff )
		return;

	m_selectedDifference = diff;

	slotDelayedRepaint();
}

void KompareConnectWidget::paintEvent( TQPaintEvent* /* e */ )
{
//	kdDebug(8106) << "KompareConnectWidget::paintEvent()" << endl;

	TQPixmap pixbuf(size());
	TQPainter paint(&pixbuf, this);
	TQPainter* p = &paint;

	p->fillRect( 0, 0, pixbuf.width(), pixbuf.height(), white.dark(110) );

	if ( m_selectedModel )
	{
		int firstL = m_leftView->firstVisibleDifference();
		int firstR = m_rightView->firstVisibleDifference();
		int lastL = m_leftView->lastVisibleDifference();
		int lastR = m_rightView->lastVisibleDifference();

		int first = firstL < 0 ? firstR : TQMIN( firstL, firstR );
		int last = lastL < 0 ? lastR : TQMAX( lastL, lastR );

//		kdDebug(8106) << "    left: " << firstL << " - " << lastL << endl;
//		kdDebug(8106) << "   right: " << firstR << " - " << lastR << endl;
//		kdDebug(8106) << " drawing: " << first << " - " << last << endl;
		if ( first >= 0 && last >= 0 && first <= last )
		{
			const DifferenceList* differences  = const_cast<DiffModel*>(m_selectedModel)->differences();
			DifferenceListConstIterator diffIt = differences->at( first );
			DifferenceListConstIterator dEnd   = differences->at( last + 1 );

			TQRect leftRect, rightRect;

			for ( int i = first; i <= last; ++diffIt, ++i )
			{
				Difference* diff = *diffIt;
				bool selected = ( diff == m_selectedDifference );

				if ( TQApplication::reverseLayout() )
				{
					leftRect = m_rightView->itemRect( i );
					rightRect = m_leftView->itemRect( i );
				}
				else
				{
					leftRect = m_leftView->itemRect( i );
					rightRect = m_rightView->itemRect( i );
				}

				int tl = leftRect.top();
				int tr = rightRect.top();
				int bl = leftRect.bottom();
				int br = rightRect.bottom();

				// Bah, stupid 16-bit signed shorts in that crappy X stuff...
				tl = tl >= -32768 ? tl : -32768;
				tr = tr >= -32768 ? tr : -32768;
				bl = bl <=  32767 ? bl :  32767;
				br = br <=  32767 ? br :  32767;

//				kdDebug(8106) << "drawing: " << tl << " " << tr << " " << bl << " " << br << endl;
				TQPointArray topBezier = makeTopBezier( tl, tr );
				TQPointArray bottomBezier = makeBottomBezier( bl, br );

				TQColor color = m_settings->colorForDifferenceType( diff->type(), selected, diff->applied() ).dark(110);
				p->setPen( color );
				p->setBrush( color );
				p->drawPolygon ( makeConnectPoly( topBezier, bottomBezier ) );

				if ( selected )
				{
					p->setPen( color.dark(135) );
					p->drawPolyline( topBezier );
					p->drawPolyline( bottomBezier );
				}
			}
		}
	}

	p->flush();
	bitBlt(this, 0, 0, &pixbuf);
}

TQPointArray KompareConnectWidget::makeTopBezier( int tl, int tr )
{
	int l = 0;
	int r = width();
	int o = (int)((double)r*0.4); // 40% of width
	TQPointArray controlPoints;

	if ( tl != tr )
	{
		controlPoints.setPoints( 4, l,tl, o,tl, r-o,tr, r,tr );
		return controlPoints.cubicBezier();
	}
	else
	{
		controlPoints.setPoints( 2, l,tl, r,tr );
		return controlPoints;
	}
}

TQPointArray KompareConnectWidget::makeBottomBezier( int bl, int br )
{
	int l = 0;
	int r = width();
	int o = (int)((double)r*0.4); // 40% of width
	TQPointArray controlPoints;

	if ( bl != br )
	{
		controlPoints.setPoints( 4, r,br, r-o,br, o,bl, l,bl );
		return controlPoints.cubicBezier();
	}
	else
	{
		controlPoints.setPoints( 2, r,br, l,bl );
		return controlPoints;
	}
}

TQPointArray KompareConnectWidget::makeConnectPoly( const TQPointArray& topBezier, const TQPointArray& bottomBezier )
{
	TQPointArray poly( topBezier.size() + bottomBezier.size() );
	for( uint i = 0; i < topBezier.size(); i++ )
		poly.setPoint( i, topBezier.point( i ) );
	for( uint i = 0; i < bottomBezier.size(); i++ )
		poly.setPoint( i + topBezier.size(), bottomBezier.point( i ) );

	return poly;
}

#include "kompareconnectwidget.moc"
