/* Bluefish HTML Editor
 * project.c - project functionality
 *
 * Copyright (C) 2003-2026 Olivier Sessink
 * Copyright (C) 2011 James Hayward
 *
 * 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/>.
 */

/*#define DEBUG*/

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

#include "bluefish.h"

#ifdef MAC_INTEGRATION
/*#include <ige-mac-integration.h>*/
#include <gtkosxapplication.h>
#endif

#include "bf_lib.h"
#include "bftextview2_spell.h"
#include "bfwin.h"
#include "bfwin_uimanager.h"
#include "bookmark.h"
#include "dialog_utils.h"
#include "document.h"
#include "filebrowser2.h"
#include "file_dialogs.h"
#include "gtk_easy.h"
#include "plugins.h"
#include "preferences.h"
#include "project.h"
#include "rcfile.h"
#include "stringlist.h"


static void
free_session(Tsessionvars * session)
{
	/* call free_session for any of the plugins that have free_session defined */
	bfplugins_session_cleanup(session);
	free_stringlist(session->classlist);
	free_stringlist(session->colorlist);
	free_stringlist(session->targetlist);
	free_stringlist(session->urllist);
	free_stringlist(session->fontlist);
	free_stringlist(session->positionlist);
	free_stringlist(session->searchlist);
	free_stringlist(session->replacelist);
	free_stringlist(session->filegloblist);
	free_arraylist(session->bmarks);
	free_stringlist(session->recent_files);
	free_stringlist(session->recent_dirs);
	g_free(session->snr3_filepattern);
	g_free(session->snr3_basedir);
	g_free(session->ssearch_text);
	g_free(session->opendir);
	g_free(session->savedir);
	g_free(session->encoding);
	g_free(session->last_filefilter);
	g_free(session->default_mime_type);
	g_free(session->template);
	g_free(session->webroot);
	g_free(session->documentroot);
	g_free(session->sync_local_uri);
	g_free(session->sync_remote_uri);
	g_free(session->convertcolumn_separator);
	g_free(session->convertcolumn_fillempty);
#ifdef HAVE_LIBENCHANT
	g_free(session->spell_lang);
#endif
	g_free(session);
}

static void
project_setup_initial_session(Tsessionvars * session, gboolean before_parse)
{
	if (!before_parse) {
		/* session parts that will be filled by rcfile_parse() will not be included
		   if before parse is TRUE (this is thus only used for new projects) */
		session->webroot = g_strdup(main_v->session->webroot);
		session->documentroot = g_strdup(main_v->session->documentroot);
		session->encoding = g_strdup(main_v->session->encoding);
		session->opendir = g_strdup(main_v->session->opendir);
		session->savedir = g_strdup(main_v->session->savedir);
		session->last_filefilter = g_strdup(main_v->session->last_filefilter);
		session->default_mime_type = g_strdup(main_v->session->default_mime_type);
		session->template = g_strdup(main_v->session->template);
		session->snr3_basedir = g_strdup(main_v->session->snr3_basedir);
		session->snr3_filepattern = g_strdup(main_v->session->snr3_filepattern);
#ifdef HAVE_LIBENCHANT
		session->spell_lang = g_strdup(main_v->session->spell_lang);
		session->spell_check_default = main_v->session->spell_check_default;
#endif
	}

	/* THE NUBER OF BYTES THAT IS COPIED HERE MUST BE EQUAL TO THE NUMBER OF INTEGERS
	   IN THE STRUCT IN bluefish.h ELSE ALL WILL FAIL */
	memcpy(session, main_v->session, 49 * sizeof(gint));
}

Tbfwin *
project_is_open(GFile * uri)
{
	GList *tmplist;
	tmplist = g_list_first(main_v->bfwinlist);
	while (tmplist) {
		if (BFWIN(tmplist->data)->project
			&& BFWIN(tmplist->data)->project->uri && g_file_equal(BFWIN(tmplist->data)->project->uri, uri)) {
			return BFWIN(tmplist->data);
		}
		tmplist = g_list_next(tmplist);
	}
	return NULL;
}
/*
static void
update_project_filelist(Tbfwin * bfwin, Tproject * prj)
{
	GList *tmplist;
	DEBUG_MSG("update_project_filelist, started, bfwin=%p, prj=%p\n", bfwin, prj);
	free_arraylist(prj->files);
	DEBUG_MSG("update_project_filelist, old list free'd, creating new list from documentlist %p (len=%d)\n",
			  bfwin->documentlist, g_list_length(bfwin->documentlist));
	tmplist = return_urilist_from_doclist(bfwin->documentlist);
	prj->files = urilist_to_stringlist(tmplist);
	free_urilist(tmplist);

}*/

static void
update_project_filearray_list(Tbfwin * bfwin, Tproject * prj)
{
	DEBUG_MSG("update_project_filearray_list, started, bfwin=%p, prj=%p\n", bfwin, prj);
	free_arraylist(prj->files);
	DEBUG_MSG("update_project_filearray_list, old list free'd, creating new list from documentlist %p (len=%d)\n",
			  bfwin->documentlist, g_list_length(bfwin->documentlist));
	prj->files = return_arraylist_from_doclist(bfwin->documentlist);
}

void
set_project_menu_actions(Tbfwin * bfwin, gboolean win_has_project)
{
	gtk_action_group_set_sensitive(bfwin->projectGroup, win_has_project);
}


static void
setup_bfwin_for_project(Tbfwin * bfwin, Tdocument *active_doc, Tuimode uimode)
{
	DEBUG_MSG("setup_bfwin_for_project, bfwin=%p, bfwin->project=%p, bfwin->session=%p\n, current_document=%p, active_doc=%p\n", bfwin,
			  bfwin->project, bfwin->session, bfwin->current_document, active_doc);
	if (active_doc && active_doc->uri) {
		bfwin->focus_next_new_doc = FALSE;
	} else {
		/* if there is no document, the project title will not be shown in the window title unless we call this directly */
		bfwin_set_title(bfwin, bfwin->current_document, 0);
	}
	bfwin->bmarkdata = bfwin->project->bmarkdata;
	bmark_set_store(bfwin);
	bmark_reload(bfwin);
#ifdef HAVE_LIBENCHANT
	reload_spell_dictionary(bfwin);
#endif
	set_project_menu_actions(bfwin, TRUE);
#ifdef MAC_INTEGRATION
/*	ige_mac_menu_sync(GTK_MENU_SHELL(BFWIN(doc->bfwin)->menubar));*/
	gtkosx_application_sync_menubar(g_object_new(GTKOSX_TYPE_APPLICATION, NULL));
#endif
}

static void
setup_bfwin_for_nonproject(Tbfwin * bfwin)
{
	DEBUG_MSG("setup_bfwin_for_nonproject, bfwin=%p\n", bfwin);
	bfwin->session = main_v->session;
	bfwin->bmarkdata = main_v->bmarkdata;
	bfwin->project = NULL;
	bmark_set_store(bfwin);
	/* normally there is always a current_document, but this function might be called in the transition
	   after all documents are just closed */
	if (bfwin->current_document)
		bfwin_set_title(bfwin, bfwin->current_document, 0);

	bfwin_apply_session(bfwin, bfwin->current_document, ui_undefined);
	set_project_menu_actions(bfwin, FALSE);
#ifdef MAC_INTEGRATION
/*	ige_mac_menu_sync(GTK_MENU_SHELL(BFWIN(bfwin)->menubar));*/
	gtkosx_application_sync_menubar(g_object_new(GTKOSX_TYPE_APPLICATION, NULL));
#endif
}

static void
project_destroy(Tproject * project)
{
	DEBUG_MSG("project_destroy, project=%p, project->session=%p\n", project, project->session);
	bookmark_data_cleanup(project->bmarkdata);
	if (project->files)
		free_arraylist(project->files);
	if (project->session)
		free_session(project->session);
	if (project->uri)
		g_object_unref(project->uri);
	if (project->name)
		g_free(project->name);
	g_free(project);
}

/*  create_new_project() creates a new project
if the current window has a single empty unnamed document it is re-used for this project
in other cases (bfwibn will be NULL) there will be a new window opened for this project after it is created

*** bfwin is allowed to be NULL for an empty project ***
 
*/
static Tproject *
create_new_project(Tbfwin * bfwin)
{
	Tproject *prj;
	prj = g_new0(Tproject, 1);
	DEBUG_MSG("create_new_project, project=%p, bfwin=%p\n", prj, bfwin);
	prj->name = g_strdup(_("New project"));
	prj->session = g_new0(Tsessionvars, 1);
	project_setup_initial_session(prj->session, FALSE);
	prj->bmarkdata = bookmark_data_new();
	/*Project MUST have recent_dirs*/
	if (bfwin && bfwin->current_document && bfwin->current_document->uri) {/* We have document with uri */
		GFile *dir_uri = g_file_get_parent(bfwin->current_document->uri);
		prj->session->recent_dirs = g_list_append(prj->session->recent_dirs, g_file_get_uri(dir_uri));
		g_object_unref(dir_uri);
	}

	if (prj->session->recent_dirs == NULL) { /* If still no recent_dirs, then set $HOME */
		GFile *uri = g_file_new_for_path(g_get_home_dir());
		prj->session->recent_dirs = g_list_append(prj->session->recent_dirs, g_file_get_uri(uri));
		g_object_unref(uri);
	}

	if (bfwin) {
		DEBUG_MSG("create_new_project, new project for bfwin %p\n", bfwin);
		update_project_filearray_list(bfwin, prj);
		if (prj->files) {
			GList *tmplist;
			tmplist = g_list_first(bfwin->documentlist);
			while (tmplist) {
				bmark_clean_for_doc(DOCUMENT(tmplist->data));
				tmplist = g_list_next(tmplist);
			}

			tmplist = g_list_first(bfwin->session->bmarks);
			while (tmplist) {
				gchar **entry = (gchar **) tmplist->data;
				if (g_strv_length(entry) > 2) {
					GList *tmplist2 = g_list_first(prj->files);
					while (tmplist2) {
						if (strcmp(tmplist2->data, entry[2]) == 0) {
							/* move it out of the default session into this session */
							bfwin->session->bmarks = g_list_remove_link(bfwin->session->bmarks, tmplist);
							prj->session->bmarks = g_list_concat(prj->session->bmarks, tmplist);
							/* no further filenames to check */
							tmplist2 = g_list_last(tmplist2);
						}
						tmplist2 = g_list_next(tmplist2);
					}
				}
				tmplist = g_list_next(tmplist);
			}
		}
		bfwin->project = prj;
		bfwin->session = prj->session;
		setup_bfwin_for_project(bfwin, NULL, ui_undefined);
	}
	return prj;
}

static void
set_last_project_dir_from_file_uri(GFile *file)
{
	GFile *dir = g_file_get_parent(file);
	if (dir) {
		g_free(main_v->globses.last_project_dir);
		main_v->globses.last_project_dir = g_file_get_uri(dir);
		g_object_unref(dir);
	}
}


gboolean
project_save(Tbfwin * bfwin, gboolean save_as)
{
	gboolean retval;
	DEBUG_MSG("project_save, bfwin=%p, save_as=%d\n", bfwin, save_as);
	if (!bfwin->project) {
		/* there is no project yet, we have to create one */
		DEBUG_MSG("project_save, bfwin=%p does not have a project yet, create one\n", bfwin);
		bfwin->project = create_new_project(bfwin);
		bmark_reload(bfwin);
	}
	DEBUG_MSG("project_save, project=%p, num files was %d\n", bfwin->project,
			  g_list_length(bfwin->project->files));
	/*update_project_filelist(bfwin, bfwin->project); */
	update_project_filearray_list(bfwin, bfwin->project);

	/*bfwin->project->session->searchlist = limit_stringlist(bfwin->project->session->searchlist, 10, TRUE);
	bfwin->project->session->replacelist = limit_stringlist(bfwin->project->session->replacelist, 10, TRUE);
	bfwin->project->session->urllist = limit_stringlist(bfwin->project->session->urllist, 10, TRUE);*/
	bmark_store_all(bfwin);

	if (save_as || bfwin->project->uri == NULL) {
		gint suflen, filen;
		GtkWidget *dialog;
		GFile *newuri = NULL;
		dialog =
			file_chooser_dialog(bfwin, _("Enter Bluefish project filename"), GTK_FILE_CHOOSER_ACTION_SAVE,
								bfwin->project->name, TRUE, FALSE, "bfproject", FALSE);
		if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
			gchar *filename;
			newuri = gtk_file_chooser_get_file(GTK_FILE_CHOOSER(dialog));
			set_last_project_dir_from_file_uri(newuri);
			filename = g_file_get_parse_name(newuri);
			suflen = strlen(main_v->props.project_suffix);
			filen = strlen(filename);
			if (filen < suflen || strcmp(&filename[filen - suflen], main_v->props.project_suffix) != 0) {
				GFile *tmp2;
				gchar *tmp = g_strconcat(filename, main_v->props.project_suffix, NULL);
				tmp2 = g_file_parse_name(tmp);
				g_free(tmp);
				g_object_unref(newuri);
				newuri = tmp2;
			}
			g_free(filename);
		}
		gtk_widget_destroy(dialog);
		if (!newuri) {
			return FALSE;
		}
		if (save_as || bfwin->project->uri == NULL) {
			gboolean exists;
			exists = g_file_query_exists(newuri, NULL);
			if (exists) {
				gchar *tmpstr, *filename;
				gint retval;
				const gchar *buttons[] = { _("_Cancel"), _("_Overwrite"), NULL };
				filename = g_file_get_parse_name(newuri);
				tmpstr = g_strdup_printf(_("A file named \"%s\" already exists."), filename);
				retval = message_dialog_new_multi(bfwin->main_window,
												  GTK_MESSAGE_WARNING,
												  buttons,
												  tmpstr, _("Do you want to replace the existing file?"));
				g_free(tmpstr);
				g_free(filename);
				if (retval == 0) {
					g_object_unref(newuri);
					return FALSE;
				}
			}
		}
		bfwin->project->uri = newuri;
	}

	retval = rcfile_save_project(bfwin->project, bfwin->project->uri);
	DEBUG_MSG("project_save, retval=%d\n", retval);
	return retval;
}

