/* Manage toolkits and their display.
 */

/*

	Copyright (C) 1991-2003 The National Gallery

	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.,
	51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

 */

/*

	These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk

 */

/*
#define DEBUG
 */

#include "nip4.h"

G_DEFINE_TYPE(Toolkit, toolkit, FILEMODEL_TYPE)

Tool *
toolkit_map(Toolkit *kit, tool_map_fn fn, void *a, void *b)
{
	return (Tool *) icontainer_map(ICONTAINER(kit),
		(icontainer_map_fn) fn, a, b);
}

static void
toolkit_changed(iObject *iobject)
{
	/* If we change, signal change on our parent too (toolkitgroup) ...
	 * things like Program and Toolkitbrowser which need to spot any
	 * change to any kit can connect to that, rather than having to
	 * connect to all kits independently.
	 */
	if (IS_ICONTAINER(iobject) && ICONTAINER(iobject)->parent)
		iobject_changed(IOBJECT(ICONTAINER(iobject)->parent));
}

static void
toolkit_info(iObject *iobject, VipsBuf *buf, int indent)
{
	Toolkit *kit = TOOLKIT(iobject);

	IOBJECT_CLASS(toolkit_parent_class)->info(iobject, buf, indent);

	vips_buf_space(buf, indent);
	vips_buf_appendf(buf, "group = \"%s\"\n", IOBJECT(kit->kitg)->name);
}

static View *
toolkit_view_new(Model *model, View *parent)
{
	return toolkitview_new();
}

static gboolean
toolkit_save_text(Model *model, iOpenFile *of)
{
	if (icontainer_map(ICONTAINER(model),
			(icontainer_map_fn) model_save_text, of, NULL))
		return FALSE;

	return TRUE;
}

/* Load from an iOpenFile.
 */
static gboolean
toolkit_load_text(Model *model, Model *parent, iOpenFile *of)
{
	Toolkit *kit = TOOLKIT(model);
	int pos = icontainer_pos_last(ICONTAINER(model)) + 1;
	gboolean res;

	/* Load up definitions.
	 */
	filemodel_set_filename(FILEMODEL(model), of->fname_real);
	attach_input_file(of);
	if (!(res = parse_toplevel(kit, pos)))
		/* The sub won't have filename or line number: zap them in.
		 */
		error_sub("%s:%d\n%s\n",
			FILEMODEL(kit)->filename, input_state.lineno, error_get_sub());

#ifdef DEBUG
	(void) dump_kit(kit);
#endif /*DEBUG*/

	return res;
}

void
toolkit_set_name(Toolkit *kit, const char *name)
{
	iobject_set(IOBJECT(kit), name, NULL);
	if (name[0] == '_')
		MODEL(kit)->display = FALSE;
	toolkitgroup_sort(kit->kitg);
}

static void
toolkit_link(Toolkit *kit, Toolkitgroup *kitg, const char *name)
{
	icontainer_child_add(ICONTAINER(kitg), ICONTAINER(kit), -1);
	kit->kitg = kitg;
	filemodel_register(FILEMODEL(kit));
	toolkit_set_name(kit, name);
}

static Filemodel *
toolkit_real_new_from_filename(Filemodel *filemodel,
	Model *parent, const char *filename)
{
	Toolkitgroup *kitg = TOOLKITGROUP(parent);

	Toolkit *kit;

#ifdef DEBUG
	printf("toolkit_new: %s\n", name);
#endif /*DEBUG*/

	/* New kit, destroying any old kit.
	 */
	char name[VIPS_PATH_MAX];
	name_from_filename(filename, name);
	kit = toolkit_new(kitg, name);

	// superclass loads into this filemodel
	return FILEMODEL_CLASS(toolkit_parent_class)->
		new_from_filename(FILEMODEL(kit), parent, filename);
}

GtkFileFilter *
toolkit_filter_new(Filemodel *filemodel)
{
	GtkFileFilter *filter = gtk_file_filter_new();

	gtk_file_filter_set_name(filter, "nip4 definitions");
	gtk_file_filter_add_pattern(filter, "*.def");

	return filter;
}

static void
toolkit_class_init(ToolkitClass *class)
{
	iObjectClass *iobject_class = (iObjectClass *) class;
	ModelClass *model_class = (ModelClass *) class;
	FilemodelClass *filemodel_class = (FilemodelClass *) class;

	/* Create signals.
	 */

	/* Init methods.
	 */
	iobject_class->info = toolkit_info;
	iobject_class->changed = toolkit_changed;
	iobject_class->user_name = _("toolkit");

	model_class->view_new = toolkit_view_new;
	model_class->save_text = toolkit_save_text;
	model_class->load_text = toolkit_load_text;

	filemodel_class->new_from_filename = toolkit_real_new_from_filename;
	filemodel_class->filter_new = toolkit_filter_new;
	filemodel_class->suffix = ".def";
}

static void
toolkit_init(Toolkit *kit)
{
	kit->kitg = NULL;
	kit->pseudo = FALSE;
}

/* Find a kit by kit name.
 */
Toolkit *
toolkit_find(Toolkitgroup *kitg, const char *name)
{
	return (Toolkit *) icontainer_map(ICONTAINER(kitg),
		(icontainer_map_fn) iobject_test_name, (char *) name, NULL);
}

Toolkit *
toolkit_new(Toolkitgroup *kitg, const char *name)
{
	Toolkit *kit;

#ifdef DEBUG
	printf("toolkit_new: %s\n", name);
#endif /*DEBUG*/

	/* Exists already?
	 */
	if ((kit = toolkit_find(kitg, name)))
		IDESTROY(kit);

	/* Make a new kit.
	 */
	kit = TOOLKIT(g_object_new(TOOLKIT_TYPE, NULL));
	toolkit_link(kit, kitg, name);

	return kit;
}

/* Load a file as a toolkit.
 */
Toolkit *
toolkit_new_from_file(Toolkitgroup *kitg, const char *filename)
{
	FilemodelClass *class = FILEMODEL_CLASS(g_type_class_peek(TOOLKIT_TYPE));

	return TOOLKIT(filemodel_new_from_filename(class, MODEL(kitg), filename));
}

/* Look up a toolkit, make an empty one if not there.
 */
Toolkit *
toolkit_by_name(Toolkitgroup *kitg, const char *name)
{
	Toolkit *kit;

	if (!(kit = toolkit_find(kitg, name))) {
		char filename[VIPS_PATH_MAX];

		g_snprintf(filename, VIPS_PATH_MAX,
			"$SAVEDIR" G_DIR_SEPARATOR_S "start" G_DIR_SEPARATOR_S
			"%s.def",
			name);

		kit = toolkit_new(kitg, name);
		filemodel_set_filename(FILEMODEL(kit), filename);
	}

	return kit;
}
