/***************************************************************************
 *   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 "dxf.h"
#include <math.h>
#include <qfile.h>
#include <qstring.h>
#include <qtextstream.h>
#include "general/drawingfield.h"
#include "elements/pointarray.h"
#include "general/layers.h"
#include "elements/celllist.h"
#include "elements/cell.h"
#include "elements/path.h"
#include "elements/polygon.h"
#include <qmessagebox.h>
#include "general/setup.h"
#include "elements/element.h"
#include <qstringlist.h>
#include "layout.h"
#include "elements/cell.h"
#include <QString>
#include <QHash>


dxf::dxf(QObject *parent, const char *)
 : QObject(parent)
{
}


dxf::~dxf()
{
}


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

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

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

void dxf::addVertex(pointArray *array,QPoint np, double bulge){
  	if ((bulge==0)||(array->size()==0)){
	  array->resize(array->size()+1);
	  array->setPoint(array->size()-1,np.x(),np.y());
	} else {
	  QPoint last=array->point(array->size()-1);
	  QPoint center=(last+np)/2;
	  QPoint perp=QPoint(-np.y(),np.x())-QPoint(-last.y(),last.x());
	  double length=element::length(perp);
	  double chord = length;
	  double s = chord / 2 * bulge;
	  double radius = (pow(chord / 2, 2) + pow(s, 2)) / (2 * s);
	  double mul=sqrt(radius*radius-(length*length/4))/length;
	  //printf("radius %f\n",radius);
	  if (bulge>0) {
	    if (bulge<1) center=center+perp*(mul);
	    else center=center-perp*(mul);
	    pointArray pa2=element::spirale(center,last,np,setup::circularDefault);
	    (*array)<<pa2;
	  } else {
	    bulge=-bulge;
	    if (bulge<1) center=center-perp*(mul);
	    else center=center+perp*(mul);
	    pointArray pa2=element::spirale(center,np,last,setup::circularDefault);
	    pa2.flip();
	    (*array)<<pa2;
	  }
	  
	}
}

void dxf::load(QString fileName,drawingField *d,fileOpenType typ){
  if (typ==fileImport) {
  	report.setTitle(tr("Import of DXF-File \"")+fileName+"\"");}
  else if (typ==fileOpen){
	report.setTitle(tr("Open of DXF-File \"")+fileName+"\"");}
  else if (typ==fileUpdate){
	report.setTitle(tr("Update with DXF-File \"")+fileName+"\"");}
try { 
  cellList *firstcellhelp=d->firstCell;
  double databaseunitshelp=d->databaseunits;
  double userunitshelp=d->userunits;
  QFile f( fileName );
  if ( !f.open( QIODevice::ReadOnly ) )
	throw QString(tr("Can not open File."));
  QTextStream ts( &f );
  stream=&ts;
  if ((typ==fileImport)||(typ==fileUpdate)) {
	d->firstCell=NULL;
  }
  for (int i=0; i<layersMax;i++){
  	 layerused[i]=false;
  	 if ((typ==fileImport)||(typ==fileUpdate)) {
		if (firstcellhelp->useLayer(i)) layerused[i]=true;
  }
}
#ifdef printtime
  setup::centralTimer.start();
#endif
  QString s="";
  int type;
  int elem=0;
  int group=0;
  int section=0;
  int seq=0;
  int layer=1;
  int x=0,y=0;
  int x1=0,y1=0;
  QString sname="";
  cellList *cell_list;
  cell *cell_;
  cell_=NULL;
  cell_list=NULL; 
  element *element_=NULL;
  pointArray array;
  double angle=0,angleEnd=0,mag=1;
  double mirror_x;
  int width=0;
  int radius=0;
  int cap=0;
  int presentation=0;
  int anzx=0,anzy=0,anz=0;
  bool textAligmentX=false,textAligmentY=false;
  double bulge=0,newBulge=0;
  // to avoid compilerwarning:
  userunitshelp=d->userunits;
  d->fileType="DXF";
  group=0;
  mirror_x=0;
  //
  int lines=0;
  array.resize(0);
  s=readString(&type);
  QTime dxfTimer;
  dxfTimer.start();
  QHash<QString,cell *> cellMap;
  while (!ts.atEnd()&&(s!="EOF")){
	lines++;
  	switch (type){
	case 0: //new Group
		//close last element
		//printf("start finish %d\n",elem);
		switch (elem){
		case 101: //VERTEXelement_=cell_->
			addVertex(&array,QPoint(x,y),bulge);
			break;
		case 130: //cellrefarray 
			{
			cell *c=cellMap.value(sname,NULL);
			if (c==NULL) c=d->findCell(sname);
			element_=cell_->addCellrefArray(c,QPoint(x,y),QPoint(x1,y1)+QPoint(x,y),anzx,anzy);
			element_->setName(sname);
			element_->rotate(angle);
			element_->scale(mag);
			if(mirror_x)element_->setMirrorx();
			sname="";
			if (layout::debug) printf("cellrefarray\n");
			break; }
		case 120: //cellref 
			{
			cell *c=cellMap.value(sname,NULL);
			if (c==NULL) c=d->findCell(sname);
			element_=cell_->addCellref();
			element_->setPos(QPoint(x,y));
			element_->setCellRef(c);
			element_->setName(sname);
			element_->rotate(angle);
			element_->scale(mag);
			if(mirror_x)element_->setMirrorx();
			sname="";
			if (layout::debug) printf("cellref\n");
			break; }
		case 140: //text
			// process alignment
			if (textAligmentX) {
			  if (presentation!=8) x=x1; 
			  /*if ((presentation&3) == 1)  //center
			    x=(x+x1)/2;
			  else if ((presentation&3) == 2){ //right
			    if (x1>x) x=x1;
			  }
			  else  if ((presentation&3) == 0 ) {
			            if (x1<x) x=x1;  //left
			  }*/
			}
			if (textAligmentY){
			  if (presentation!=8) y=y1; 
			  /*if ((presentation&12) == 8) {  //baseline
			    if (y1<y) y=y1;
			  }
			  if ((presentation&12) == 4) {  //middle
			    y=(y+y1)/2;
			  }
			  if ((presentation&12) == 0) {  //top
			    if (y1>y) y=y1;
			  }*/
			}
		case 141: //text
			element_=cell_->addText(layer,QPoint(x,y),sname);
			element_->setWidth(width);
			element_->rotate(angle);
			if (width==0) {element_->setWidth(-10);}
			if (width==1) {element_->setWidth(-10);}
			element_->setPresentation( presentation);
			if (layout::debug) printf("TEXT %s\n",sname.toLatin1().data());
			break;
		case 151: //Line
			array.resize(2);
			array.setPoint(0,x,y);
			array.setPoint(1,x1,y1);
			element_=cell_->addPath(array,layer);
			break;
		case 152: //LWPOLYLINE
			element_=cell_->addPolygon(array,layer);
			break;
		case 191: //circle
			element_=cell_->addCircle(layer,QPoint(x,y),radius);
			break;
		case 193: //arc
			{
			QPoint pc=QPoint(x,y);
			QMatrix m(1,0,0,1,0,0);
			m.rotate(angle);
			QPoint pstart=pc+m.map(QPoint(radius,0));
			m.setMatrix(1,0,0,1,0,0);
			m.rotate(angleEnd);
			QPoint pend=pc+m.map(QPoint(radius,0));
			array=element::spirale(pc,pstart,pend,setup::circularDefault);
			element_=cell_->addPath(array,layer);
			}
			break;
		case 1001: //solid
			//printf("SOLID size %d\n",array.size());
			//printf("SOLID P1 %d,%d\n",array.point(0).x(),array.point(0).y());
			//printf("SOLID P2 %d,%d\n",array.point(1).x(),array.point(1).y());
			//printf("SOLID P3 %d,%d\n",array.point(2).x(),array.point(2).y());
			//printf("SOLID P4 %d,%d\n",array.point(3).x(),array.point(3).y());
			//printf("cellname %s\n",cell_->cellName.toAscii().data());
			if (width!=0){
				element_=cell_->addPath(array,layer);
				element_->setWidth(width);}
			else {
					if (array.size()==4){
				//for (int i=0; i<array.size();i++){printf("%d %d\n",array.point(i).x(),array.point(i).y());}
					pointArray pa2=array;
					array<<array.point(0);
					//printf("%f\n",array.area());
					pointArray pa;
					pa<<pa2.point(0)<<pa2.point(1)<<pa2.point(3)<<pa2.point(2)<<pa2.point(0);
					//printf("%f\n",pa.area());
					if (pa.area()>array.area()) { array=pa;}
					pa.resize(0);
					pa<<pa2.point(0)<<pa2.point(2)<<pa2.point(1)<<pa2.point(3)<<pa2.point(0);
					//printf("%f\n",pa.area());
					if (pa.area()>array.area()) { array=pa;}
					pa.resize(0);
					pa<<pa2.point(0)<<pa2.point(2)<<pa2.point(3)<<pa2.point(1)<<pa2.point(0);
					//printf("%f\n",pa.area());
					if (pa.area()>array.area()) { array=pa;}
					pa.resize(0);
					pa<<pa2.point(0)<<pa2.point(3)<<pa2.point(1)<<pa2.point(2)<<pa2.point(0);
					//printf("%f\n",pa.area());
					if (pa.area()>array.area()) { array=pa;}
					
					}
				//printf("add\n");
				//for (int i=0; i<array.size();i++){printf("%d %d\n",array.point(i).x(),array.point(i).y());}
				element_=cell_->addPolygon(array,layer);
			}
			break;
		case 1002: //attrib
			element_=cell_->addText(layer,QPoint(x,y),sname);
			element_->setWidth(width);
			if (width==0) {element_->setWidth(-10);}
			if (width==1) {element_->setWidth(-10);}
			element_->setPresentation( presentation);
			if (layout::debug) printf("ATTRIB %s\n",sname.toLatin1().data());
			break;
		}
		//printf("finished\n");
		// set new element
		if ((elem==101)&&(s!="VERTEX")&&(s!="SEQEND")){
			if (layout::debug) printf("SEQEND\n");
			switch (seq){
			case 150: //PATH
				element_=cell_->addPath(array,layer);
				element_->setWidth(width);
				break;
			case 110: //polygon
				if (array.size()!=0) addVertex(&array,array.point(0),newBulge);
				//array.resize(array.size()+1);
				//array.setPoint(array.size()-1,array.point(0));
				element_=cell_->addPolygon(array,layer);
				break;
			default: seq=0;
			}
			seq=0;}
		if (s=="SECTION") {
			section=0;
			s=readString(&type);
			if (type!=2) throw QString(tr("Section Name missing."));
			if (s=="HEADER") readHeader();
			else if (s=="TABLES") readTables();
			else if (s=="OBJECTS") readObjects();
			else if (s=="BLOCKS") {
				if (layout::debug) printf("START BLOCKS\n");
				section=3;}
			else if (s=="ENTITIES") {
				if (layout::debug) printf("START ENTITIES\n");
				section=4;
				cell_list=d->addCell();
				cell_=cell_list->this_cell;
				cell_->cellName="main";
				}
			else if (s=="ENDSEC") {
				if (layout::debug) printf("ENDSEC\n");
				section=0;}
			else {section=0;report.addItem(tr("unknow section"),2,s);}
			}
		else if (s=="VERTEX") {
				elem=101;x=0;y=0;bulge=newBulge;newBulge=0;
				if (layout::debug) printf("VERTEX\n");}
		else if (s=="LINE") {elem=151;seq=151;x=0;y=0;x1=0;y1=0;
				if (layout::debug) printf("LINE\n");}
		else if (s=="POLYLINE") {
				array.resize(0);elem=150;seq=150;width=0;
				if (layout::debug) printf("POLYLINE\n");}
		else if (s=="LWPOLYLINE") {
				array.resize(0);elem=152;seq=152;width=0;anzx=0;anzy=0;anz=0;
				if (layout::debug) printf("LWPOLYLINE\n");}
		else if (s=="SEQEND"){
			if (layout::debug) printf("SEQEND\n");
			switch (seq){
			case 150: //PATH
				element_=cell_->addPath(array,layer);
				element_->setWidth(width);
				break;
			case 110: //polygon
			        if (array.size()!=0) addVertex(&array,array.point(0),newBulge);
				//array.resize(array.size()+1);
				//array.setPoint(array.size()-1,array.point(0));
				element_=cell_->addPolygon(array,layer);
				break;
			default: seq=0;
			}
			seq=0;}
		else if (s=="BLOCK"){
			elem=0;
			seq=0;
			cell_list=d->addCell();
			cell_=cell_list->this_cell;
			do {
			s=readString(&type);}
			while ((type!=2)&& (!(stream->atEnd()||(s=="EOF"))));
			if (type!=2)throw QString(tr("Block Name expected."));
			cell_->cellName=s;
			cellMap[cell_->cellName]=cell_;
			if (layout::debug) printf("BLOCK %s\n",s.toLatin1().data());
			}
		else if (s=="ENDBLK"){//end block
			elem=0;
			if (layout::debug) printf("ENDBLK\n");
			}
		else if (s=="ENDSEC"){//end section
			if (layout::debug) printf("ENDSEC\n");
			elem=0;
			}
		else if (s=="INSERT"){
			array.resize(0);
			mirror_x=false;angle=0;mag=1;seq=120;elem=120;anzx=1;anzy=1;
			do {
			s=readString(&type);}
			while ((type!=2)&& (!(stream->atEnd()||(s=="EOF"))));
			if (type!=2) throw QString(tr("Name of Cellref expected."));
			sname=s;
			if (layout::debug) printf("INSERT %s\n",s.toLatin1().data());
			}
		else if (s=="TEXT"){seq=140;elem=140;mirror_x=false;angle=0;mag=1; presentation=8;width=-10;
			textAligmentX=false;textAligmentY=false;
			if (layout::debug) printf("TEXT %s\n",s.toLatin1().data());
			}
		else if (s=="MTEXT"){elem=141;seq=141;mirror_x=false;angle=0;mag=1; presentation=8;width=-10;
			if (layout::debug) printf("METEXT %s\n",s.toLatin1().data());
			}
		else if (s=="CIRCLE"){elem=191;seq=191;
			if (layout::debug) printf("CIRCLE\n");
			}
		else if (s=="ARC"){elem=193;seq=193;width=0;angle=0;angleEnd=0;
			if (layout::debug) printf("ARC\n");
			}
		else if (s=="SOLID"){elem=1001;seq=1001;array.resize(0);width=0;
			if (layout::debug) printf("ARC\n");
			}
		else if (s=="ATTRIB"){seq=1002;elem=1002;mirror_x=false;angle=0;mag=1; presentation=8;width=-10;
			if (layout::debug) printf("ATTRIB %s\n",s.toLatin1().data());
			}
		else {elem=0; report.addItem(tr("unknow group"),2,s);seq=0;elem=0;}
		s=readString(&type);
		break;
	case 1: // text
		sname=s;
		s=readString(&type);
		break;
	case 7: //textsylename -> ignore
		s=readString(&type);
		break;
	case 8: //layer
		if ((elem!=0)&&(elem!=120)&&(elem!=130)) {
			layer=layers::findLayer(s);
			if (layer==-1) {
				 int layerNum=1;
				 while ( layerused[layerNum]) layerNum++;
				 if (layerNum<layersMax){
				 	layers::num[layerNum].name=s;
				 	layerused[layerNum]=true;
				 	report.addItem(tr("Add layer"),4,s);
				 	layer=layerNum;}
				 else {
				 	layer=1;
					report.addItem(tr("unknow layer"),2,s);
				 	}
				}
			else layerused[layer]=true;
			}
		s=readString(&type);
		break;
	case 10: //x-coordinate
		if (elem==152) { //lwpolyline
			x=element::runden(s.toDouble()/d->userunits);
			s=readString(&type);
			if (type!=20) {QString s1;report.addItem(tr("missing y coordinate"),2,s);}
			else {
				anz--;
				y=element::runden(s.toDouble()/d->userunits);
				array.setPoint(anz,x,y);}
			}
		if (elem==1001) { //solid
			if (array.size()<1) array.resize(1);
			array.setPoint(0,QPoint(element::runden(s.toDouble()/d->userunits),array.point(0).y()));
			}
		else x=element::runden(s.toDouble()/d->userunits);
		s=readString(&type);
		break;
	case 11: //x1-coordinate
		if (elem==1001) {
			if (array.size()<2) array.resize(2);
			array.setPoint(1,QPoint(element::runden(s.toDouble()/d->userunits),array.point(1).y()));
			}
		else x1=element::runden(s.toDouble()/d->userunits);
		if (elem==140) textAligmentX=true;
		s=readString(&type);
		break;
	case 12:
		if (elem==1001) {
			if (array.size()<3) array.resize(3);
			array.setPoint(2,QPoint(element::runden(s.toDouble()/d->userunits),array.point(2).y()));
			}
		s=readString(&type);
		break;
	case 13:
		if (elem==1001) {
			if (array.size()<4) array.resize(4);
			array.setPoint(3,QPoint(element::runden(s.toDouble()/d->userunits),array.point(3).y()));
			}
		s=readString(&type);
		break;
	case 20: //y-coordinate
		if (elem==1001) { //solid
			if (array.size()<1) array.resize(1);
			array.setPoint(0,QPoint(array.point(0).x(),element::runden(s.toDouble()/d->userunits)));
			}
		else y=element::runden(s.toDouble()/d->userunits);
		s=readString(&type);
		break;
	case 21: //y1-coordinate
		if (elem==1001) { //solid
			if (array.size()<2) array.resize(2);
			array.setPoint(1,QPoint(array.point(1).x(),element::runden(s.toDouble()/d->userunits)));
			}
		else y1=element::runden(s.toDouble()/d->userunits);
		if (elem==140) textAligmentY=true;
		s=readString(&type);
		break;
	case 22: //
		if (elem==1001) { //solid
			if (array.size()<3) array.resize(3);
			array.setPoint(2,QPoint(array.point(2).x(),element::runden(s.toDouble()/d->userunits)));
			}
		s=readString(&type);
		break;
	case 23: //
		if (elem==1001) { //solid
			if (array.size()<4) array.resize(4);
			array.setPoint(3,QPoint(array.point(3).x(),element::runden(s.toDouble()/d->userunits)));
			}
		s=readString(&type);
		break;
	case 30: //z-coordinate ->ignore
	case 31: //z1-coordinate ->ignore
	case 32: //z1-coordinate ->ignore
	case 33: //z1-coordinate ->ignore
		s=readString(&type);
		break;
	case 39: //width 
		if (elem==193) width=element::runden(s.toDouble()/d->userunits); //arc
		else if (elem==1001) width=element::runden(s.toDouble()/d->userunits); //solid
		s=readString(&type);
		break;
	case 40: //textheight
		//mag=s.toDouble();
		if ((elem==191)||(elem==193)) radius=element::runden(s.toDouble()/d->userunits);
		else if (elem==101) mag=s.toDouble();
		else if (elem==1002) width=element::runden(s.toDouble()/d->userunits); //attrib
		else width=element::runden(s.toDouble()/d->userunits); //not for width in vertex
		s=readString(&type);
		break;
	case 41: //x-mag
		if ((elem==140)||(elem==141)){ //text
			width=width*element::runden(s.toDouble());
		}
		else {
			mag=s.toDouble();
			if (elem!=101) width=element::runden(mag/d->userunits); //not for width in vertex
			if (mag<0) {mirror_x=!mirror_x;angle+=180;mag*=-1;}
			if (mag==0) {mag=1;};
		}
		s=readString(&type);
		break;
	case 42: //y-mag or Bulge
		mag=s.toDouble();
		if (elem!=101) width=element::runden(s.toDouble()/d->userunits); //not for width in vertex
		if (elem==101) newBulge=mag;
		if (mag<0) {mirror_x=!mirror_x;mag*=-1;}
		if (mag==0) {mag=1;};
		s=readString(&type);
		break;
	case 43: //z-mag -> ignore
		s=readString(&type);
		break;
	case 44: //space_x
		x1=element::runden(s.toDouble()/d->userunits);
		s=readString(&type);
		break;
	case 45: //space_y
		y1=element::runden(s.toDouble()/d->userunits);
		s=readString(&type);
		break;
	case 50: //angle
		angle+=s.toDouble();
		s=readString(&type);
		break;
	case 51: //angle end for arc
		angleEnd+=s.toDouble();
		s=readString(&type);
		break;
	case 66: //Elemente folgen
		switch (seq){
		case 150: //POLYLINE
			array.resize(0);
			break;
		case 110: //POLYLINE->polygon
			array.resize(0);
			break;
		}
		s=readString(&type);
		break;
	case 70: //Flags
		anzx=s.toInt();
		switch (seq){
		case 150: //POLYLINE
			if (s.toInt()==1){seq=110;elem=110;}
			break;
		case 120: //cellref
			if (s.toInt()!=1){seq=130;elem=130;} //cellrefarray
			break;
		}
		s=readString(&type);
		break;
	case 71: //Flags
		anzy=s.toInt();
		switch (seq){
		case 120: //cellref
			if (s.toInt()!=1){seq=130;elem=130;} //cellrefarray
			break;
		}
		s=readString(&type);
		break;
	case 72: //textausrichtung x
		cap=s.toInt();
		switch (seq){
		case 140: //text
			if (s.toInt()==0){ presentation=(presentation&12) ;} //left
			if (s.toInt()==1){ presentation=(presentation&12) + 1;} //center
			if (s.toInt()==2){ presentation=(presentation&12) + 2;} //right
			if (s.toInt()==3){ presentation=(presentation&12) + 1;} //aligned
			if (s.toInt()==4){ presentation=(presentation&12) + 1;} //middel
			if (s.toInt()==5){ presentation=(presentation&12) + 1;} //fit
			break;
		}
		s=readString(&type);
		break;
	case 73: //textausrichtung y
		cap=s.toInt();
		switch (seq){
		case 140: //text
			if (s.toInt()==0){ presentation=(presentation&3) + 8;}  //baseline
			if (s.toInt()==1){ presentation=(presentation&3) + 8;}  //bottom
			if (s.toInt()==2){ presentation=(presentation&3) + 4;}  //middle
			if (s.toInt()==3){ presentation=(presentation&3) ;}  //top
			break;
		}
		s=readString(&type);
		break;
	case 90: //number of vetices
		anz=s.toInt();
		array.resize(anz);
		s=readString(&type);
		break;
	case 3: //
	case 5: //handle
	case 6: //linetype
	case 62: //colornumber
	case 67: //
	case 100: // subclass ->ignore
	case 330: //
	case 370: //linewidth
	case 999: //version extras ->ignore
		s=readString(&type);
		break;
	default:
		{
		QString s1;
		report.addItem(tr("unused: ")+s1.setNum(type),2,s);
		}
		s=readString(&type);
		break;
	}
  if (((lines%5000)==0)||(ts.atEnd()) ){
		QString sh;
		sh.setNum(lines);
		if ((ts.atEnd())||(dxfTimer.elapsed()>200)){
			d->showMessage(tr("%1 records loaded.").arg(sh));
			dxfTimer.start();
			}
		}
  }
  f.close();
   cell_=d->findCell("$MODEL_SPACE");if (cell_!=NULL) d->deleteCell(cell_);
   cell_=d->findCell("*Model_Space");if (cell_!=NULL) d->deleteCell(cell_);
   cell_=d->findCell("*MODEL_SPACE");if (cell_!=NULL) d->deleteCell(cell_);
   cell_=d->findCell("$PAPER_SPACE");if (cell_!=NULL) d->deleteCell(cell_);
   cell_=d->findCell("*PAPER_SPACE");if (cell_!=NULL) d->deleteCell(cell_);
   cell_=d->findCell("*Paper_Space");if (cell_!=NULL) d->deleteCell(cell_);
   cell_=d->findCell("$PAPER_SPACE0");if (cell_!=NULL) d->deleteCell(cell_);
   cell_=d->findCell("*PAPER_SPACE0");if (cell_!=NULL) d->deleteCell(cell_);
   cell_=d->findCell("*Paper_Space0");if (cell_!=NULL) d->deleteCell(cell_);
   cell_=d->findCell("$PAPER_SPACE1");if (cell_!=NULL) d->deleteCell(cell_);
   cell_=d->findCell("*PAPER_SPACE1");if (cell_!=NULL) d->deleteCell(cell_);
   d->currentCell=d->findCell("main");
   if (d->currentCell==NULL) d->findTopCell();
   // resolving brocken cellrefs
