#include <sys/stat.h>
#include <gtk/gtk.h>

#include "../include/string.h"
#include "../include/disk.h"

#include "guiutils.h"
#include "cdialog.h"

#include "editor.h"
#include "viewer.h"
#include "viewerfio.h"

#include "manedit.h"
#include "maneditcb.h"
#include "maneditop.h"
#include "aboutdialog.h"
#include "config.h"


void MEditHelpManPageProceduresCB(GtkWidget *widget, gpointer data);
void MEditHelpManPageXMLRefCB(GtkWidget *widget, gpointer data);
void MEditHelpManualCB(GtkWidget *widget, gpointer data);

void MEditAboutDialogMapCB(GtkWidget *widget, gpointer data);
void MEditEditorNewCB(GtkWidget *widget, gpointer data);
void MEditViewerNewCB(GtkWidget *widget, gpointer data);


#define ATOI(s)		(((s) != NULL) ? atoi(s) : 0)
#define ATOL(s)		(((s) != NULL) ? atol(s) : 0)
#define ATOF(s)		(((s) != NULL) ? atof(s) : 0.0f)
#define STRDUP(s)	(((s) != NULL) ? g_strdup(s) : NULL)

#define MAX(a,b)	(((a) > (b)) ? (a) : (b))
#define MIN(a,b)	(((a) < (b)) ? (a) : (b))
#define CLIP(a,l,h)	(MIN(MAX((a),(l)),(h)))
#define STRLEN(s)	(((s) != NULL) ? strlen(s) : 0)
#define STRISEMPTY(s)	(((s) != NULL) ? (*(s) == '\0') : TRUE)


/* Creates a new viewer window or maps an existing initialized but
 * unmapped viewer on the core structure, uses variables core_ptr,
 * last_null_num, viewer_num, and viewer
 */
#define DO_NEW_VIEWER	{			\
 last_null_num = -1;				\
 for(viewer_num = 0; viewer_num < core_ptr->total_viewers; viewer_num++) \
 {						\
  viewer = core_ptr->viewer[viewer_num];	\
  if(viewer == NULL) {				\
   last_null_num = viewer_num;			\
   continue;					\
  }						\
  if(!GTK_WIDGET_MAPPED(viewer->toplevel))	\
   break;					\
 }						\
 if(viewer_num < core_ptr->total_viewers) {	\
  /* Found one that was initialized and unmapped */ \
  viewer = core_ptr->viewer[viewer_num];	\
  ViewerMap(viewer);				\
 } else {					\
  /* Need to create a new viewer */		\
  if(last_null_num > -1) {			\
   viewer_num = last_null_num;			\
  } else {					\
   viewer_num = core_ptr->total_viewers;	\
   core_ptr->total_viewers = viewer_num + 1;	\
   core_ptr->viewer = (viewer_struct **)g_realloc( \
    core_ptr->viewer,				\
    core_ptr->total_viewers * sizeof(viewer_struct *) \
   );						\
   if(core_ptr->viewer == NULL)	{		\
    core_ptr->total_viewers = 0;		\
    return;					\
   }						\
   core_ptr->viewer[viewer_num] = NULL;		\
  }						\
  /* Allocate and create a new viewer */	\
  viewer = ViewerNew(core_ptr, -1);		\
  core_ptr->viewer[viewer_num] = viewer;	\
  if(viewer != NULL)				\
   ViewerMap(viewer);				\
  else						\
   viewer_num = -1;				\
 }						\
}


/*
 *	Help man page creation procedures.
 */
