/**
* This file is a part of the Cairo-Dock project
*
* Copyright : (C) see the 'copyright' file.
* E-mail    : see the 'copyright' file.
*
* 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 3
* 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, see <http://www.gnu.org/licenses/>.
*/

#include <string.h>
#include <stdlib.h>

#include "cairo-dock-log.h"
#include "cairo-dock-keyfile-utilities.h"


GKeyFile *cairo_dock_open_key_file (const gchar *cConfFilePath)
{
	GKeyFile *pKeyFile = g_key_file_new ();
	GError *erreur = NULL;
	g_key_file_load_from_file (pKeyFile, cConfFilePath, G_KEY_FILE_KEEP_COMMENTS | G_KEY_FILE_KEEP_TRANSLATIONS, &erreur);
	if (erreur != NULL)
	{
		cd_debug ("while trying to load %s : %s", cConfFilePath, erreur->message);  // on ne met pas de warning car un fichier de conf peut ne pas exister la 1ere fois.
		g_error_free (erreur);
		g_key_file_free (pKeyFile);
		return NULL;
	}
	return pKeyFile;
}

void cairo_dock_write_keys_to_file (GKeyFile *pKeyFile, const gchar *cConfFilePath)
{
	cd_debug ("%s (%s)", __func__, cConfFilePath);
	GError *erreur = NULL;

	gchar *cDirectory = g_path_get_dirname (cConfFilePath);
	if (! g_file_test (cDirectory, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_EXECUTABLE))
	{
		g_mkdir_with_parents (cDirectory, 7*8*8+7*8+5);
	}
	g_free (cDirectory);


	gsize length=0;
	gchar *cNewConfFileContent = g_key_file_to_data (pKeyFile, &length, &erreur);
	if (erreur != NULL)
	{
		cd_warning ("Error while fetching data : %s", erreur->message);
		g_error_free (erreur);
		return ;
	}
	g_return_if_fail (cNewConfFileContent != NULL && *cNewConfFileContent != '\0');

	g_file_set_contents (cConfFilePath, cNewConfFileContent, length, &erreur);
	if (erreur != NULL)
	{
		cd_warning ("Error while writing data to %s : %s", cConfFilePath, erreur->message);
		g_error_free (erreur);
		return ;
	}
	g_free (cNewConfFileContent);
}


void cairo_dock_flush_conf_file_full (GKeyFile *pKeyFile, const gchar *cConfFilePath, const gchar *cShareDataDirPath, gboolean bUseFileKeys, const gchar *cTemplateFileName)
{
	gchar *cTemplateConfFilePath = (*cTemplateFileName == '/' ? g_strdup (cTemplateFileName) : g_strdup_printf ("%s/%s", cShareDataDirPath, cTemplateFileName));
	cd_message ("%s (%s)", __func__, cTemplateConfFilePath);
	
	if (! g_file_test (cTemplateConfFilePath, G_FILE_TEST_EXISTS))
	{
		cd_warning ("Couldn't find any installed conf file in %s", cShareDataDirPath);
	}
	else
	{
		gchar *cCommand = g_strdup_printf ("/bin/cp \"%s\" \"%s\"", cTemplateConfFilePath, cConfFilePath);
		int r = system (cCommand);
		g_free (cCommand);
		
		cairo_dock_replace_values_in_conf_file (cConfFilePath, pKeyFile, bUseFileKeys, 0);
	}
	g_free (cTemplateConfFilePath);
}



