/***************************************************************************
 *   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 "gerber.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"
#include "layout.h"
#include "macro/macro.h"
#include "filedialog.h"
#include <QDir>


gerber::gerber(QObject *parent, const char *)
 : QObject(parent)
{
  omitLeadingZeroes=true;
  absCoordinates=true;
  dig1x=2;
  dig2x=3;
  dig1y=2;
  dig2y=3;
  unit="inch";
}


gerber::~gerber()
{
}


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

void gerber::openMacro(QString fileName,drawingField *d){
  layout *l=reinterpret_cast <layout*>(d->parent());
  QString s1,s2;
  if (macro::isMacro(&fileName,&s1,&s2)) {
			l->executeMacro(fileName);}
  else {
	errorreport report;
	report.setTitle(tr("Save of gerber-File \"")+fileName+"\"");
	report.addItem(tr("Aborted. "),0);
	report.addItem(tr("Gerber file format yet can not be loaded. No valid macro!"),1);
	QString s=report.getReport();
	d->showReport(s,report.getLastRang());
  };
}

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

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

void gerber::load(QString fileName,drawingField *d, fileOpenType typ){
 
  if (typ==fileImport) {
  	report.setTitle(tr("Import of Gerber-File \"")+fileName+"\"");}
  else  if (typ==fileOpen){
	report.setTitle(tr("Open of Gerber-File \"")+fileName+"\"");}
  else  if (typ==fileUpdate){
	report.setTitle(tr("Update with Gerber-File \"")+fileName+"\"");}
try { 
#ifdef printtime
  setup::centralTimer.start();
#endif
  //cellList *firstcellhelp=d->firstCell;
  //double databaseunitshelp=d->databaseunits;
  QFile f( fileName );
  if ( !f.open( QIODevice::ReadOnly ) )
	  throw QString(tr("Can not open File: %1").arg(fileName));
  /*if ((typ==fileImport)||(typ==fileUpdate)) {
	d->firstCell=NULL;
  }*/
  QTextStream ts( &f );
  QString s="";
  cellList *cell_list=NULL;
  cell *cell_=NULL;
  if (typ==fileOpen){
	cell_list=d->addCell();
	cell_=cell_list->thisCell;
	d->currentCell=cell_;
  }
  else {
	cell_=d->currentCell;
	  
  }
  databaseunits=d->databaseunits;
  int layer=d->activeLayer;
  int layerDark=layer;
  int layerClear=d->activeLayer+1;
  if (layerClear>=layersMax)layerClear=0;
  if ((typ==fileUpdate)){
	cell_->deselectAll();
	cell_->selectLayer(layer);
	cell_->deleteSelect();
  }
  bool command=false;
  int gCode=-1;
  int dCode=-1;
  int mCode=-1;
  int aperture=0;
  int interpolation=-1;
  QStringList apertures;
  bool ende=false;
  bool polygonmode=false;
  bool multiquadrant=false;
  pointArray polygon;
  QPoint oldPoint,newPoint;
  while (!ende){
  
  int i=s.indexOf("*");
  if (i>=0) {
	QString com=s.left(i);
	s=s.mid(i+1);
	while (com[0]=='%') {
		command= !command;
		com=com.mid(1);
	}
	if (command){
		//report.addItem(tr("command"),1,com);
		if (com=="MOIN") unit="inch";
		else if (com=="MOMM") unit="mm";
		else if (com.left(2)=="IN"){
			QString name=com.mid(2);
			if (typ==fileOpen) 
				cell_->cellName=name;
		}
		else if (com.left(2)=="FS"){
			if (com[2]=='T') omitLeadingZeroes=false;
			if (com[3]=='I') absCoordinates=false;
			com=com.mid(4);
			if (com[0]=='N') com=com.mid(2);
			if (com[0]=='G') com=com.mid(2);
			if (com[0]=='X') {
				dig1x=QString(com[1]).toInt();
				dig2x=QString(com[2]).toInt();
				com=com.mid(3);
			}
			if (com[0]=='Y') {
				dig1y=QString(com[1]).toInt();
				dig2y=QString(com[2]).toInt();
				com=com.mid(3);
			}
		}
		else if (com.left(3)=="ADD"){
			//report.addItem(tr("ADD"),3,com);
			com=com.mid(3);
			int num=readInt(&com);
			while (num>=apertures.size())apertures<<"";
			apertures[num]=com;
		}
		else if (com.left(3)=="LPD"){
			layer=layerDark;
			}
		else if (com.left(3)=="LPC"){
			layer=layerClear;
			QString lc;
			lc.setNum(layerClear);
			report.addItem(tr("clear layer polarity is used and put on layer"),3,lc);
			}
		else {
			// unsupported command ->warning
			report.addItem(tr("unsupported parameter"),3,com);
		}
	}
	else {
		oldPoint=newPoint;
		if ((com.length()>2)&&(!com.contains("D"))&&(dCode>=0))
			if ((com.contains("X"))||(com.contains("Y"))){
				QString sd;
				sd.setNum(dCode);
				com+="D"+sd;
				}
		gCode=-1;
		dCode=-1;
		mCode=-1;
		int iCode=0;
		int jCode=0;
		while (com.length()>0)
		if (com[0]=='G'){
			if (layout::debug) printf("G-code %s:",com.toAscii().data());
			com=com.mid(1);
			gCode=readInt(&com);
			if (layout::debug) printf(" (%d)\n",gCode);
			if (gCode==4) {
				//kommentar
				com="";
			}
			else if (gCode==36) {
				polygonmode=true;
				polygon.resize(0);
			}
			else if (gCode==37) {
				polygonmode=false;
				cell_->addPolygon(polygon,layer);
			}
			else if (gCode==2) interpolation=1;
			else if (gCode==3) interpolation=2;
			else if (gCode==75)	multiquadrant=true;
			else if (gCode==1) interpolation=-1;
			else if (gCode==10) interpolation=-1;
			else if (gCode==11) interpolation=-1;
			else if (gCode==12) interpolation=-1;
			else if (gCode==74) multiquadrant=false;
			else if (gCode==54) {
					if (com[0]=='D'){
						com=com.mid(1);
						aperture=readInt(&com);
					} else report.addItem(tr("D code expected"),2,com);
				}
			else
				report.addItem(tr("unsupported G code"),2,com);
		}
		else if (com[0]=='X'){
			com=com.mid(1);
			int x=readX(&com);
			if (absCoordinates) newPoint.setX(x);
			else newPoint.setX(x+newPoint.x());
		}
		else if (com[0]=='Y'){
			com=com.mid(1);
			int y=readY(&com);
			if (absCoordinates) newPoint.setY(y);
			else newPoint.setY(y+newPoint.y());
		}
		else if (com[0]=='I'){
			com=com.mid(1);
			iCode=readX(&com);
		}
		else if (com[0]=='J'){
			com=com.mid(1);
			jCode=readY(&com);
		}
		else if (com[0]=='D'){
			com=com.mid(1);
			dCode=readInt(&com);
			if (dCode==1) {
				//expose on
				QString s4;
				s4.setNum(aperture);
				pointArray inter;
				if (iCode+jCode==0)interpolation=-1;
				if ((interpolation==1)&&(!multiquadrant)){
					QPoint p1=QPoint(iCode,jCode)+oldPoint;
					QPoint p2=QPoint(iCode,-jCode)+oldPoint;
					QPoint p3=QPoint(-iCode,jCode)+oldPoint;
					QPoint p4=QPoint(-iCode,-jCode)+oldPoint;
					pointArray pa;
					QPoint center;
					double a=element::angle(oldPoint,p1,newPoint);
					if ((a>=0)&&(a<=90)) pa<<p1;
					a=element::angle(oldPoint,p2,newPoint);
					if ((a>=0)&&(a<=90)) pa<<p2;
					a=element::angle(oldPoint,p3,newPoint);
					if ((a>=0)&&(a<=90)) pa<<p3;
					a=element::angle(oldPoint,p4,newPoint);
					if ((a>=0)&&(a<=90)) pa<<p4;
					if (pa.size()==1) center=pa.point(0);
					else if (pa.size()==2) {
						double dis0=abs((int)(element::distance(pa.point(0),oldPoint)-element::distance(pa.point(0),newPoint)));
						double dis1=abs((int)(element::distance(pa.point(1),oldPoint)-element::distance(pa.point(1),newPoint)));
						if (dis0<dis1) center=pa.point(0);
						else center=pa.point(1);
					} else center=QPoint (0,0);
					inter=element::spirale(center,newPoint,oldPoint,setup::circularDefault);
					inter.flip();
				} 
				else if ((interpolation==2)&&(!multiquadrant)){
					QPoint p1=QPoint(iCode,jCode)+oldPoint;
					QPoint p2=QPoint(iCode,-jCode)+oldPoint;
					QPoint p3=QPoint(-iCode,jCode)+oldPoint;
					QPoint p4=QPoint(-iCode,-jCode)+oldPoint;
					pointArray pa;
					QPoint center;
					double a=element::angle(oldPoint,p1,newPoint);
					if ((a<=0)&&(a>=-90)) pa<<p1;
					a=element::angle(oldPoint,p2,newPoint);
					if ((a<=0)&&(a>=-90)) pa<<p2;
					a=element::angle(oldPoint,p3,newPoint);
					if ((a<=0)&&(a>=-90)) pa<<p3;
					a=element::angle(oldPoint,p4,newPoint);
					if ((a<=0)&&(a>=-90)) pa<<p4;
					if (pa.size()==1) center=pa.point(0);
					else if (pa.size()==2) {
						double dis0=abs((int)(element::distance(pa.point(0),oldPoint)-element::distance(pa.point(0),newPoint)));
						double dis1=abs((int)(element::distance(pa.point(1),oldPoint)-element::distance(pa.point(1),newPoint)));
						if (dis0<dis1) center=pa.point(0);
						else center=pa.point(1);
					} else center=QPoint (0,0);
					inter=element::spirale(center,oldPoint,newPoint,setup::circularDefault);
				}
				else if ((interpolation==1)&&(multiquadrant)){
					QPoint center=QPoint(iCode,jCode)+oldPoint;
					inter=element::spirale(center,newPoint,oldPoint,setup::circularDefault);
					inter.flip();
				}
				else if ((interpolation==2)&&(multiquadrant)){
					QPoint center=QPoint(iCode,jCode)+oldPoint;
					inter=element::spirale(center,oldPoint,newPoint,setup::circularDefault);
				}
				else {
					inter<<oldPoint;
					inter<<newPoint;
				}
				if (polygonmode) {
					if (polygon.size()>0) inter.deletePoint(0);
					polygon<<inter;
				}
				else if (aperture<apertures.size()){
					QString s1=apertures[aperture];
					QList<int> parameter=readParameter(s1.mid(2));
					if (s1[0]=='C'){
						element *e=cell_->addPath(inter,layer);
						e->setWidth(parameter[0]);
						e->setCap(1);
					}					
					else if (s1[0]=='R'){
						element *e=cell_->addPath(inter,layer);
						e->setWidth(parameter[0]);
						//e->setCap(1);
					}
					else 
						 report.addItem(tr("unsupported aperture"),2,s1);
				}
				else report.addItem(tr("undefined aperture"),2,s4);


			}
			else if (dCode==2) {
				//expose off
			}
			else if (dCode==3) {
				//flash
				QString s4;
				s4.setNum(aperture);
				if (aperture<apertures.size()){
					QString s1=apertures[aperture];
					if (s1.left(4)=="RECT"){
						QString aper=s1.mid(5);
						int para1=readPos(&aper);
						aper=aper.mid(1);
						int para2=readPos(&aper);
						aper=aper.mid(1);
						double para3=aper.toDouble();
						//printf("%s %d %d %d\n",aper.toAscii().data(),para1,para2,para3);
						{
							pointArray pa;
							pa<<QPoint(-para1/2,-para2/2);
							pa<<QPoint(-para1/2,+para2/2);
							pa<<QPoint(+para1/2,+para2/2);
							pa<<QPoint(+para1/2,-para2/2);
							pa<<QPoint(-para1/2,-para2/2);
							element *e = cell_->addPolygon(pa,layer);
							strans m;
							m.translate(newPoint.x(),newPoint.y());
							m.rotate(para3);
							e->map(m);
							}
						
						}
					else {
					QList<int> parameter=readParameter(s1.mid(2));
					if (s1[0]=='C'){
						if (parameter.size()==1){
							//circle
							cell_->addCircle(layer,newPoint,parameter[0]/2);
						}
						else if (parameter.size()==2){
								//circle with circle hole
								pointArray pa=element::spirale(newPoint,newPoint+QPoint(parameter[1]/2,0),newPoint+QPoint(parameter[1]/2,0),setup::circularDefault);
							    pa.flip();
								pa<<element::spirale(newPoint,newPoint+QPoint(parameter[0]/2,0),newPoint+QPoint(parameter[0]/2,0),setup::circularDefault);
								pa<<pa.point(0);
								cell_->addPolygon(pa,layer);
						}
						else if (parameter.size()==3){
								//circle with rectangular hole
								pointArray pa=element::spirale(newPoint,newPoint+QPoint(parameter[0]/2,0),newPoint+QPoint(parameter[0]/2,0),setup::circularDefault);
								pa<<QPoint(parameter[1]/2,0)+newPoint;
							    pa<<QPoint(parameter[1]/2,-parameter[2]/2)+newPoint;
							    pa<<QPoint(-parameter[1]/2,-parameter[2]/2)+newPoint;
							    pa<<QPoint(-parameter[1]/2,parameter[2]/2)+newPoint;
							    pa<<QPoint(parameter[1]/2,parameter[2]/2)+newPoint;
							    pa<<QPoint(parameter[1]/2,0)+newPoint;
							    pa<<QPoint(parameter[0]/2,0)+newPoint;
								cell_->addPolygon(pa,layer);
							}
					}
					else if (s1[0]=='R'){
						s1=s1.mid(2);
						if (parameter.size()==1){
							//square
							cell_->addBox(newPoint.x()-parameter[0]/2,newPoint.y()-parameter[0]/2,parameter[0],parameter[0],layer);
							}
						else if (parameter.size()==2){
							// rectangle
							cell_->addBox(newPoint.x()-parameter[0]/2,newPoint.y()-parameter[1]/2,parameter[0],parameter[1],layer);
							}
						else if (parameter.size()==3){
							//rec with circle hole
							pointArray pa=element::spirale(newPoint,newPoint+QPoint(parameter[2]/2,0),newPoint+QPoint(parameter[2]/2,0),setup::circularDefault);
							pa<<QPoint(parameter[0]/2,0)+newPoint;
							pa<<QPoint(parameter[0]/2,-parameter[1]/2)+newPoint;
							pa<<QPoint(-parameter[0]/2,-parameter[1]/2)+newPoint;
							pa<<QPoint(-parameter[0]/2,parameter[1]/2)+newPoint;
							pa<<QPoint(parameter[0]/2,parameter[1]/2)+newPoint;
							pa<<QPoint(parameter[0]/2,0)+newPoint;
							pa<<pa.point(0);
							cell_->addPolygon(pa,layer);
							}
						else if (parameter.size()==4){
							//rec with rec hole
							pointArray pa;
							pa<<QPoint(parameter[0]/2,0)+newPoint;
							pa<<QPoint(parameter[0]/2,parameter[1]/2)+newPoint;
							pa<<QPoint(-parameter[0]/2,parameter[1]/2)+newPoint;
							pa<<QPoint(-parameter[0]/2,-parameter[1]/2)+newPoint;
							pa<<QPoint(parameter[0]/2,-parameter[1]/2)+newPoint;
							pa<<QPoint(parameter[0]/2,0)+newPoint;
							pa<<QPoint(parameter[2]/2,0)+newPoint;
							pa<<QPoint(parameter[2]/2,-parameter[3]/2)+newPoint;
							pa<<QPoint(-parameter[2]/2,-parameter[3]/2)+newPoint;
							pa<<QPoint(-parameter[2]/2,parameter[3]/2)+newPoint;
							pa<<QPoint(parameter[2]/2,parameter[3]/2)+newPoint;
							pa<<QPoint(parameter[2]/2,0)+newPoint;
							pa<<QPoint(parameter[0]/2,0)+newPoint;
							cell_->addPolygon(pa,layer);
							}
					}
					else 
						 report.addItem(tr("unsupported aperture"),2,s1);
					}
				}
				else report.addItem(tr("undefined aperture"),2,s4);
				//cell_->addBox(newPoint.x(),newPoint.y(),2000,2000,layer+1);
			}else{
				aperture=dCode;
			}
		}
		else if (com[0]=='M'){
			com=com.mid(1);
			mCode=readInt(&com);
			if (mCode==2) ende=true;
		}
		else if (com[0]=='%'){
			com="";
			command= !command;
		}
		else {
			com=com.mid(1);
			readInt(&com);
		}
	}
  }
  else {
	  if (!ts.atEnd()) s+=ts.readLine().trimmed();
	  else ende=true;
  }
  //ts.atEnd()
  }
  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()));
					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("gerber 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());

}

