/* Bluefish HTML Editor
* paths_state_config.c - file locations for config files and state
*
* Copyright (C) 2025-2026 Olivier Sessink
*
* 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/>.
*

previously bluefish used $HOME/.bluefish/ on all platforms

On Unix/Linux this uses the Freedesktop specification for XDG Base Directory Specification 
https://specifications.freedesktop.org/basedir/latest/ 

On OSX this uses "~/Library/Application Support/nl.openoffice.bluefish/"

On Windows64 this uses %USER%/Appdata/
*/
/*#define DEBUG*/

#include "bluefish.h"
#include "paths_state_config.h"

#ifdef WIN32
#include <shlobj.h>
#endif

#define CURCONFIG "rcfile-2.0"
#define CURSESSION "session-2.0"

static GFile *user_bfdir(const gchar *filename) {
	GFile *file;
	gchar *path = g_strconcat(g_get_home_dir(), "/."PACKAGE"/", filename, NULL);
	file = g_file_new_for_path(path);
	g_free(path);
	return file;
}

#ifdef WIN32
/*
*
*&FOLDERID_RoamingAppData
*&FOLDERID_LocalAppData
*/
static gchar* get_known_folder(REFKNOWNFOLDERID folder_id) {
	PWSTR path_wide = NULL;
	static char path[MAX_PATH];
	if (SHGetKnownFolderPath(folder_id, 0, NULL, &path_wide) != S_OK) {
		return NULL;
	}
	// Convert wide string to multibyte
	WideCharToMultiByte(CP_UTF8, 0, path_wide, -1, path, MAX_PATH, NULL, NULL);
	CoTaskMemFree(path_wide);
	return path;
}

GFile *get_gfile_for_dir_filename(REFKNOWNFOLDERID folder_id, gchar *filename) {
	gchar *dir, *path;
	GFile *file; 
	dir = get_known_folder(folder_id);
	path = g_strconcat(dir,"/"PACKAGE"/", filename, NULL);
	file = g_file_new_for_path(path);
	g_free(path);
	return file;
}

GFile *paths_config_gfile() {
	return get_gfile_for_dir_filename(&FOLDERID_RoamingAppData, CURCONFIG);
}

GFile *paths_session_gfile() {
	return get_gfile_for_dir_filename(&FOLDERID_RoamingAppData, CURSESSION);
}

gchar *paths_user_accelmap(void) {
	return g_strconcat(get_known_folder(&FOLDERID_LocalAppData), "/" PACKAGE "/menudump_2", NULL);
	/*return g_strconcat(g_get_home_dir(), "/." PACKAGE "/menudump_2", NULL);*/
}

gchar *paths_autosavejournaldir_char() {
	return g_strconcat(get_known_folder(&FOLDERID_LocalAppData), "/" PACKAGE "/", NULL);
}

gchar *paths_autosavedir_char() {
	return g_strconcat(get_known_folder(&FOLDERID_LocalAppData), "/" PACKAGE "/autosave/", NULL);
}

GFile *paths_templatesdir_gfile() {
	return get_gfile_for_dir_filename(&FOLDERID_LocalAppData, "templates/");
}
gchar *paths_datadir_char(const gchar *filename) {
	return g_strconcat(get_known_folder(&FOLDERID_LocalAppData), "/"PACKAGE"/",filename,NULL);
}
void paths_create_dirs_and_migrate() {
	gchar *dir;
	GFile *src, *dst;
	gchar *chardst;
	dir = g_strconcat(get_known_folder(&FOLDERID_RoamingAppData), "/"PACKAGE, NULL);
	DEBUG_MSG("paths_create_dirs_and_migrate, create %s\n",dir);
	g_mkdir_with_parents(dir, 0755);
	g_free(dir);
	
	dir = g_strconcat(get_known_folder(&FOLDERID_LocalAppData), "/" PACKAGE "/templates/", NULL);
	DEBUG_MSG("paths_create_dirs_and_migrate, create %s\n",dir);
	g_mkdir_with_parents(dir, 0755);
	g_free(dir);

	/* we will not create the autosave dir. 
	if it does not exist, the autosave code 
	will do the migration code itself */
	
	src = user_bfdir(CURCONFIG);
	dst = paths_config_gfile();
	g_file_copy(src,dst,0, NULL, NULL, NULL, NULL);
	g_object_unref(src);
	g_object_unref(dst);
	
	src = user_bfdir(CURSESSION);
	dst = paths_session_gfile();
	g_file_copy(src,dst,0, NULL, NULL, NULL, NULL);
	g_object_unref(src);
	g_object_unref(dst);

	/* we do not migrate autosave files, the autosave code will handle that for us */
	
	/* we need to migrate snippets */
	src = user_bfdir("snippets");
	chardst = paths_datadir_char("snippets");
	dst = g_file_new_for_path(chardst);
	g_file_copy(src,dst,0, NULL, NULL, NULL, NULL);
	g_object_unref(src);
	g_object_unref(dst);
	g_free(chardst);
	
	/* do we need to migrate templates ? or make the user handle that him/herself? */
}

