/*
 * Copyright (c) 2005 Sasha Vasko <sasha at aftercode.net>
 *
 * 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.
 *
 */


/*#define LOCAL_DEBUG */

#include "../configure.h"

#include <unistd.h>

#include "../libAfterStep/asapp.h"
#include "../libAfterStep/afterstep.h"
#include "../libAfterStep/session.h"
#include "../libAfterStep/desktop_category.h"

#include "afterconf.h"

const char *default_aliases[][2] = {
	{"ArcadeGame", "Arcade"},
	{"Application", "Applications"},
	{"Game", "Games"},
	{"Utility", "Utilities"},
	{NULL, NULL}

};

static char *filter_desktop_entry_exec (const char *exec)
{
	char *clean_exec = mystrdup (exec);
	int start = 0, ts;

	while (clean_exec[start] != '\0' && !isspace (clean_exec[start]))
		++start;
	while (clean_exec[start] != '\0') {
		ts = start;
		while (isspace (clean_exec[ts]))
			++ts;
		if (clean_exec[ts] == '%' && isalpha (clean_exec[ts + 1])) {
			while (!isspace (clean_exec[ts]) && clean_exec[ts] != '\0') {
				clean_exec[ts] = ' ';
				++ts;
			}
			start = ts;
		} else if (mystrncasecmp (&clean_exec[ts], "-caption ", 9) == 0) {
			ts += 9;
			while (isspace (clean_exec[ts]))
				++ts;
			if (mystrncasecmp (&clean_exec[ts], "\"%c\"", 4) == 0) {
				ts += 3;
				while (start < ts)
					clean_exec[++start] = ' ';
			} else if (clean_exec[ts] == '%' && isalpha (clean_exec[ts + 1])) {
				ts += 1;
				while (start < ts)
					clean_exec[++start] = ' ';
			}
		} else if (clean_exec[ts] == '\"') {
			char *end = find_doublequotes (&clean_exec[ts]);

			if (end != NULL)
				start = end - &clean_exec[0];
			else
				start = ts;
			++start;
		} else
			for (start = ts;
					 !isspace (clean_exec[start]) && clean_exec[start] != '\0';
					 ++start) ;
	}
	while (isspace (clean_exec[start - 1])) {
		--start;
		clean_exec[start] = '\0';
	}
	return clean_exec;
}

char *stripcpy_localized (char *ptr)
{
	int i = 0;
	static char default_locale[] = "us";
	char *locale = MyArgs.locale[0] ? MyArgs.locale : &default_locale[0];

	while (locale[i] != '.' && locale[i] != '\0' && ptr[i] != ']') {
		if (ptr[i] != locale[i])
			break;
		++i;
	}
	if ((locale[i] == '.' || locale[i] == '_' || locale[i] == '\0')
			&& ptr[i] == ']')
		return stripcpy (ptr + i + 2);
	return NULL;
}

