/***************************************************************************
                          geowidget.cpp  -  description
                             -------------------
    begin                : Mon Feb 14 2000
    copyright            : (C) 2000 by Marc Bartsch
    email                : marc.bartsch@topmail.de
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   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 <kdebug.h>

#include "geowidget.h"
#include "geowidget.moc"

GeoWidget::GeoWidget( QWidget *parent, const char *name ) : QWidget( parent,name )
{
 	setBackgroundMode( NoBackground );

  int scnum = QApplication::desktop()->screenNumber(parent);
  QRect d = QApplication::desktop()->screenGeometry(scnum);
	intCanvasWidth = d.width();
  intCanvasHeight = d.height();
	maxX = 11;
	maxY = 7;
	unitInPercent = 5; // percent of screen height for one unit
	unitInPixel = (int)( 5 * intCanvasHeight / 100 );

	backgroundColor = Qt::white;
	gridColor = gray;
  gridLines = true;
  numbers 	= true;
  axes 			= true;
  center 		= true;
  move 			= false;
	isKiosk 	= false;
  leftPressed = false;
	boundingRects = false;

  setMouseTracking( true );

	staticOverlayList.setAutoDelete( true );
	moveOverlayList.setAutoDelete( true );

  intCanvas 		 = new QPixmap( intCanvasWidth, intCanvasHeight ); // Grid and objects
  gridOnlyCanvas = new QPixmap( intCanvasWidth, intCanvasHeight ); // Grid only
  tempMoveCanvas = new QPixmap( intCanvasWidth, intCanvasHeight ); // Grid and static objects
}

GeoWidget::~GeoWidget()
{
    delete gridOnlyCanvas;
  delete tempMoveCanvas;
  delete intCanvas;

}

void GeoWidget::paint( QRect *rect )
{
	QPoint pt = mapCanvasToWidget( rect->topLeft() );
	bitBlt( this, pt, intCanvas, *rect );
}

void 	GeoWidget::paint( QList <QRect> list )
{
	//	And now loop through all QRects in list and copy those that can	be seen.
	QRect *actual;

	for ( actual = list.first(); actual; actual = list.next() )
	{
		paint( actual );
	}
}

void GeoWidget::paintEvent( QPaintEvent * )
{
	paintWholeWidget();
}

void GeoWidget::paintWholeWidget()
{
	// if startup ( or after kiosk mode ) the grid should to be centered
	if ( center )
	{
		intCanvasLeftTopX = ( intCanvasWidth - width() ) / 2;
		intCanvasLeftTopY = ( intCanvasHeight - height() ) / 2;
	}

	//	If right border has moved so that we have to move the grid to the right
	if ( ( intCanvasWidth - intCanvasLeftTopX ) < width() )
	{
		intCanvasLeftTopX -= ( width() - ( intCanvasWidth - intCanvasLeftTopX ) );
	}

	if ( ( intCanvasHeight - intCanvasLeftTopY ) < height() )
	{
		intCanvasLeftTopY -= ( height() - ( intCanvasHeight - intCanvasLeftTopY ) );
	}

	if ( isKiosk )
	{
		bitBlt( this, 0, 0, intCanvas, 0, 0, width(), height() );
	} else {
		paint( new QRect( intCanvasLeftTopX, intCanvasLeftTopY, width(), height() ) );
	}
}

void GeoWidget::drawObjects( QList <GeoObjects> & objectList )
{
	bitBlt( intCanvas, 0, 0, gridOnlyCanvas );

	drawObjects( objectList, intCanvas );

	paintWholeWidget();
}

void GeoWidget::drawObjects( QList <GeoObjects> & objectList, QPixmap *canvas )
{
	int MaxZOrder = 0;

  QPainter *p = new QPainter;
	p->begin( canvas );

	GeoObjects *actual;
  QListIterator<GeoObjects> it( objectList );

	//	For every layer go through all objects
	for ( int y = 0; y <= MaxZOrder; y++ )
	{
		for ( actual = it.toFirst(); actual; actual = ++it )
		{
			if ( actual->getZOrder() > MaxZOrder )
			{
				MaxZOrder = actual->getZOrder();
			}

			if ( actual->getZOrder() == y )
			{
				actual->paint( p );
			}
  	}
	}

	p->end();
	delete p;
}

void GeoWidget::drawMovedObjects( QList <GeoObjects> & objectList )
{
	//	First, delete old objects.
	QRect *actual;

	//	Delete objects, that moved last time.
  QListIterator<QRect> it2( moveOverlayList );

 	for ( actual = it2.toFirst(); actual; actual = ++it2 )
 	{
 		bitBlt( intCanvas, actual->topLeft(), tempMoveCanvas, *actual );
 	}

	//	Draw objects at new position
	drawObjects( objectList, intCanvas );

	if ( boundingRects )
	{
    QPainter *p = new QPainter;
  	p->begin( intCanvas );
  	QRect *actually;
    QListIterator<QRect> it4( moveOverlayList );
   	for ( actually = it4.toFirst(); actually; actually = ++it4 )
   	{
   		p->drawRect( *actually );
  		kdDebug() << "width: " << actually->width() << " height: " << actually->height() << endl;
   	}
    QListIterator<QRect> it5( staticOverlayList );
   	for ( actually = it5.toFirst(); actually; actually = ++it4 )
   	{
   		p->drawRect( *actually );
   	}
  	p->end();
  	delete p;
	}

  paint( moveOverlayList );

	//	Save moveOverlay for next move.
	GeoObjects *actual2;
	moveOverlayList.clear();
  QListIterator<GeoObjects> it3( objectList );

 	for ( actual2 = it3.toFirst(); actual2; actual2 = ++it3 )
 	{
		actual2->getObjectOverlay( moveOverlayList );
 	}

  paint( staticOverlayList );
  paint( moveOverlayList );
}

void GeoWidget::prepareMoving( 	QList <GeoObjects> & staticObjectList,
																QList <GeoObjects> & moveObjectList   )
{
	//	Fill tempMoveCanvas with grid Background.
	bitBlt( tempMoveCanvas,0, 0, gridOnlyCanvas );

	//	Save list of overlay rects of these static and move objects.
	staticOverlayList.clear();
	moveOverlayList.clear();

	GeoObjects *actual;
  QListIterator<GeoObjects> it1( staticObjectList );

 	for ( actual = it1.toFirst(); actual; actual = ++it1 )
 	{
		actual->getObjectOverlay( staticOverlayList );
 	}

  QListIterator<GeoObjects> it2( moveObjectList );

 	for ( actual = it2.toFirst(); actual; actual = ++it2 )
 	{
		actual->getObjectOverlay( moveOverlayList );
 	}

	//	Draw objects, that will definitely not be moved on the temp canvas.
	drawObjects( staticObjectList, tempMoveCanvas );
}

void GeoWidget::clear()
{
 	bitBlt( tempMoveCanvas, 0, 0, gridOnlyCanvas );
 	bitBlt( intCanvas, 0, 0, gridOnlyCanvas );
}

void GeoWidget::mapWidgetToCanvas( Coordinates & coords )
{
	//	This function turns widget coordinates into
	//  coordinates of the pixmap canvas
	coords.setX( coords.getD_X() +  intCanvasLeftTopX - 1 );
	coords.setY( coords.getD_Y() +  intCanvasLeftTopY - 1 );
}

QPoint GeoWidget::mapCanvasToWidget( QPoint pt )
{
	//	This function turns canvas coordinates into
	//  coordinates of the widget you see on screen

	//	Coordinates in intCanvas for X
	int x = pt.x();
	x = x - intCanvasLeftTopX;

	//	Coordinates in intCanvas for Y
	int y = pt.y();
	y = y - intCanvasLeftTopY;

	return QPoint( x, y );
}

void GeoWidget::drawGrid( QPainter & p )
{
 	if ( gridLines )
 	{
 		p.setPen( QPen( lightGray, 0.5, DotLine ) );
 		for ( int k = -maxX; k <= maxX; k++ )
 		{
 			p.drawLine( k * unitInPixel, -maxY * unitInPixel, k * unitInPixel, maxY * unitInPixel );
 		}
 		for ( int k = -maxY; k <= maxY; k++ )
 		{
 			p.drawLine( -maxX * unitInPixel, k * unitInPixel, maxX * unitInPixel, k * unitInPixel );
 		}
 	}

 	if ( axes )
 	{
 		p.setPen( QPen( gridColor, 1, Qt::SolidLine ) );
 		p.drawLine( -maxX * unitInPixel, 0, maxX * unitInPixel, 0 );
		p.drawLine( 0, maxY * unitInPixel, 0, -maxY * unitInPixel );

 		if ( numbers )
 		{
 			for ( int k = -maxX; k <= maxX; k++ )
 			{
 				if ( k != 0 )
 				{
 					p.drawText( (k-1) * unitInPixel, 2, 2 * unitInPixel, unitInPixel, AlignHCenter | AlignTop, QString().setNum( k ) );
 				}
 			}
			for ( int k = -maxY; k <= maxY; k++ )
			{
 				if ( k != 0 )
				{
 					p.drawText( 2, ( k * unitInPixel ) - 13, 24, 24, AlignCenter, QString().setNum( -k ) );
 				}
 			}
 		}

		//	Little arrows
		int right = maxX * unitInPixel;
		int top = -maxY * unitInPixel;
 		p.setPen( QPen( gridColor, 1, Qt::SolidLine ) );
 		p.setBrush( gridColor );
 		QPointArray a;
 		a.setPoints ( 3, right + 6, - 3, right + 12 , 0, right + 6, 3 );
 		p.drawPolygon( a, true );
 		p.drawLine( right, 0, right + 5, 0 );
 		a.setPoints ( 3, - 3, top - 6, 0, top - 13, 3, top - 6 );
 		p.drawPolygon( a, true );
 	  p.drawLine( 0, top, 0, top - 6 );
  }
}

void GeoWidget::drawGrid()
{
	intCanvas->fill( backgroundColor );
	gridOnlyCanvas->fill( backgroundColor );
	tempMoveCanvas->fill( backgroundColor );

	QPainter p( intCanvas );
	p.setWindow( -intCanvasWidth / 2, -intCanvasHeight / 2, intCanvasWidth, intCanvasHeight );
//	p.setViewport( intCanvasWidth * 0.25, intCanvasHeight * 0.25, intCanvasWidth * 0.5, intCanvasHeight * 0.5 );
	//	p.scale( 1, -1 );
	drawGrid( p );
	p.end();

	bitBlt( gridOnlyCanvas, 0, 0, intCanvas );
	bitBlt( tempMoveCanvas, 0, 0, intCanvas );
}

void GeoWidget::moveGrid ( Coordinates coords )
{
 	int x = coords.getI_X();
 	x = x - intCanvasLeftTopX + 1;
 	int y = coords.getI_Y();
 	y = y - intCanvasLeftTopY + 2;

 	int dx = intCanvasLeftTopX - ( x - extCanvasPosX );
 	int dy = intCanvasLeftTopY - ( y - extCanvasPosY );

 	if ( dx < 0 )
 	{
 		dx = 0;
 	}
 	if ( dx + width() > intCanvasWidth )
 	{
 		dx = intCanvasWidth - width() + 2;
 	}
 	if ( dy < 0 )
 	{
 		dy = 0;
 	}
 	if ( dy + height() > intCanvasHeight )
 	{
 		dy = intCanvasHeight - height() + 2;
 	}

 	intCanvasLeftTopX = dx;
 	intCanvasLeftTopY = dy;
 	extCanvasPosX = x;
 	extCanvasPosY = y;
 	paintWholeWidget();
}

void GeoWidget::mouseMoveEvent ( QMouseEvent *ev )
{
	Coordinates coords( ev->pos() );
	mapWidgetToCanvas( coords );

	if ( leftPressed )
	{
		emit mouseMoveLeftButton( coords );
		if ( move )
		{
			moveGrid( coords );
		}
	}

	emit mouseMove( coords );
}

void GeoWidget::mousePressEvent ( QMouseEvent *ev )
{
	Coordinates coords( ev->pos() );

	if ( ev->button() == RightButton )
	{
		emit mouseRightPressEvent( coords );
	}

	if ( ev->button() == LeftButton )
	{
		leftPressed = true;
  	extCanvasPosX = ev->x();
		extCanvasPosY = ev->y();
		mapWidgetToCanvas( coords );
		emit mouseLeftPressEvent( coords );
	}
}

void GeoWidget::mouseReleaseEvent ( QMouseEvent *ev )
{
	Coordinates coords( ev->pos() );
	mapWidgetToCanvas( coords );

	if ( ev->button() == LeftButton )
	{
  	leftPressed = false;
		emit mouseLeftClickEvent( coords );
	}
}

void GeoWidget::focusOutEvent( QFocusEvent * )
{
	emit focusOut();
}

void GeoWidget::resizeEvent ( QResizeEvent * )
{
	if ( intCanvasWidth - intCanvasLeftTopX < width() )
	{
		intCanvasLeftTopX = intCanvasWidth - width() + 2;
	}

	if ( intCanvasHeight - intCanvasLeftTopY < height() )
	{
		intCanvasLeftTopY = intCanvasHeight - height() + 2;
	}
}

void GeoWidget::dragEnterEvent( QDragEnterEvent* event )
{
	event->accept( QUriDrag::canDecode( event ) );
}

void GeoWidget::dropEvent( QDropEvent* event )
{
	QStrList files;

	if ( QUriDrag::decode( event, files ) )
	{
		emit loadDropFile( QUriDrag::uriToLocalFile( files.at(0) ) );
	}
}
