/***************************************************************************
 *   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.             *
 ***************************************************************************/
#include "layers.h"
#include <qstring.h>
#include <qfile.h>
//Added by qt3to4:
#include <QTextStream>
#include <QMap>
#include "general/errorreport.h"
#include "general/setup.h"
#include "general/drawingfield.h"

int layers::displayedLayers=128;
layer layers::num[layersMax];
uint layers::layerColor[layersMax];

layers::layers(): QObject(0)
{
int i;
QString s;
for (i=0;i<layersMax;i++){num[i].name=s.setNum(i);}

/*num[1].brush.setStyle(Qt::HorPattern);
num[1].brush.setColor(qRgb(200,0,0));
num[1].pen.setStyle(Qt::SolidLine);
num[1].pen.setWidth(0);
num[1].pen.setColor(qRgb(200,0,0));
num[2].brush.setStyle(Qt::Dense6Pattern);
num[2].brush.setColor(qRgb(0,200,0));
num[2].pen.setStyle(Qt::SolidLine);
num[2].pen.setWidth(0);
num[2].pen.setColor(qRgb(0,200,0));
num[3].brush.setStyle(Qt::BDiagPattern);
num[3].brush.setColor(qRgb(200,200,0));
num[3].pen.setStyle(Qt::SolidLine);
num[3].pen.setWidth(0);
num[3].pen.setColor(qRgb(200,200,0));
num[4].brush.setStyle(Qt::FDiagPattern);
num[4].brush.setColor(qRgb(0,200,200));
num[4].pen.setStyle(Qt::SolidLine);
num[4].pen.setWidth(0);
num[4].pen.setColor(qRgb(0,200,200));
num[5].brush.setStyle(Qt::DiagCrossPattern);
num[5].brush.setColor(qRgb(200,0,200));
num[5].pen.setStyle(Qt::SolidLine);
num[5].pen.setWidth(0);
num[5].pen.setColor(qRgb(200,0,200));*/
for (i=0;i<layersMax;i++){
	//num[i].brush.setColor(qRgb((unsigned char)(i*4),(unsigned char)(i*7),(unsigned char)(i*25)));
	num[i].pen.setColor(qRgb((unsigned char)(i*4),(unsigned char)(i*7),(unsigned char)(i*25)));
	}
}


layers::~layers()
{
}

int layers::findLayer(QString s){
for (int i=0;i<layersMax;i++){
 if (num[i].name==s){return i;}
}
return -1;
}
#ifdef netlistutility
#include "net/netlistmodule.h"
#endif

void layers::writeLayerMacro(int startLayer,int stopLayer,QString fileName){
 errorreport report;
 report.setTitle(tr("Generate Macro Technogiefile \"")+fileName+"\"");
 try { 
  QFile f( fileName );
  if ( !f.open( QIODevice::WriteOnly ) ) {
	throw QString(tr("Can not open File."));
  }
  QString s;
  QTextStream stream( &f );
  stream<<"#!/usr/bin/layout\n";
  int i=fileName.lastIndexOf("/",-1);
  if (i!=0) fileName=fileName.mid(i+1);
  stream<<"#name=technology file: "<<fileName<<"\n";
  stream<<"#help=technology file automatically generated\n\n\n";
  stream<<"int main(){\n";
  stream<<"layers::enableAllLayer();\n";
  for (int i=startLayer; i<=stopLayer;i++){
    if (layers::num[i].use){
    	stream<<"layers::num["<<s.setNum(i)<<"].name=\""<<layers::num[i].name<<"\";\n";
    	int style=layers::num[i].getStyle();
    	stream<<"layers::num["<<s.setNum(i)<<"].setStyle(";
    	stream<<s.setNum(style)<<");\n";
    	stream<<"layers::num["<<s.setNum(i)<<"].setColor(";
    	stream<<s.setNum(layers::num[i].pen.color().red())<<",";
    	stream<<s.setNum(layers::num[i].pen.color().green())<<",";
    	stream<<s.setNum(layers::num[i].pen.color().blue())<<");\n";
	if (setup::gdsMapLayer||setup::oasisMapLayer){
		stream<<"layers::num["<<s.setNum(i)<<"].mapToLayer= ";
		stream<<s.setNum(layers::num[i].mapToLayer)<<";\n";
		stream<<"layers::num["<<s.setNum(i)<<"].mapToDatatype= ";
		stream<<s.setNum(layers::num[i].mapToDatatype)<<";\n";
	}
	if (layers::num[i].shortkey!="")
		  stream<<"layers::num["<<s.setNum(i)<<"].shortkey=\""<<layers::num[i].shortkey<<"\";\n";
	}
    else {
	 stream<<"layers::num["<<s.setNum(i)<<"].disable();\n";
	}
  }
#ifdef netlistutility
  netListModule::saveTechnologyLayerMacro(&stream,startLayer,stopLayer);
  netListModule::saveLibraryMacro(&stream);
#endif
  stream<<"}\n";
  f.close();
}
catch (QString s){
  report.addItem(tr("Aborted. "),0);
  report.addItem(s,1);
 }
  report.showReport();   
}