static void parse_desktop_entry_line (ASDesktopEntry * de, char *ptr)
{
#define PARSE_ASDE_TYPE_VAL(val)	if(mystrncasecmp(ptr, #val, ASDE_KEYWORD_##val##_LEN) == 0){de->type = ASDE_Type##val; return;}
#define PARSE_ASDE_STRING_VAL(val)	if(mystrncasecmp(ptr, #val "=", ASDE_KEYWORD_##val##_LEN+1) == 0){if( de->val ) free( de->val ) ; de->val = stripcpy(ptr+ASDE_KEYWORD_##val##_LEN+1); return;}
#define PARSE_ASDE_FLAG_VAL(val)	if(mystrncasecmp(ptr, #val "=", ASDE_KEYWORD_##val##_LEN+1) == 0){char *tmp = stripcpy(ptr+ASDE_KEYWORD_##val##_LEN+1); if( tmp[0] == '1' || mystrcasecmp(tmp, "true") == 0 ) set_flags(de->flags, ASDE_##val); free(tmp); return;}

	if (ptr[0] == 'X' && ptr[1] == '-') {
		ptr += 2;
		if (mystrncasecmp (ptr, "AfterStep-", 10) == 0) {
			ptr += 10;
			PARSE_ASDE_STRING_VAL (IndexName)
					PARSE_ASDE_STRING_VAL (Aliases)
					PARSE_ASDE_FLAG_VAL (ASModule)
		PARSE_ASDE_FLAG_VAL (CheckAvailability)} else
				if (mystrncasecmp (ptr, "KDE-", 4) == 0)
			set_flags (de->flags, ASDE_KDE);
		else if (mystrncasecmp (ptr, "GNOME-", 6) == 0)
			set_flags (de->flags, ASDE_GNOME);
	} else if (mystrncasecmp (ptr, "Name[", 5) == 0
						 && MyArgs.locale[0] == ptr[5]) {
		char *val = stripcpy_localized (ptr + 5);

		if (val)
			set_string (&(de->Name_localized), val);
	} else if (mystrncasecmp (ptr, "Type=", 5) == 0) {
		ptr += 5;

		PARSE_ASDE_TYPE_VAL (Application)
				PARSE_ASDE_TYPE_VAL (Link)
				PARSE_ASDE_TYPE_VAL (FSDevice)
	PARSE_ASDE_TYPE_VAL (Directory)} else
			if (mystrncasecmp (ptr, "Comment[", 8) == 0
					&& MyArgs.locale[0] == ptr[8]) {
		char *val = stripcpy_localized (ptr + 8);

		if (val)
			set_string (&(de->Comment_localized), val);
	} else if (mystrncasecmp (ptr, "Encoding=", 9) == 0
						 && mystrncasecmp (ptr + 9, "UTF-8", 5) != 0) {
		set_flags (de->flags, ASDE_EncodingNonUTF8);
	} else {
		PARSE_ASDE_STRING_VAL (Name)
				PARSE_ASDE_STRING_VAL (GenericName)
				PARSE_ASDE_STRING_VAL (Comment)
				PARSE_ASDE_STRING_VAL (Icon)
				PARSE_ASDE_STRING_VAL (TryExec)
				PARSE_ASDE_STRING_VAL (Exec)
				PARSE_ASDE_STRING_VAL (Path)
				PARSE_ASDE_STRING_VAL (SwallowTitle)
				PARSE_ASDE_STRING_VAL (SwallowExec)
				PARSE_ASDE_STRING_VAL (SortOrder)
				PARSE_ASDE_STRING_VAL (Categories)
				PARSE_ASDE_STRING_VAL (OnlyShowIn)
				PARSE_ASDE_STRING_VAL (NotShowIn)
				PARSE_ASDE_STRING_VAL (StartupWMClass)
				PARSE_ASDE_FLAG_VAL (NoDisplay)
	PARSE_ASDE_FLAG_VAL (Hidden) PARSE_ASDE_FLAG_VAL (Terminal)
				PARSE_ASDE_FLAG_VAL (StartupNotify)}
}