#elif PLATFORM_DARWIN
/*
see following docs for background: 
https://developer.apple.com/library/archive/documentation/FileManagement/Conceptual/FileSystemProgrammingGuide/MacOSXDirectories/MacOSXDirectories.html
*/

#define LIBRARYAPPSUPPORT "/Library/Application Support/nl.openoffice.bluefish/"
static GFile *user_libraryappsupport(const gchar *filename) {
	GFile *file;
	gchar *path = g_strconcat(g_get_home_dir(),LIBRARYAPPSUPPORT , filename, NULL);
	file = g_file_new_for_path(path);
	g_free(path);
	return file;
}

GFile *paths_config_gfile() {
	return user_libraryappsupport(CURCONFIG);
}

GFile *paths_session_gfile() {
	return user_libraryappsupport(CURSESSION);
}
gchar *paths_user_accelmap(void) {
	return g_strconcat(g_get_home_dir(), LIBRARYAPPSUPPORT, "menudump_2", NULL);
	/*return g_strconcat(g_get_home_dir(), "/." PACKAGE "/menudump_2", NULL);*/
}

gchar *paths_autosavejournaldir_char() {
	return g_strconcat(g_get_home_dir(), LIBRARYAPPSUPPORT, NULL);
}
gchar *paths_autosavedir_char() {
	return g_strconcat(g_get_home_dir(), LIBRARYAPPSUPPORT"autosave/", NULL);
}

GFile *paths_templatesdir_gfile() {
	return user_libraryappsupport("templates/");
}
gchar *paths_datadir_char(const gchar *filename) {
	return g_strconcat(g_get_home_dir(), LIBRARYAPPSUPPORT,filename,NULL);
}
void paths_create_dirs_and_migrate() {
	gchar *dir;
	GFile *src, *dst;
	gchar *chardst;
	dir = paths_autosavedir_char();
	g_mkdir_with_parents(dir, 0755);
	g_free(dir);
	dir = g_strconcat(g_get_home_dir(), LIBRARYAPPSUPPORT"templates/", NULL);
	g_mkdir_with_parents(dir, 0755);
	g_free(dir);
	
	/* we will not create the autosave dir. 
	if it does not exist, the autosave code 
	will do the migration code itself */
	
	src = user_bfdir(CURCONFIG);
	dst = paths_config_gfile();
	g_file_copy(src,dst,0, NULL, NULL, NULL, NULL);
	g_object_unref(src);
	g_object_unref(dst);
	
	src = user_bfdir(CURSESSION);
	dst = paths_session_gfile();
	g_file_copy(src,dst,0, NULL, NULL, NULL, NULL);
	g_object_unref(src);
	g_object_unref(dst);

	/* we do not migrate autosave files, the autosave code will handle that for us */
	
	/* we need to migrate snippets */
	src = user_bfdir("snippets");
	chardst = paths_datadir_char("snippets");
	dst = g_file_new_for_path(chardst);
	g_file_copy(src,dst,0, NULL, NULL, NULL, NULL);
	g_object_unref(src);
	g_object_unref(dst);
	g_free(chardst);
	
	/* do we need to migrate templates ? or make the user handle that him/herself? */
		
	
}
#else
/** xdg_get_path()
* Generic XDG path getter
* Returns allocated string that must be freed by caller
*/