void cairo_dock_replace_key_values (GKeyFile *pOriginalKeyFile, GKeyFile *pReplacementKeyFile, gboolean bUseOriginalKeys, gchar iIdentifier)
{
	//g_print ("%s (%d, %d)\n", __func__, iIdentifier, bUseOriginalKeys);
	GError *erreur = NULL;
	gsize length = 0;
	gchar **pKeyList;
	gchar **pGroupList = g_key_file_get_groups ((bUseOriginalKeys ? pOriginalKeyFile : pReplacementKeyFile), &length);
	g_return_if_fail (pGroupList != NULL);
	gchar *cGroupName, *cKeyName, *cKeyValue, *cComment;
	int i, j;

	i = 0;
	while (pGroupList[i] != NULL)
	{
		cGroupName = pGroupList[i];

		length = 0;
		pKeyList = g_key_file_get_keys ((bUseOriginalKeys ? pOriginalKeyFile : pReplacementKeyFile), cGroupName, NULL, NULL);
		g_return_if_fail (pKeyList != NULL);
		
		j = 0;
		while (pKeyList[j] != NULL)
		{
			cKeyName = pKeyList[j];
			//g_print ("%s\n  %s", cKeyName, g_key_file_get_comment (pOriginalKeyFile, cGroupName, cKeyName, NULL));

			if (iIdentifier != 0)
			{
				cComment = g_key_file_get_comment (bUseOriginalKeys ? pOriginalKeyFile : pReplacementKeyFile, cGroupName, cKeyName, NULL);
				//g_print ("%s\n  %s", cKeyName, cComment);
				if (cComment == NULL || strlen (cComment) < 2 || cComment[1] != iIdentifier)
				{
					//g_print ("  on saute %s;%s (%s)\n", cGroupName, cKeyName, cComment);
					g_free (cComment);
					j ++;
					continue ;
				}
				g_free (cComment);
			}

			cKeyValue =  g_key_file_get_string (pReplacementKeyFile, cGroupName, cKeyName, &erreur);
			if (erreur != NULL)
			{
				cd_warning (erreur->message);
				g_error_free (erreur);
				erreur = NULL;
			}
			else
			{
				//g_print (" -> %s\n", cKeyValue);
				if (cKeyValue[strlen(cKeyValue) - 1] == '\n')
					cKeyValue[strlen(cKeyValue) - 1] = '\0';
				g_key_file_set_string (pOriginalKeyFile, cGroupName, cKeyName, (cKeyValue != NULL ? cKeyValue : ""));
			}
			g_free (cKeyValue);
			j ++;
		}

		g_strfreev (pKeyList);
		i ++;
	}
	g_strfreev (pGroupList);
	
	if (bUseOriginalKeys)
	{
		pGroupList = g_key_file_get_groups (pReplacementKeyFile, &length);
		i = 0;
		while (pGroupList[i] != NULL)
		{
			cGroupName = pGroupList[i];

			length = 0;
			pKeyList = g_key_file_get_keys (pReplacementKeyFile, cGroupName, NULL, NULL);

			j = 0;
			while (pKeyList[j] != NULL)
			{
				cKeyName = pKeyList[j];
				//g_print ("%s\n  %s", cKeyName, g_key_file_get_comment (pOriginalKeyFile, cGroupName, cKeyName, NULL));

				cComment = g_key_file_get_comment (pReplacementKeyFile, cGroupName, cKeyName, NULL);
				if (cComment == NULL || strlen (cComment) < 3 || (cComment[1] != '0' && cComment[2] != '0'))
				{
					g_free (cComment);
					j ++;
					continue ;
				}
				if (iIdentifier != 0)
				{
					if (cComment == NULL || strlen (cComment) < 2 || cComment[1] != iIdentifier)
					{
						//g_print ("  on saute %s;%s (%s)\n", cGroupName, cKeyName, cComment);
						g_free (cComment);
						j ++;
						continue ;
					}
				}

				cKeyValue =  g_key_file_get_string (pReplacementKeyFile, cGroupName, cKeyName, &erreur);
				if (erreur != NULL)
				{
					cd_warning (erreur->message);
					g_error_free (erreur);
					erreur = NULL;
				}
				else
				{
					//g_print (" -> %s\n", cKeyValue);
					if (cKeyValue[strlen(cKeyValue) - 1] == '\n')
						cKeyValue[strlen(cKeyValue) - 1] = '\0';
					g_key_file_set_string (pOriginalKeyFile, cGroupName, cKeyName, (cKeyValue != NULL ? cKeyValue : ""));
					if (cComment != NULL)
					{
						g_key_file_set_comment (pOriginalKeyFile, cGroupName, cKeyName, cComment, &erreur);
						if (erreur != NULL)
						{
							cd_warning (erreur->message);
							g_error_free (erreur);
							erreur = NULL;
						}
					}
				}
				g_free (cKeyValue);
				g_free (cComment);
				j ++;
			}

			g_strfreev (pKeyList);
			i ++;
		}
		g_strfreev (pGroupList);
	}
}


void cairo_dock_replace_values_in_conf_file (const gchar *cConfFilePath, GKeyFile *pValidKeyFile, gboolean bUseFileKeys, gchar iIdentifier)
{
	GKeyFile *pConfKeyFile = cairo_dock_open_key_file (cConfFilePath);
	if (pConfKeyFile == NULL)
		return ;

	cd_debug ("%s (%s)\n", __func__,cConfFilePath );
	cairo_dock_replace_key_values (pConfKeyFile, pValidKeyFile, bUseFileKeys, iIdentifier);

	cairo_dock_write_keys_to_file (pConfKeyFile, cConfFilePath);

	g_key_file_free (pConfKeyFile);
}

void cairo_dock_replace_keys_by_identifier (const gchar *cConfFilePath, gchar *cReplacementConfFilePath, gchar iIdentifier)
{
	GKeyFile *pReplacementKeyFile = cairo_dock_open_key_file (cReplacementConfFilePath);
	if (pReplacementKeyFile == NULL)
		return ;
	
	cd_debug ("%s (%s <- %s, '%c')\n", __func__, cConfFilePath, cReplacementConfFilePath, iIdentifier);
	cairo_dock_replace_values_in_conf_file (cConfFilePath, pReplacementKeyFile, TRUE, iIdentifier);

	g_key_file_free (pReplacementKeyFile);
}