static void
fix_desktop_entry (ASDesktopEntry * de, const char *default_category,
									 const char *icon_path, const char *origin, Bool applnk)
{
	if (de->Categories == NULL && default_category) {
		if (get_flags (de->flags, ASDE_KDE | ASDE_GNOME) == 0) {
			if (mystrncasecmp (default_category, "KDE", 3) == 0)
				set_flags (de->flags, ASDE_KDE);
			else if (mystrncasecmp (default_category, "GNOME", 5) == 0)
				set_flags (de->flags, ASDE_GNOME);
		}
		if (de->type != ASDE_TypeDirectory)
			de->Categories = mystrdup (default_category);
	}
	if (applnk)
		set_flags (de->flags, ASDE_KDE);

	if (de->Categories != NULL) {
		de->categories_len = strlen (de->Categories);
		de->categories_shortcuts =
				compound_string2string_list (de->Categories, ';', False,
																		 &(de->categories_num));
		if (get_flags (de->flags, ASDE_KDE | ASDE_GNOME) == 0) {
			int i = de->categories_num;
			ASFlagType kind = 0;

			while (--i >= 0 && kind == 0) {
				char *ptr = de->categories_shortcuts[i];

				if (ptr[0] == 'X') {
					if (ptr[1] != '-')
						continue;
					ptr += 2;
				}
				if (mystrncasecmp (ptr, "KDE", 3) == 0)
					set_flags (kind, ASDE_KDE);
				else if (mystrncasecmp (ptr, "GNOME", 5) == 0)
					set_flags (kind, ASDE_GNOME);
			}
			set_flags (de->flags, kind);
		}
	}
	if (get_flags (de->flags, ASDE_KDE | ASDE_GNOME) == 0 && de->Name) {
		if (de->Name[0] == 'G')
			set_flags (de->flags, ASDE_GNOME);
		else if (de->Name[0] == 'K')
			set_flags (de->flags, ASDE_KDE);
	}
	if (de->Aliases != NULL) {
		de->aliases_len = strlen (de->Aliases);
		de->aliases_shortcuts =
				compound_string2string_list (de->Aliases, ';', False,
																		 &(de->aliases_num));
	}

	if (de->OnlyShowIn != NULL) {
		de->show_in_len = strlen (de->OnlyShowIn);
		de->show_in_shortcuts =
				compound_string2string_list (de->OnlyShowIn, ';', False,
																		 &(de->show_in_num));
	}
	if (de->NotShowIn != NULL) {
		de->not_show_in_len = strlen (de->NotShowIn);
		de->not_show_in_shortcuts =
				compound_string2string_list (de->NotShowIn, ';', False,
																		 &(de->not_show_in_num));
	}
	if (de->Exec)
		de->clean_exec = filter_desktop_entry_exec (de->Exec);

	de->origin = mystrdup (origin);

	if (get_flags (de->flags, ASDE_CheckAvailability)) {
		if (!is_executable_in_path (de->clean_exec))
			set_flags (de->flags, ASDE_Unavailable);
		LOCAL_DEBUG_OUT
				("checking availability(clean_exec) for \"%s\" - %s available",
				 de->clean_exec,
				 (get_flags (de->flags, ASDE_Unavailable) ? "not" : ""));
	} else if (de->TryExec != NULL) {
		if (!is_executable_in_path (de->TryExec))
			set_flags (de->flags, ASDE_Unavailable);
		LOCAL_DEBUG_OUT
				("checking availability(TryExec) for \"%s\" - %s available",
				 de->clean_exec,
				 (get_flags (de->flags, ASDE_Unavailable) ? "not" : ""));
	}

}

static ASDesktopEntry *parse_desktop_entry (const char *fullfilename,
																						const char *default_category,
																						ASDesktopEntryTypes
																						default_type,
																						const char *icon_path,
																						Bool applnk)
{
	ASDesktopEntry *de = NULL;
	FILE *fp = NULL;

	if (fullfilename)
		fp = fopen (fullfilename, "r");

	if (fp) {
		static char rb[MAXLINELENGTH + 1];

		de = create_desktop_entry (default_type);
		while (fgets (&(rb[0]), MAXLINELENGTH, fp) != NULL)
			parse_desktop_entry_line (de, &(rb[0]));
		fix_desktop_entry (de, default_category, icon_path, fullfilename,
											 applnk);
		fclose (fp);
	}
	return de;
}

int
parse_desktop_entry_list (const char *fullfilename,
													ASBiDirList * entry_list,
													const char *default_category,
													ASDesktopEntryTypes default_type,
													const char *icon_path, Bool applnk)
{
	ASDesktopEntry *de = NULL;
	int count = 0;
	FILE *fp = NULL;

	/*LOCAL_DEBUG_OUT( "PARSING \"%s\"", fullfilename );    */
	if (fullfilename)
		fp = fopen (fullfilename, "r");

	if (fp) {
		static char rb[MAXLINELENGTH + 1];

#define FIX_DE do {if (de) {fix_desktop_entry (de, default_category, icon_path, fullfilename, applnk); \
										append_bidirelem (entry_list, de); de = NULL;} } while(0)

		while (fgets (&(rb[0]), MAXLINELENGTH, fp) != NULL) {
			/*LOCAL_DEBUG_OUT( "rb = \"%s\", de = %p", &(rb[0]), de ); */
			if (rb[0] == '[') {
				if ((rb[1] == 'D'
						 && (mystrncasecmp (&(rb[2]), "esktop Entry]", 13) == 0
								 || mystrncasecmp (&(rb[2]), "esktopEntry]", 12) == 0))
						|| (rb[1] == 'K'
								&& mystrncasecmp (&(rb[2]), "DE Desktop Entry]",
																	17) == 0)) {
					FIX_DE;
					de = create_desktop_entry (default_type);
					++count;
				} else
					FIX_DE;
			} else if (de)
				parse_desktop_entry_line (de, &(rb[0]));
		}
		FIX_DE;
		fclose (fp);
	}
	return count;
}



