/***************************************************************************
 *   Copyright (C) 2005 by Ian Reinhart Geiser                             *
 *   geiseri@sourcextreme.com                                              *
 *                                                                         *
 *   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 <dhwpage.h>
#include <QByteArray>
#include <QSizeF>
#include <QLine>
#include <QPolygonF>
#include <QList>
#include <QPaintDevice>
#include <QPainter>
#include <QPicture>

#include <qdebug.h>

DHWPage::DHWPage( const QByteArray &array ) :
	mBytes(array)
{
	setBytes(array);
}

DHWPage::DHWPage()
{

}

DHWPage::~DHWPage()
{

}

void DHWPage::setBytes(const QByteArray &array)
{
	mBytes = array;
	mLayers = readLayerData();
	mPicture = picture();
}

DHWPage::PageTypes DHWPage::readPageType(  ) const
{
	return (PageTypes)(int)mBytes.at(0x25);  //Stupidest manuver ever.
}

int DHWPage::readVersion( ) const
{
	return mBytes.at(0x20);
}

QSizeF DHWPage::readPageSize() const
{
	int bx1 = mBytes.at(0x21) & 0xFF;
	int bx2 = mBytes.at(0x22) & 0xFF;
	int by1 = mBytes.at(0x23) & 0xFF;
	int by2 = mBytes.at(0x24) & 0xFF;
	double width = double(bx1+(bx2<<8));
	double height = double(by1+(by2<<8));

	return QSizeF(width,height);
}

DHWPage::ByteType DHWPage::idBytes( int idx ) const
{
	int byte = mBytes.at(idx) & 0xFF;
	switch(byte)
	{
		case 0x80:
		case 0x82:
		case 0x84:
		case 0x86:
			return PenUp;
			break;
		case 0x81:
		case 0x83:
		case 0x85:
		case 0x87:
			return PenDown;
		case 0x88:
			return TimeStamp;
		case 0x90:
			return Layer;
		default:
			if(  0x7f >= byte )
				return Data;
			else
			{
				qWarning("Invalid data %x", byte );
				return Invalid;
			}
			break;
	}

}

QPointF DHWPage::readPoint( int start ) const
{
	QByteArray bytes = mBytes.mid(start,4);
	int bx1=bytes.at(0) & 0xFF;
	int bx2=bytes.at(1) & 0xFF;
	int by1=bytes.at(2) & 0xFF;
	int by2=bytes.at(3) & 0xFF;
	bx1=bx1+(bx2<<7);
	by1=by1+(by2<<7);
	return QPointF(bx1, readPageSize().height() - by1 );
}

QColor DHWPage::readColor( int idx ) const
{
	switch( mBytes.at(idx) & 0xFF )
	{
		case 0x81:
			return Qt::black;
			break;
		case 0x83:
			return Qt::red;
			break;
		case 0x85:
			return Qt::blue;
			break;
		case 0x87:
			return Qt::green;
			break;
		default:
			return Qt::black;
			break;
	}
}

int DHWPage::size() const
{
	return mBytes.size();
}

QList<DHWLayer> DHWPage::readLayerData() const
{
	int offset = 40;
	QList<DHWLayer> layers;
	QPolygonF currentPoly;
	DHWLayer currentLayer;
	DHWPage::ByteType lastType = DHWPage::Invalid;
	QColor currentColor = Qt::black;

	while( offset <  size() )
	{
		DHWPage::ByteType type =  idBytes( offset );
		if( type == DHWPage::Data )
		{
			if( lastType == DHWPage::Data)  // Add point to poly array
			{
				currentPoly +=  readPoint( offset );
				offset += 4;
			}
			else if ( lastType == DHWPage::PenUp ) // Add last points to poly array and close it.
			{
				currentPoly +=  readPoint( offset );
				currentLayer.polyList += currentPoly;
				offset += 4;
			}
			else if( lastType == DHWPage::TimeStamp ) // Read timestamp data
			{
				offset += 1;
			}
			else if( lastType == DHWPage::Layer ) // Read layer data
			{
				currentLayer.number = mBytes.at(0x20) & 0xFF;
				layers += currentLayer;
				offset += 1;
			}
			else if ( lastType == DHWPage::PenDown )
			{
				currentPoly.clear();
				currentPoly += readPoint( offset );
				offset += 4;
			}
			else
			{
				lastType =  idBytes( offset );
				offset += 1;
			}
		}
		else if ( type == DHWPage::PenDown )
		{
			currentColor = readColor( offset );
			offset += 1;
		}
		else
		{
			offset += 1;
		}
		lastType = type;
	}
	return layers;
}

QSizeF DHWPage::scaleTo( const QSizeF &size  ) const
{
	QSizeF pgSize = readPageSize();
	pgSize.scale(size, Qt::KeepAspectRatio);
	return pgSize;
}

void DHWPage::drawLayer(const QSizeF &painterSize, QPainter *painter, bool aa )  const
{

	drawSection( painterSize, QRectF(0,0,painterSize.width(), painterSize.height()), painter, aa);
}

QPicture DHWPage::picture( ) const
{
	QPicture pic;
	QPainter painter(&pic);
	foreach( DHWLayer layer, mLayers )
		foreach( QPolygonF poly, layer.polyList)
		{
			painter.drawPolyline(poly );
		}
	return pic;
}

int DHWPage::layers() const
{
	return mLayers.count();
}

void DHWPage::drawSection(const QSizeF &painterSize,
		const QRectF &painterRect, QPainter *painter, bool aa ) const
{
	QMatrix m;
	QSizeF pgSize = scaleTo(painterSize);

	float xScale = (float)pgSize.width()/(float)readPageSize().width();
	float yScale = (float)pgSize.height()/(float)readPageSize().height();

	m.translate( -painterRect.x(), -painterRect.y());
	m.scale( xScale, yScale );

	QList<DHWLayer> layers = mLayers;
	painter->save();
	painter->setMatrix(m);
	painter->setRenderHint(QPainter::Antialiasing, aa);

	foreach( DHWLayer layer, layers )
		foreach( QPolygonF poly, layer.polyList)
			painter->drawPolyline( poly );
	painter->restore();
}

QImage DHWPage::drawImage( const QSizeF &pgSize, const QRectF &area ) const
{
	QImage image;
	if( !area.isNull() )
		image = QImage( area.size().toSize(), QImage::Format_RGB32);
	else
		image = QImage( pgSize.toSize(), QImage::Format_RGB32);

	image.fill(qRgb(0xff,0xff,0xff));
	QPainter painter( &image );
	painter.setPen(QPen(Qt::black));

	if( !area.isNull() )
		drawSection( pgSize, area, &painter, true );
	else
		drawLayer(pgSize, &painter, true);
	painter.end();
	return image;
}