void MEditHelpManPageProceduresCB(GtkWidget *widget, gpointer data)
{
	gint last_null_num, viewer_num;
	const gchar *s;
	gchar *help_path, *help_file;
	struct stat stat_buf;
	viewer_struct *viewer;
	medit_core_struct *core_ptr = (medit_core_struct *)data;
	if(core_ptr == NULL)
	    return;
		
	/* Get template path */
	s = PrefParmGetValueP(
	    core_ptr->pref, MEDIT_PREF_PARM_LOCATIONS_GLOBAL_DIR
	);
	if(s == NULL)
	    s = MEDIT_GLOBAL_DIR;
	if(s != NULL)
	{
	    s = PrefixPaths(s, MEDIT_HELP_DIR);
	    if(s == NULL)
		s = "/";
	    help_path = STRDUP(s);
	}
	else
	{
	    help_path = STRDUP("/");
	}

	/* Get help file path */
	s = PrefixPaths(  
	    help_path, MEDIT_MANPAGE_WRITING_FILE
	);
	if(s == NULL)
	    s = MEDIT_MANPAGE_WRITING_FILE;
	help_file = STRDUP(s);

	/* Check if help file exists */
	if(stat(help_file, &stat_buf))
	{
	    gchar *s = g_strdup_printf(
"Unable to find the Manual Page file\n\n    %s",
		help_file
	    );
	    CDialogSetTransientFor(NULL);
	    CDialogGetResponse(
"Help Failed",
		s,
"The specified Manual Page file could not be found\n\
please check the specified paths in the preferences\n\
(go to edit->preferences). Also make sure that the\n\
program is installed properly.",
		CDIALOG_ICON_ERROR,
		CDIALOG_BTNFLAG_OK | CDIALOG_BTNFLAG_HELP,
		CDIALOG_BTNFLAG_OK
	    );
	    CDialogSetTransientFor(NULL);
	    g_free(s);
	    g_free(help_path);
	    g_free(help_file);
	    return;
	}


	/* Create a new viewer */
	DO_NEW_VIEWER

	ViewerSetBusy(viewer);
	ViewerViewTextRecordScrollPositions(viewer);
	ViewerTextDelete(viewer, 0, -1);
	ViewerTextInsertPosition(viewer, 0);
	ViewerOpenFile(
	    viewer, help_file, MEDIT_MANPAGE_WRITING_FILE
	);
	ViewerSetReady(viewer);

	g_free(help_path);
	g_free(help_file);
}

/*
 *	Help man page XML references.
 */
void MEditHelpManPageXMLRefCB(GtkWidget *widget, gpointer data)
{
	const gchar *s;
	gint last_null_num, viewer_num;
	viewer_struct *viewer;
	gchar *help_path, *help_file;
	struct stat stat_buf;
	medit_core_struct *core_ptr = (medit_core_struct *)data;
	if(core_ptr == NULL)
	    return;

	/* Get template path */
	s = PrefParmGetValueP(
	    core_ptr->pref, MEDIT_PREF_PARM_LOCATIONS_GLOBAL_DIR
	);
	if(s == NULL)
	    s = MEDIT_GLOBAL_DIR;
	if(s != NULL)
	{
	    s = PrefixPaths(s, MEDIT_HELP_DIR);
	    if(s == NULL)
		s = "/";
	    help_path = STRDUP(s);
	}
	else
	{
	    help_path = STRDUP("/");
	}

	/* Get help file path */
	s = PrefixPaths(
	    help_path, MEDIT_MANPAGE_XML_REFERENCE_FILE
	);
	if(s == NULL)
	    s = MEDIT_MANPAGE_XML_REFERENCE_FILE;
	help_file = STRDUP(s);

	/* Check if help file exists */
	if(stat(help_file, &stat_buf))
	{
	    gchar *s = g_strdup_printf(
"Unable to find the Manual Page file\n\n    %s",
		help_file
	    );
	    CDialogSetTransientFor(NULL);
	    CDialogGetResponse(
"Help Failed",
		s,
"The specified Manual Page file could not be found\n\
please check the specified paths in the preferences\n\
(go to edit->preferences). Also make sure that the\n\
program is installed properly.",
		CDIALOG_ICON_ERROR,
		CDIALOG_BTNFLAG_OK | CDIALOG_BTNFLAG_HELP,
		CDIALOG_BTNFLAG_OK
	    );
	    CDialogSetTransientFor(NULL);
	    g_free(s);
	    g_free(help_path);
	    g_free(help_file);
	    return;
	}


	/* Create a new viewer */
	DO_NEW_VIEWER

	ViewerSetBusy(viewer);
	ViewerViewTextRecordScrollPositions(viewer);
	ViewerTextDelete(viewer, 0, -1);
	ViewerTextInsertPosition(viewer, 0);
	ViewerOpenFile(
	    viewer, help_file, MEDIT_MANPAGE_XML_REFERENCE_FILE
	);
	ViewerSetReady(viewer);

	g_free(help_path);
	g_free(help_file);
}

/*
 *	Help manual callback.
 */
void MEditHelpManualCB(GtkWidget *widget, gpointer data)
{
	gint last_null_num, viewer_num;
	viewer_struct *viewer;
	medit_core_struct *core_ptr = (medit_core_struct *)data;
	if(core_ptr == NULL)
	    return;

	/* Create a new viewer */
	DO_NEW_VIEWER

	ViewerSetBusy(viewer);
	ViewerViewTextRecordScrollPositions(viewer);
	ViewerTextDelete(viewer, 0, -1);
	ViewerTextInsertPosition(viewer, 0);
	ViewerOpenFile(viewer, "manedit", "manedit");
	ViewerSetReady(viewer);
}