void layers::write3dSetupMacro(QString fileName){
 errorreport report;
 report.setTitle(tr("Generate 3D Setup Macro \"")+fileName+"\"");
 try { 
  QFile f( fileName );
  if ( !f.open( QIODevice::WriteOnly ) ) {
	throw QString(tr("Can not open File."));
  }
  QString s;
  QTextStream stream( &f );
  stream<<"#!/usr/bin/layout\n";
  int i=fileName.lastIndexOf("/",-1);
  if (i!=0) fileName=fileName.mid(i+1);
  stream<<"#name=3d layer setup: "<<fileName<<"\n";
  stream<<"#help=sets up the 3d view \n\n\n";
  stream<<"int main(){\n";
  stream<<"layers::reset3dView();\n";
  for (int i=0; i<layersMax;i++)
    if (layers::num[i].use)
	if (layers::num[i].thickness3d!=0){
		QString thick,level;
		thick.setNum(layers::num[i].thickness3d);
		level.setNum(layers::num[i].level3d);
    		stream<<"layers::num["<<s.setNum(i)<<"].set3dView("<<level<<","<<thick<<");\n";
  }
  stream<<"}\n";
  f.close();
}
catch (QString s){
  report.addItem(tr("Aborted. "),0);
  report.addItem(s,1);
 }
  report.showReport();   
}

void layers::checkLayer(){
	QList<int> levelList;
	QMap<int, int> map; 
	int globalLayer=-1;
	for (int i=0;i<layersMax;i++){
		if (num[i].layerType!=layerTypeUnknown){
		int level=num[i].getTypeParameter(0);
		if (level==-2)globalLayer=i;
		else {
		//if (!levelList.contains(level))levelList<<level;
		map.insertMulti(level,i);
		}
		}
	}
	//qSort(levelList.begin(), levelList.end());
	int num_=0;
	int lastGobal=-1;
	//printf("global %d\n",globalLayer);
	for(int i=0;i<layersMax;i++){
		QList<int> l=map.values(i);
		if ((l.size()==0)&&(globalLayer>=0)&&(lastGobal+1!=num_)){
			//printf("use global %d\n",num_);
			lastGobal=num_;
			num_++;
		} else
		for (int k=0;k<l.size();k++){
			num[l[k]].setTypeParameter(0,num_);
			num_++;
		}
	}
}

int layers::maxLevel(){
	int max=-1;
	for (int i=0;i<layersMax;i++){
		if (num[i].layerType!=layerTypeUnknown){
		int level=num[i].getTypeParameter(0);
		if (level>max) max=level;
		}
	}
//printf("max level %d\n",max);
	return max;
}


int layers::findLevel(int j){
	int globalVia=-1;
	for (int i=0;i<layersMax;i++){
		if (num[i].layerType!=layerTypeUnknown){
		int level=num[i].getTypeParameter(0);
		if (level==-2) globalVia=i;
		if (level==j) return i;
		}
	}
	if (globalVia>=0) return globalVia;
	return -1;
}

int layers::globalVia(){
	for (int i=0;i<layersMax;i++){
		if (num[i].layerType!=layerTypeUnknown){
		int level=num[i].getTypeParameter(0);
		if (level==-2) return i;
		}
	}
	return -1;
}

QList<int> layers::viaLevels(){
QList<int> list;
for (int i=maxLevel();i>=0;i--){
	int lay=findLevel(i);
	if (num[lay].layerType==layerTypeVia) list<<i;
}
return list;
}

QList<int> layers::conductorLayers()
{
QList<int> list;
for (int i=layersMax;i>=0;i--){
	if (num[i].layerType==layerTypeConductor) list<<i;
}
return list;
}

int layers::unusedLayer(){
for (int i=layersMax;i>=0;i--){
	if (num[i].layerType==layerTypeUnknown) return i;
}
return 0;
}

short layers::layerMap[layersMax][datatypeMax+1];

void layers::generateLayerMap(){
for (int i=0;i<layersMax;i++)
 for (int k=0;k<datatypeMax;k++)
  layerMap[i][k]=i;
for (int i=0;i<layersMax;i++) {
  if (num[i].mapToDatatype<0)
    for (int k=0;k<datatypeMax;k++)
  	layerMap[num[i].mapToLayer][k]=i;
  }
for (int i=0;i<layersMax;i++) 
	if ((num[i].mapToDatatype>=0)&&(num[i].mapToDatatype<datatypeMax)){
  		layerMap[num[i].mapToLayer][num[i].mapToDatatype]=i;
  }
}

