/* -*- mode: c++; tab-width: 4; c-basic-offset: 4 -*- */
/*
 * Copyright (C) 2005 Atmark <atmarkat _AT_ msn _DOT_ com>
 *                    AGAWA Koji <i _AT_ atty _DOT_ jp>
 *
 * 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 <qdir.h>
#include <qfileinfo.h>
#ifdef QTOPIA
#include <qpe/config.h>
#else
#include <config.h>
#endif
#include "skinmanager.h"
#include "skin.h"
#include "debug.h"

/*!
  \class SkinManager
  \author AGAWA Koji
  \brief SkinManagerクラスはスキンの管理をします。

  2Wayスタイルのスキンは、内部ではそれぞれ独立したスキンとして扱われています。
*/

/*!
  スキンディレクトリ、および親オブジェクトと名前を指定してスキンマネージャを作成します。
*/
SkinManager::SkinManager(const QString &skinDir, QObject *parent, const char *name)
	: QObject(parent, name),
	  skinDir_(skinDir),
	  style_(Portrait),
	  skins_(2),
	  info_(3)
{
	ASSERT(skinDir_ != QString::null);
	ASSERT(!skinDir_.isEmpty());

	skins_.setAutoDelete(true);

	refreshSkinList();
}

/*!
  スキンマネージャを破棄し、全てのスキンを削除します。
*/
SkinManager::~SkinManager()
{
}

/*!
  スキンディレクトリに置かれているスキンを走査し、このクラスの状態を更新します。
*/
void SkinManager::refreshSkinList()
{
	DPRINTF("SkinManager::refreshSkinList()");

	QDir dir(skinDir_);
	dir.setFilter(QDir::Files || QDir::Dirs || QDir::Readable);
	dir.setSorting(QDir::Name);

	if (!dir.isReadable()) {
		qWarning(tr("Skin directory <%s> not readable"), skinDir_.latin1());
		skinNameList_.clear();
		return;
	}

	// スキンディレクトリを走査する
	// エントリがディレクトリであれば、展開されているスキンなのかを検査する
	// .skin拡張子を持つファイルであれば、圧縮済みスキンであると判断する(中身は検査しない)
	const QFileInfoList *list = dir.entryInfoList();
	QFileInfoListIterator it(*list);

	for (QFileInfo *fi; (fi = it.current()); ++it) {
		DPRINTF("<%s>", fi->absFilePath().latin1());
		if (fi->isReadable()) {
			if (fi->isDir()) {
				QFileInfo ini(fi->absFilePath() + "/skin.ini");
				if (ini.isFile() && ini.isReadable()) {
					skinNameList_ += fi->fileName();
					DPRINTF(" %s is directory skin", fi->fileName().latin1());
				}
			} else {
				if (fi->extension(false).lower() == "skin") {
					skinNameList_ += fi->fileName();
					DPRINTF(" is archived skin");
				}
			}
		}
	}
}

/*!
  スキン \a name を読み込みます。

  読み込みに成功した場合は skinChanged() シグナルを発行します。

  \todo QVGA<->VGA解像度の変換
 */
bool SkinManager::load(const QString &name)
{
	DPRINTF("SkinManager::load(<%s>)", name.latin1());

	if (skinNameList_.find(name) == skinNameList_.end()) {
		qWarning(tr("Skin <%s> not found"), name.latin1());
		return false;
	}

	QString skinDir;
	QFileInfo fi(skinDir_ + "/" + name);
	if (fi.isDir()) {
		skinDir = fi.absFilePath() + "/";
	} else {
#if 0
		QString cmd("tar zxf ");
		cmd += fi.absFilePath();
		cmd += " -C /tmp";
		::system(cmd.utf8());
		skinDir = "/tmp/";
#endif
	}
	DPRINTF("  skinDir = <%s>", skinDir.latin1());

	Config c(skinDir + "skin.ini", Config::File);
	if (!c.isValid()) {
		qWarning(tr("Couldn't open <%sskin.ini>"), skinDir.latin1());
		return false;
	}
	c.setGroup("global");

#if 0
	QString resolution = c.readEntry("resolution");
	if (resolution == "QVGA")
		isQVGA_ = true;
	else
		isQVGA_ = false;
	DPRINTF("Skin: resolution = %s", isQVGA_ ? "QVGA" : "VGA");
#endif

	for (int i = 0; i < 2; ++i) {
		if (i == 0) {
			c.setGroup("portrait");
		} else {
			c.setGroup("landscape");
		}

		Skin *skin = new Skin(c, skinDir);
		if (skin->isValid()) {
			skins_.insert(i, skin);
		} else {
			skins_.clear();
			return false;
		}
	}

	if (!loadSkinModeInformation(c, "bigmode", skinDir, BigMode))
		qFatal("Couldn't read bigmode settings.");
		
	if (!loadSkinModeInformation(c, "normalmode", skinDir, NormalMode))
		qFatal("Couldn't read normalmode settings.");
		
	if (!loadSkinModeInformation(c, "smallmode", skinDir, SmallMode))
		qFatal("Couldn't read smallmode settings.");
		
	emit skinChanged(skins_[style_]);

	return true;
}