//printf("1\n");
  for (cellList *f =d->firstCell; f!=NULL;f=f->nextCell) {
  	if (f->this_cell!=NULL){
		//f->this_cell->clean();
  		for (elementList *e=f->thisCell->firstElement;e!=NULL;e=e->nextElement){
			if (e->thisElement->isCellref()||e->thisElement->isCellrefArray()) {
				 if (e->thisElement->depend()==NULL){
				    cell *c=cellMap.value(e->thisElement->getName(),NULL);
				    if (c==NULL) c=d->findCell(e->thisElement->getName());
				    e->thisElement->setCellRef(c);
				 }
				 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;
  					c=d->addCell();
  					c->thisCell->cellName=e->thisElement->getName();
					e->thisElement->setCellRef(c->thisCell);
				 	//f->this_cell->deleteElement(e->this_element);
				 	//e=f->this_cell->first_element;
					report.addItem(tr("Cellref(s) can not be resolved. Empty cell added."),1,e->thisElement->getName());}
			}
			if (e==0) {break;}
			
		}
		f->thisCell->clean();
  	}
  }
//printf("2\n");
  //  
  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("DXF load: %d ms\n", setup::centralTimer.elapsed());
#endif
  }
catch (QString s){
  report.addItem(tr("Aborted. "),0);
  report.addItem(s,1);
 }
  //report.showReport(); 
  QString s=report.getReport();
  d->showReport(s,report.getLastRang());
