/***************************************************************************
 *   Copyright (C) 2006 by Alexandru Olaru                                 *
 *   qumbetlian@yahoo.com                                                  *
 *                                                                         *
 *   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 <fcntl.h>
#include <fstream>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
#include <sys/stat.h>
#include <gtkmmconfig.h>
#include <gtkmm/messagedialog.h>
#include "configuration.hh"
#include "config.hh"
#include "../config.h"

#if GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION > 2
#include <sigc++/compatibility.h>
#define GMM_GTKMM_22_24(a,b) b
#else //gtkmm 2.2
#define GMM_GTKMM_22_24(a,b) a
#endif //

#if defined WINDOWS_PLATFORM
	#include <windows.h>
	#define HOME_ENVNAME "APPDATA"
#else
	#include <fcntl.h>
	#define HOME_ENVNAME "HOME"
#endif
#if !defined MAX_PATH
#	define MAX_PATH 256
#endif


Configuration& config(void){
	static Configuration config;
	return(config);
}

Configuration::Configuration(){
	char buffer[MAX_PATH + 1];
	GetCurrentProcessFileName(buffer);
	m_processFileName = new char[strlen(buffer) * sizeof(char) + 1];
	strcpy(m_processFileName, buffer);
	establishConfigElements();
	m_optionModify = false;
	m_font.m_optionName = new char[5];
	m_font.m_optionValue = NULL;
	strcpy(m_font.m_optionName, "Font");
	m_modify.m_optionName = new char[7];
	m_modify.m_optionValue = NULL;
	strcpy(m_modify.m_optionName, "Modify");
	m_current_dictionary.m_optionName = new char[19];
	m_current_dictionary.m_optionValue = NULL;
	strcpy(m_current_dictionary.m_optionName, "Current Dictionary");
	if(!read(m_font)){
		m_font.m_optionValue = new char[10];
		strcpy(m_font.m_optionValue, "tahoma 10");
	}
	if(!read(m_modify)){
		m_modify.m_optionValue = new char[6];
		strcpy(m_modify.m_optionValue, "false");
	}
	if(!read(m_current_dictionary)){
		m_current_dictionary.m_optionValue = new char[2];
		strcpy(m_current_dictionary.m_optionValue, " ");
	}
}

Configuration::~Configuration(){
	if(m_optionModify)
		write();
	if(m_processFileName)
		delete[] m_processFileName;
	if(m_configFileName)
		delete[] m_configFileName;
	if(m_homePath)
		delete[] m_homePath;
	if(m_font.m_optionName)
		delete[] m_font.m_optionName;
	if(m_font.m_optionValue)
		delete[] m_font.m_optionValue;
	if(m_modify.m_optionName)
		delete[] m_modify.m_optionName;
	if(m_modify.m_optionValue)
		delete[] m_modify.m_optionValue;
	if(m_current_dictionary.m_optionName)
		delete[] m_current_dictionary.m_optionName;
	if(m_current_dictionary.m_optionValue)
		delete[] m_current_dictionary.m_optionValue;
}

void Configuration::establishConfigElements(){
	char buffer[MAX_PATH + 1], homePath[MAX_PATH + 1], *fileName;
	strcpy(buffer, m_processFileName);
	#if defined WINDOWS_PLATFORM
	fileName = strrchr(buffer, '\\') ? strrchr(buffer, '\\') + 1 : buffer;
	#else
	fileName = strrchr(buffer, '/') ? strrchr(buffer, '/') + 1 : buffer;
	#endif
	if(strrchr(fileName, '.'))
		*(strrchr(fileName, '.')) = '\0';
	// Pe platforme Windows variabilele de sistem se obtin si cu functia
	// 'GetEnvironmentVariable'
	strncpy(homePath, getenv(HOME_ENVNAME), MAX_PATH);
	m_homePath = new char[sizeof(char) * (strlen(homePath) + strlen(fileName) + 3)];
	#if defined WINDOWS_PLATFORM
	sprintf(m_homePath, "%s\\%s", homePath, fileName);
	createDirIfNotExist(m_homePath);
	m_configFileName = new char[sizeof(char) *(strlen(m_homePath) + strlen(fileName) + 6)];
	sprintf(m_configFileName, "%s\\%s", m_homePath, fileName);
	#else
	sprintf(m_homePath, "%s/.%s", homePath, fileName);
	createDirIfNotExist(m_homePath);
	m_configFileName = new char[sizeof(char) *(strlen(m_homePath) + strlen(fileName) + 6)];
	sprintf(m_configFileName, "%s/%s", m_homePath, fileName);
	#endif
	strcat(m_configFileName, ".cfg");
}

void Configuration::write(void) {
	if(m_optionModify) {
		creat(m_configFileName, S_IREAD | S_IWRITE);
		std::ofstream oFileStream(m_configFileName);
		if(oFileStream) {
			oFileStream << m_font.m_optionName << "=" << m_font.m_optionValue << std::endl;
			oFileStream << m_modify.m_optionName << "=" << m_modify.m_optionValue << std::endl;
			oFileStream << m_current_dictionary.m_optionName << "=" \
				<< m_current_dictionary.m_optionValue << std::endl;
		}
		oFileStream.close();
	}
}

void Configuration::createDirIfNotExist(const char *path) {
	if(!opendir(path))
	#if defined WINDOWS_PLATFORM
		if(errno == ENOENT) mkdir(path);
	#else
	#	if defined LINUX_PLATFORM
		if(errno == ENOENT) mkdir(path, S_ISGID | S_IRUSR | S_IWUSR | S_IXUSR
			| S_IRGRP | S_IWGRP | S_IXGRP | S_IROTH | S_IXOTH);
	#	else error Either LINUX_PLATFORM or WINDOWS_PLATFORM must be defined
	#	endif
	#endif
			else {
				Glib::ustring msg = strerror(errno);
				msg += Glib::ustring(" ");
				msg += Glib::ustring(path);
				Gtk::MessageDialog msgdlg(msg, false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true);
			}
}
bool Configuration::read(struct Configuration::Option &option) {
	char buffer[256];
	std::ifstream iFileStream(m_configFileName);
	if(iFileStream)
		while(!iFileStream.eof()) {
			iFileStream.getline(buffer, 255, '=');
			if(!strcmp(buffer, option.m_optionName)) {
				iFileStream.getline(buffer, 255);
				if(option.m_optionValue)
					delete[] option.m_optionValue;
				option.m_optionValue = new char[strlen(buffer) + 1];
				strcpy(option.m_optionValue, buffer);
				iFileStream.close();
				return(true);
			}
			iFileStream.getline(buffer, 255);
		}
	else
		return(false);
}

bool Configuration::GetCurrentProcessFileName(char *pathName) {
	memset(pathName, 0, MAX_PATH + 1);
	#if defined WINDOWS_PLATFORM
	HMODULE moduleHandle = GetModuleHandle(NULL);
	return (moduleHandle == (HMODULE)0)
          ? false
          : (GetModuleFileName(moduleHandle, pathName, MAX_PATH) > 0);
	#else
	readlink("/proc/self/exe", pathName, MAX_PATH);
	return(true);
	#endif
}

const char* Configuration::processFileName(void) {
	return(m_processFileName);
}

const char* Configuration::configFileName(void) {
	return(m_configFileName);
}

const char* Configuration::homePath(void) {
	return(m_homePath);
}

const char* Configuration::font(void) {
	return(m_font.m_optionValue);
}

void Configuration::set_font(const char* fontName) {
	if(m_font.m_optionValue)
		delete[] m_font.m_optionValue;
	m_font.m_optionValue = new char[strlen(fontName) + 1];
	strcpy(m_font.m_optionValue, fontName);
	m_optionModify = true;
}

const char* Configuration::current_dictionary(void) {
	return(m_current_dictionary.m_optionValue);
}

void Configuration::set_current_dictionary(const char *dictionary) {
	if(m_current_dictionary.m_optionValue)
		delete[] m_current_dictionary.m_optionValue;
	m_current_dictionary.m_optionValue = new char[strlen(dictionary) + 1];
	strcpy(m_current_dictionary.m_optionValue, dictionary);
	m_optionModify = true;
}

bool Configuration::modify(void) {
	if(!strcmp(m_modify.m_optionValue, "true"))
		return(true);
	else
		return(false);
}

void Configuration::set_modify(bool modify) {
	if(m_modify.m_optionValue)
		delete[] m_modify.m_optionValue;
	if(modify) {
		m_modify.m_optionValue = new char[5];
		strcpy(m_modify.m_optionValue, "true");
	}
	else {
		m_modify.m_optionValue = new char[6];
		strcpy(m_modify.m_optionValue, "false");
	}
	m_optionModify = true;
}