/* Returns 0 on fail and 1 on success */
gint
project_open_from_file(Tbfwin * bfwin, GFile * fromuri)
{
	Tbfwin *prwin;
	Tproject *prj;
	gboolean retval;
	GList *tmplist;
	gchar *curi;

	/* first we test if the project is already open */
	prwin = project_is_open(fromuri);
	if (prwin != NULL) {
		DEBUG_MSG("project_open_from_file, project is open in bfwin=%p\n", prwin);
		gtk_window_present(GTK_WINDOW(prwin->main_window));
		return 1;
	}

	prj = g_new0(Tproject, 1);
	prj->session = g_new0(Tsessionvars, 1);
	DEBUG_MSG("project_open_from_file, project=%p, session=%p\n", prj, prj->session);
	project_setup_initial_session(prj->session, TRUE);
	prj->bmarkdata = bookmark_data_new();
	retval = rcfile_parse_project(prj, fromuri);
	if (!retval) {
		DEBUG_MSG("project_open_from_file, failed parsing the project\n");
		project_destroy(prj);
		/* TODO: use project_destroy()
		   bookmark_data_cleanup(prj->bmarkdata);
		   g_free(prj->session);
		   g_free(prj); */
		return 0;
	}
	curi = g_file_get_uri(fromuri);
	main_v->globses.recent_projects =
				add_to_history_stringlist(main_v->globses.recent_projects, curi, TRUE);
	if (main_v->props.recent_means_recently_closed) {
		bfwin_recent_menu_remove(bfwin, TRUE, curi, fromuri);
	} else {
		bfwin_recent_menu_add(bfwin,TRUE, curi, fromuri);
	}
	if (main_v->props.register_recent_mode != 0) {
		gtk_recent_manager_add_item(main_v->recentm, curi);
	}
	g_free(curi);
	prj->uri = fromuri;
	g_object_ref(fromuri);
	if (bfwin->project == NULL && test_only_empty_doc_left(bfwin->documentlist)) {
		/* we will use this Bluefish window to open the project */
		prwin = bfwin;
		prwin->project = prj;
		prwin->session = prj->session;
		DEBUG_MSG("project_open_from_file, project %p will be in existing prwin=%p\n", prj, bfwin);
		/* destroy the current empty document, it should use settings from the new session */
		if (prwin->current_document)
			doc_destroy(prwin->current_document, TRUE);
		bfwin->current_document=NULL;
		bfwin->notebook_page=-1;
		bfwin->notebook2_page=-1;
	} else {
		/* we will open a new Bluefish window for this project */
		DEBUG_MSG("project_open_from_file, we need a new window\n");
		prwin = bfwin_window_new_with_project(prj, FALSE);
	}
	tmplist = g_list_first(prj->files);
	gint doc_index = 0;
	gint i =0;
	gint cursor_offset = -1;
	gint goto_offset = -1;
	gint is_active = 0;
	if (tmplist) {
		bfwin_notebook_block_signals(prwin); /* Block switch-page signal while we are creating doc backends */
		while (tmplist) {
			GFile *uri;
			gchar **tmparr = (gchar **) tmplist->data;
			uri = g_file_parse_name(tmparr[0]);
			/*if (strstr(tmparr[0], "://") == NULL) {
				uri = g_file_new_for_path(tmparr[0]);
			} else {
				uri = g_file_new_for_uri(tmparr[0]);
			}*/

			if (tmparr[1] && tmparr[1]!=NULL) {
				cursor_offset = atoi(tmparr[1]);
				if (tmparr[2] && tmparr[2]!=NULL) {
					goto_offset = atoi(tmparr[2]);
					if (tmparr[3] && tmparr[3]!=NULL) {
						is_active = atoi(tmparr[3]);
					}
				}
			}
			if (is_active) {
				doc_index = i;
				DEBUG_MSG("project_open, active_doc has index %d\n",i);
				doc_new_from_uri(prwin, uri, NULL, TRUE, TRUE, -1, goto_offset, cursor_offset, FALSE, TRUE);
			} else {
				doc_new_from_uri(prwin, uri, NULL, TRUE, TRUE, -1, goto_offset, cursor_offset, FALSE, FALSE);
			}
			g_object_unref(uri);
			tmplist = g_list_next(tmplist);
			i++;
		}
		/* Now switch to tab that holds last active document from previous session */
		bfwin_notebook_unblock_signals(prwin);  /* Unblock signals, doc will be activated in setup_bfwin_for_project*/
		bfwin_switch_to_document_by_index(prwin, doc_index);
		bfwin_notebook_changed(prwin, prwin->notebook, doc_index);
	} else {
		doc_new(prwin, FALSE);
	}
	Tdocument * active_doc = documentlist_return_document_from_index(prwin->documentlist, doc_index);
	DEBUG_MSG("project_open_from_file, new window with files ready at prwin=%p\n", prwin);
	setup_bfwin_for_project(prwin, active_doc, ui_undefined);
	bfwin_apply_session(bfwin, active_doc, ui_undefined);
	DEBUG_MSG("project_open_from_file, done\n");
	return 1;
}

static void
project_open_response_lcb(GtkDialog * dialog, gint response, Tbfwin * bfwin)
{
	if (response == GTK_RESPONSE_ACCEPT) {
		GFile *file;
		file = gtk_file_chooser_get_file(GTK_FILE_CHOOSER(dialog));
		project_open_from_file(bfwin, file);
		set_last_project_dir_from_file_uri(file);
		g_object_unref(file);
	}
	gtk_widget_destroy(GTK_WIDGET(dialog));
}

void
project_open(Tbfwin * bfwin)
{
	GtkWidget *dialog;
	dialog =
		file_chooser_dialog(bfwin, _("Select Bluefish project filename"), GTK_FILE_CHOOSER_ACTION_OPEN, NULL,
							TRUE, FALSE, "bfproject", FALSE);
	gtk_file_chooser_set_current_folder_uri(GTK_FILE_CHOOSER(dialog), main_v->globses.last_project_dir);
	
	g_signal_connect(dialog, "response", G_CALLBACK(project_open_response_lcb), bfwin);
	gtk_widget_show_all(dialog);
}