static void
parse_desktop_entry_tree (char *fullpath, const char *dirname,
													ASBiDirList * entry_list,
													ASDesktopEntry * parent, const char *icon_path,
													const char *default_app_category, Bool applnk)
{
	struct direntry **list = NULL;
	int list_len, i, curr_dir_index = -1;
	char *dir_category = NULL;
	ASDesktopEntry *tmp, *curr_dir = NULL;


	list_len = my_scandir (fullpath, &list, no_dots_except_directory, NULL);

	fprintf (stderr, "number of items in %s = %d\n", fullpath, list_len);
	for (i = 0; i < list_len; i++) {
		if (!S_ISDIR (list[i]->d_mode) && list[i]->d_name[0] == '.') {
			if (strcasecmp (list[i]->d_name, ".directory") == 0) {
				curr_dir_index = i;
				tmp =
						parse_desktop_entry (fullpath, parent ? parent->Name : NULL,
																 ASDE_TypeDirectory, icon_path, applnk);
				if (tmp) {
					if (tmp->Name == NULL)
						tmp->Name = mystrdup (dirname);
					if (mystrcasecmp (tmp->Name, DEFAULT_DESKTOP_CATEGORY_NAME) != 0)
						dir_category = mystrdup (tmp->Name);
					curr_dir = tmp;
					append_bidirelem (entry_list, tmp);
				}
				break;
			}
		}
	}
	if (curr_dir == NULL) {
		curr_dir =
				parse_desktop_entry (fullpath, parent ? parent->Name : NULL,
														 ASDE_TypeDirectory, icon_path, applnk);
		if (curr_dir) {
			if (curr_dir->Name == NULL) {
				curr_dir->Name = mystrdup (dirname);
				append_bidirelem (entry_list, curr_dir);
			}
		}
	}
	for (i = 0; i < list_len; i++) {
		if (list[i]->d_name[0] != '.') {
			char *entry_fullpath = make_file_name (fullpath, list[i]->d_name);

			if (S_ISDIR (list[i]->d_mode)) {
/*fprintf(stderr, "Parsing subtree %s.\n", entry_fullpath);*/
				parse_desktop_entry_tree (entry_fullpath, list[i]->d_name,
																	entry_list, curr_dir, icon_path,
																	default_app_category, applnk);
			} else if (i != curr_dir_index) {
/*fprintf(stderr, "Parsing subitem %s.\n", entry_fullpath);*/
				parse_desktop_entry_list (entry_fullpath, entry_list,
																	dir_category ? dir_category :
																	default_app_category,
																	ASDE_TypeApplication, icon_path, applnk);
			}
			free (entry_fullpath);
		}
		free (list[i]);
	}

	if (list)
		free (list);

	if (dir_category)
		free (dir_category);
}

static void desktop_entry_destroy_list_item (void *data)
{
	unref_desktop_entry ((ASDesktopEntry *) data);
}

static Bool register_desktop_entry_list_item (void *data, void *aux_data)
{
	register_desktop_entry ((ASCategoryTree *) aux_data,
													(ASDesktopEntry *) data);
	return True;
}

/*************************************************************************/
/* public methods : 													 */
/*************************************************************************/

int compareDesktopEntry (void *data1, void *data2) {
	ASDesktopEntry *de1 = (ASDesktopEntry*)data1;
	ASDesktopEntry *de2 = (ASDesktopEntry*)data2;
	return (de1->type == ASDE_TypeApplication &&
	        de2->type == ASDE_TypeApplication)? mystrcasecmp(de1->Name, de2->Name) : 1;
}

