/*
 * Keramik KWin embed tool (version 1.0)
 *
 * Copyright (C) 2002 Fredrik Höglund <fredrik@kde.org>
 *
 * 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; see the file COPYING.  If not, write to
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301, USA.
 */

#include <qimage.h>
#include <qtextstream.h>
#include <qregexp.h>
#include <qfile.h>
#include <qfileinfo.h>
#include <qdatetime.h>

#include <iostream>

static int primes[] = {
	   2,   3,   5,   7,  11,  13,  17,  19,  23,  29,
	  31,  37,  41,  43,  47,  53,  59,  61,  67,  71,
	  73,  79,  83,  89,  97, 101, 103, 107, 109, 113,
	 127, 131, 137, 139, 149, 151, 157, 163, 167, 173,
	 179, 181, 191, 193, 197, 199, 211, 223, 227, 229
};

struct EmbedImage {
	QString string;
	int width;
	int height;
	bool alpha;
	QString name;
};

class KeramikEmbedder {
public:
	KeramikEmbedder();
	~KeramikEmbedder();
	
	void embed( const char * );
	void writeIndex();
	
private:
	QFile *file;
	QPtrList<EmbedImage> *index;
	QTextStream stream;
};

KeramikEmbedder::KeramikEmbedder()
{
	QDateTime date( QDateTime::currentDateTime() );
	QString datestring( date.toString() );
	
	file = new QFile( "tiles.h" );
	file->open( IO_WriteOnly | IO_Truncate );

	stream.setDevice( file );
	
	stream << "/*\n";
	stream << " * Generated by embedtool 1.0 on " << datestring << endl;
	stream << " */\n\n";
	
	stream << "#ifndef __TILES_H\n";
	stream << "#define __TILES_H\n\n";
	stream << "#include <qimage.h>\n"; 
	stream << "#include <qdict.h>\n\n";
	stream << "namespace Keramik {\n\n";
	
	index = new QPtrList<EmbedImage>;
	index->setAutoDelete( true );
}

KeramikEmbedder::~KeramikEmbedder()
{	
	stream << "} // namespace Keramik\n\n";
	stream << "#endif // __TILES_H\n\n";
	stream << "// vim: set noet ts=4 sw=4:\n";

	file->close();
	delete file;
	delete index;
}

void KeramikEmbedder::embed( const char *name )
{
	QFileInfo   fileinfo( name );
	QString     basename( fileinfo.baseName() );
	QString     codename( basename );
	QImage      image( name );
	
	codename = codename.replace( QRegExp("[^a-zA-Z0-9]"), "_" );
	
	stream << "\tstatic const QRgb " << codename << "_data[] = {" << endl << "\t\t";
	stream.setf( QTextStream::hex | QTextStream::right );
	stream.fill( '0' );
	
	int pixels = image.width() * image.height();
	Q_UINT32 *data = reinterpret_cast<Q_UINT32*>( image.bits() );
	bool hasAlpha = false;

	
	for ( int i = 0, j = 0; i < pixels; i++ ) {
		if ( qAlpha( *data ) && qAlpha( *data ) != 0xff )
			hasAlpha = true;
		
		stream << "0x" << qSetW(8) << *(data++);
		
		if ( i != pixels-1 ) {
			stream << ',';
		
			if ( j++ > 4 ) {
				j = 0;
				stream << endl << "\t\t";
			} else
				stream << ' ';
		}
	}

	stream.reset();
	
	stream << endl << "\t}; // " << codename << "_data" << endl << endl;

	EmbedImage *imginfo = new EmbedImage;
	imginfo->width = image.width();
	imginfo->height = image.height();
	imginfo->alpha = hasAlpha;
	imginfo->name = codename;
	imginfo->string = basename;
	index->append( imginfo ); 
}

void KeramikEmbedder::writeIndex()
{
	stream << "\tstruct EmbedImage {\n";
	stream << "\t\tconst char *name;\n";
	stream << "\t\tint width;\n";
	stream << "\t\tint height;\n";
	stream << "\t\tbool alpha;\n";
	stream << "\t\tconst QRgb *data;\n";
	stream << "\t};\n\n";

	uint i = 0;
	stream << "\tstatic const EmbedImage image_db[] = {\n";
	for ( EmbedImage *image = index->first(); image; image = index->next() )
	{
		stream << "\t\t{ \"" << image->string << "\", "
			<< image->width << ", " << image->height <<
			", " << (image->alpha ? "true" : "false")
			<< ", " << image->name << "_data }";
		if ( i++ < index->count() - 1 )
			stream << ',';
		stream << endl;
	}
	stream << "\t};\n\n";

	uint prime = 0;
	
	for ( i = 0; i < 50; i++ )
		if ( (prime = primes[i]) >= index->count() )
			break;
	
	stream << "\tclass KeramikImageDb {\n";
	stream << "\tprivate:\n";
	stream << "\t\tstatic KeramikImageDb *m_inst;\n";
	stream << "\t\tQDict<QImage> *db;\n\n";
	stream << "\t\tKeramikImageDb() {\n";
	stream << "\t\t\tdb = new QDict<QImage>( " << prime << " );\n";
	stream << "\t\t\tdb->setAutoDelete( true );\n\n";
	stream << "\t\t\tfor ( int i = 0; i < " << index->count() << "; i++ ) {\n";
	stream << "\t\t\t\tQImage *img = new QImage( (uchar*)image_db[i].data,\n";
	stream << "\t\t\t\t\t\timage_db[i].width, image_db[i].height,\n";
	stream << "\t\t\t\t\t\t32, NULL, 0, QImage::LittleEndian );\n\n";
	stream << "\t\t\t\tif ( image_db[i].alpha )\n";
	stream << "\t\t\t\t\timg->setAlphaBuffer( true );\n\n";
	stream << "\t\t\t\tdb->insert( image_db[i].name, img );\n";
	stream << "\t\t\t}\n";
	stream << "\t\t}\n\n";
	stream << "\t\t~KeramikImageDb() {\n";
	stream << "\t\t\tdelete db;\n";
	stream << "\t\t}\n\n";
	stream << "\tpublic:\n";
	stream << "\t\tstatic KeramikImageDb* instance() {\n";	
	stream << "\t\t\tif ( ! m_inst ) m_inst = new KeramikImageDb;\n";
	stream << "\t\t\treturn m_inst;\n";
	stream << "\t\t}\n\n";
	stream << "\t\tstatic void release() {\n";
	stream << "\t\t\tif ( m_inst ) delete m_inst;\n";
	stream << "\t\t\tm_inst = NULL;\n";
	stream << "\t\t}\n\n";
	stream << "\t\tQImage *image( const QString &name ) const {\n";
	stream << "\t\t\treturn db->find( name );\n";
	stream << "\t\t}\n\n";
	stream << "\t}; // class KeramikImageDb\n\n";
	stream << "\tKeramikImageDb *KeramikImageDb::m_inst = NULL;\n\n";
}

int main( int argv, char **argc )
{
	if ( argv < 2 ) {
		std::cout << "Insufficient arguments" << std::endl;
		return 1;
	}

	KeramikEmbedder embedder;

	for ( int i = 1; i < argv; i++ )
	{
		std::cout << argc[i] << std::endl;
		embedder.embed( argc[i] );
	}

	embedder.writeIndex();
	
	return 0;
}

// vim: set noet ts=4 sw=4:

