/* The GIMP -- an image manipulation program
 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
 *
 * The GIMP Help Browser for Win32
 * 
 * Interface based on Help Browser:
 * Copyright (C) 1999 Sven Neumann <sven@gimp.org>
 *                    Michael Natterer <mitschel@cs.tu-berlin.de>
 *
 * Windows specific implementation:
 * Copyright (C) 1999 Hans Breuer <Hans@Breuer.Org>
 *
 * 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.
 */

#include "config.h"

#include <string.h> 
#include <stdio.h>
#include <stdlib.h>
#include <glib.h>
#include "libgimp/gimp.h"
#include "libgimp/stdplugins-intl.h"

#undef RGB
#include <windows.h>
#include <direct.h>
#include <io.h>

#if 0 /* debug spew ? */
#define D(op) op
#else
#define D(op)
#endif

/*  defines  */

#define GIMP_HELP_EXT_NAME      "extension_gimp_help_browser"
#define GIMP_HELP_TEMP_EXT_NAME "extension_gimp_help_browser_temp"

#define GIMP_HELP_PREFIX        "help"

/*  the three help notebook pages  */
/*
   Context \
   Index    >-> Implement as HTML Frame ?
   Help    /
 */

/* globals */
DWORD g_dwidInst = 0L; 
static gchar * current_locale = "C";
static gchar *gimp_help_root = NULL;

/*  GIMP plugin stuff  */
static void query (void);
static void run   (gchar      *name, 
                   gint        nparams,
		   GimpParam  *param,
		   gint       *nreturn_vals,
		   GimpParam **return_vals);

GimpPlugInInfo PLUG_IN_INFO =
{
	NULL,   /*  init_proc   */
	NULL,   /*  quit_proc   */
	query,  /*  query_proc  */
	run,    /*  run_proc    */
};

static gboolean temp_proc_installed = FALSE;

/*  forward declaration  */
HDDEDATA CALLBACK 
DdeCallBack (UINT type, 
             UINT fmt, 
             HCONV hconv, 
             HSZ hsz1, HSZ hsz2, 
             HDDEDATA hData, 
             DWORD dwData1, DWORD dwData2);

static gboolean
report_if_missing(gchar* path);

/* implementation */
gboolean
open_browser (gchar *help_path,
              gchar *locale,
              gchar *help_file)
{
  gchar  *root_dir;
  gchar  *sPage;

  HDDEDATA hRetVal;
  HCONV hConv = NULL;

  root_dir = g_strdup (gimp_help_root);

  if (_chdir (root_dir) == -1)
    {
      g_message (_("GIMP Help Browser Error.\n\n"
		   "Couldn't find my root html directory.\n"
		   "(%s)"), root_dir);
      return FALSE;
    }

  if (0L == g_dwidInst)
    {
      gimp_message("Dde Initialization Failed...");
      return FALSE;
    }

  /* 
   * Built the correct path
   */
  if (help_file)
    {
      sPage = g_strconcat (help_path, G_DIR_SEPARATOR_S,
                           locale, G_DIR_SEPARATOR_S,
				   help_file, NULL);
    }
  else
    {
      sPage = g_strconcat(root_dir, G_DIR_SEPARATOR_S,
                          "index.html", NULL);
    }

  if (!report_if_missing(sPage))
    {
      /* Connect to the (Netscape) server. */
      HSZ hszService;
      HSZ hszTopic;
      char sExecutable[_MAX_PATH*2];
      char sFile[_MAX_PATH*2];
      char *sServer = NULL;

      /* remove anchor from filename for FindExecutable */
      strcpy (sFile, sPage);
      if (strrchr (sFile, '#'))
        strrchr (sFile, '#')[0] = 0;

      if ((void*)32 < FindExecutable (sFile, "c:\\", sExecutable))
        D (g_print ("Found executable: %s\n", sExecutable));

      /* we need the 'server' name w/o extension and path */
      if (strrchr (sExecutable, '.')) /* remove extension */
        strrchr (sExecutable, '.')[0] = 0;
      if (strrchr (sExecutable, '\\')) /* without path */
        sServer = strrchr (sExecutable, '\\') + 1;
      else
        sServer = "IExplore"; /* most probable */
      D (g_print ("Server: %s\n", sServer));

      hszService = DdeCreateStringHandle(g_dwidInst, sServer, CP_WINANSI);
      hszTopic = DdeCreateStringHandle(g_dwidInst, "WWW_OpenURL", CP_WINANSI);
      hConv = DdeConnect(g_dwidInst, hszService, hszTopic, NULL);
      D (g_print ("Conv: 0x%X\n", hConv));
    }

  if (NULL == hConv)
    {
      /* try to execute filename */
      HINSTANCE hInst = NULL;
      hInst = ShellExecute (NULL, /* hWnd */
                            "open",
                            sPage,
                            NULL, /* no parameters */
                            gimp_directory (), /* needs a valid working dir */
                            0);   /* show command */

      if ((int)hInst > 32) // it works
        return TRUE;
      else
        {
          gimp_message("Unable to start/communicate with BROWSER ...");
          return FALSE;
        }
    }

  /* Convert the Item into string handle and pass it to server. */
  {
    HSZ hszItem;
    unsigned char *psWinId;
    gchar* sItem;

    /* Add quotes to the URL argument as it's of type 
     * qcs (quoted string)
     * "\"%s\",,0,0,,,NETREPORT", sPage); // 0 for New Window.
     *  0xFFFFFFFF for last active Window
     */
    /* w/o converting to url form Mozilla insists to open a new 
     * window. Netscape and IExplore behave with both forms ...
     */
    gchar *p = sPage;
    while (*p++)
      if (*p == '\\') *p = '/'; 
    
    sItem = g_strdup_printf("\"file:///%s\",,0xFFFFFFFF,0,,,NETREPORT", sPage);
		
    hszItem = DdeCreateStringHandle(g_dwidInst, sItem, CP_WINANSI);
    hRetVal = DdeClientTransaction (NULL, 0ul, hConv, hszItem, 
                                    CF_TEXT, XTYP_REQUEST, 1000L, NULL);

    psWinId = DdeAccessData(hRetVal,NULL);
    D (g_print("Window ID %s\n", psWinId));
#if 0
    /* Memory and handles leaked???
     * BUT doing The Right Thing (?) causes crashes ...  
     */

    DdeFreeStringHandle( g_dwidInst, hszItem );
    g_free(sItem);
    /* call DdeUnaccessData when finished */
    DdeUnaccessData( psWinId );
#endif
  }

  g_free(sPage);
  g_free(root_dir);

  return TRUE;
}

static gboolean
open_url (gchar *help_path,
          gchar *locale,
          gchar *help_file)
{
  /* Find the browser
   */

  g_dwidInst = 0UL; /* 0 or valid! */
  DdeInitialize(&g_dwidInst, DdeCallBack, 
                APPCLASS_STANDARD | APPCMD_CLIENTONLY, 0UL);

  if (!open_browser (help_path, locale, help_file))
    return FALSE;

  /* Uninitialize dde application. */
  if (g_dwidInst) 
    DdeUninitialize(g_dwidInst);
      
  return TRUE;
}

static gboolean
report_if_missing(gchar* path)
{
  if (-1 != _access(path, 4)) /* read permission ... */
    return FALSE;
  /* try to remove anchor */
  if (strrchr(path, '#'))
    {
      gchar* real_path = g_strdup(path);
      gboolean bFound = FALSE;
      g_strdelimit (real_path, "#",'\0');
      bFound = (-1 != _access(real_path, 4));

      g_free(real_path);
      if (bFound)
        return FALSE; /* file found ... */
    }
  /*
   * File doesn't exist, todo: built the error page
   */
  g_message ("Helpbrowser page missing: %s\n", path);
  return TRUE; /* was missing */
}

MAIN ()

static void
query ()
{
  static GimpParamDef args[] =
  {
    { GIMP_PDB_INT32,  "run_mode", "Interactive, non-interactive" },
    { GIMP_PDB_STRING, "help_path", "" },
    { GIMP_PDB_STRING, "locale"  , "Language to use" },
    { GIMP_PDB_STRING, "help_file", "Path of a local document to open. "
                                    "Can be relative to GIMP_HELP_PATH." }
  };
  static int nargs = sizeof (args) / sizeof (args[0]);
  static GimpParamDef *return_vals = NULL;
  static int nreturn_vals = 0;

  gimp_install_procedure (GIMP_HELP_EXT_NAME,
                          "Browse the GIMP help pages.",
                          "",
                          "Sven Neumann <sven@gimp.org>, "
                          "Michael Natterer <mitschel@cs.tu-berlin.de>, "
                          "Hans Breuer <Hans@Breuer.Org>",
                          "Sven Neumann & Michael Natterer & Hans Breuer",
                          "1999",
                          NULL,
                          "",
                          GIMP_EXTENSION,
                          nargs, nreturn_vals,
                          args, return_vals);
}