void cairo_dock_get_conf_file_version (GKeyFile *pKeyFile, gchar **cConfFileVersion)
{
	*cConfFileVersion = NULL;
	
	gchar *cFirstComment =  g_key_file_get_comment (pKeyFile, NULL, NULL, NULL);
	
	if (cFirstComment != NULL && *cFirstComment != '\0')
	{
		gchar *str = strchr (cFirstComment, '\n');
		if (str != NULL)
			*str = '\0';
		
		str = strchr (cFirstComment, ';');  // le 1er est pour la langue (obsolete).
		if (str != NULL)
		{
			*cConfFileVersion = g_strdup (str+1);
		}
		else
		{
			*cConfFileVersion = g_strdup (cFirstComment + (*cFirstComment == '!'));  // le '!' est obsolete.
		}
	}
	g_free (cFirstComment);
}

gboolean cairo_dock_conf_file_needs_update (GKeyFile *pKeyFile, const gchar *cVersion)
{
	gchar *cPreviousVersion = NULL;
	cairo_dock_get_conf_file_version (pKeyFile, &cPreviousVersion);
	gboolean bNeedsUpdate;
	if (cPreviousVersion == NULL || strcmp (cPreviousVersion, cVersion) != 0)
		bNeedsUpdate = TRUE;
	else
		bNeedsUpdate = FALSE;
	
	g_free (cPreviousVersion);
	return bNeedsUpdate;
}


void cairo_dock_add_remove_element_to_key (const gchar *cConfFilePath, const gchar *cGroupName, const gchar *cKeyName, gchar *cElementName, gboolean bAdd)
{
	GKeyFile *pKeyFile = cairo_dock_open_key_file (cConfFilePath);
	if (pKeyFile == NULL)
		return ;
	
	gchar *cElementList = g_key_file_get_string (pKeyFile, cGroupName, cKeyName, NULL), *cNewElementList = NULL;
	if (cElementList != NULL && *cElementList == '\0')
	{
		g_free (cElementList);
		cElementList= NULL;
	}
	
	if (bAdd)
	{
		//g_print ("on rajoute %s\n", cElementName);
		if (cElementList != NULL)
			cNewElementList = g_strdup_printf ("%s;%s", cElementList, cElementName);
		else
			cNewElementList = g_strdup (cElementName);
	}
	else
	{
		//g_print ("on enleve %s\n", cElementName);
		gchar *str = g_strstr_len (cElementList, strlen (cElementList), cElementName);
		g_return_if_fail (str != NULL);
		if (str == cElementList)
		{
			if (str[strlen (cElementName)] == '\0')
				cNewElementList = g_strdup ("");
			else
				cNewElementList = g_strdup (str + strlen (cElementName) + 1);
		}
		else
		{
			*(str-1) = '\0';
			if (str[strlen (cElementName)] == '\0')
				cNewElementList = g_strdup (cElementList);
			else
				cNewElementList = g_strdup_printf ("%s;%s", cElementList, str + strlen (cElementName) + 1);
		}
	}
	g_key_file_set_string (pKeyFile, cGroupName, cKeyName, cNewElementList);
	cairo_dock_write_keys_to_file (pKeyFile, cConfFilePath);
	g_free (cElementList);
	g_free (cNewElementList);
	g_key_file_free (pKeyFile);
}


void cairo_dock_add_widget_to_conf_file (GKeyFile *pKeyFile, const gchar *cGroupName, const gchar *ckeyName, const gchar *cInitialValue, CairoDockGUIWidgetType iWidgetType, const gchar *cAuthorizedValues, const gchar *cDescription, const gchar *cTooltip)
{
	g_key_file_set_string (pKeyFile, cGroupName, ckeyName, cInitialValue);
	gchar *Comment = g_strdup_printf ("%c0%s %s%s%s%s", iWidgetType, cAuthorizedValues ? cAuthorizedValues : "", cDescription, cTooltip ? "\n{" : "", cTooltip ? cTooltip : "", cTooltip ? "}" : "");
	g_key_file_set_comment (pKeyFile, cGroupName, ckeyName, Comment, NULL);
	g_free (Comment);
}

void cairo_dock_remove_group_key_from_conf_file (GKeyFile *pKeyFile, const gchar *cGroupName, const gchar *ckeyName)
{
	g_key_file_remove_comment (pKeyFile, cGroupName, ckeyName, NULL);
	g_key_file_remove_key (pKeyFile, cGroupName, ckeyName, NULL);
}

gboolean cairo_dock_rename_group_in_conf_file (GKeyFile *pKeyFile, const gchar *cGroupName, const gchar *cNewGroupName)
{
	if (g_key_file_has_group (pKeyFile, cNewGroupName))
		return FALSE;
	
	gchar **pKeyList = g_key_file_get_keys (pKeyFile, cGroupName, NULL, NULL);
	g_return_val_if_fail (pKeyList != NULL, FALSE);
	gchar *cValue;
	int i;
	for (i = 0; pKeyList[i] != NULL; i ++)
	{
		cValue = g_key_file_get_value (pKeyFile, cGroupName, pKeyList[i], NULL);
		g_key_file_set_value (pKeyFile, cNewGroupName, pKeyList[i], cValue);
		g_free (cValue);
	}
	g_strfreev (pKeyList);
	
	g_key_file_remove_group (pKeyFile, cGroupName, NULL);
	
	return TRUE;
}