static char* xdg_get_path(const char *env_var, const char *default_subdir, const char *filename) {
	char *xdg_dir = getenv(env_var);
	char *path;
	size_t len;
	
	if (xdg_dir && xdg_dir[0] != '\0') {
		len = strlen(xdg_dir) + strlen(filename) + strlen(PACKAGE) + 3;
		path = malloc(len);
		if (path) snprintf(path, len, "%s/"PACKAGE"/%s", xdg_dir, filename);
		DEBUG_MSG("xdg_get_path, return $%s based path %s\n",env_var,path);
	} else {
		const gchar *home = g_get_home_dir();
		if (!home) return NULL;
		
		len = strlen(home) + strlen(default_subdir) + strlen(filename) + strlen(PACKAGE) + 4;
		path = malloc(len);
		if (path) snprintf(path, len, "%s/%s/"PACKAGE"/%s", home, default_subdir, filename);
		DEBUG_MSG("xdg_get_path, return default path %s\n",path);
	}
	return path;
}

/*static char* xdg_get_config_path(const char *filename) {
	return xdg_get_path("XDG_CONFIG_HOME", ".config", filename);
}

static char* xdg_get_data_path(const char *filename) {
	return xdg_get_path("XDG_DATA_HOME", ".local/share", filename);
}

static char* xdg_get_state_path(const char *filename) {
	return xdg_get_path("XDG_STATE_HOME", ".local/state", filename);
}*/

GFile *paths_config_gfile() {
	GFile *file;
	gchar *path = xdg_get_path("XDG_CONFIG_HOME", ".config", CURCONFIG);
	file = g_file_new_for_path(path);
	g_free(path);
	return file;
}
GFile *paths_session_gfile() {
	GFile *file;
	gchar *path = xdg_get_path("XDG_STATE_HOME", ".local/state", CURSESSION);
	file = g_file_new_for_path(path);
	g_free(path);
	return file;
}
gchar *paths_user_accelmap(void) {
	return xdg_get_path("XDG_STATE_HOME", ".local/state", "menudump_2");
	/*return g_strconcat(g_get_home_dir(), "/." PACKAGE "/menudump_2", NULL);*/
}

gchar *paths_autosavejournaldir_char() {
	return xdg_get_path("XDG_STATE_HOME", ".local/state", "");
}
gchar *paths_autosavedir_char() {
	return xdg_get_path("XDG_STATE_HOME", ".local/state", "autosave/");
}
GFile *paths_templatesdir_gfile() {
	GFile *file;
	gchar *path = xdg_get_path("XDG_DATA_HOME", ".local/share", "templates/");
	file = g_file_new_for_path(path);
	g_free(path);
	return file;
}
/* used for bflang files and plugins and snippets */
gchar *paths_datadir_char(const gchar *filename) { 
	return xdg_get_path("XDG_DATA_HOME", ".local/share", filename?filename:"");
}

void paths_create_dirs_and_migrate() {
	gchar *dir;
	GFile *src, *dst;
	gchar *chardst;
	dir = xdg_get_path("XDG_CONFIG_HOME", ".config", "");
	DEBUG_MSG("paths_create_dirs_and_migrate, creating %s\n",dir);
	g_mkdir_with_parents(dir, 0755);
	g_free(dir);
	dir = xdg_get_path("XDG_DATA_HOME", ".local/share", "templates/");
	DEBUG_MSG("paths_create_dirs_and_migrate, creating %s\n",dir);
	g_mkdir_with_parents(dir, 0755);
	g_free(dir);
	
	/* we will not create the autosave dir in XDG_STATE_HOME. 
	if it does not exist, the autosave code 
	will do the migration code itself */
	
	src = user_bfdir(CURCONFIG);
	dst = paths_config_gfile();
	g_file_copy(src,dst,0, NULL, NULL, NULL, NULL);
	g_object_unref(src);
	g_object_unref(dst);
	
	src = user_bfdir(CURSESSION);
	dst = paths_session_gfile();
	g_file_copy(src,dst,0, NULL, NULL, NULL, NULL);
	g_object_unref(src);
	g_object_unref(dst);

	/* we do not migrate autosave files, the autosave code will handle that for us */
	
	/* we need to migrate snippets */
	src = user_bfdir("snippets");
	chardst = paths_datadir_char("snippets");
	dst = g_file_new_for_path(chardst);
	g_file_copy(src,dst,0, NULL, NULL, NULL, NULL);
	g_object_unref(src);
	g_object_unref(dst);
	g_free(chardst);
	
	/* do we need to migrate templates ? or make the user handle that him/herself? */
	
}

#endif 