int gerber::readInt(QString *com){
	int pos=com->indexOf(QRegExp("[ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwx*]"));
	if (pos>=0){
		int ret=com->left(pos).toInt();
		*com=com->mid(pos);
		return ret;
	}
	else {
		int ret=com->toInt();
		*com="";
		return ret;
	}
}

int gerber::readPos(QString *com){
	int pos=com->indexOf(QRegExp("[ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwx*]"));
	double ret;
	if (pos>=0){
		ret=com->left(pos).toDouble();
		*com=com->mid(pos);
	}
	else {
		ret=com->toDouble();
		*com="";
	}
	double sc=0.0254;
	if (unit=="mm") sc=0.001;
	sc=sc/databaseunits;
	return element::runden(sc*ret);
}

QList<int> gerber::readParameter(QString s){
	QList<int> list;
	while (s!="") {
		list<<readPos(&s);
		s=s.mid(1);
	}
	return list;
}

int gerber::readX(QString *com){
	int size=com->indexOf(QRegExp("[ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwx*]"));
	if (size<0)size=com->length();
	int val=readInt(com);
	if (!omitLeadingZeroes){
		for (int k=0;k<(dig1x+dig2x)-size;k++) val*=10;
	}
	double sc=0.0254;
	if (unit=="mm") sc=0.001;
	sc=sc/databaseunits;
	for (int k=0;k<(dig2x);k++) sc/=10;
	val=element::runden(sc*val);
	return val;
}