void
project_save_and_mark_closed(Tbfwin * bfwin)
{
	if (bfwin->project) {
		project_save(bfwin, FALSE);

		if (bfwin->project->uri && main_v->props.recent_means_recently_closed) { /* Add menu entry only if we use "recently_closed" logic otherwise it is already there*/
			gchar *curi = g_file_get_uri(bfwin->project->uri);
			bfwin_recent_menu_add(bfwin, TRUE, curi, bfwin->project->uri);
			g_free(curi);
		}

		bfwin->project->close = TRUE;
	}
}

gboolean
project_final_close(Tbfwin * bfwin, gboolean close_win)
{
	if (!bfwin->project)
		return TRUE;
	DEBUG_MSG("project_final_close, call project_destroy(%p)\n",bfwin->project);
	project_destroy(bfwin->project);
	/* we should only set the window for nonproject if the window will keep alive */
	if (!close_win) {
		DEBUG_MSG("project_final_close, call setup_bfwin_for_nonproject(%p)\n",bfwin);
		setup_bfwin_for_nonproject(bfwin);
	}
	return TRUE;
}

void
project_save_and_close(Tbfwin * bfwin)
{
	/* if there are multiple windows we can simply close the window, else we have to convert it to a non-project window */
	if (main_v->bfwinlist && main_v->bfwinlist->next) {
		bfwin_delete_event(NULL, NULL, bfwin);
	} else {
		project_save_and_mark_closed(bfwin);
		if (!bfwin->documentlist) {
			project_final_close(bfwin, FALSE);
		} else if (have_modified_documents(bfwin->documentlist)) {
			Tclose_mode retval = multiple_files_modified_dialog(bfwin);
			switch (retval) {
			case close_mode_cancel:
				return;
				break;
			case close_mode_per_file:
				if (choose_per_file(bfwin, FALSE))
					bfwin->project->close = TRUE;
				break;
			case close_mode_save_all:
			case close_mode_close_all:
				doc_close_multiple_backend(bfwin, FALSE, retval);
				break;
			}
		} else {
			doc_close_multiple_backend(bfwin, FALSE, close_mode_close_all);
		}
	}
}

typedef enum {
	name,
	projecteditor_entries_num
} Tprojecteditor_entries;

typedef struct {
	GtkWidget *win;
	Tbfwin *bfwin;
	Tproject *project;
	Tsessionprefs sprefs;
	Tdefault_ui du;
	GtkWidget *entries[projecteditor_entries_num];
	gboolean destroy_project_on_close;
} Tprojecteditor;

static void
project_edit_destroy_lcb(GtkWidget * widget, Tprojecteditor * pred)
{
	DEBUG_MSG("project_edit_destroy_lcb, called for pred=%p\n", pred);
/*	gtk_widget_destroy(pred->win);*/
	if (pred->destroy_project_on_close) {
		if (pred->bfwin) {
			setup_bfwin_for_nonproject(pred->bfwin);
		}
		project_destroy(pred->project);
		pred->project = NULL;
	}
	if (pred->project) {
		pred->project->editor = NULL;
	}
	g_free(pred);
}

static void
project_edit_cancel_clicked_lcb(GtkWidget * widget, Tprojecteditor * pred)
{
	gtk_widget_destroy(pred->win);
}

static void
project_edit_ok_clicked_lcb(GtkWidget * widget, Tprojecteditor * pred)
{
	Tproject *prj = pred->project;

	pred->destroy_project_on_close = FALSE;

	gtk_widget_hide(pred->win);
	DEBUG_MSG("project_edit_ok_clicked_lcb, Tproject at %p, bfwin at %p\n", prj, pred->bfwin);
	string_apply(&prj->name, pred->entries[name]);
	
	sessionprefs_apply(&pred->sprefs, pred->project->session);
	if (pred->bfwin == NULL) {
		pred->bfwin = bfwin_window_new_with_project(pred->project, TRUE);
		pred->bfwin->session = pred->project->session;
		setup_bfwin_for_project(pred->bfwin, NULL, pred->du.uimode);
	} else {
#ifdef MAC_INTEGRATION
	if (main_v->osx_status == 2){
		gtk_widget_show(pred->bfwin->main_window);
		bfwin_action_groups_set_sensitive(pred->bfwin, TRUE);
		main_v->osx_status = 0;
	}
#endif
		bfwin_set_title(pred->bfwin, pred->bfwin->current_document, 0);
	}
	bfwin_apply_session(pred->bfwin, pred->bfwin->current_document, pred->du.uimode);
	project_save(pred->bfwin, FALSE);
	gtk_widget_destroy(pred->win);
}