bool SkinManager::loadSkinModeInformation(Config &config, const QString &group, const QString &skinDir, InfoMode mode)
{
	SkinModeInformation *modeInfo = new SkinModeInformation();

	config.setGroup(group);
	
	// load play list font
	readFontInfo(config, "playlist_font", modeInfo->playListFont_);
	
	// load play list background colors (for even and odd indexed items)
	if (config.hasKey("playlist_background"))
	{
		QStringList value = config.readListEntry("playlist_background", ',');

		modeInfo->playListBackgroundColorEven_.setNamedColor(value[0]);
		modeInfo->playListBackgroundColorEven_.setUsed(true);

		if (value.count() == 2)
		{
			modeInfo->playListBackgroundColorOdd_.setNamedColor(value[1]);
			modeInfo->playListBackgroundColorOdd_.setUsed(true);
		}
		else
			modeInfo->playListBackgroundColorOdd_.setUsed(false);
	}
	else
	{
		modeInfo->playListBackgroundColorEven_.setUsed(false);
		modeInfo->playListBackgroundColorOdd_.setUsed(false);
	}

	// load play list selected background color
	readColor(config, "playlist_selected_background", modeInfo->playListBackgroundColorSelected_);

	// load play list selected font color
	readColor(config, "playlist_selected_fontcolor", modeInfo->playListFontColorSelected_);
	
	// load play and pause indicator images
	QString imageName = config.readEntry("playlist_playindicator");

	QImage playListPlayIndicatorImage;
	playListPlayIndicatorImage.setAlphaBuffer(true);
	playListPlayIndicatorImage.load(skinDir + imageName);

	QImage playListPauseIndicatorImage;
	imageName = config.readEntry("playlist_pauseindicator");
	playListPauseIndicatorImage.setAlphaBuffer(true);
	playListPauseIndicatorImage.load(skinDir + imageName);
 
	modeInfo->playListPlayIndicatorImage_ = playListPlayIndicatorImage;
	modeInfo->playListPauseIndicatorImage_ = playListPauseIndicatorImage;	

	// load play list header font
	readFontInfo(config, "playlist_header_font", modeInfo->playListHeaderFont_);

	// load play list header color
	readColor(config, "playlist_header_background", modeInfo->playListHeaderColor_);
	
	// load play list scrollbar color
	readColor(config, "playlist_scrollbar_background", modeInfo->playListScrollBarColor_);	
	
	
	readColor(config, "playlistoverview_separatorcolor", modeInfo->playListOverviewSeparatorColor_);
	
	
	// load play list overview font
	readFontInfo(config, "playlistoverview_font", modeInfo->playListOverviewFont_);

	// load play list overview selected background color
	readColor(config, "playlistoverview_background", modeInfo->playListOverviewBackgroundColor_);
	
	// load play list overview selected background color
	readColor(config, "playlistoverview_selected_background", modeInfo->playListOverviewBackgroundColorSelected_);

	// load play list overview selected font color
	readColor(config, "playlistoverview_selected_fontcolor", modeInfo->playListOverviewFontColorSelected_);
	
	// load play list overview header font
	readFontInfo(config, "playlistoverview_header_font", modeInfo->playListOverviewHeaderFont_);

	// load play list overview header color
	readColor(config, "playlistoverview_header_background", modeInfo->playListOverviewHeaderColor_);
	
	// load play list overview scrollbar color
	readColor(config, "playlistoverview_scrollbar_background", modeInfo->playListOverviewScrollBarColor_);	
	
	
	// load play info font
	readFontInfo(config, "playinfo_font", modeInfo->playInfoFont_);
	
	// load play info background color
	readColor(config, "playinfo_background", modeInfo->playInfoBackgroundColor_);

	// load toolbar font
	readFontInfo(config, "toolbar_font", modeInfo->toolBarFont_);

	// load toolbar color
	readColor(config, "toolbar_background", modeInfo->toolBarColor_);

	// load filterbox font
	readFontInfo(config, "filterbox_font", modeInfo->filterBoxFont_);

	// load filterbox background color
	readColor(config, "filterbox_background", modeInfo->filterBoxBackgroundColor_);

	// load filterbox focused font color
	readColor(config, "filterbox_focused_fontcolor", modeInfo->filterBoxFontColorFocused_);

	// load filterbox focused background color
	readColor(config, "filterbox_focused_background", modeInfo->filterBoxBackgroundColorFocused_);

	info_.insert(mode, modeInfo);

	return true;
}

bool SkinManager::readColor(Config &config, const QString &key, SkinColor &color)
{
	if (config.hasKey(key))
	{
		color.setNamedColor(config.readEntry(key));
		color.setUsed(true);
		return true;
	}
	else
	{
		color.setUsed(false);
		return false;
	}
}

bool SkinManager::readFontInfo(Config &config, const QString &key, SkinModeInformation::FontInformation &fontInfo)
{
	QStringList value = config.readListEntry(key, ',');
	if (value.count() < 2)
	{
		fontInfo.font.setUsed(false);
		fontInfo.fontColor.setUsed(false);
		return false;
	}

	fontInfo.font.setFamily(value[0]);
	fontInfo.font.setPointSize(value[1].toInt());
	fontInfo.font.setUsed(true);
	
	if (value.count() == 3)
	{
		fontInfo.fontColor.setNamedColor(value[2]);
		fontInfo.fontColor.setUsed(true);
	}
	else
		fontInfo.fontColor.setUsed(false);
	
	return true;	
}

QStringList SkinManager::skinList() const
{
	return skinNameList_;
}

/*!
  \brief スキンのスタイルを \a style に設定します。

  実際にスタイルが変更された場合は skinChanged() シグナルを発行します。

  アプリケーションのルートウィジェットでresizeEvent()をオーバーライドし、
  そこでスタイルの変更を検出してこの関数を呼んでください。
*/
void SkinManager::setStyle(Style style)
{
	if (style_ != style) {
		style_ = style;
		emit skinChanged(skins_[style]);
// 		DPRINTF("SkinManager::setStyle : skinChanged(%s)",
// 			   style_ == Landscape ? "Landscape" : "Portrait");
	}
}
