/***************************************************************************
*   Copyright (C) 2006-2012 by Thomas Schweitzer                          *
*   thomas-schweitzer(at)arcor.de                                         *
*                                                                         *
*   This program is free software; you can redistribute it and/or modify  *
*   it under the terms of the GNU General Public License version 2.0 as   *
*   published by the Free Software Foundation.                            *
*                                                                         *
*   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 in the file LICENSE.GPL; if not, write to the *
*   Free Software Foundation, Inc.,                                       *
*   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
***************************************************************************/

#include "UiGuiSettings.h"
#include "SettingsPaths.h"

#include <tqdatetime.h>
#include <tqdir.h>
#include <tqpoint.h>
#include <tqregexp.h>
#include <tqsettings.h>
#include <tqsize.h>
#include <tqwidget.h>


/*
    \class UiGuiSettings
    \brief Handles the settings of the program. Reads them on startup and saves them on exit.
    Is a singleton class and can only be accessed via getInstance().
*/

// Inits the single class instance pointer.
UiGuiSettings *UiGuiSettings::m_instance = nullptr;

/*
    \brief The constructor for the settings.
*/
UiGuiSettings::UiGuiSettings() : TQObject()
{
	// Create the main application settings object from the UniversalIndentGUIrc file.
	m_qsettings = new TQSettings(TQSettings::Ini);
	// The next lines make user the settings are always stored in
	// $HOME/.universalindentgui/universalindentguirc
	m_qsettings->insertSearchPath(TQSettings::Unix, SettingsPaths::getSettingsPath());
  m_qsettings->setPath("UniversalIndentGUI", "UniversalIndentGUI", TQSettings::User);
	// settings are stored in the universalindentguirc file, group UniversalIndentGUI
	m_qsettings->beginGroup("universalindentgui/UniversalIndentGUI");

	m_indenterDirectoryStr = SettingsPaths::getGlobalFilesPath() + "/indenters";

  m_actionSettings["actionEnableSyntaxHighlighting"] = "SyntaxHighlightingEnabled";
  m_actionSettings["actionLoadLastOpenedFileOnStartup"] = "LoadLastOpenedFileOnStartup";
  m_actionSettings["actionWhiteSpaceIsVisible"] = "WhiteSpaceIsVisible";
  m_actionSettings["actionIndenterParameterTooltipsEnabled"] = "IndenterParameterTooltipsEnabled";

	readAvailableTranslations();
	loadSettings();
}

/*
    \brief Returns the instance of the settings class. If no instance exists, one will be created.
 */
UiGuiSettings* UiGuiSettings::getInstance()
{
	if (!m_instance)
	{
		// Create the settings object, which loads all UiGui settings from a file.
		m_instance = new UiGuiSettings();
	}

	return m_instance;
}

/*
    \brief Deletes the existing instance of UiGuiSettings and removes the created temp dir.
 */
void UiGuiSettings::deleteInstance()
{
	SettingsPaths::cleanAndRemoveTempDir();
	if (m_instance)
	{
		delete m_instance;
		m_instance = nullptr;
	}
}

/*
    \brief The destructor saves the settings to a file.
 */
UiGuiSettings::~UiGuiSettings()
{
	saveSettings();
	delete m_qsettings;
}

/*
    \brief Scans the translations directory for available translation files and
    stores them in the TQList \a m_availableTranslations.
 */
void UiGuiSettings::readAvailableTranslations()
{
	TQStringList languageFileList;

	// English is the default language. A translation file does not exist but to have a menu entry,
	// added here.
	languageFileList << "universalindent_en.qm";

	// Find all translation files in the "translations" directory.
	TQDir translationDirectory = TQDir(SettingsPaths::getGlobalFilesPath() + "/translations");
	for (const TQString &file : translationDirectory.entryList(TQString("universalindent_*.qm")))
	{
		languageFileList << file;
	}

	// Loop for each found translation file
	for (TQString &languageShort : languageFileList)
	{
		// Remove the leading string "universalindent_" from the filename.
		languageShort.remove(0, 16);
		// Remove trailing file extension ".qm".
		languageShort.truncate(languageShort.length() - 3);

		m_availableTranslations.append(languageShort);
	}
}

/*
    \brief Returns a list of the mnemonics of the available translations.
 */
TQStringList& UiGuiSettings::getAvailableTranslations()
{
	return m_availableTranslations;
}

