/***************************************************************************
                          kgeoFileHandling.cpp  -  description
                             -------------------
    begin                : Fri Sep 29 2000
    copyright            : (C) 2000 by Marc Bartsch
    email                : marc.bartsch@web.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 "kgeo.h"

void KGeoApp::deleteAllObjects()
{
	canvas->clear();

	newObject = 0;
	currentObject = 0;
	paramObjects.clear();

	objectList.setAutoDelete( true );
	objectList.clear();
	objectList.setAutoDelete( false );
}

void KGeoApp::newDrawing()
{
	int result;
	result = QMessageBox::warning ( 0, i18n( "KGeo - Unsaved Data" ),
						i18n( "The construction might contain "
									"unsaved data!\n\nDo you want to save "
									"before creating a new drawing?" ),
						QMessageBox::Yes | QMessageBox::Default,
						QMessageBox::No, QMessageBox::Cancel | QMessageBox::Escape );

	if ( result == QMessageBox::Yes )
	{
			saveDrawingDialog();
			deleteAllObjects();
			canvas->drawObjects( objectList );
			currentFilename = i18n( "New drawing" );
			printFilenameInWindowTitle();
			unnamedDrawing = true;
	}

	if ( result == QMessageBox::No )
	{
			kapp->setOverrideCursor( waitCursor );
			deleteAllObjects();
			canvas->drawObjects( objectList );
			currentFilename = i18n( "New drawing" );
			printFilenameInWindowTitle();
			kapp->restoreOverrideCursor();
			unnamedDrawing = true;
	}
}

void KGeoApp::loadDrawingDialog()
{
	QString fileName = KFileDialog::getOpenFileName ( 0, "*.kgeo" );

	if ( ( !fileName.isEmpty() ) && ( QFile::exists( fileName ) ) )
	{
		loadDrawing( fileName );
	}
}

void KGeoApp::loadDrawing( QString fileName )
{
	if ( ( !fileName.isEmpty() ) && ( QFile::exists( fileName ) ) )
	{
		kapp->setOverrideCursor( waitCursor );

		KSimpleConfig *config = new KSimpleConfig( fileName );

		loadMetrics( config );
		loadObjects( config );

		delete config;

		canvas->drawGrid();
		canvas->drawObjects( objectList );

		currentFilename = fileName;
		printFilenameInWindowTitle();
		updateRecentFiles( fileName );
		kapp->restoreOverrideCursor();
		unnamedDrawing = false;
	}
}

void KGeoApp::saveDrawing( QString fileName )
{
 	kapp->setOverrideCursor( waitCursor );

 	//	Create configObject
 	QFile file( fileName );
 	file.remove();
 	file.close();

 	KSimpleConfig *config = new KSimpleConfig( fileName );

 	saveMetrics( config );
 	saveObjects( config );

 	config->sync();
 	delete config;

 	currentFilename = fileName;
 	printFilenameInWindowTitle();
 	kapp->restoreOverrideCursor();
 	unnamedDrawing = false;
}

void KGeoApp::saveObjects( KSimpleConfig *config )
{
 	QString parentList;
 	QString group;
 	QString temp;
 	GeoObjects *actual;

 	config->setGroup( "Main" );
 	config->writeEntry( "Version", "KGeo 1.0.2" );

 	int number = objectList.count();
 	config->writeEntry( "Number", number );

 	//	Save object internal data like size, color etc.
 	//	and list of parents. The number assign corresponds with
 	//	the number of the object
 	for ( int i = 0; i < ( int ) objectList.count(); i++ )
 	{
 		group = "";
 		group.setNum( i + 1 );
 		group.prepend( "Object " );
 		config->setGroup( group );
 		objectList.at( i )->writeToFile( config );

 		//	Save parents of object
 		parentList = "";
 		for ( actual = objectList.at( i )->parents.first(); actual; actual = objectList.at( i )->parents.next() )
 		{
 			temp = "";
 			temp.setNum( objectList.find( actual ) + 1 );
 			parentList.append( temp + ",");
 		}
 		parentList.truncate( parentList.length() - 1 );
 		config->writeEntry( "Parents",  parentList );
 	}
}

void KGeoApp::saveMetrics( KSimpleConfig *config )
{
 	config->setGroup( "Main" );
 	config->writeEntry( "XMax", MetricsCenter::xMax );
 	config->writeEntry( "YMax", MetricsCenter::yMax );
 	config->writeEntry( "Scaling", !MetricsCenter::isSquare );
 	config->writeEntry( "Grid", MetricsCenter::grid );
 	config->writeEntry( "Axes", MetricsCenter::axes );
 	config->writeEntry( "Numbers", MetricsCenter::numbers );

 	config->setGroup( "Colors" );
 	kapp->config()->setGroup( "Colors" );
	config->writeEntry( "Draw", kapp->config()->readColorEntry( "Draw" ) );
	config->writeEntry( "Background", kapp->config()->readColorEntry( "Background" ) );
}

void KGeoApp::loadObjects( KSimpleConfig *config )
{
 	QString group;
 	deleteAllObjects();
 	QList <GeoObjects> list;

 	config->setGroup( "Main" );
 	int number = config->readNumEntry( "Number" );

 	//	Iterate over all objects, create the specific object and insert it into list
 	for ( int i = 0; i < number; i++ )
 	{
 		group = "";
 		group.setNum( i + 1 );
 		group.prepend( "Object " );
 		config->setGroup( group );
 		int geo = config->readNumEntry( "Geo" );

 		switch ( geo )
 		{
 			case ID_point:
 				list.append( new Point() );
 				break;
 			case ID_segment:
 				list.append( new Segment() );
 				break;
 			case ID_circle:
 				list.append( new Circle() );
 				break;
 			case ID_line:
 				list.append( new Line() );
 				break;
 			case ID_bisection:
 				list.append( new Bisection() );
 				break;
 			case ID_fixedCircle:
 				list.append( new FixedCircle() );
 				break;
 			case ID_pointOfConc:
 				list.append( new PointOfConc() );
 				break;
 			case ID_angle:
 				list.append( new Angle() );
 				break;
 			case ID_mirrorPoint:
 				list.append( new MirrorPoint() );
 				break;
 			case ID_distance:
 				list.append( new Distance() );
 				break;
 			case ID_arc:
 				list.append( new Arc() );
 				break;
 			case ID_area:
 				list.append( new Area() );
 				break;
 			case ID_slope:
 				list.append( new Slope() );
 				break;
 			case ID_circumference:
 				list.append( new Circumference() );
 				break;
 			case ID_vector:
 				list.append( new Vector() );
 				break;
 			case ID_ray:
 				list.append( new Ray() );
 				break;
 			case ID_perpendicular:
 				list.append( new Perpendicular() );
 				break;
 			case ID_parallel:
 				list.append( new Parallel() );
 				break;
 			case ID_move:
 				list.append( new Move() );
 				break;
 			case ID_rotation:
 				list.append( new Rotation() );
 				break;
 			case ID_text:
 				list.append( new Text() );
 				break;
 		}
 	}

 	//	Iterate over objects again and set parents and children
 	//	according to what's in the file.
 	QStrList parentList;

 	for ( int i = 0; i < number; i++ )
 	{
 		parentList.clear();
 		group = "";
 		group.setNum( i + 1 );
 		group.prepend( "Object " );
 		config->setGroup( group );
 		config->readListEntry( "Parents", parentList );

 		char *parent;
 		int  parentIndex;

 		for ( parent = parentList.first(); parent; parent = parentList.next() )
 		{
 			parentIndex = QString( parent ).toInt();

	   	if ( parentIndex != 0 )
			{

 				( list.at( i ) )->parents.append( ( list.at( parentIndex - 1) ) );
 				( list.at( parentIndex - 1 ) )->children.append( list.at( i ) );
			}
 		}
 	}

	//	Call the object to load its own data from the file
 	for ( int i = 0; i < number; i++ )
 	{
 		group = "";
 		group.setNum( i + 1 );
 		group.prepend( "Object " );
 		config->setGroup( group );
 		list.at( i )->readFromFile( config );
 	}

	//	Call the object to move once so everything is up to date.
 	for ( int i = 0; i < number; i++ )
 	{
		list.at( i )->move();
 		list.at( i )->setUniqueID( i );
 	}

	objectList = list;
}

void KGeoApp::loadMetrics( KSimpleConfig *config )
{
	//	Load new metrics from file
	config->setGroup( "Main" );
	MetricsCenter::xMax = config->readNumEntry( "XMax", 16 );
	MetricsCenter::yMax = config->readNumEntry( "YMax", 11 );
	MetricsCenter::grid = config->readBoolEntry( "Grid", true );
	MetricsCenter::axes = config->readBoolEntry( "Axes", true );
	MetricsCenter::numbers = config->readBoolEntry( "Numbers", true );
	MetricsCenter::isSquare = !config->readBoolEntry( "Scaling", false );
	MetricsCenter::generateMetrics();

	//	Save new metrics to global config file
	kapp->config()->setGroup( "Grid" );
	kapp->config()->writeEntry( "GridLines", MetricsCenter::grid );
	kapp->config()->writeEntry( "Axes", MetricsCenter::axes	);
	kapp->config()->writeEntry( "Numbers", MetricsCenter::numbers );
	kapp->config()->writeEntry( "HighestXValue", MetricsCenter::xMax );
	kapp->config()->writeEntry( "HighestYValue", MetricsCenter::yMax );
	kapp->config()->writeEntry( "AllowScaling", !MetricsCenter::isSquare );

 	config->setGroup( "Colors" );
	kapp->config()->setGroup( "Colors" );
	QColor backgroundColor, drawColor;

	if ( config->hasKey( "Draw" ) )
	{
		drawColor = config->readColorEntry( "Draw" );
	}
	else
	{
		drawColor = Qt::black;
	}

	if ( config->hasKey( "Background" ) )
	{
		backgroundColor = config->readColorEntry( "Background" );
	}
	else
	{
		backgroundColor = Qt::white;
	}

	kapp->config()->writeEntry( "Draw", drawColor );
	kapp->config()->writeEntry( "Background", backgroundColor );
  colorLabel->setDrawColor( drawColor );
  colorLabel->setBackgroundColor( backgroundColor );
  canvas->setBackgroundColor( backgroundColor );
}

void KGeoApp::saveDrawingDialog()
{
}

void KGeoApp::saveAsDrawingDialog()
{
}

void KGeoApp::fillRecentMenu()
{
	recentFilesMenu->clear();
	recentFiles.first();
	for (int i = 1; i <= 5; i++ )
	{
		char *name = recentFiles.current();
		if( !name) break;
		QString s = QString().setNum( i );
		s = "&" + s + "."+ name;
		recentFilesMenu->insertItem( s, i);
		recentFiles.next();
	}
}

void KGeoApp::loadRecent( int id )
{
	QString fileName = recentFiles.at( id - 1 );
	loadDrawing( fileName );
}

void KGeoApp::updateRecentFiles( QString newName )
{
#if QT_VERSION < 300
	recentFiles.remove( newName );
	recentFiles.insert( 0, newName );
#else
        recentFiles.remove( newName.ascii() );
	recentFiles.insert( 0, newName.ascii() );
#endif
	while ( recentFiles.count() > 5 )
		recentFiles.removeLast();

	kapp->config()->setGroup("Recent");
	kapp->config()->writeEntry( "List", recentFiles );
}

void KGeoApp::printDialog()
{
	KPrinter prn;
	prn.setOrientation( KPrinter::Landscape );

	if ( prn.setup() )
	{
		kapp->setOverrideCursor( waitCursor );

		//	Create painter object
	  QPainter *p = new QPainter;
		p->begin( &prn );

		// Generate ratio of width and height of pixmap on screen
        int scnum = QApplication::desktop()->screenNumber(this);
   	QRect d = QApplication::desktop()->screenGeometry(scnum);
	 	double intCanvasWidth = d.width();
  	double intCanvasHeight = d.height();
		double intCanvasRatio = intCanvasWidth / intCanvasHeight;

		// Generate the height and width of the printer area minus
		// left/right/top/bottom margins ( = 5mm ?)
		QPaintDeviceMetrics metrics ( &prn );
		double widthMMRatio = (double)5 / (double)metrics.widthMM();
		double heightMMRatio = (double)5 / (double)metrics.heightMM();
  	double leftMargin =  (double) metrics.width() * (double) widthMMRatio;
  	double topMargin =  (double) metrics.height() * (double) heightMMRatio;
		double printerWidth = (double) metrics.width() - ( 2 * leftMargin );
		double printerHeight = (double) metrics.height() - ( 2 * topMargin );

		// Generate the ratio of the printer width and height
		double printerRatio = printerWidth / printerHeight;

		// If the ratio is higher, then take the height as defining value,
		// if lower take the width. That is because then we can be sure the
		// dimension (width/height) fits in the page. Recalculate second dimension
		//	and margin.
    if ( printerRatio > intCanvasRatio )
		{
			printerWidth = printerHeight * intCanvasRatio;
	  	leftMargin =  ( metrics.width() - printerWidth ) / 2;
		}
		else
		{
			printerHeight = printerHeight / intCanvasRatio;
	  	topMargin =  ( metrics.height() - printerHeight ) / 2;
		}

		// Set viewPort
		p->setWindow( -intCanvasWidth / 2, -intCanvasHeight / 2, intCanvasWidth, intCanvasHeight );
		p->setViewport( leftMargin, topMargin, printerWidth, printerHeight );

		//	Draw grid
		canvas->drawGrid( *p );

		p->setWindow( 0, 0, intCanvasWidth, intCanvasHeight );
		p->setViewport( leftMargin, topMargin, printerWidth, printerHeight );

  	int MaxZOrder = 0;

  	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 );
  			}
    	}
  	}

		//	Print page
  	p->end();
		delete p;

		kapp->restoreOverrideCursor();
	}
}