//printf("3\n");
}

void dxf::readHeader(){
 QString s; 
 int type;
 if (layout::debug) printf("START HEADER\n");
 do {
 	s=readString(&type);	
 	if (stream->atEnd()||(s=="EOF")){throw QString(tr("Unexpected end of file."));}
 }
 while (!((type==0)&&(s=="ENDSEC")));
 if (layout::debug) printf("ENDSEC HEADER\n");
}
void dxf::readObjects(){
 QString s; 
 int type;
 if (layout::debug) printf("START OBJECTS\n");
 do {
 	s=readString(&type);	
 	if (stream->atEnd()||(s=="EOF")){throw QString(tr("Unexpected end of file."));}
 }
 while (!((type==0)&&(s=="ENDSEC")));
 if (layout::debug) printf("ENDSEC OBJECTS\n");
}

void dxf::readTables(){
QString s;
bool layertable=false; 
QStringList list;
 int type;
 if (layout::debug) printf("START TABLE\n");
 do {
 	s=readString(&type);	
 	if (stream->atEnd()||(s=="EOF")){throw QString(tr("Unexpected end of file."));}
	switch (type){
	case 0 :
		if (s=="ENDSEC") {
			if (layout::debug) printf("ENDSEC TABLE\n");
			return;}
		if (s=="TABLE") {
			layertable=false;
			s=readString(&type);
			list.clear();
			if (type!=2) throw QString(tr("Table Name expected."));	
			if (s=="LAYER") layertable=true;
			if (layout::debug) printf("TABLE %s\n",s.toLatin1().data());
			}
		else if (s=="LAYER") {
			if (!layertable) throw QString(tr("Layer outside layertable."));
			do {
			s=readString(&type);}
			while ((type!=2)&& (!(stream->atEnd()||(s=="EOF"))));
			if (type!=2) throw QString(tr("Layer Name expected."));
			int num=layers::findLayer(s);
			if (num>=0) {layerused[num]=true;}
			else {list.append(s);}
			if (layout::debug) printf("LAYER %s\n",s.toLatin1().data());
			}
		else if (s=="ENDTAB") {
			if (layout::debug) printf("ENDTAB\n");
			if (layertable){
				layertable=false;
				int layerNum=1;
				for ( int i=0; i<list.count(); i++ ){
        			 s=list[i];
                		 while ( layerused[layerNum]) layerNum++;
				 layers::num[layerNum].name=s;
				 layerused[layerNum]=true;
				 report.addItem(tr("Add layer"),4,s);
				}
				}
			}
		break;
	case 70: // ignore
		break;
	
	default:
		break;
	}
 }
 while (!((type==0)&&(s=="ENDSEC")));
 }