#undef DO_NEW_VIEWER

/*
 *	Maps the program's about dialog.
 */
void MEditAboutDialogMapCB(GtkWidget *widget, gpointer data)
{
	about_dialog_struct *about;
	medit_core_struct *core_ptr = (medit_core_struct *)data;
	if(core_ptr == NULL)
	    return;

	/* Get pointer to about window structure and initialize as
	 * needed
	 */
	about = core_ptr->about;
	if(about == NULL)
	{
	    about = AboutDialogNew(core_ptr);
	    core_ptr->about = about;
	}
	if(about == NULL)
	    return;

	AboutDialogMap(about);
}

/*
 *	Creates a new editor or maps an existing initialized and
 *	unmapped editor if possible.
 */
void MEditEditorNewCB(GtkWidget *widget, gpointer data)
{
	gint i, last_null_num = -1;
	editor_struct *editor;
	medit_core_struct *core_ptr = (medit_core_struct *)data;
	if(core_ptr == NULL)
	    return;

	/* Search for existing initialized but unmapped editor on
	 * the core structure.
	 */
	for(i = 0; i < core_ptr->total_editors; i++)
	{
	    editor = core_ptr->editor[i];
	    if(editor == NULL)
	    {
		last_null_num = i;
		continue;
	    }

	    if(!GTK_WIDGET_MAPPED(editor->toplevel))
		break;
	}
	if(i < core_ptr->total_editors)
	{
	    /* Found one that was initialized and unmapped */
	    EditorMap(core_ptr->editor[i]);
	}
	else
	{
	    /* Need to create a new editor */
	    if(last_null_num > -1)
	    {
		i = last_null_num;
	    }
	    else
	    {
		i = core_ptr->total_editors;
		core_ptr->total_editors = i + 1;
		core_ptr->editor = (editor_struct **)g_realloc(
		    core_ptr->editor,
		    core_ptr->total_editors * sizeof(editor_struct *)
		);
		if(core_ptr->editor == NULL)
		{
		    core_ptr->total_editors = 0;
		    return;
		}
		core_ptr->editor[i] = NULL;
	    }

	    /* Allocate and create a new editor */
	    editor = EditorNew((void *)core_ptr);
	    core_ptr->editor[i] = editor;

	    if(editor != NULL)
	    {
		EditorMap(editor);
	    }
	}

	return;
}


/*
 *	Creates a new viewer or maps an existing initialized and
 *	unmapped viewer if possible.
 */
void MEditViewerNewCB(GtkWidget *widget, gpointer data)
{
	gint i, last_null_num = -1;
	viewer_struct *viewer;
	medit_core_struct *core_ptr = (medit_core_struct *)data;
	if(core_ptr == NULL)
	    return;

	/* Search for existing initialized but unmapped viewer on
	 * the core structure.
	 */
	for(i = 0; i < core_ptr->total_viewers; i++)
	{
	    viewer = core_ptr->viewer[i];
	    if(viewer == NULL)
	    {
		last_null_num = i;
		continue;
	    }
		
	    if(!GTK_WIDGET_MAPPED(viewer->toplevel))
		break;
	}
	if(i < core_ptr->total_viewers)
	{
	    /* Found one that was initialized and unmapped */
	    ViewerMap(core_ptr->viewer[i]);
	}
	else
	{
	    /* Need to create a new viewer */
	    if(last_null_num > -1)
	    {
		i = last_null_num;
	    }
	    else
	    {
		i = core_ptr->total_viewers;
		core_ptr->total_viewers = i + 1;
		core_ptr->viewer = (viewer_struct **)g_realloc(
		    core_ptr->viewer,
		    core_ptr->total_viewers * sizeof(viewer_struct *)
		);
		if(core_ptr->viewer == NULL)
		{
		    core_ptr->total_viewers = 0;
		    return;
		}
		core_ptr->viewer[i] = NULL;
	    }

	    /* Allocate and create a new viewer */
	    viewer = ViewerNew((void *)core_ptr, -1);
	    core_ptr->viewer[i] = viewer;

	    if(viewer != NULL)
	    {
		ViewerMap(viewer);
	    }
	}

	return;
}