int gerber::readY(QString *com){
	int size=com->indexOf(QRegExp("[ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwx*]"));
	if (size<0)size=com->length();
	int val=readInt(com);
	if (!omitLeadingZeroes){
		for (int k=0;k<(dig1y+dig2y)-size;k++) val*=10;
	}
	double sc=0.0254;
	if (unit=="mm") sc=0.001;
	sc=sc/databaseunits;
	for (int k=0;k<(dig2y);k++) sc/=10;
	val=element::runden(sc*val);
	return val;
}

void gerber::save(QString fileName,drawingField *d){
errorreport report;
report.setTitle(tr("Save of gerber-File \"")+fileName+"\"");
try { 
  QString fn=filedialog::extension(fileName);
  int pos=fileName.lastIndexOf(fn); 
  QString fnBase=fileName;
  if (pos>0) fnBase=fileName.left(pos-1);
// -> check extension
  //throw QString(tr("Gerber file format yet can not be saved. Choose an other format!"));
  d->prepareUndo();
  d->currentCell->selectAll();
  elementCount ec1= d->currentCell->countSelect();
  d->currentCell->flatAllSelect();
  d->currentCell->deselectAll();
  if (ec1.cellref+ec1.cellrefarray!=0) {
	report.addItem(tr("No hierachy in gerber, current cell is flatten"),2,"");
	d->recountSelect();
	}
  int numLayer=0;
  bool layerused[layersMax];
  for (int i=0; i<layersMax;i++){
  	 if ((d->useLayer(i))&&(layers::num[i].use==true)) {
	 	numLayer++;
		layerused[i]=true;
		QFile f( fnBase+"-"+layers::num[i].name+".gbx" );
		if ( !f.open( QIODevice::WriteOnly ) ) {
			throw QString(tr("Can not open File."));
		}
		QTextStream stream( &f );
		gerber gerberClass;
		gerberClass.save(&stream,d,&report,i);
		f.close();
		}
	 else layerused[i]=false;
	 }
  QFile f( fnBase+".gerber.layout" );
  if ( !f.open( QIODevice::WriteOnly ) ) {
	throw QString(tr("Can not open File."));
  }
  QTextStream stream( &f );
  //printf("%s\n",QDir::currentPath().toAscii().data());

  fnBase.remove(QFileInfo(f).path()+"/");
  stream<<"#!/usr/bin/layout\n#name=Load \"";
  stream<<fnBase;
  stream<<"\"\n#help=Macro to load the gerber files;";
  stream<<"\n\n\n";
  stream<<"int  main() {\n";
  stream<<"file f;\n";
  stream<<"string s;\n";
  stream<<"s=f.currentPath()+\"/\";\n";
  stream<<"layout->filename=s+\""+fnBase+".gerber.layout"+"\";\n";
  bool first=true;
  for (int i=0; i<layersMax;i++){
  	 if (layerused[i]) {
		QString s;
		s.setNum(i);
		stream<<"layers::num["+s+"].name=\""+layers::num[i].name+"\";\n";
		stream<<"layout->drawing->activeLayer="+s+";\n";
		if (first) {
			stream<<"layout->drawing->openFile(\""<<fnBase+"-"+layers::num[i].name+".gbx"<<"\");\n";
			first=false;
		} else {
			stream<<"layout->drawing->importFile(\""<<fnBase+"-"+layers::num[i].name+".gbx"<<"\");\n";
		}
		}
	 }
  stream<<"}\n";
  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 gerber::save(QTextStream *streamPtr, drawingField *d , errorreport *e ,int layer){
	/*	if (com=="MOIN") unit="inch";
		else if (com=="MOMM") unit="mm";*/
  *streamPtr<<"G04 GERBER FILE EXPORTED BY LAYOUTEDITOR (HTTP://WWW.LAYOUTEDITOR.NET)*\r\n";
  reportSave=e;
  //*streamPtr<<"MOIN\r\n";
  //*streamPtr<<"%FSLAX46Y46%\r\n";
   databaseunits=d->databaseunits*1000;
   int nach=0;
   int vor;
   while (databaseunits<0.99){
	databaseunits*=10;
	nach++;
	}
   bool inch=false;
    if (databaseunits==2.54) {
		inch=true;
		nach--;
		*streamPtr<<"%MOIN*%\r\n";
		}
    else {
	//mm
	*streamPtr<<"%MOMM*%\r\n";
   }
   if (nach>6) nach=6;
   vor=10-nach;
   if (vor>6) vor=6;
   scale=d->databaseunits*1000;
   for (int i=0;i<nach;i++) scale*=10;
   QString s1,s2;
   s1.setNum(vor);
   s2.setNum(nach);
   *streamPtr<<"%FSLAX"<<s1<<s2<<"Y"<<s1<<s2<<"*%\r\n";
   if (inch){
	scale/=2.54;
	}
   databaseunits=scale;
   for (int i=0;i<nach;i++) databaseunits/=10;
   s1=d->currentCell->cellName;
   s1.remove("*");
   *streamPtr<<"%IN"<<s1<<"*%\r\n";
   saveLayer=layer;
   apertur.clear();
   elements.clear();
   output="";
   d->currentCell->saveGerber(this);
   for (int i=0;i<apertur.size();i++){
	QString snum;
	snum.setNum(i+10);
	if (snum.length()<2) snum="0"+snum;
	if (snum.length()<3) snum="0"+snum;
	snum="D"+snum;
	*streamPtr<<"%AD"<<snum<<apertur[i]<<"*%\r\n";
	}
   for (int i=0;i<apertur.size();i++){
	QString snum;
	snum.setNum(i+10);
	if (snum.length()<2) snum="0"+snum;
	if (snum.length()<3) snum="0"+snum;
	snum="D"+snum;
	*streamPtr<<snum<<"*\r\n";
	*streamPtr<<elements[i];
	}
  *streamPtr<<output;
}

QString gerber::aperturSquare(int length){
 QString s;
 s.setNum(databaseunits*length,'g');
 s="R,"+s+"X"+s+"";
 return s;
}

QString gerber::aperturCircle(int length){
 QString s;
 s.setNum(databaseunits*length,'g');
 s="C,"+s+"";
 return s;
}
  

QString gerber::aperturRect(int width, int hight){
 QString s,s1;
 s.setNum(databaseunits*width,'g');
 s1.setNum(databaseunits*hight,'g');
 s="R,"+s+"X"+s1+"";
 return s;
}

void gerber::writeOutput(QString s){
output+=s;
}

void gerber::writeOutput(QPoint p,int d){
	QString val,sx,sy;
	sx.setNum(element::runden(scale*p.x()));
	sy.setNum(element::runden(scale*p.y()));
	val="X"+sx+"Y"+sy;
	sx.setNum(d);
	if (sx.length()==1)sx="0"+sx;
	val+="D"+sx+"*\r\n";
	output+=val;
}


void gerber::write(QString aper,QPoint p,int d){
	QString val,sx,sy;
	sx.setNum(element::runden(scale*p.x()));
	sy.setNum(element::runden(scale*p.y()));
	val="X"+sx+"Y"+sy;
	sx.setNum(d);
	if (sx.length()==1)sx="0"+sx;
	val+="D"+sx+"*\r\n";
	int pos=apertur.indexOf(aper);
	if (pos<0) {
		elements<<val;
		apertur<<aper;
	}
	else
	{
	elements[pos]+=val;
	}
}


