/***************************************************************************
 *   Copyright (C) 2008 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 "pixel.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 "general/setup.h"
#include "elements/element.h"
#include <qstringlist.h>
#include "layout.h"
#include "elements/pointarray.h"
#include <QFileInfo>
#include <QHash>

drawingField *pixel::df=NULL;

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


pixel::~pixel()
{
}


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

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

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

void pixel::load(QString fileName,drawingField *d,fileOpenType typ){
  if (typ==fileImport) {
  	report.setTitle(tr("Import of Pixel-Image-File \"")+fileName+"\"");}
  else if (typ==fileOpen){
	report.setTitle(tr("Open of Pixel-Image-File \"")+fileName+"\"");}
  else if (typ==fileUpdate){
	report.setTitle(tr("Update with Pixel-Image-File \"")+fileName+"\"");}
try { 
  QFileInfo f( fileName );
  QString name=f.baseName();
  /*if ( !f.open( QIODevice::ReadOnly ) )
	throw QString(tr("Can not open File."));*/
  cellList *firstcellhelp=d->firstCell;
  d->firstCell=NULL;
  df=d;
  d->currentCell=d->addCell()->thisCell;
  d->currentCell->cellName=name;
#ifdef printtime
  setup::centralTimer.start();
#endif
  QImage i(fileName);
  int count=0;
  int space=element::runden(1.0/df->userunits);
  if (setup::pixelResolution >0){
	space=element::runden(1.0/df->databaseunits/setup::pixelResolution);
	}
  else if (setup::pixelResolution == -1){
	space=element::runden(1.0/df->databaseunits/i.dotsPerMeterX());
	}
  if (space<= 0) space=element::runden(1.0/df->userunits);
  QTime timer;
  timer.start();
  QHash<uint,int> colorMap;
  uint colorSteps=0x00e0e0e0;
  int bits=setup::pixelColorBits;
  switch (bits){
  case 1: colorSteps=0x00808080; break;
  case 2: colorSteps=0x00c0c0c0; break;
  case 3: colorSteps=0x00e0e0e0; break;
  case 4: colorSteps=0x00f0f0f0; break;
  case 5: colorSteps=0x00f8f8f8; break;
  case 6: colorSteps=0x00fcfcfc; break;
  case 7: colorSteps=0x00fefefe; break;
  case 8: colorSteps=0x00ffffff; break;
	}
  int layerCount=setup::pixelLayerMap;
  int stepx=(i.width()/(layersMax-layerCount)*8);
  int stepy=i.height()/(8);
  QImage layerMap(i.width(),i.height(),QImage::Format_ARGB32);
  if (stepx<3) stepx=3;
  if (stepy<3) stepy=3;
//printf("layer count- %d %d %d %d %d %d\n",layerCount,setup::pixelLayerMap,stepx,stepy,(layer_max-layerCount),i.width());
  colorMap[(uint)(setup::backgroundColor.rgb())&colorSteps]=layersMax+1;
  if (layerCount<0) layerCount=layersMax+1;
  else {
  for (int x=0;x<i.width();x+=stepx)
	for (int y=0;y<i.height();y+=stepy){
		uint rgb=(uint)(i.pixel(x,y))& colorSteps;
		int lay=colorMap.value(rgb,-1);
		if (lay==-1) {
			if (layerCount<layersMax){
				layers::num[layerCount].setColor(qRed(i.pixel(x,y)), qGreen(i.pixel(x,y)), qBlue(i.pixel(x,y)));
				layers::num[layerCount].setStyle(9);
				colorMap[rgb]=layerCount;
				layerCount++;
				
			} else {
				QColor c=QColor(i.pixel(x,y));
			  	lay=layers::bestColor(c);
			 	if (lay<layerCount) colorMap[rgb]=lay;
				}
			}
		}
       }
//printf("layer count %d\n",layerCount);
for (int x=0;x<i.width();x++){
	for (int y=0;y<i.height();y++){
		count++;
		uint rgb=(uint)(i.pixel(x,y))& colorSteps;
		int lay=colorMap.value(rgb,-1);
		if (lay==-1) {
			if (layerCount<layersMax){
				layers::num[layerCount].setColor(qRed(i.pixel(x,y)), qGreen(i.pixel(x,y)), qBlue(i.pixel(x,y)));
				layers::num[layerCount].setStyle(9);
				colorMap[rgb]=layerCount;
				lay=layerCount;
				layerCount++;
				
			} else {
				QColor c=QColor(i.pixel(x,y));
			  	lay=layers::bestColor(c);
			 	colorMap[rgb]=lay;
				}
			}
		layerMap.setPixel(x,y,lay);
		//printf("%d %d %d\n",x,y,lay);
	}
	if ((timer.elapsed()>200)){
		d->showMessage(tr("%1 pixel converted.").arg(count/2));
		timer.start();
		}
}
  image=&layerMap;
  Space=space;
  for (int x=0;x<i.width();x++){
	for (int y=0;y<i.height();y++){
		count++;
		int lay=layerMap.pixel(x,y);
		//printf("%d %d %d\n",x,y,lay);
		if ((lay<layersMax)&&(lay>=0)){
			pa.resize(0);
			pa<<QPoint(x*space,(-y)*space);
			add=false;
			layer=lay;
			posX=x;
			posY=y;
			addPolygonH();
			pa<<QPoint(x*space,(-y-1)*space);
			pa<<QPoint(x*space,(-y)*space);
			if (!add){
				pa.resize(0);
				pa<<QPoint(x*space,(-y)*space);
				pa<<QPoint((x+1)*space,(-y)*space);
				addPolygonV();
				pa<<QPoint(x*space,(-y)*space);
				}
			if (add) d->currentCell->addPolygon(pa,lay);
			else d->currentCell->addBox(x*space,(-y-1)*space,space,space,lay);
			}
	}
	if ((timer.elapsed()>200)){
		d->showMessage(tr("%1 pixel converted.").arg(count/2));
		timer.start();
		}
 }
  d->showMessage(tr("%1 pixel converted.").arg(count));
  if (typ==fileImport) filegeneral::import(&report,d,firstcellhelp);
  if (typ==fileUpdate) filegeneral::update(&report,d,firstcellhelp);