void layers::generateLayerAutoMap(drawingField *d){
for (int i=0;i<layersMax;i++)
 for (int k=0;k<=datatypeMax;k++)
  layerMap[i][k]=-1;
if (d!=NULL){
	QBitArray b(layersMax,false);
	d->firstCell->useLayer(&b);
	for (int i=0;i<layersMax;i++)
		if (b.testBit(i))layerMap[i][datatypeMax]=0;
		else layerMap[i][datatypeMax]=-1;
	}
}

int layers::mapLayer(int layer,int datatype){
if (layer<0)return 0;
if (layer>=layersMax)return 0;
if (datatype<0)return 0;
if (datatype>=datatypeMax)return 0;
short result=layerMap[layer][datatype];
if (result<0){
	int i=2;
	while ((i<layersMax)&&(layerMap[i-1][datatypeMax]>=0)) {i++;}
	//printf("%d\n",i);
	if (i<layersMax){
		--i;
		layerMap[layer][datatype]=i;
		layerMap[i][datatypeMax]=0;
		result=i;
		num[i].mapToLayer=layer;
		num[i].mapToDatatype=datatype;
		QString s1,s2;
		s1.setNum(layer);
		s2.setNum(datatype);
		num[i].name=s1+"/"+s2;
		}
	else return 0;
	}
return result;
}


int layers::bestColor(QColor col){
int dif=60*256;
int lay=0;
for (int i=0;i<layersMax;i++) if (num[i].use==true){
	QColor colLayer=num[i].pen.color();
	int d=abs(colLayer.red()-col.red())+ abs(colLayer.green()-col.green()) +
	abs(colLayer.blue()-col.blue())+ abs(colLayer.hue()-col.hue())+ abs(colLayer.saturation () -col.saturation () );
	if (d<dif) {
		dif=d;
		lay=i;
	}	
  }
return lay;
}

int layers::bestColorUsed(QColor col){
int dif=60*256;
int lay=0;
for (int i=0;i<displayedLayers;i++) if (num[i].use==true){
	QColor colLayer=num[i].pen.color();
	int d=abs(colLayer.red()-col.red())+ abs(colLayer.green()-col.green()) +
	abs(colLayer.blue()-col.blue())+ abs(colLayer.hue()-col.hue())+ abs(colLayer.saturation () -col.saturation () );
	if (d<dif) {
		dif=d;
		lay=i;
	}	
  }
return lay;
}


void layers::disableUnusedLayers(drawingField *d){
QBitArray b(layersMax,false);
d->firstCell->useLayer(&b);
for (int i=0;i<layersMax;i++)
		if (b.testBit(i))num[i].enable();
		else num[i].disable();
/*
	for (int i=0;i<layer_max;i++)
		if (d->useLayer(i))num[i].enable();
		else num[i].disable();*/
}

void layers::hideUnusedLayers(drawingField *d){
QBitArray b(layersMax,false);
d->firstCell->useLayer(&b);
for (int i=0;i<layersMax;i++)
		if (b.testBit(i))num[i].visible=true;
		else num[i].visible=false;
/*
	for (int i=0;i<layer_max;i++)
		if (d->useLayer(i))num[i].visible=true;
		else num[i].visible=false;*/
}

void layers::hideCurrentUnusedLayers(drawingField *d){
QBitArray b(layersMax,false);
d->firstCell->clearMarker();
d->currentCell->markDepend();
d->firstCell->useLayerMarked(&b);
for (int i=0;i<layersMax;i++)
		if (b.testBit(i))num[i].visible=true;
		else num[i].visible=false;
/*
	for (int i=0;i<layer_max;i++)
		if (d->useLayer(i))num[i].visible=true;
		else num[i].visible=false;*/
}

void layers::calLayerColor(){
  int min=0;
  int max=1;
  for (int i=0;i<layersMax;i++){
    if (num[i].level3d>max) max=num[i].level3d;
    if (num[i].level3d<min) min=num[i].level3d;
  }
  int of=-min+1;
  double f=double(max-min)/253;
  for (int i=0;i<layersMax;i++){
    layerColor[i]=(uint)(layers::num[i].pen.color().rgb()& 0xffffff)+((uint(double(num[i].level3d+of)/f)+1)<<24);//(uint(num[i].level3d+of)/f)<<24;
    //printf("%d %d %d %d\n",(uint(num[i].level3d+of)/f),f,of,num[i].level3d);
    //printf("%d %d %d (%d %d)\n",i,layerColor[i]& 0xffffff,layers::num[i].pen.color().rgb()& 0xffffff,layerColor[i]>>24,layers::num[i].pen.color().rgb()>>24);
  }
}