/*
    \brief Returns the value of the by \a settingsName defined setting as TQVariant.

    If the named setting does not exist, 0 is being returned.
*/
TQVariant UiGuiSettings::getValueByName(const TQString &settingName) const
{
	// Test if the named setting really exists.
	if (m_settings.contains(settingName))
	{
		return m_settings[settingName];
	}
	return TQVariant(0);
}

/*
    \brief Sets the value of the by \a settingsName defined setting to the value \a value.

    The to \a settingsName corresponding signal is emitted, if the value has changed.
 */
bool UiGuiSettings::setValueByName(const TQString &settingName, TQVariant value)
{
	// Test if the named setting really exists.
	if (m_settings.contains(settingName))
	{
		// Test if the new value is different to the one before.
		if (m_settings[settingName] != value)
		{
			m_settings[settingName] = value;
			// Emit the signal for the changed setting.
			emitSignalForSetting(settingName);
		}
		return true;
	}
	return false;
}

/*!
    \brief Loads the settings for the main application.

    Settings are for example last selected indenter, last loaded source code file and so on.
*/
void UiGuiSettings::loadSettings()
{
	// Read the version string
	m_settings["VersionInSettingsFile"] = m_qsettings->readEntry("version", TQString::null);

	// Read window's maximized status
	m_settings["WindowIsMaximized"] = m_qsettings->readBoolEntry("maximized", false);

	// Read window's position
	TQString positionString = m_qsettings->readEntry("position", "@Point(50 50)");
	TQRegExp posrx("@Point\\((-?\\d+)[ \\t]+(-?\\d+)\\)");
	TQPoint position(50, 50);
	if (posrx.exactMatch(positionString.stripWhiteSpace()))
	{
		TQStringList posList = posrx.capturedTexts();
		position.setX(posList[1].toInt());
		position.setY(posList[2].toInt());
	}
	m_settings["WindowPosition"] = position;

	// Read window's size
	TQString sizeString = m_qsettings->readEntry("size", "@Size(800 600)");
	TQRegExp sizerx("@Size\\((-?\\d+)[ \\t]+(-?\\d+)\\)");
	TQSize size(800, 600);
	if (sizerx.exactMatch(sizeString.stripWhiteSpace()))
	{
		TQStringList sizeList = sizerx.capturedTexts();
		size.setWidth(sizeList[1].toInt());
		size.setHeight(sizeList[2].toInt());
	}
	m_settings["WindowSize"] = size;

	// Read last selected encoding for the opened source code file.
	m_settings["FileEncoding"] = m_qsettings->readEntry("encoding", "UTF-8");

	// Read maximum length of list for recently opened files.
	m_settings["RecentlyOpenedListSize"] = m_qsettings->readNumEntry("recentlyOpenedListSize", 5);

	// Read if last opened source code file should be loaded on startup.
	m_settings["LoadLastOpenedFileOnStartup"] = m_qsettings->readBoolEntry(
	        "loadLastSourceCodeFileOnStartup", true);

	// Read last opened source code file from the settings file.
	m_settings["LastOpenedFiles"] = m_qsettings->readEntry("lastSourceCodeFile",
	        m_indenterDirectoryStr + "/example.cpp");

	// Read last selected indenter from the settings file.
	int selectedIndenter = m_qsettings->readNumEntry("selectedIndenter", 0);
	if (selectedIndenter < 0)
	{
		selectedIndenter = 0;
	}
	m_settings["SelectedIndenter"] = selectedIndenter;

	// Read if syntax highlighting is enabled.
	m_settings["SyntaxHighlightingEnabled"] = m_qsettings->readBoolEntry(
	        "SyntaxHighlightingEnabled", true);

	// Read if white space characters should be displayed.
	m_settings["WhiteSpaceIsVisible"] = m_qsettings->readBoolEntry("whiteSpaceIsVisible", false);

	// Read if indenter parameter tool tips are enabled.
	m_settings["IndenterParameterTooltipsEnabled"] = m_qsettings->readBoolEntry(
	        "indenterParameterTooltipsEnabled", true);

	// Read the tab width from the settings file.
	m_settings["TabWidth"] = m_qsettings->readNumEntry("tabWidth", 4);

	// Read the last selected language and stores the index it has in the list of available
	// translations.
	TQString language = m_qsettings->readEntry("language", "en");
	int idx = m_availableTranslations.findIndex(language);
	if (idx < 0)
	{
		idx = m_availableTranslations.findIndex("en"); // "en" is always present
	}
	m_settings["Language"] = idx;

	// TODO - MainWindow::saveState() missing in TQt3
	// Read the main window state.
	// m_settings["MainWindowState"] = m_qsettings->readEntry("MainWindowState", "@ByteArray()");
}