/*
if NULL is passed as bfwin, a new window will be created for this project once OK is clicked
*/
void
project_edit(Tbfwin * bfwin)
{
	GtkWidget *notebook, *vbox, *but, *hbox, *label, *table, *parent_window=NULL;
	gchar *wintitle = NULL;
	Tprojecteditor *pred;

	if (bfwin && bfwin->project && bfwin->project->editor) {
		gtk_window_present(GTK_WINDOW(((Tprojecteditor *) bfwin->project->editor)->win));
		return;
	}
	pred = g_new(Tprojecteditor, 1);
	if (!bfwin || !bfwin->project) {
		/* there is no project yet, we have to create one */
		DEBUG_MSG("project_edit, no project yet, create one\n");
		pred->project = create_new_project(bfwin);
		if (bfwin) {
			bfwin->project = pred->project;
			parent_window = bfwin->main_window;
		}
		/* id the user does not press OK, we destroy the project */
		pred->destroy_project_on_close = TRUE;
		wintitle = g_strdup(_("Create New Project"));
	} else {
		pred->destroy_project_on_close = FALSE;
		wintitle = g_strdup(_("Edit Project"));
		pred->project = bfwin->project;
		parent_window = bfwin->main_window;
	}
	DEBUG_MSG("project_edit, Tproject at %p\n", pred->project);
	pred->bfwin = bfwin;
	pred->project->editor = pred;
	pred->win =
		window_full2(wintitle, 0, 5, G_CALLBACK(project_edit_destroy_lcb), pred, TRUE,
					parent_window);
	vbox = gtk_vbox_new(FALSE, 0);
	gtk_container_add(GTK_CONTAINER(pred->win), vbox);

	if (wintitle) {
		g_free(wintitle);
	}

	label = gtk_label_new(NULL);
	gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, TRUE, 0);
	gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
	{
		gchar *message;
		gint numdocs = g_list_length(pred->project->files);
		message =
			g_strdup_printf(ngettext
							("This project contains %d file", "This project contains %d files",
							 numdocs), numdocs);
		gtk_label_set_markup(GTK_LABEL(label), message);
		g_free(message);
	}

	table = gtk_table_new(1, 2, FALSE);
	gtk_table_set_col_spacings(GTK_TABLE(table), 12);
	gtk_table_set_row_spacings(GTK_TABLE(table), 6);
	gtk_box_pack_start(GTK_BOX(vbox), table, FALSE, FALSE, 12);

	pred->entries[name] = dialog_entry_in_table(pred->project->name, table, 1, 2, 0, 1);
	gtk_widget_set_size_request(GTK_WIDGET(pred->entries[name]), 250, -1);
	dialog_mnemonic_label_in_table(_("Project _Name:"), pred->entries[name], table, 0, 1, 0, 1);
	
	sessionprefs(_("<b>Default settings for this project</b>"), &pred->sprefs, pred->project->session);
	if (pred->destroy_project_on_close) {
		notebook = gtk_notebook_new();
		gtk_box_pack_start(GTK_BOX(vbox), notebook, FALSE, FALSE, 6);

		default_ui_settings(_("<b>User interface for this project</b>"), &pred->du);
		gtk_notebook_append_page(GTK_NOTEBOOK(notebook),pred->du.grid, gtk_label_new(_("User interface layout")));
		gtk_container_set_border_width(GTK_CONTAINER(pred->du.grid), 10);	
		gtk_notebook_append_page(GTK_NOTEBOOK(notebook),pred->sprefs.frame, gtk_label_new(_("Initial document settings")));
	} else { 
		gtk_box_pack_start(GTK_BOX(vbox), pred->sprefs.frame, FALSE, FALSE, 6);
	}
	