Bool load_category_tree (ASCategoryTree * ct)
{
	if (ct && ct->dir_list) {
		int i;
		ASBiDirList *entry_list =
				create_asbidirlist (desktop_entry_destroy_list_item);

		for (i = 0; i < ct->dir_num; ++i) {
			Bool applnk = (strstr (ct->dir_list[i], "/applnk") != NULL);

			if (CheckDir (ct->dir_list[i]) == 0) {
/*				fprintf( stderr, "location : \"%s\", applnk == %d\n", ct->dir_list[i], applnk );
*/
				parse_desktop_entry_tree (ct->dir_list[i], NULL, entry_list, NULL,
																	ct->icon_path, ct->name, applnk);
			} else if (CheckFile (ct->dir_list[i]) == 0)
				parse_desktop_entry_list (ct->dir_list[i], entry_list, ct->name,
																	ASDE_TypeDirectory, ct->icon_path,
																	applnk);
		}
		LOCAL_DEBUG_OUT ("Done parsing for tree %s, total entris %d", ct->name, entry_list->count);
		dedup_asbidirlist(entry_list, compareDesktopEntry);
		LOCAL_DEBUG_OUT ("Done deduping for tree %s, total entris %d", ct->name, entry_list->count);
		iterate_asbidirlist (entry_list, register_desktop_entry_list_item, ct,
												 NULL, False);
		destroy_asbidirlist (&entry_list);
/*		flush_asbidirlist_memory_pool(); */
/*		print_unfreed_mem (); */
		return True;
	}
	return False;
}

void DestroyCategories ()
{
	if (StandardCategories)
		destroy_category_tree (&StandardCategories);
	if (AfterStepCategories)
		destroy_category_tree (&AfterStepCategories);
	if (KDECategories)
		destroy_category_tree (&KDECategories);
	if (GNOMECategories)
		destroy_category_tree (&GNOMECategories);
	if (OtherCategories)
		destroy_category_tree (&OtherCategories);
	if (CombinedCategories)
		destroy_category_tree (&CombinedCategories);
#ifdef DEBUG_ALLOCS
/*	print_unfreed_mem (); */
#endif													/* DEBUG_ALLOCS */
}

void save_category_tree_cache (ASCategoryTree * ct, const char *fname)
{
	char *configfile;
	FILE *fp;

	configfile = make_session_data_file (Session, False, 0, fname, NULL);
	if (configfile) {
		fp = fopen (configfile, "wb");
		if (fp) {
			save_category_tree (ct, fp);
			fclose (fp);
		}
		free (configfile);
	}
}

void UpdateCategoriesCache ()
{
	save_category_tree_cache (AfterStepCategories, AFTERSTEP_CACHE_FILE);
	save_category_tree_cache (KDECategories, KDE_CACHE_FILE);
	save_category_tree_cache (GNOMECategories, GNOME_CACHE_FILE);
	save_category_tree_cache (OtherCategories, OTHER_CACHE_FILE);
}

