/***************************************************************************
 *   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.             *
 ***************************************************************************/
//#undef multithread

#include "gds.h"
#include <qfile.h>
#include <qdatetime.h>
//Added by qt3to4:
#include "elements/element.h"
#include "elements/pointarray.h"
#include "general/drawingfield.h"
#include <math.h>
#include "layout.h"
#include "general/errorreport.h"
#include <qmessagebox.h>
#include "elements/propertylist.h"
#ifndef multithread
#include "file_read.h"
#else
#include "threads/fileread.h"
#include "threads/cleandispatcher.h"
#include "elements/polygon.h"
#endif
#include <QFileInfo>

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


gds::~gds()
{

}

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

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

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

void gds::load(QString fileName,drawingField *d, fileOpenType typ){
  if (layout::debug){printf("start gds open\n");}
  errorreport report;
  QString s;
  if (typ==fileImport) {
  	report.setTitle(tr("Import of GDSII-File \"")+fileName+"\"");}
  else  if (typ==fileOpen){
	report.setTitle(tr("Open of GDSII-File \"")+fileName+"\"");}
  else  if (typ==fileUpdate){
	report.setTitle(tr("Update with GDSII-File \"")+fileName+"\"");}
try { 
  d->fileType="GDSII";
#ifdef printtime
  setup::centralTimer.start();
#endif
  QTime gdsTimer;
  gdsTimer.start();
  cellList *firstcellhelp=d->firstCell;
  double databaseunitshelp=d->databaseunits;
  if (setup::gdsAutoMapDatatypes) {
	setup::gdsMapLayer=true;
	if ((typ==fileImport)||(typ==fileUpdate)) layers::generateLayerAutoMap(d);
	else layers::generateLayerAutoMap(NULL);
	}
  else if (setup::gdsMapLayer) layers::generateLayerMap();
  fileRead f( fileName );
  if ( f.open() ) {
        throw QString(tr("Can not open File."));}
  //QDataStream ts( &f );
  if ((typ==fileImport)||(typ==fileUpdate)) {
	d->firstCell=NULL;
  }
  quint16 reclen; //bytes pro eintrag
  quint8 record, //type of record
  	  type;   //datatype
 
  // statistics
  int unused=0; // not used records
  int used=0; // used records
  int items=0; //element pro eintrag
  
  // import variables
  quint8 help;   //help
  qint16 int16,
          year,month,day,hour,min,sec,  //date/time load
          help16; //help
  qint32 int32,int32x,int32y;
  
  int anzx=0,anzy=0;
  int layer=1;
  int presentation=0;
  float float_=0;
  double double_=0;
  double angle=0,mag=1;
  bool mirror_x=false;
  bool rotate=false;
  bool mag_=false;
  int beginExt=0,endExt=0;
  int width=0;
  int cap=0;
  QHash<QString,cell *> cellMap;
  QString s,  //help
  	sname;
  int elementmode=0;
  int datatype=0;
  int propertyNumber=0;
  QList<propertyItem> property;

  element *element_=NULL;
  pointArray point_array;
  QPoint point;
  
  cellList *cell_list;
  cell *cell_;
  cell_=NULL;
  cell_list=NULL;
  uint recordCount=0;
  

#ifdef multithread
cleanDispatcher *cleanDis=new cleanDispatcher();
#endif
 
  if (f.end) throw QString(tr("File empty."));
  while (!(f.end))
  { 
	recordCount++;
        reclen=f.readUInt16();
	record=f.readUInt8(); /* Record Type */
	type=f.readUInt8(); /* Data Type */
	if ((record>5)&&(record<31)&&(cell_==NULL)) throw QString(tr("File corrupt."));
	switch (type) {
	case 0:
		break;	/* No Data */
	case 1:			/* Bit Array */
		items = (reclen-4)/2;
		break;
	case 2: 			/* Two Byte signed int */
		items = (reclen-4)/2;
		break;
	case 3: 			/* Four Byte signed int */
		items = (reclen-4)/4;
		break;
	case 4: 			/* Four byte real */
		items = (reclen-4)/4;
		break;
	case 5: 			/* Eight byte real */
	        items = (reclen-4)/8;
		break;
	case 6: 			/* ASC */
	        items = (reclen-4);
		break;
	}
	//if (layout::debug){printf("record %d :\n",record);}
	switch (record){
	case 0: //HEADER
		help16=f.readInt16();
		used++;
		d->fileType.setNum(help16);
		d->fileType="GDSII version "+d->fileType;
		if (layout::debug){printf("HEADER %d \n",help16);}
		break;
	case 1: //BGNLIB
		year=f.readInt16();
		month=f.readInt16();
		day=f.readInt16();
		hour=f.readInt16();
		min=f.readInt16();
		sec=f.readInt16();
	        //ts>>year>>month>>day>>hour>>min>>sec;
		d->date_modification.setYMD(year+1900,month,day);
		d->time_modification.setHMS(hour,min,sec);
		if (layout::debug){printf("BGNLIB\n");
			printf("Modification: %d:%d:%d,%d:%d:%d\n",year+1900,month,day,hour,min,sec);}
		year=f.readInt16();
		month=f.readInt16();
		day=f.readInt16();
		hour=f.readInt16();
		min=f.readInt16();
		sec=f.readInt16();
		//ts>>year>>month>>day>>hour>>min>>sec;
		d->date_access.setYMD(year+1900,month,day);
		d->time_access.setHMS(hour,min,sec);
		if (layout::debug){printf("Access: %d:%d:%d,%d:%d:%d\n",year+1900,month,day,hour,min,sec);}
		used++;
		break;
	case 2: //LIBNAM
		d->libname=readString(&f,items);
		if (layout::debug){printf("LIBNAM %s\n",d->libname.toLatin1().data());}
		used++;
		break;
	case 3: //UNITS 
		double_=read8ByteReal(&f);
		if (typ==fileOpen) d->userunits = double_;
		d->databaseunits = read8ByteReal(&f);
		if (layout::debug){
		  printf("UNITS\n");
		  printf("userunits %e\n",d->userunits);
		  printf("databaseunits %e\n",d->databaseunits);
		}
		used++;
		break;
	case 4: //ENDLIB
		if (layout::debug){
		  printf("ENDLIB\n");
		}
		f.end=true;
		used++;
		break;
	case 5: //BGNSTR
		if (layout::debug){
		  printf("BGNSTR\n");
		}
		used++;
		cell_list=d->addCell();
		cell_=cell_list->this_cell;
		year=f.readInt16();
		month=f.readInt16();
		day=f.readInt16();
		hour=f.readInt16();
		min=f.readInt16();
		sec=f.readInt16();
		//ts>>year>>month>>day>>hour>>min>>sec;
		cell_->date_modification.setYMD(year+1900,month,day);
		cell_->time_modification.setHMS(hour,min,sec);
		if (layout::debug){printf("Modification: %d:%d:%d,%d:%d:%d\n",year+1900,month,day,hour,min,sec);}
		year=f.readInt16();
		month=f.readInt16();
		day=f.readInt16();
		hour=f.readInt16();
		min=f.readInt16();
		sec=f.readInt16();
		//ts>>year>>month>>day>>hour>>min>>sec;
		cell_->date_access.setYMD(year+1900,month,day);
		cell_->time_access.setHMS(hour,min,sec);
		if (layout::debug){printf("Access: %d:%d:%d,%d:%d:%d\n",year+1900,month,day,hour,min,sec);}
		break;
	case 6: //STRNAM
		cell_->cellName=readString(&f,items);
		if (layout::debug){
		  printf("STRNAM\n");
		  printf("Libname %s\n",cell_->cellName.toLatin1().data());
		}
		if (cellMap[cell_->cellName]!=NULL)report.addItem("Double cell name ",1,cell_->cellName);
		cellMap[cell_->cellName]=cell_;
		used++;
		break;
	case 7: //ENDSTR
		if (layout::debug){
		  printf("ENDSTR\n");
		}
		used++;
		break;
	case 8: //BONDRY ->Polygon
	        elementmode=110;
		point_array.resize(0);
		if (layout::debug){
		  printf("BONDRY\n");
		}
		used++;
		break;
	case 9: //PATH 
	 	elementmode=150;
		point_array.resize(0);
		angle=0;
		mag=1;
		mirror_x=false;
		width=0;
		cap=0;
		endExt=0;
		beginExt=0;
		if (layout::debug){
		  printf("PATH\n");
		}
		used++;
		break;
	case 10: //SREF
		elementmode=120;
		angle=0;
		mag=1;
		mirror_x=false;
		rotate=false;
		mag_=false;
		if (layout::debug){
		  printf("SREF\n");
		}
		used++;
		break;
	case 11: //AREF
		elementmode=130;
		angle=0;
		mag=1;
		mirror_x=false;
		rotate=false;
		mag_=false;
		if (layout::debug){
		  printf("AREF\n");
		}
		used++;
		break;
	case 12: //TEXT
		elementmode=140;
		angle=0;
		mag=1;
		width=0;
		mirror_x=false;
		rotate=false;
		mag_=false;
		presentation=0;
		if (layout::debug){
		  printf("TEXT\n");
		}
		used++;
		break;
	case 13: //LAYER
		//ts>>int16;
		layer=f.readInt16();
		if (layout::debug){
		  printf("LAYER %d\n",layer);
		}
		if (layer<0){layer=0;}
		if (layer>=layersMax){layer=layersMax-1;}
		used++;
		break;
	case 14: //DTATYP
		//ts>>int16;
		used++;
		datatype=f.readInt16();
		if (layout::debug){
		  printf("DATATYPE %d\n",datatype);
		}
		break;
	case 15: //WIDTH 
		//ts>>int32;
		width=f.readInt32();
		if (layout::debug){
		  printf("WIDTH %d\n",width);
		}
		//if (width<0) {width=-width;}
		if (width<0) {report.addItem("Element(s) with negative (=absolute) width.",4,s.setNum(width));}
		used++;
		break;
	case 16: //XY
		if (layout::debug){
		  printf("XY %d\n",(items/2));
		}
		//if (items/2==1337) items+=5*8192*2;
		if ((elementmode==110)&&(point_array.size()>0)){
			for (uint g=0;g<(uint)(items/2);g++){
				int32x=f.readInt32();
				int32y=f.readInt32();
				//ts>>int32x>>int32y;
				if (layout::debug){
					printf("multi xy %d: %d %d %d\n",g,int32x,int32y,(uint)(items/2));
				}
				QPoint p(int32x,int32y);
				point_array.attachPoint(p);
			}
			}
		else {
			point_array.resize((uint)(items/2));
			for (uint g=0;g<(uint)(items/2);g++){
				int32x=f.readInt32();
				int32y=f.readInt32();
				//ts>>int32x>>int32y;
				if (layout::debug){
					printf("%d: %d %d %d\n",g,int32x,int32y,(uint)(items/2));
				}
				point_array.setPoint(g,int32x,int32y);
			}
		}
		used++;
		break;
	case 17: //ENDEL
		{
		int leLayer=layer;
		if (setup::gdsMapLayer) {
		    if (layout::debug){printf("mapping %d, %d\n",layer,datatype);}
		    leLayer=layers::mapLayer(layer,datatype);
		    if (layout::debug){printf("to %d\n",leLayer);}
		}
		if (leLayer>=layers::displayedLayers) {report.addItem("Disabled layer is used",4,s.setNum(leLayer));}
		if (layout::debug){
		  	printf("ENDEL\n");
		  	//printf("element %d\n",elementmode);
		}
		/*if (point_array.size()==0) {
		  printf("element %d\n",elementmode);
		  printf("cell %s\n",cell_->cellName.toAscii().data());
		}*/
		used++;
		switch (elementmode){
		case 100: element_=cell_->addBox(point_array,leLayer);
			  element_->setDatatype(datatype);
			break;
		case 110: 
#ifndef multithread
			element_=cell_->addPolygon(point_array,leLayer);
			  element_->setDatatype(datatype);
#else
			{
			elementList *el=cell_->addElement();
			el->thisElement=new polygon(point_array,leLayer,datatype);
			cleanDis->clean(el->thisElement);
			element_=el->thisElement;
			}
#endif
			break;
		case 120: {
			element_=cell_->addCellref();
			element_->setPos(point_array.point(0));
			cell *c=cellMap.value(sname,NULL);
			if (c==NULL) element_->setName(sname);
			else element_->setCellRef(c);//d->findCell(sname));
			if(mirror_x)element_->rotate(-angle);
			else element_->rotate(angle);
			element_->scale(mag);
			if(mirror_x)element_->setMirrorx();
			sname="";
			mirror_x=false;
			rotate=false;
			}
			break;
		case 130:{
			/*if (mirror_x){
				point=point_array.point(1);
				point.setY(-point.y());
				point_array.setPoint(1,point);
				point=point_array.point(2);
				point.setY(-point.y());
				point_array.setPoint(2,point);};*/
			
			element_=cell_->addCellrefArray(NULL,point_array,anzx,anzy);
			cell *c=cellMap.value(sname,NULL);
			if (c==NULL) element_->setName(sname);
			else element_->setCellRef(c);//d->findCell(sname));
			if(mirror_x)element_->rotate(-angle);
			else element_->rotate(angle);
			element_->scale(mag);
			//element_->setName(sname);
			if(mirror_x)element_->setMirrorx();
			sname="";
			mirror_x=false;
			rotate=false;
			mag_=false;
			anzx=0;
			anzy=0;
			}
			break;
		case 140:
			if (mag==0){mag=1;}
			element_=cell_->addText(leLayer,point_array.point(0),sname);
			if(mirror_x)element_->rotate(-angle);
			else element_->rotate(angle);
			element_->scale(mag);
			element_->setName(sname);
			if(mirror_x)element_->setMirrorx();
			element_->setWidth(width);
			element_->setPresentation(presentation);
			mirror_x=false;
			rotate=false;
			mag_=false;
			sname="";
			break;
		case 150:
			element_=cell_->addPath(point_array,leLayer);
			element_->setWidth(width);
			if (cap!=4) element_->setCap(cap);
			else element_->expandCaps(beginExt,endExt);
			break;
		}
		if (property.size()!=0) {
			element_->addProperty(property);
			property.clear();
		}
		elementmode=0;
		datatype=0;
		}
		break;
	case 18: //SNAME
		sname=readString(&f,items);
		if (layout::debug){
		  printf("SNAME %s\n",sname.toLatin1().data());
		}
		used++;
		break;
	case 19: //COLROW
		//ts>>int16;
		anzx=f.readInt16();
		//ts>>int16;
		anzy=f.readInt16();
		if (layout::debug){
		  printf("COLROW\n");
		}
		used++;
		break;
	/*case 20: //TXTNOD
		break;
	case 21: //NODE
		break;*/
	case 22: //TXTTYP
		//ts>>int16;
		used++;
		datatype=f.readInt16();
		break;
	case 23: //PRSTTN
		//ts>>int16;
		presentation=(f.readInt16()&0x000F);
		if (layout::debug){
		  printf("PRSTIN\n");
		}
		used++;
		break;
	/*case 24: //SPACNG
		break;*/
	case 25: //STRING
		sname=readString(&f,items);
		if (layout::debug){
		  printf("STRING %s\n",sname.toLatin1().data());
		}
		used++;
		break;
		break;
	case 26: //STRANS
		//ts>>int16;
		int16=f.readInt16();
		if ((int16& 0x8000)!=0){mirror_x=true;}else{mirror_x=false;};
		if ((int16& 0x0002)!=0){rotate=true;}else{rotate=false;};
		if ((int16& 0x0004)!=0){mag_=true;}else{mag_=false;};
		if (layout::debug){
		  printf("STRANS\n");
		}
		used++;
		break;
	case 27: //MAG
		mag = read8ByteReal(&f);
		if (layout::debug){
		  printf("MAG\n");
		}
		used++;
		break;
	case 28: //ANGLE 
		angle = read8ByteReal(&f);
		if (layout::debug){
		  printf("ANGLE\n");
		}
		used++;
		break;
	/*case 29: //UINTEG
		break;
	case 30: //USTRNG
		break;
	case 31: //REFLIB
		s=readString(&ts,items);
		if (layout::debug){
		  printf("REFLIB %s\n",s.toLatin1().data());
		}
		break;
	case 32: //FONTS 
		break;*/
	case 33: //PTHTYP
		//ts>>int16;
		cap=f.readInt16();
		if (layout::debug){
		  printf("PATHTYPE %d\n",cap);
		}
		used++;
		break;
		break;
	/*case 34: //GENRTS
		break;
	case 35: //ATRTBL
		break;
	case 36: //STPTBL
		break;
	case 37: //STRTYP
		break;
	case 38: //EFLAGS
		break;
	case 39: //ELKEY 
		break;
	case 40: //LNKTYP
		break;
	case 41: //LNKKEYa
		break;
	case 42: //NODTYP
		break;*/
	case 43: //PROATR 
		propertyNumber=f.readInt16();
		if (layout::debug){
		  printf("PROPERTY %d\n",propertyNumber);
		}
		break;
	case 44: //PROVAL
		{
		QString sPropertyAttrib=readString(&f,items);
		if (layout::debug){
		  printf("PROPERTY Attribute %s\n",sPropertyAttrib.toAscii().data());
		}
		property<<propertyItem(propertyNumber,sPropertyAttrib);
		}
		break; 

	case 45: //BOX 
		elementmode=100; 
		if (layout::debug){
		  printf("BOX\n");
		}
		used++;
		break;
	case 46: //BOXTYP
		//ts>>int16;
		if (layout::debug){
		  printf("BOXTYPE\n");
		}
		used++;
		datatype=f.readInt16();
		break;
	/*case 47: //PLEX  
		break;*/
	case 48: //BGNEXTN
		beginExt=f.readInt32();
		if (layout::debug){
		  printf("BGNEXTN %d\n",beginExt);
		}
		used++;
		break;
	case 49: //ENDEXTN
		endExt=f.readInt32();
		if (layout::debug){
		  printf("ENDEXTN %d\n",endExt);
		}
		used++;
		break;
	/*case 50: //TAPNUM
		break;
	case 51: //TAPCOD
		break;
	case 52: //STRCLS
		break;
	case 53: //RESRVD
		break;
	case 54: //FORMAT
		break;
	case 55: //MASK
		break;
	case 56: //ENDMSK
		break;
	case 57: //LDIRSZ
		break;
	case 58: //SRFNAM
		break;
	case 59: //LIBSCR
		break;*/
	default: { if (layout::debug){
		  printf("unused record %d, type %d :",record,type);
		}
		report.addItem(tr("unknown/unsupported record(s)."),3,s.setNum(record));
		unused++;
		for (int i=0;i<items;i++){
	    	switch (type) {
		case 0:
			break;	/* No Data */
		case 1:			/* Bit Array */
			int16=f.readInt16();
			if (layout::debug){ printf("%d ",int16);}
			break;
		case 2: 			/* Two Byte signed int */
			int16=f.readInt16();
			if (layout::debug){ printf("%d ",int16);}
			break;
		case 3: 			/* Four Byte signed int */
			int32=f.readInt32();
			if (layout::debug){ printf("%d ",int32);}
			break;
		case 4: 			/* Four byte real */
			//ts>>float_;
			int32=f.readInt32();
			if (layout::debug){ printf("%f ",float_);}
			break;
		case 5: 			/* Eight byte real */
		        int32=f.readInt32();
			int32=f.readInt32();
			if (layout::debug){ printf("%f ",double_);}
			break;
		case 6: 			/* ASC */
		        help=f.readInt8();
			if (layout::debug){ printf("%s ",&help);}
			break;
		}}
		if (layout::debug){ printf(" (ende)\n");}
		break;}
	}
  if (((recordCount%5000)==0)||(f.end) ){
		QString sh;
		sh.setNum(recordCount);
		if ((f.end)||(gdsTimer.elapsed()>200)){
			d->showMessage(tr("%1 records loaded.").arg(sh));
			gdsTimer.start();
			}
		}
  }
  f.close();
#ifdef multithread
delete cleanDis;
#endif
#ifdef printtime
  printf("gds load: %d ms\n", setup::centralTimer.elapsed());
#endif
  // resolving brocken 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(cellMap.value(e->thisElement->getName(),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;
  					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: %d ms\n", csetup::entralTimer.elapsed());
  //  
  d->currentCell=d->findTopCell();
  //printf("3: %d ms\n", setup::centralTimer.elapsed());
  if (d->currentCell==NULL) d->currentCell=d->firstCell->thisCell;
  if ((typ==fileImport)||(typ==fileUpdate)) {
	if (d->databaseunits!=databaseunitshelp) {
		filegeneral::fitDifferentDatabaseunits(&report,d,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;*/
			}
		}
  //printf("4: %d ms\n", setup::centralTimer.elapsed());
  if (typ==fileImport) {filegeneral::import(&report,d,firstcellhelp);}
  if (typ==fileUpdate) filegeneral::update(&report,d,firstcellhelp);
  if (layout::debug) {printf("Load complete\n");
	printf("%d unused records\n",unused);
	printf("%d used records\n",used);
	}
  //printf("5: %d ms\n", setup::centralTimer.elapsed());
//setup::centralTimer.start();
 } //end try
 catch (QString s){
  if (d->firstCell==NULL) d->firstCell=new cellList();;
  report.addItem(tr("Aborted. ")+s,0);
  report.addItem(s,1);
 }
  //report.showReport(); 
  s=report.getReport();
  d->showReport(s,report.getLastRang());
}

void gds::save(QString fileName,drawingField *d){
errorreport report;
 
report.setTitle(tr("Save of GDS-File \"")+fileName+"\"");
try { 
  gds gdsClass;
  gdsClass.error=&report;
  gdsClass.drawing=d;
  gdsClass.write=new fileWrite(fileName);
  if ( !gdsClass.write->open() ) {
	throw QString(tr("Can not open File."));
  }
  gdsClass.save();
  gdsClass.write->close();
  delete gdsClass.write;
  if (setup::gdsPad2048) {	
	QFileInfo fi(fileName);
	qint64 size=fi.size ();
	int need=2048-(size%2048);
	if (need<2048){

		QFile f( fileName );
		if ( !f.open( QIODevice::Append) ) {
			throw QString(tr("Can not open File."));
		}
		QDataStream ds(&f);
		for (int i=0;i<need;i++) 
				ds<<(quint8)(0);
	}
  }
}
catch (QString s){
  report.addItem(tr("Aborted. "),0);
  report.addItem(s,1);
 }
  //report.showReport();   
  QString s=report.getReport();
  d->showReport(s,report.getLastRang());
}

void gds::save(){
 // QTime t;
  // t.start();
recordCount=0;
  write->writeUInt16(6); // header
  write->writeUInt8(0);
  write->writeUInt8(2);
  write->writeInt16(7);
  // bgnlib
  write->writeUInt16(28);
  write->writeUInt8(1);
  write->writeUInt8(2);
  write->writeInt16((qint16)(drawing->date_modification.year()-1900));
  write->writeInt16((qint16)drawing->date_modification.month());
  write->writeInt16((qint16)(drawing->date_modification.day()));
  write->writeInt16((qint16)(drawing->time_modification.hour()));
  write->writeInt16((qint16)(drawing->time_modification.minute()));
  write->writeInt16((qint16)(drawing->time_modification.second()));
  write->writeInt16((qint16)(drawing->date_access.year()-1900));
  write->writeInt16((qint16)(drawing->date_access.month()));
  write->writeInt16((qint16)(drawing->date_access.day()));
  write->writeInt16((qint16)(drawing->time_access.hour()));
  write->writeInt16((qint16)(drawing->time_access.minute()));
  write->writeInt16((qint16)(drawing->time_access.second()));
  writeString(drawing->libname,2);//libname
  //units
  write->writeUInt16(20); 
  write->writeUInt8(3);
  write->writeUInt8(5);
  write8ByteReal(drawing->userunits);
  write8ByteReal(drawing->databaseunits);	
  //cells
  cellList *e;
  for(e=drawing->firstCell;e!=NULL;e=e->nextCell){
	e->thisCell->saved=false;}
  bool saved=false;
  while (!saved){
	saved=true;
	for(e=drawing->firstCell;e!=NULL;e=e->nextCell){
		if (e->thisCell->saved==false){
			if (!e->this_cell->dependNotSaved()){
					e->thisCell->saveGDS(this);
					}
			else{saved=false;}};
		}}
   //endlib
  write->writeUInt16(4); 
  write->writeUInt8(4);
  write->writeUInt8(0);
 //printf("save: %d ms\n", t.elapsed());
}

/*void gds::save(QDataStream *stream, drawingField *d, errorreport *report){
  //QTime t;
   //t.start();
recordCount=0;
drawing =d;
error=report;
streamPtr=stream;

  (*streamPtr)<<(quint16) 6<<(quint8) 0<<(quint8)2<<(qint16)3;  //header
  (*streamPtr)<<(quint16) 28<<(quint8) 1<<(quint8)2<< (qint16)(d->date_modification.year()-1900)<< (qint16)(d->date_modification.month())<< (qint16)(d->date_modification.day())<< (qint16)(d->time_modification.hour())<< (qint16)(d->time_modification.minute())<< (qint16)(d->time_modification.second()); //bgnlib 
  (*streamPtr)<< (qint16)(d->date_access.year()-1900)<< (qint16)(d->date_access.month())<< (qint16)(d->date_access.day())<< (qint16)(d->time_access.hour())<< (qint16)(d->time_access.minute())<< (qint16)(d->time_access.second()); //bgnlib 
  writeString(d->libname,2);
  (*streamPtr)<<(quint16) 20<<(quint8) 3<<(quint8)5;//units
  write8ByteReal(d->userunits);
  write8ByteReal(d->databaseunits);	
  //cells
  cellList *e;
  for(e=d->first_cell;e!=NULL;e=e->next_cell){
	e->this_cell->saved=false;}
  bool saved=false;
  while (!saved){
	saved=true;
	for(e=d->first_cell;e!=NULL;e=e->next_cell){
		if (e->this_cell->saved==false){
			if (!e->this_cell->dependNotSaved()){e->this_cell->saveGDS(this);}
			else{saved=false;}};
		}}
  (*streamPtr)<<(quint16) 4<<(quint8) 4<<(quint8)0;  //endlib
 //printf("save: %d ms\n", t.elapsed());
}*/

void gds::count(){
recordCount++;
  if ((recordCount%5000)==0){
		QString sh;
		sh.setNum(recordCount);
		drawing->showMessage(tr("%1 elements stored.").arg(sh));
		}
}


void gds::write8ByteReal(double d,QDataStream *stream){
  int exp,k;
  double mantisse=frexp(d,&exp);
  int i= abs(exp) % 4;
  int exptwo=exp;
  exp=exp/4;
  if (i!=0) {exp++;if (exptwo>0){mantisse/=pow((double)(2),4-i);}else {mantisse/=pow((double)(2),i);exp--;}}
  quint8 help=exp+64;
  if (0>mantisse) {help|=0x80;mantisse*=-1;}
  *stream<<help;
  for (k=0;k<7;k++){
	mantisse*=256;
	help=(quint8)mantisse;
	*stream<<help;
	mantisse-=help;}
}

void gds::write8ByteReal(double d){
  //obsolete
  int exp,k;
  double mantisse=frexp(d,&exp);
  int i= abs(exp) % 4;
  int exptwo=exp;
  exp=exp/4;
  if (i!=0) {exp++;if (exptwo>0){mantisse/=pow((double)(2),4-i);}else {mantisse/=pow((double)(2),i);exp--;}}
  quint8 help=exp+64;
  if (0>mantisse) {help|=0x80;mantisse*=-1;}
  write->writeUInt8(help);
  //(*streamPtr)<<help;
  for (k=0;k<7;k++){
	mantisse*=256;
	help=(quint8)mantisse;
 	write->writeUInt8(help);
	//(*streamPtr)<<help;
	mantisse-=help;}
}

double gds::read8ByteReal(fileRead *f){
  int exp ; // help 
  int sig ; // help
  int i;
  quint8 help;   //help
  double double_;
  help=f->readUInt8();
  exp = help & 0x7f;
  sig = help & 0x80 ? -1 : 1;
  double_=0;
  for (i=0; i<7; i++) {
  	help=f->readUInt8();
	double_=double_*256+help; }
  double_ = sig * (double)double_ * pow((double)(16.0),(exp-64))/256/256/256/256/256/256/256;
  return double_;
}

QString gds::readString (fileRead *f,int items){
  QString s,s1;
  quint8 help;
  int i;
  s1="";
  for (i=0;i<items;i++){
  	help=f->readUInt8();
	if (help!=0){
		s=help; 
		s1+=s;}
	}
  return s1;
}
void gds::writeString (QDataStream *stream,QString s,int type){
  //obsolete
  int len=s.length();
  bool add=false;
  if (len % 2 == 1) {add=true;len++;}
  *stream<<(quint16) (len+4)<<(quint8) type<<(quint8)6; //strname
    stream->writeRawData(s.toAscii(),s.length()); //strname
  if (add) *stream<<(quint8) 0;
}

void gds::writeString (QString s,int type){
  int len=s.length();
  if (len>30000) len=30000;
  bool add=false;
  if (len % 2 == 1) {add=true;
			//len++;
			}
  if (add) write->writeUInt16((quint16) (len+5));
  else write->writeUInt16((quint16) (len+4));
  write->writeUInt8((quint8) (type));
  write->writeUInt8((quint8) (6));
  write->writeString(s,len);
  if (add)  write->writeUInt8((quint8) (0));
 /* (*streamPtr)<<(quint16) (len+4)<<(quint8) type<<(quint8)6; //strname
    streamPtr->writeRawData(s.toAscii(),s.length()); //strname
  if (add) (*streamPtr)<<(quint8) 0;*/
}
