/***************************************************************************
                           filesidestyle.cpp
                           -------------------
    copyright            : (C) 2004 by Jos van den Oever
    email                : jos@vandenoever.info
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   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.                                   *
 *                                                                         *
 ***************************************************************************/
#include "filesidestyle.h"
#include "testdialog.h"
#include <QtCore/QDir>
#include <Qt3Support/Q3Picture>
#include <QtGui/QPixmap>
#include <QtGui/QImage>
#include <QtGui/QPainter>
#include <QtGui/QApplication>
#include <QtGui/QImageReader>
#include <iostream>
using namespace std;

/* TODO
   - add check for identical files
   - add check for bitmap symmetry
*/


FileSideStyle::FileSideStyle() {
	readDirs(QDir::homeDirPath()+"/.cubetest/styles");
	readDirs(qApp->applicationDirPath()+"/../share/cubetest/styles");
	QStringList sl = styledirs.keys();
}
FileSideStyle::~FileSideStyle() {
	freeimages();
}
void
FileSideStyle::freeimages() {
	vector<const Q3Picture *>::const_iterator i;
	for (i=c1.begin(); i != c1.end(); ++i) {
		delete *i;
	}
	c1.clear();
	for (i=c2.begin(); i != c2.end(); ++i) {
		delete *i;
	}
	c2.clear();
	for (i=c4.begin(); i != c4.end(); ++i) {
		delete *i;
	}
	c4.clear();
}
void
FileSideStyle::readDirs(const QString &dir) {
	QDir d(dir);
	if (!d.exists()) return;
	foreach (const QFileInfo& fi, d.entryInfoList(QDir::Dirs)) {
		QString newdir = fi.absFilePath();
		QString newname = fi.fileName();
		if (!styledirs.contains(newname) && checkDir(newdir)) {
			styledirs[newname] = newdir;
		}
        }
}
bool
FileSideStyle::checkDir(const QDir &d) const {
//	cerr << d.path() << endl;
	// a valid dir has at least one C4, two of either C1 or C2
	bool hasC4 = false;
	short other = 0;
	QStringList inpf = QPicture::inputFormatList();
	if (inpf.size() == 0) inpf << "PNG";
	QString pixfilter = "c?_*."+inpf.join(";c?_*.").lower();
	foreach (const QFileInfo& fi, d.entryInfoList( QDir::Files)) {
		QString begin = fi.fileName().left(2).lower();
		if (begin == "c4" && !QImageReader::imageFormat(fi.absFilePath()).isNull()) {
			hasC4 = true;
		} else if ( (begin == "c1" || begin == "c2")
				&& !QImageReader::imageFormat(fi.absFilePath()).isNull()) {
			++other;
		}
	}
	foreach (const QFileInfo& fi, d.entryInfoList("c?_*.svg;C?_*.svg", QDir::Files)) {
		QString begin = fi.fileName().left(2).lower();
		if (begin == "c4" && checkFile(fi.absFilePath())) {
			hasC4 = true;
		} else if ( (begin == "c1" || begin == "c2") && checkFile(fi.absFilePath())) {
			++other;
		}
	}
	return hasC4 && other > 1;
}
bool
FileSideStyle::checkFile(const QString &f) const {
//	cerr << f << endl;
	Q3Picture p;
	if (f.right(4).lower() == ".svg") {
		if (p.load(f, "svg")) return true;
	} else if (p.load(f)) return true;
	return false;
}
void
FileSideStyle::loadStyle(const QString &s) {
	if (styledirs.contains(s)) {
		freeimages();
		loadDir(styledirs[s]);
	}
}
void
FileSideStyle::loadDir(const QDir &d) {
	c1.clear();
	c2.clear();
	c4.clear();
	QStringList inpf = QPicture::inputFormatList();
	if (inpf.size() == 0) inpf << "PNG";
	QString pixfilter = "c?_*."+inpf.join(";c?_*.").lower();
	foreach (const QFileInfo& fi, d.entryInfoList(pixfilter, QDir::Files)) {
		loadFile(fi.absFilePath(), true);
	}
	pixfilter = "c?_*.svg;C?_*.svg";
	foreach (const QFileInfo& fi, d.entryInfoList(pixfilter, QDir::Files)) {
		loadFile(fi.absFilePath(), false);
	}
}
namespace {
Symmetry
getSym(const QImage &img) {
	QMatrix wm180, wm90;
	wm180.rotate(180);
	wm90.rotate(90);
	if (img != img.xForm(wm180)) {
		return C1;
	} else if (img != img.xForm(wm90)) {
		return C2;
	} else {
		return C4;
	}
}
QImage
makeImage(const Q3Picture p, int res) {
	QRect r = p.boundingRect();
	r.setWidth(r.width());
	r.setHeight(r.height());
	QPixmap pm(res, res);
	pm.fill(Qt::white);
	QPainter painter;
	painter.begin(&pm);
	painter.setWindow(r);
	painter.scale(res/r.width(), res/r.height());
	painter.translate(r.width()/2, r.height()/2);
	painter.drawPicture(r.x(),r.y(), p);
	painter.end();
	return pm.convertToImage();
}
}
void
FileSideStyle::loadFile(const QString &f, bool pix) {
	Q3Picture p;
	QPainter painter;
	Q3Picture *pict;
	if (pix) {
		QImage img(f);
		painter.begin(&p);
		painter.fillRect(0,0,img.width()+1,img.height()+1,Qt::white);
		painter.drawImage(0,0,img);
		painter.end();
		pict = new Q3Picture(p);
	} else {
		if (f.right(4).lower() == ".svg") {
			if (!p.load(f, "svg")) return;
		} else if (!p.load(f)) return;
		pict = new Q3Picture();
		painter.begin(pict);
		painter.fillRect(p.boundingRect(), Qt::white);
		painter.drawPicture(0,0,p);
		painter.end();
	}
	if (f.contains("C1_", false)) {
		c1.push_back(pict);
	} else if (f.contains("C2_", false)) {
		c2.push_back(pict);
	} else {
		if (c4.size() > 0 && f.contains("c4_blank", false)) {
			c4.push_back(c4[0]);
			c4[0] = pict;
		} else {
			c4.push_back(pict);
		}
	}
}
QStringList
FileSideStyle::getStyles() {
	return styledirs.keys();
}
const Q3Picture *
FileSideStyle::getC4Picture(ushort i) const {
	if (i < c4.size()) return c4[i];
	cerr << "index " << i << " is out of range in getC4Picture" << endl;
	throw 0;
}
const Q3Picture *
FileSideStyle::getC2Picture(ushort i) const {
	if (i < c2.size()) return c2[i];
	cerr << "index " << i << " is out of range in getC2Picture" << endl;
	throw 0;
}
const Q3Picture *
FileSideStyle::getC1Picture(ushort i) const {
	if (i < c1.size()) return c1[i];
	cerr << "index " << i << " is out of range in getC1Picture" << endl;
	throw 0;
}
short
FileSideStyle::amount(Symmetry s) const {
	if (s == C1) return c1.size();
	if (s == C2) return c2.size();
	if (s == C4) return c4.size();
	return 0;
}