#if GTK_CHECK_VERSION(3,0,0)
	hbox = gtk_button_box_new(GTK_ORIENTATION_HORIZONTAL);
#else
	hbox = gtk_hbutton_box_new();
#endif
	gtk_button_box_set_layout(GTK_BUTTON_BOX(hbox), GTK_BUTTONBOX_END);
	gtk_box_set_spacing(GTK_BOX(hbox), 6);
	gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
	but = bf_stock_cancel_button(G_CALLBACK(project_edit_cancel_clicked_lcb), pred);
	gtk_box_pack_start(GTK_BOX(hbox), but, FALSE, FALSE, 0);
	if (pred->destroy_project_on_close == TRUE) {
		but = dialog_button_new_with_image(_("Create _Project"), GTK_STOCK_NEW, G_CALLBACK(project_edit_ok_clicked_lcb), pred, TRUE, TRUE);
	} else {
		but = dialog_button_new_with_image(NULL, GTK_STOCK_OK, G_CALLBACK(project_edit_ok_clicked_lcb), pred, TRUE, FALSE);
	}
	gtk_box_pack_start(GTK_BOX(hbox), but, FALSE, FALSE, 0);
	gtk_widget_grab_default(but);
	gtk_window_set_default_size (GTK_WINDOW(pred->win),500,-1);
	gtk_widget_show_all(pred->win);
}

typedef struct {
	GtkWidget *win;
	GtkWidget *rad[2];
	Tbfwin *bfwin;
} Tpc;

static void
project_create_destroy_lcb(GtkWidget * widget, Tpc * pc)
{
	g_free(pc);
}

static void
project_create_cancel_clicked_lcb(GtkWidget * widget, Tpc * pc)
{
	gtk_widget_destroy(pc->win);
}

static void
project_create_ok_clicked_lcb(GtkWidget * widget, Tpc * pc)
{
	gtk_widget_hide(pc->win);
	if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(pc->rad[0]))) {
		project_edit(pc->bfwin);
	} else {
		project_edit(NULL);
	}
	gtk_widget_destroy(pc->win);
}


void
project_create_gui(Tbfwin * bfwin)
{
	GtkWidget *vbox, *hbox, *but;
	Tpc *pc;

	pc = g_new(Tpc, 1);
	pc->bfwin = bfwin;
	pc->win =
		window_full2(_("Create project"), GTK_WIN_POS_CENTER, 5, G_CALLBACK(project_create_destroy_lcb), pc,
					 TRUE, bfwin->main_window);
	vbox = gtk_vbox_new(FALSE, 0);
	gtk_container_add(GTK_CONTAINER(pc->win), vbox);
	pc->rad[0] =
		boxed_radiobut_with_value(_("Create project with currently opened documents"), TRUE, NULL, vbox);
	pc->rad[1] =
		boxed_radiobut_with_value(_("Create empty project"), FALSE, GTK_RADIO_BUTTON(pc->rad[0]), vbox);
#if GTK_CHECK_VERSION(3,0,0)
	hbox = gtk_button_box_new(GTK_ORIENTATION_HORIZONTAL);
#else
	hbox = gtk_hbutton_box_new();
#endif
	gtk_button_box_set_layout(GTK_BUTTON_BOX(hbox), GTK_BUTTONBOX_END);
	gtk_box_set_spacing(GTK_BOX(hbox), 6);
	gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, TRUE, 0);
	but = bf_stock_cancel_button(G_CALLBACK(project_create_cancel_clicked_lcb), pc);
	gtk_box_pack_start(GTK_BOX(hbox), but, FALSE, TRUE, 0);
	but = bf_stock_ok_button(G_CALLBACK(project_create_ok_clicked_lcb), pc);
	gtk_box_pack_start(GTK_BOX(hbox), but, FALSE, TRUE, 0);
	gtk_widget_show_all(pc->win);
}

void
project_new(Tbfwin * bfwin)
{
	if (bfwin->project)
		project_edit(NULL);
	else {
		if (test_only_empty_doc_left(bfwin->documentlist))
			project_edit(bfwin);
		else
			project_create_gui(bfwin);
	}
}