QString dxf::readString (int *type){
QString s=stream->readLine();
*type = s.toInt();
//s=stream->readLine();
//printf("%d %s\n",(*type),s.toLatin1());
//return s;
return stream->readLine();
}
void dxf::save(QString fileName,drawingField *d){
dxf DXF;

DXF.report.setTitle(tr("Save of DXF-File \"")+fileName+"\"");
try { 
  QFile f( fileName );
  if ( !f.open( QIODevice::WriteOnly ) ) {
	throw QString(tr("Can not open File."));
  }
  QTextStream stream( &f );
  DXF.stream=&stream;
  DXF.df=d;
  DXF.save(d);
  f.close();
}
catch (QString s){
  DXF.report.addItem(tr("Aborted. "),0);
  DXF.report.addItem(s,1);
 }
  //report.showReport();   
  QString s=DXF.report.getReport();
  d->showReport(s,DXF.report.getLastRang());
}

void dxf::writeEntry( int nummer, QString wert){
QString s;
s=s.setNum(nummer);
if (s.length()==1) {s="  "+s;}
if (s.length()==2) {s=" "+s;}
*stream<<s<<(QString)("\r\n")<<wert<<(QString)("\r\n");
}
void dxf::writeLayer( int nummer){
QString s=layers::num[nummer].name;
s.replace(QString(" "), QString("_"));
dxf::writeEntry(8,s);
}


