/***************************************************************************
 *   Copyright (C) 2004 by Juergen Thies                                   *
 *   layout@juergenthies.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.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/
#define _USE_MATH_DEFINES
#include "tld.h"
#include <qfile.h>
#include <qstring.h>
#include <qtextstream.h>
#include "general/drawingfield.h"
//#include <q3pointarray.h>
#include "general/layers.h"
#include "elements/celllist.h"
#include "elements/cell.h"
#include "elements/path.h"
#include "elements/polygon.h"
#include "elements/strans.h"
#include <qmessagebox.h>
#include "general/setup.h"
#include "elements/element.h"
#include <qstringlist.h>
#include "layout.h"
#include <math.h>
#include <QFileInfo>
#include "general/errorreport.h"


tld::tld(QObject *parent, const char *)
 : QObject(parent)
{
  additionalLoad=false;
  additionalFiles.clear();;
  additionalPath="";
}


tld::~tld()
{
}


void tld::open(QString fileName,drawingField *d){
  tld tldClass;
  tldClass.load(fileName,d,fileOpen);
}

void tld::import(QString fileName,drawingField *d){
  tld tldClass;
  tldClass.load(fileName,d,fileImport);
}

void tld::update(QString fileName,drawingField *d){
  tld tldClass;
  tldClass.load(fileName,d,fileUpdate);
}

void tld::load(QString fileName,drawingField *d, fileOpenType typ){
  if (!additionalLoad) {
  if (typ==fileImport) {
  	report.setTitle(tr("Import of TLD/TLC-File \"")+fileName+"\"");}
  else  if (typ==fileOpen){
	report.setTitle(tr("Open of TLD/TLC-File \"")+fileName+"\"");}
  else  if (typ==fileUpdate){
	report.setTitle(tr("Update with TLD/TLC-File \"")+fileName+"\"");}
  }
try { 
#ifdef printtime
  setup::centralTimer.start();
#endif
  cellList *firstcellhelp=d->firstCell;
  double databaseunitshelp=d->databaseunits;
  //double scale=1.0/d->userunits*setup::apLamda;
  //int lamda=element::round(1.0/d->userunits*setup::apLamda);
  //int lamdaHalf=lamda/2;
//printf("%f\n",scale);
//printf("uu %f\n",d->userunits);
//printf("lamda %f\n",setup::apLamda);
//printf("load %s \n",fileName.toAscii().data());
  QFile f( fileName );
  if ( !f.open( QIODevice::ReadOnly ) )
	  throw QString(tr("Can not open File: %1").arg(fileName));
  if (!additionalLoad) {
	  QFileInfo fi(f);
	  additionalPath=fi.absolutePath();
  }
  if ((typ==fileImport)||(typ==fileUpdate)) {
	d->firstCell=NULL;
  }
  //printf("1\n");
  QTextStream ts( &f );
  QString s="";
  QString section="none";
  int secCount=0;
  cellList *cell_list=NULL;
  cell *cell_=NULL;
  int layer=1;
  int numPoints=0;
  int width=0;
  int orientation=0;
  QPoint point;
  QString cellrefname="";
  while (!ts.atEnd()){
  s=ts.readLine().trimmed();
  //printf("%s (%s)\n",s.left(1).toAscii().data(),s.toAscii().data());
  if (s.left(1)=="=") s="<"+s.mid(1,1)+">";
  if ((s.left(5)=="<?xml")||
	  (s.left(5)=="<TLC>")||
	  (s.left(5)=="<TLD>")||
	  (s.length()==0)||
	  (s.left(2)=="</")){
  }
  else if ((s.left(1)=="<")&&(s.mid(2,1)==">")){
	if (section==""){}
	if (s.left(3)=="<H>"){
		section="H";
		secCount=0;
		cell_list=d->addCell();
		cell_=cell_list->thisCell;
		}
	else if (s.left(3)=="<L>"){
		section="L";
		secCount=0;
	}
	else if (s.left(3)=="<B>"){
		section="B";
		secCount=0;
	}
	else if (s.left(3)=="<P>"){
		section="P";
		secCount=0;
	}
	else if (s.left(3)=="<T>"){
		section="T";
		secCount=0;
	}
	else if (s.left(3)=="<C>"){
		section="C";
		secCount=0;
	}
	else section="unknown";
	if (((section=="B")||(section=="T")||(section=="P")||(section=="C"))&&(cell_==NULL)){
		// post header
		cell_list=d->addCell();
		cell_=cell_list->thisCell;
	}
  }
  else {
		secCount++;
		if (section=="H") {
			switch (secCount){
			case 1: //cellname
				cell_->cellName=s;
				break;
			case 4: //TLC Units per Physical Unit
				width=getInt(&s);
				break;
			case 5: //Physical Unit
				{
					double u=1E-6;
					QString unit=getString(&s); 
					if (unit=="nm") u=1E-9;
					else if (unit=="m") u=1;
					else if (unit=="mm") u=1E-3;
					else if ((unit=="lamba")||(unit=="lam")) u=setup::tldLamda*1E-6;
					d->databaseunits=u/width;
					d->userunits=1.0/width;
				}
				break;
			case 6: //date
				break;
			case 7: //time
				break;
			}
		}
		else if (section=="L"){
			if (secCount!=1){
			QString name=getString(&s);
			layer=getInt(&s);
			if ((layer<0)||(layer>layersMax)){
				report.addItem(tr("layer out of range"),3,name);
			    //printf("layer %d %s\n",layer,name.toAscii().data());
				}
			else{
				layers::num[layer].name=name;
				if (layout::debug) printf("layer %d %s\n",layer,name.toAscii().data());
			}
			}
		}
		else if (section=="B"){
			layer=getInt(&s);
			int x1=getInt(&s);
			int y1=getInt(&s);
			int x2=getInt(&s);
			int y2=getInt(&s);
			cell_->addBox(x1,y1,x2-x1,y2-y1,layer);
			if (layout::debug) printf("box %d %d %d %d %d\n",layer,x1,x2,y1,y2);

		}
		else if (section=="C"){
			if (secCount==1){
				cellrefname=s;
				orientation=getInt(&s);
			}
			else if(secCount==2){
				orientation=getInt(&s);
				int x=getInt(&s);
				int y=getInt(&s);
				point=QPoint(x,y);
				element *e=cell_->addCellref();
				e->setPos(point);
				e->setCellRef(d->findCell(cellrefname));
				e->setName(cellrefname);
				bool mirror=false;
				int angle=0;
				if ((orientation&3)==1) angle=90;
				else if ((orientation&3)==2) angle=180;
				else if ((orientation&3)==3) angle=270;
				if ((orientation&4)!=0) mirror=true;
				if(mirror)e->rotate(-angle);
				else e->rotate(angle);
				if(mirror)e->setMirrorx();
				if (layout::debug) printf("cellref %s\n",cellrefname.toAscii().data());
			}
		}
		else if (section=="T"){
			if (secCount==1){
				layer=getInt(&s);
				width=getInt(&s);
				numPoints=getInt(&s);
				orientation=getInt(&s);
			}
			else if(secCount==2){
				int x=getInt(&s);
				int y=getInt(&s);
				point=QPoint(x,y);
			}
			else if(secCount==3){
				element *e=cell_->addText(layer,point,s);
				e->setWidth(width);
				bool mirror=false;
				int angle=0;
				if ((orientation&3)==1) angle=90;
				else if ((orientation&3)==2) angle=180;
				else if ((orientation&3)==3) angle=270;
				if ((orientation&4)!=0) mirror=true;
				if(mirror)e->rotate(-angle);
				else e->rotate(angle);
				if(mirror)e->setMirrorx();
				e->setPresentation(setup::defaultTextPresentation);
				if (layout::debug) printf("text %d\n",layer);
			}
			

		}
		else if (section=="P"){
			if (secCount==1){
				layer=getInt(&s);
				width=getInt(&s);
				numPoints=getInt(&s);
				if (layout::debug)printf("path/polygon %d %d %d \n",layer,numPoints,width);
			}
			else if (secCount==2){
				pointArray p;
				p.resize(numPoints);
				for (int k=0;k<numPoints;k++){
					int x,y;
					if (s=="") s=ts.readLine().trimmed();
					x=getInt(&s);
					y=getInt(&s);
					p.setPoint(k,x,y);
				}
				if (p.size()>1){
				if (p.point(0)==p.point(p.size()-1)){
							cell_->addPolygon(p,layer);
				}else{
							element *e=cell_->addPath(p,layer);
							e->setWidth(width);
				}
				}
			}

		}
		}
  

  }
  f.close();
  // resolving cellrefs
  for (cellList *f =d->firstCell; f!=NULL;f=f->nextCell) {
  	if (f->thisCell!=NULL){
  		for (elementList *e=f->thisCell->firstElement;e!=NULL;e=e->nextElement){
			if (e->thisElement->isCellref()||e->thisElement->isCellrefArray()) {
				 if (e->thisElement->depend()==NULL){e->thisElement->setCellRef(d->findCell(e->thisElement->getName()));}
				 if ((e->thisElement->depend()==NULL)&&(typ==fileImport)){  //refs to before existing cells
						cellList *c=d->firstCell;
						d->firstCell=firstcellhelp;
				 		e->thisElement->setCellRef(d->findCell(e->thisElement->getName()));
						d->firstCell=c;}
				 if (e->thisElement->depend()==NULL){
				 	//add empty cells
					cellList *c;
					//printf("addCell %s\n",e->thisElement->getName().toAscii().data());
  					c=d->addCell();
  					c->this_cell->cellName=e->thisElement->getName();
					e->thisElement->setCellRef(d->findCell(e->thisElement->getName()));
					if (!additionalFiles.contains(e->thisElement->getName()))
							additionalFiles<<e->thisElement->getName();
				 	//additionalLoad=false;
					//additionalFiles.clear();;
					//additionalPath="";
					//report.addItem(tr("Cellref(s) can not be resolved. Empty cell added."),1,e->thisElement->getName());
				 }
			}
			if (e==0) {break;}
			
		}
	f->thisCell->clean();
  	}
  }
  d->currentCell=d->findTopCell();
  if (d->currentCell==NULL) d->currentCell=d->firstCell->thisCell;
  if ((typ==fileImport)||(typ==fileUpdate)) {
	if (d->databaseunits!=databaseunitshelp) {
		report.addItem(tr("Databaseunits are different.Import is fitted."),3,s.setNum(d->databaseunits,'g',10));
		for (cellList *f =d->firstCell; f!=NULL;f=f->nextCell) {f->thisCell->resize(d->databaseunits/databaseunitshelp);}
		d->databaseunits=databaseunitshelp;}
		}
  if (typ==fileImport) filegeneral::import(&report,d,firstcellhelp);
  if (typ==fileUpdate) filegeneral::update(&report,d,firstcellhelp);

#ifdef printtime
  printf("tlc/tld load: %d ms\n", setup::centralTimer.elapsed());
#endif
  }
catch (QString s){
  report.addItem(tr("Aborted. "),0);
  report.addItem(s,1);
 }
  if (!additionalLoad){
    while ((additionalFiles.size()!=0)){
		additionalLoad=true;
		QString file=additionalFiles.at(0);
		additionalFiles.removeAt(0);
		load(additionalPath+"/"+file+".tlc",d,fileUpdate);
		additionalLoad=false;
	}
	d->currentCell=d->findTopCell();
	}
	

  //report.showReport(); 
  QString  s=report.getReport();
  d->showReport(s,report.getLastRang());

}

int tld::getInt(QString *s){
	if (s->length()==0) report.addItem(tr("File corrupt."),1,*s);
	int i=s->indexOf(" ");
	if (i<0) {
		int r=s->toInt();
		*s="";
		return r;
	}
	int r=s->left(i).toInt();
	*s=s->mid(i).trimmed();
	return r;
}

QString tld::getString(QString *s){
	if (s->length()==0) report.addItem(tr("File corrupt."),1,*s);
	int i=s->indexOf(" ");
	if (i<0) {
		QString r=*s;
		*s="";
		return r;
	}
	QString r=s->left(i).trimmed();
	*s=s->mid(i).trimmed();
	return r;
}

void tld::save(QString fileName,drawingField *d){
errorreport report;
report.setTitle(tr("Save of TLD-File \"")+fileName+"\"");
try { 
  throw QString(tr("TLD file format can not be saved. Choose an other format!"));
  QFile f( fileName );
  if ( !f.open( QIODevice::WriteOnly ) ) {
	throw QString(tr("Can not open File."));
  }
 
  QTextStream stream( &f );
  tld tldClass;
  tldClass.save(&stream,d,&report);
  f.close();
}
catch (QString s){
  report.addItem(tr("Aborted. "),0);
  report.addItem(s,1);
 }
  //report.showReport();   
  QString s=report.getReport();
  d->showReport(s,report.getLastRang());

}
void tld::save(QTextStream *,drawingField *, errorreport *){
  /*
  stream = streamPtr;
  reportSave = error;
  double factor=d->databaseunits*(double)100000000;
  a=1;
  b=1;
  if (factor>1) a=element::runden(factor);
  else b=element::runden(1/factor);
  cellNum=1;
  cellList *e;
  for(e=d->firstCell;e!=NULL;e=e->nextCell){
	e->thisCell->saved=false;}
  bool saved=false;
  while (!saved){
	saved=true;
	for(e=d->firstCell;e!=NULL;e=e->nextCell){
		if (e->thisCell->saved==false){
			if (!e->thisCell->dependNotSaved()){e->thisCell->saveCIF(this);}
			else{saved=false;}};
		}}
 *stream<<(QString)("E\r\n");*/
}