#ifdef printtime
  printf("pixel image 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 pixel::addPolygonH(){
image->setPixel(posX,posY,layersMax+1);
//printf("%d %d %d\n",posX,posY,layer);
int startX=posX;
if (posX<image->width()-1){
	if ((int)(image->pixel(posX+1,posY))==layer){
		++posX;
		add=true;
		addPolygonH();
		}
	}
if (startX==posX) {
	pa<<QPoint((posX+1)*Space,(-posY)*Space);
	pa<<QPoint((posX+1)*Space,(-posY-1)*Space);
	}

}

void pixel::addPolygonV(){
image->setPixel(posX,posY,layersMax+1);
//printf("%d %d %d\n",posX,posY,layer);
int startY=posY;
if (posY<image->height()-1){
	if ((int)(image->pixel(posX,posY+1))==layer){
		++posY;
		add=true;
		addPolygonV();
		}
	}
if (startY==posY) {
	pa<<QPoint((posX+1)*Space,(-posY-1)*Space);
	pa<<QPoint((posX)*Space,(-posY-1)*Space);
	}

}


void pixel::save(QString fileName,drawingField *d){
errorreport report;
report.setTitle(tr("Save of Pixel-File \"")+fileName+"\"");
try { 
  report.addItem(tr("Only visible layers in the current cell are saved!"),3,"");
  QPoint max=QPoint(INT_MIN,INT_MIN);
  QPoint min=QPoint(INT_MAX,INT_MAX);
  d->currentCell->minimum(&min);
  d->currentCell->maximum(&max);
  int res=(int)((double)(1.0)/d->databaseunits*d->userunits);
  double scale=d->userunits;
  int y=element::runden(d->userunits*(double(max.y())-double(min.y())))+10;
  int x=element::runden(d->userunits*(double(max.x())-double(min.x())))+10;
  if (setup::pixelResolution>0){
	res=setup::pixelResolution;
	scale=(double)(setup::pixelResolution)*d->databaseunits;
	x=element::runden(scale*(double(max.x())-double(min.x())))+10;
	y=element::runden(scale*(double(max.y())-double(min.y())))+10;
	}

  int limit=530000000;
  //limit=150000000; //? for testing
  {
  int yStep=y;
  if ( ((long long)(y)*(long long)(x))>limit) {
	yStep=limit/(x);
	}
  bool end=true;
  do {
   end=true;
   QImage im(x+2,yStep+1,QImage::Format_RGB32);
   if (im.isNull()&&(limit>100000)){
	end=false;
	limit=limit/2;
	yStep=limit/(x);
	}
  } while (!end);
  }
  if ( ((long long)(y)*(long long)(x))>limit){
	int yStep=limit/(x);
	layoutImage im(x,yStep-1);
	//printf("%d %d %d\n",x,yStep,y*x);
	int count =1;
	for (int i=0;i<y;i+=yStep){
		strans trans;
		trans.setMirror_x();
		trans.translate(5,-y+5+i);
		trans.scale(scale);
		trans.translate(-min.x(),-min.y());
		im.setDrawTrans(trans);
		if (setup::paintEngine==1) im.fill(QColor(0, 0, 0).rgb());
		else im.fill(setup::backgroundColor.rgb());
		d->currentCell->paint(im.imagePainter);
		QImage *ih=im.getImage();
		ih->setDotsPerMeterX (res );
		ih->setDotsPerMeterY (res );
		int pos=fileName.lastIndexOf(".");
		QString  num;
 		num.setNum(count);
		QString  name=fileName.left(pos)+"-"+num+fileName.mid(pos);
		ih->save(name);
		count++;
	}
	}
  else {
	layoutImage im(x,y);
	strans trans;
	//trans.translate(-min.x(),-min.y());
	trans.setMirror_x();
	trans.translate(5,-y+5);
	
	trans.scale(scale);
	//trans.setMirror_x();
	trans.translate(-min.x(),-min.y());
	im.setDrawTrans(trans);
	// printf (" %f %f\n",s.mag,trans.mag);
	// printf (" %f \n",scaleX);
	// printf (" %f %f\n",s.matrix.dx(),trans.matrix.dx());
	// printf (" %f %f\n",s.matrix.dy(),trans.matrix.dy());
	if (setup::paintEngine==1) im.fill(QColor(0, 0, 0).rgb());
	else im.fill(setup::backgroundColor.rgb());
	d->currentCell->paint(im.imagePainter);
	QImage *i=im.getImage();
	i->setDotsPerMeterX (res );
	i->setDotsPerMeterY (res );
	i->save(fileName);
  }
}
catch (QString s){
  report.addItem(tr("Aborted. "),0);
  report.addItem(s,1);
 }
  //report.showReport();   
  QString s=report.getReport();
  d->showReport(s,report.getLastRang());
}