void ReloadCategories (Bool cached)
{
	char *configfile;

	START_TIME (started);

	DestroyCategories ();

	if ((configfile =
			 make_session_file (Session, STANDARD_CATEGORIES_FILE,
													False)) != NULL) {
		StandardCategories =
				create_category_tree ("Default", configfile,
															Environment ? Environment->
															pixmap_path : NULL, 0, -1);
		free (configfile);
	}

	if (cached) {
		char *configfile =
				make_session_data_file (Session, False, 0, AFTERSTEP_CACHE_FILE,
																NULL);

		AfterStepCategories =
				create_category_tree ("AfterStep", configfile,
															Environment ? Environment->
															pixmap_path : NULL, 0, -1);
		free (configfile);
		configfile =
				make_session_data_file (Session, False, 0, KDE_CACHE_FILE, NULL);
		KDECategories =
				create_category_tree ("KDE", configfile, KDE_ICONS_PATH, 0, -1);
		free (configfile);
		configfile =
				make_session_data_file (Session, False, 0, GNOME_CACHE_FILE, NULL);
		GNOMECategories =
				create_category_tree ("GNOME", configfile, GNOME_ICONS_PATH, 0,
															-1);
		free (configfile);
		configfile =
				make_session_data_file (Session, False, 0, OTHER_CACHE_FILE, NULL);
		OtherCategories =
				create_category_tree ("OTHER", configfile, OTHER_ICONS_PATH, 0,
															-1);
		free (configfile);
	} else {
		char *path = make_session_apps_path (Session);

		if (path) {
			AfterStepCategories =
					create_category_tree ("AfterStep", path,
																Environment ? Environment->
																pixmap_path : NULL, 0, -1);
			free (path);
		}

		KDECategories =
				create_category_tree ("KDE", KDE_APPS_PATH, KDE_ICONS_PATH,
															ASCT_OnlyKDE, -1);
		GNOMECategories =
				create_category_tree ("GNOME", GNOME_APPS_PATH, GNOME_ICONS_PATH,
															ASCT_OnlyGNOME, -1);
		OtherCategories =
				create_category_tree ("OTHER", OTHER_APPS_PATH, OTHER_ICONS_PATH,
															ASCT_ExcludeGNOME | ASCT_ExcludeKDE, -1);

	}

	CombinedCategories = create_category_tree ("", NULL, NULL, 0, -1);

	load_category_tree (StandardCategories);
	SHOW_TIME ("Standard categories", started);
	if (!cached) {
		add_category_tree_subtree (AfterStepCategories, StandardCategories);
		add_category_tree_subtree (KDECategories, StandardCategories);
		add_category_tree_subtree (GNOMECategories, StandardCategories);
		add_category_tree_subtree (OtherCategories, StandardCategories);
	}
	load_category_tree (AfterStepCategories);
	SHOW_TIME ("AfterStep categories", started);
	load_category_tree (KDECategories);
	SHOW_TIME ("KDE categories", started);
	load_category_tree (GNOMECategories);
	SHOW_TIME ("GNOME categories", started);
	load_category_tree (OtherCategories);
	SHOW_TIME ("Other categories", started);

	LOCAL_DEBUG_OUT
			("@ Building up Combined: @@@@@@@@@@@@@@@@@@@@@@@@@@@@%s", "");

	add_category_tree_subtree (CombinedCategories, StandardCategories);
	add_category_tree_subtree (CombinedCategories, AfterStepCategories);
	add_category_tree_subtree (CombinedCategories, KDECategories);
	add_category_tree_subtree (CombinedCategories, GNOMECategories);
	add_category_tree_subtree (CombinedCategories, OtherCategories);

	SHOW_TIME (__FUNCTION__, started);
}


#ifdef PRINT_DESKTOP_ENTRIES
int main (int argc, char **argv)
{
	int i;
	ASDesktopCategory *dc = NULL;
	ASCategoryTree *ct = NULL;
	Bool cached = False;

	InitMyApp ("PrintDesktopEntries", argc, argv, NULL, NULL, 0);
	InitSession ();
	for (i = 1; i < argc; ++i)
		if (argv[i] && strcmp (argv[i], "--cached") == 0)
			cached = True;

	ReloadCategories (cached);

	for (i = 1; i < argc; ++i)
		if (argv[i] && strcmp (argv[i], "--cached") != 0) {
			char *name = NULL;
			char *colon = strchr (argv[i], ':');
			int len = strlen (argv[i]);

			if (colon == NULL) {
				name = safemalloc (len + 1 + 7 + 1);
				sprintf (name, "%s:Default", argv[i]);
			} else if (colon[1] == '\0') {
				name = safemalloc (len + 7 + 1);
				sprintf (name, "%sDefault", argv[i]);
			} else
				name = mystrdup (argv[i]);

			dc = name2desktop_category (name, &ct);
			if (dc == NULL) {
				fprintf (stderr, "Invalid category name \"%s\"", argv[i]);
				return 0;
			}
			free (name);
			break;
		}
	if (dc && ct) {
		print_category_tree2 (ct, dc);

	} else {
		fprintf (stderr,
						 "#Standard: ####################################################\n");
		print_category_tree2 (StandardCategories, NULL);
		fprintf (stderr,
						 "#AfterStep:####################################################\n");
		print_category_tree2 (AfterStepCategories, NULL);
		fprintf (stderr,
						 "#KDE:      ####################################################\n");
		print_category_tree2 (KDECategories, NULL);
		fprintf (stderr,
						 "#GNOME:    ####################################################\n");
		print_category_tree2 (GNOMECategories, NULL);
		fprintf (stderr,
						 "#OTHER:   ####################################################\n");
		print_category_tree2 (OtherCategories, NULL);
		fprintf (stderr,
						 "#Combined: ####################################################\n");
		print_category_tree2 (CombinedCategories, NULL);
		fprintf (stderr,
						 "#####################################################\n");
	}
	DestroyCategories ();
	FreeMyAppResources ();
	return 1;
}

