/* This file is part of the KDE project
   Copyright (C) 2003-2005 Jaroslaw Staniek <js@iidea.pl>

   This program is free software; you can redistribute it and/or
   modify it under the terms of the GNU Library 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
   Library General Public License for more details.

   You should have received a copy of the GNU Library 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 "kexi.h"
#include "kexiaboutdata.h"
#include "kexicmdlineargs.h"

#include <kexiutils/identifier.h>
#include <kexidb/msghandler.h>

#include <tqtimer.h>
#include <tqimage.h>
#include <tqpixmap.h>
#include <tqpixmapcache.h>
#include <tqcolor.h>
#include <tqfileinfo.h>

#include <kdebug.h>
#include <kcursor.h>
#include <tdeapplication.h>
#include <kiconloader.h>
#include <kiconeffect.h>
#include <ksharedptr.h>
#include <kmimetype.h>
#include <kstaticdeleter.h>
#include <tdeglobalsettings.h>

using namespace Kexi;

//! used for speedup
//! @internal
class KexiInternal : public TDEShared
{
	public:
		KexiInternal() : TDEShared()
		 , connset(0)
		 , smallFont(0)
		{
		}
		~KexiInternal()
		{
			delete connset;
			delete smallFont;
		}
		KexiDBConnectionSet* connset;
		KexiProjectSet recentProjects;
		KexiDBConnectionSet recentConnections;
		KexiDB::DriverManager driverManager;
		KexiPart::Manager partManager;
		TQFont *smallFont;
};

static KStaticDeleter<KexiInternal> Kexi_intDeleter;
KexiInternal* _int = 0;

#define _INIT_SHARED { if (!_int) Kexi_intDeleter.setObject( _int, new KexiInternal() ); }

KexiDBConnectionSet& Kexi::connset()
{
	_INIT_SHARED;
	//delayed
	if (!_int->connset) {
		//load stored set data, OK?
		_int->connset = new KexiDBConnectionSet();
		_int->connset->load();
	}
	return *_int->connset;
}

KexiProjectSet& Kexi::recentProjects() { 
	_INIT_SHARED;
	return _int->recentProjects;
}

KexiDB::DriverManager& Kexi::driverManager()
{
	_INIT_SHARED;
	return _int->driverManager;
}

KexiPart::Manager& Kexi::partManager()
{
	_INIT_SHARED;
	return _int->partManager;
}

void Kexi::deleteGlobalObjects()
{
	delete _int;
}

//temp
bool _tempShowForms = true;
bool& Kexi::tempShowForms() { 
#ifndef KEXI_FORMS_SUPPORT
	_tempShowForms = false; 
#endif
	return _tempShowForms;
}

bool _tempShowReports = true;
bool& Kexi::tempShowReports() { 
#ifndef KEXI_REPORTS_SUPPORT
	_tempShowReports = false; 
#endif
	return _tempShowReports;
}

bool _tempShowMacros = true;
bool& Kexi::tempShowMacros() {
#ifndef KEXI_MACROS_SUPPORT
	_tempShowMacros = false; 
#endif
	return _tempShowMacros;
}

bool _tempShowScripts = true;
bool& Kexi::tempShowScripts() { 
#ifndef KEXI_SCRIPTS_SUPPORT
	_tempShowScripts = false; 
#endif
	return _tempShowScripts;
}

//--------------------------------------------------------------------------------

TQFont Kexi::smallFont(TQWidget *init)
{
	_INIT_SHARED;
	if (!_int->smallFont) {
		_int->smallFont = new TQFont( init->font() );
		const int wdth = TDEGlobalSettings::desktopGeometry(init).width();
		int size = 10 + TQMAX(0, wdth - 1100) / 100;
		size = TQMIN( init->fontInfo().pixelSize(), size );
		_int->smallFont->setPixelSize( size );
	}
	return *_int->smallFont;
}

//--------------------------------------------------------------------------------
TQString Kexi::nameForViewMode(int m)
{
	if (m==NoViewMode) return i18n("No View");
	else if (m==DataViewMode) return i18n("Data View");
	else if (m==DesignViewMode) return i18n("Design View");
	else if (m==TextViewMode) return i18n("Text View");

	return i18n("Unknown");
}

//--------------------------------------------------------------------------------

TQString Kexi::msgYouCanImproveData() {
	return i18n("You can correct data in this row or use \"Cancel row changes\" function.");
}

//--------------------------------------------------------------------------------

ObjectStatus::ObjectStatus()
: msgHandler(0)
{
}

ObjectStatus::ObjectStatus(const TQString& message, const TQString& description)
: msgHandler(0)
{
	setStatus(message, description);
}

ObjectStatus::ObjectStatus(KexiDB::Object* dbObject, const TQString& message, const TQString& description)
: msgHandler(0)
{
	setStatus(dbObject, message, description);
}

ObjectStatus::~ObjectStatus()
{
	delete msgHandler;
}

const ObjectStatus& ObjectStatus::status() const
{
	return *this;
}

bool ObjectStatus::error() const
{
	return !message.isEmpty() 
		|| (dynamic_cast<KexiDB::Object*>((TQObject*)dbObj) && dynamic_cast<KexiDB::Object*>((TQObject*)dbObj)->error());
}

void ObjectStatus::setStatus(const TQString& message, const TQString& description)
{
	this->dbObj=0;
	this->message=message;
	this->description=description;
}

void ObjectStatus::setStatus(KexiDB::Object* dbObject, const TQString& message, const TQString& description)
{
	if (dynamic_cast<TQObject*>(dbObject)) {
		dbObj = dynamic_cast<TQObject*>(dbObject);
	}
	this->message=message;
	this->description=description;
}

void ObjectStatus::setStatus(KexiDB::ResultInfo* result, const TQString& message, const TQString& description)
{
	if (result) {
		if (message.isEmpty())
			this->message = result->msg;
		else
			this->message = message + " " + result->msg;

		if (description.isEmpty())
			this->description = result->desc;
		else
			this->description = description + " " + result->desc;
	}
	else
		clearStatus();
}

void ObjectStatus::setStatus(KexiDB::Object* dbObject, KexiDB::ResultInfo* result, 
	const TQString& message, const TQString& description)
{
	if (!dbObject)
		setStatus(result, message, description);
	else if (!result)
		setStatus(dbObject, message, description);
	else {
		setStatus(dbObject, message, description);
		setStatus(result, this->message, this->description);
	}
}

void ObjectStatus::clearStatus()
{
	message=TQString();
	description=TQString();
}

TQString ObjectStatus::singleStatusString() const { 
	if (message.isEmpty() || description.isEmpty())
		return message;
	return message + " " + description;
}

void ObjectStatus::append( const ObjectStatus& otherStatus ) {
	if (message.isEmpty()) {
		message = otherStatus.message;
		description = otherStatus.description;
		return;
	}
	const TQString s( otherStatus.singleStatusString() );
	if (s.isEmpty())
		return;
	if (description.isEmpty()) {
		description = s;
		return;
	}
	description = description + " " + s;
}

//! @internal
class ObjectStatusMessageHandler : public KexiDB::MessageHandler
{
	public:
		ObjectStatusMessageHandler(ObjectStatus *status) 
			: KexiDB::MessageHandler()
			, m_status(status)
		{
		}
		virtual ~ObjectStatusMessageHandler()
		{
		}

		virtual void showErrorMessage(const TQString &title, 
			const TQString &details = TQString())
		{
			m_status->setStatus(title, details);
		}
		
		virtual void showErrorMessage(KexiDB::Object *obj, const TQString& msg = TQString())
		{
			m_status->setStatus(obj, msg);
		}

		ObjectStatus *m_status;
};

ObjectStatus::operator KexiDB::MessageHandler*()
{
	if (!msgHandler)
		msgHandler = new ObjectStatusMessageHandler(this);
	return msgHandler;
}

void Kexi::initCmdLineArgs(int argc, char *argv[], TDEAboutData* aboutData)
{
	TDEAboutData *about = aboutData;
	if (!about)
		about = Kexi::createAboutData();
#ifdef CUSTOM_VERSION
# include "../custom_startup.h"
#endif
	TDECmdLineArgs::init( argc, argv, about );
	TDECmdLineArgs::addCmdLineOptions( options );
}

void KEXI_UNFINISHED(const TQString& feature_name, const TQString& extra_text) 
{
	TQString msg;
	if (feature_name.isEmpty())
		msg = i18n("This function is not available for version %1 of %2 application.")
			.arg(KEXI_VERSION_STRING)
			.arg(KEXI_APP_NAME); 
	else {
		TQString feature_name_(feature_name);
		msg = i18n("\"%1\" function is not available for version %2 of %3 application.")
			.arg(feature_name_.replace("&",""))
			.arg(KEXI_VERSION_STRING)
			.arg(KEXI_APP_NAME);
	}

	TQString extra_text_(extra_text);
	if (!extra_text_.isEmpty())
		extra_text_.prepend("\n");

	KMessageBox::sorry(0, msg + extra_text_);
}