static void
run (gchar      *name,
     gint        nparams,
     GimpParam  *param,
     int        *nreturn_vals,
     GimpParam **return_vals)
{
  static GimpParam  values[1];
  GimpRunModeType   run_mode;
  GimpPDBStatusType status = GIMP_PDB_SUCCESS;
  gchar *env_root_dir   = NULL;
  gchar *help_path      = NULL;
  gchar *locale         = NULL;
  gchar *help_file      = NULL;

  run_mode = param[0].data.d_int32;

  values[0].type = GIMP_PDB_STATUS;
  values[0].data.d_status = status;

  *nreturn_vals = 1;
  *return_vals = values;

  if (strcmp (name, GIMP_HELP_EXT_NAME) == 0)
    {
      switch (run_mode)
        {
        case GIMP_RUN_INTERACTIVE:
        case GIMP_RUN_NONINTERACTIVE:
	case GIMP_RUN_WITH_LAST_VALS:
	  /*  set default values  */
	  env_root_dir = g_getenv ("GIMP_HELP_ROOT");

	  if (env_root_dir)
	    {
	      if (chdir (env_root_dir) == -1)
		{
		  g_message (_("GIMP Help Browser Error.\n\n"
			       "Couldn't find GIMP_HELP_ROOT html directory.\n"
			       "(%s)"), env_root_dir);

		  status = GIMP_PDB_EXECUTION_ERROR;
		  break;
		}

	      gimp_help_root = g_strdup (env_root_dir);
	    }
	  else
	    {
            gchar *gimp_root = g_strdup (gimp_data_directory());
            /* /bin get's removed automatically, but we get plug-ins ... */
            if (strstr (gimp_root, G_DIR_SEPARATOR_S "plug-ins"))
              strstr (gimp_root, G_DIR_SEPARATOR_S "plug-ins")[0] = 0;
            if (strstr (gimp_root, G_DIR_SEPARATOR_S "PLUG-INS"))
              strstr (gimp_root, G_DIR_SEPARATOR_S "PLUG-INS")[0] = 0;
	      gimp_help_root = g_strconcat (gimp_root,
					    G_DIR_SEPARATOR_S, 
					    GIMP_HELP_PREFIX, NULL);
            g_free (gimp_root);

	    }

	  help_path = g_strdup (gimp_help_root);
	  locale    = g_strdup ("C");
	  help_file = g_strdup ("introduction.html");
	  
	  /*  Make sure all the arguments are there!  */
	  if (nparams == 4)
	    {
	      if (param[1].data.d_string && strlen (param[1].data.d_string))
		{
		  g_free (help_path);
		  help_path = g_strdup (param[1].data.d_string);
		  g_strdelimit (help_path, "/", G_DIR_SEPARATOR);
		}
	      if (param[2].data.d_string && strlen (param[2].data.d_string))
		{
		  g_free (locale);
		  locale = g_strdup (param[2].data.d_string);
		}
	      if (param[3].data.d_string && strlen (param[3].data.d_string))
		{
		  g_free (help_file);
		  help_file = g_strdup (param[3].data.d_string);
		  g_strdelimit (help_file, "/", G_DIR_SEPARATOR);
		}
	    }
          break;

        default:
	  status = GIMP_PDB_CALLING_ERROR;
          break;
        }

      if (status == GIMP_PDB_SUCCESS)
        {
       	  if (!open_url (help_path, locale, help_file))
            values[0].data.d_status = GIMP_PDB_EXECUTION_ERROR;
	  else
	    values[0].data.d_status = GIMP_PDB_SUCCESS;

	  g_free (help_path);
	  g_free (locale);
	  g_free (help_file);
        }
      else
        values[0].data.d_status = status;
    }
  else
    values[0].data.d_status = GIMP_PDB_CALLING_ERROR;
}

/*
 * Dde call back function.
 */
HDDEDATA CALLBACK 
DdeCallBack (UINT type, 
             UINT fmt,
             HCONV hconv, 
             HSZ hsz1, HSZ hsz2, 
             HDDEDATA hData, 
             DWORD dwData1, DWORD dwData2)	
{
  /* Being a simple client application not taking care of 
   * any transaction. simply return NULL
   */
  return (HDDEDATA) NULL;
}