#else
#ifdef TEST_AS_DESKTOP_ENTRY

#define REDHAT_APPLNK	"/etc/X11/applnk"
#define DEBIAN_APPLNK	"/usr/share/applications"

/*
 * From e-mail :
 * The paths to the directories should be given by the DESKTOP_FILE_PATH
 * enviromental variable if other directories then /usr/share/applications/ are
 * needed.  This environment variable has the same format as the PATH
 * evironment variable, ':'separating entries.  If DESKTOP_FILE_PATH is present,
 * /usr/share/applications is not checked by default, and thus shoul dbe included
 * in the path.
 *
 * see: https://listman.redhat.com/archives/xdg-list/2002-July/msg00049.html
 * 		http://standards.freedesktop.org/menu-spec/menu-spec-0.9.html#paths
 * 		http://www.freedesktop.org/Standards/desktop-entry-spec
*/

int main (int argc, char **argv)
{


//  ASBiDirList *entry_list = create_asbidirlist( desktop_entry_destroy_list_item );

	InitMyApp ("TestASDesktopEntry", argc, argv, NULL, NULL, 0);
	InitSession ();
	ReloadCategories (False);
//  ReloadCategories();
//  ReloadCategories();

	fprintf (stderr,
					 "#Standard: ####################################################\n");
	print_category_tree2 (StandardCategories, NULL);
	fprintf (stderr,
					 "#AfterStep: ####################################################\n");
	print_category_tree2 (AfterStepCategories, NULL);
	fprintf (stderr,
					 "#KDE: ####################################################\n");
	print_category_tree2 (KDECategories, NULL);
	fprintf (stderr,
					 "#GNOME: ####################################################\n");
	print_category_tree2 (GNOMECategories, NULL);
	fprintf (stderr,
					 "#OTHER: ####################################################\n");
	print_category_tree2 (OtherCategories, NULL);
	fprintf (stderr,
					 "#Combined: ####################################################\n");
	print_category_tree2 (CombinedCategories, NULL);
	fprintf (stderr,
					 "#####################################################\n");

	DestroyCategories ();
	FreeMyAppResources ();
#ifdef DEBUG_ALLOCS
	print_unfreed_mem ();
#endif													/* DEBUG_ALLOCS */
	return 1;
}
#else
#ifdef MAKE_STANDARD_CATEGORIES
/* helper app to generate set of .desktop files for the list */
int main (int argc, char **argv)
{
	char *doc_str;
	xml_elem_t *doc;
	xml_elem_t *tr, *td;



	if (argc < 2) {
		show_error ("Usage: make_standard_categories <source_file_name>\n");
		exit (1);
	}

	doc_str = load_file (argv[1]);
	if (!doc_str) {
		show_error ("Unable to load file [%s]: %s.\n", argv[1],
								strerror (errno));
		exit (1);
	}

	doc = xml_parse_doc (doc_str, NULL);
	if (!doc) {
		show_error ("Unable to parse data: %s.\n", strerror (errno));
		exit (1);
	}

	for (tr = doc->child; tr; tr = tr->next) {
		if (strcmp (tr->tag, "tr") == 0) {
			char *name = NULL, *parent = NULL, *comment = NULL;

			td = tr->child;
			if (td && td->child && strcmp (td->child->tag, XML_CDATA_STR) == 0) {
				name = td->child->parm;
				td = td->next;
				if (td) {
					if (td->child && strcmp (td->child->tag, XML_CDATA_STR) == 0)
						comment = td->child->parm;
					td = td->next;
					if (td && td->child
							&& strcmp (td->child->tag, XML_CDATA_STR) == 0)
						parent = td->child->parm;
				}
			}
			if (name && strlen (name) < 200) {
				char filename[1024];
				FILE *fp;

				sprintf (filename, "categories/%s.desktop", name);
				fp = fopen (filename, "wt");
				if (fp) {
					fprintf (fp, "[DesktopEntry]\nName=%s\n", name);
					fprintf (fp, "X-AfterStep-IndexName=%s\n", name);
					fprintf (fp, "Categories=%s\n", parent ? parent : "");
					fprintf (fp, "Comment=%s\n", comment ? comment : "");
					fclose (fp);
				}
			}

		}
	}

	return 1;
}
#endif
#endif
#endif