void dxf::save(drawingField *d){
  QString s;
  cell *topcell;
  topcell=d->findCell("main");
  if (topcell==NULL) topcell=d->findTopCell();
  QPoint max=QPoint(INT_MIN,INT_MIN);
  QPoint min=QPoint(INT_MAX,INT_MAX);
  topcell->minimum(&min);
  topcell->maximum(&max);
  if (max==QPoint(INT_MIN,INT_MIN)){
    max=QPoint(0,0);
    min=QPoint(0,0);
  }
  // write header
  writeEntry(0,"SECTION");
  writeEntry(2,"HEADER");
  writeEntry(9,"$EXTMIN");
  writeEntry(10,s.setNum(min.x()*d->userunits));
  writeEntry(20,s.setNum(min.y()*d->userunits));
  writeEntry(9,"$EXTMAX");
  writeEntry(10,s.setNum(max.x()*d->userunits));
  writeEntry(20,s.setNum(max.y()*d->userunits));
  writeEntry(0,"ENDSEC");
   // write layers
  writeEntry(0,"SECTION");
  writeEntry(2,"TABLES");
  writeEntry(0,"TABLE");
  writeEntry(2,"LAYER");
  int numLayer=0;
  for (int i=0; i<layersMax;i++){
  	 if (d->useLayer(i)) {
	 	numLayer++;
		layerused[i]=true;}
	 else layerused[i]=false;
	 }
  writeEntry(70,"   "+s.setNum(numLayer));  //Anzahl Layer meist unbeachtet
  for (int i=0; i<layersMax;i++)
    if (layerused[i]) {
  	writeEntry(0,"LAYER");
	QString s=layers::num[i].name;
	s.replace(QString(" "), QString("_"));
	writeEntry(2,s);
	writeEntry(70,"    0");
	writeEntry(62,"    7");
	writeEntry(6,"CONTINUOUS");
  	};
  writeEntry(0,"ENDTAB");
  writeEntry(0,"ENDSEC");
  // write Cells
  writeEntry(0,"SECTION");
  writeEntry(2,"BLOCKS");
  cellList *e;
  for(e=d->firstCell;e!=NULL;e=e->nextCell){
	e->thisCell->saved=false;}
  bool saved=false;
  topcell->saved=true;
  while (!saved){
	saved=true;
	for(e=d->firstCell;e!=NULL;e=e->nextCell){
		if (e->thisCell->saved==false){
			if (!e->thisCell->dependNotSaved()){
				 writeEntry(0,"BLOCK");
				 writeEntry(8,"0");
  				 writeEntry(2,e->thisCell->cellName);
				writeEntry(70,"64");
				writeEntry(10,"0.0");
				writeEntry(20,"0.0");
				writeEntry(30,"0.0");
				e->thisCell->saveDXF(this);
				writeEntry(0,"ENDBLK");
				writeEntry(8,"0");
				}
			else{saved=false;}};
		}}
  writeEntry(0,"ENDSEC");
  // maincell
  writeEntry(0,"SECTION");
  writeEntry(2,"ENTITIES");
  topcell->saved=false;
  topcell->saveDXF(this);
  writeEntry(0,"ENDSEC");
  writeEntry(0,"EOF");
}