/*!
    \brief Saves the settings for the main application.

    Settings are for example last selected indenter, last loaded source code file and so on.
*/
void UiGuiSettings::saveSettings()
{
	// Write the version string
	m_qsettings->writeEntry("version", m_settings["VersionInSettingsFile"].toString());

	// Write window's maximized status
	m_qsettings->writeEntry("maximized", m_settings["WindowIsMaximized"].toBool());

	// Write window's position
	TQPoint position = m_settings["WindowPosition"].toPoint();
	TQString positionString = TQString("@Point(%1 %2)").arg(position.x()).arg(position.y());
	m_qsettings->writeEntry("position", positionString);

	// Write window's size
	TQSize size = m_settings["WindowSize"].toSize();
	TQString sizeString = TQString("@Size(%1 %2)").arg(size.width()).arg(size.height());
	m_qsettings->writeEntry("size", sizeString);

	// Write last selected encoding for the opened source code file.
	m_qsettings->writeEntry("encoding", m_settings["FileEncoding"].toString());

	// Write maximum length of list for recently opened files.
	m_qsettings->writeEntry("recentlyOpenedListSize", m_settings["RecentlyOpenedListSize"].toInt());

	// Write if last opened source code file should be loaded on startup.
	m_qsettings->writeEntry("loadLastSourceCodeFileOnStartup",
	        m_settings["LoadLastOpenedFileOnStartup"].toBool());

	// Write last opened source code file from the settings file.
	m_qsettings->writeEntry("lastSourceCodeFile", m_settings["LastOpenedFiles"].toString());

	// Write last selected indenter from the settings file.
	m_qsettings->writeEntry("selectedIndenter", m_settings["SelectedIndenter"].toInt());

	// Write if syntax highlighting is enabled.
	m_qsettings->writeEntry("SyntaxHighlightingEnabled",
	        m_settings["SyntaxHighlightingEnabled"].toBool());

	// Write if white space characters should be displayed.
	m_qsettings->writeEntry("whiteSpaceIsVisible", m_settings["WhiteSpaceIsVisible"].toBool());

	// Write if indenter parameter tool tips are enabled.
	m_qsettings->writeEntry("indenterParameterTooltipsEnabled",
	        m_settings["IndenterParameterTooltipsEnabled"].toBool());

	// Write the tab width from the settings file.
	m_qsettings->writeEntry("tabWidth", m_settings["TabWidth"].toInt());

	// Write the last selected language and stores the index it has in the list of available
	m_qsettings->writeEntry("language", m_availableTranslations[m_settings["Language"].toInt()]);

	// TODO - MainWindow::saveState() missing in TQt3
	// Write the main window state.
	//m_qsettings->writeEntry("MainWindowState", m_settings["MainWindowState"].toByteArray());
}

/*
    \brief Extern widgets can connect to this slot to change settings.

    According to the objects property "connectedSettingName" the corresponding
    setting is known and set.
 */
void UiGuiSettings::handleValueChangeFromExtern(bool value)
{
	if (sender())
	{
		// Get the corresponding setting name from the sender objects property
		TQString senderName = TQString(sender()->name());
		if (m_actionSettings.contains(senderName))
		{
			TQString settingName = m_actionSettings[senderName];

			// Set the value of the setting to the objects value.
			setValueByName(settingName, value);
		}
	}
}

void UiGuiSettings::emitSignalForSetting(TQString settingName)
{
	// Emit the signal for the changed value.
	if (settingName == "RecentlyOpenedListSize")
	{
		emit recentlyOpenedListSize(m_settings[settingName].toInt());
	}
	else if (settingName == "LoadLastOpenedFileOnStartup")
	{
		emit loadLastOpenedFileOnStartup(m_settings[settingName].toBool());
	}
	else if (settingName == "SyntaxHighlightingEnabled")
	{
		emit syntaxHighlightingEnabled(m_settings[settingName].toBool());
	}
	else if (settingName == "WhiteSpaceIsVisible")
	{
		emit whiteSpaceIsVisible(m_settings[settingName].toBool());
	}
	else if (settingName == "IndenterParameterTooltipsEnabled")
	{
		emit indenterParameterTooltipsEnabled(m_settings[settingName].toBool());
	}
	else if (settingName == "TabWidth")
	{
		emit tabWidth(m_settings[settingName].toInt());
	}
	else if (settingName == "Language")
	{
		emit language(m_settings[settingName].toInt());
	}
}

#include "UiGuiSettings.moc"
