/*
 * Copyright (c) 2004 Jean-Yves Lefort
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. Neither the name of Jean-Yves Lefort nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include "config.h"
#include <stdio.h>
#include <string.h>
#include <Python.h>
#include <pygobject.h>
#include <glib/gi18n.h>
#include "streamtuner.h"
#include "pst.h"
#include "pst-helpers.h"

/*** variable declarations ***************************************************/

static PyObject *main_dict;

/*** function declarations ***************************************************/

static gboolean check_api_version (GError **err);

static void pst_main_init_pygobject (gboolean *status);

static void pst_main_load_all_scripts (void);
static void pst_main_load_scripts (const char *dirname);

static gboolean pst_main_load_script (const char *filename, GError **err);

/*** implementation **********************************************************/

static gboolean
check_api_version (GError **err)
{
  if (st_check_api_version(5, 8))
    return TRUE;
  else
    {
      g_set_error(err, 0, 0, _("API version mismatch"));
      return FALSE;
    }
}

G_MODULE_EXPORT gboolean
plugin_get_info (STPlugin *plugin, GError **err)
{
  GdkPixbuf *pixbuf;

  if (! check_api_version(err))
    return FALSE;

  st_plugin_set_name(plugin, "python");
  st_plugin_set_label(plugin, "Python");

  pixbuf = st_pixbuf_new_from_file(UIDIR "/python.png");
  if (pixbuf)
    {
      st_plugin_set_icon_from_pixbuf(plugin, pixbuf);
      g_object_unref(pixbuf);
    }

  return TRUE;
}

G_MODULE_EXPORT gboolean
plugin_init (GError **err)
{
  gboolean status = FALSE;
  PyObject *module;

  if (! check_api_version(err))
    return FALSE;
  
  /*
   * Workaround http://bugzilla.gnome.org/show_bug.cgi?id=160349:
   * always use the PyGILState API.
   */
  if (! g_setenv("PYGTK_USE_GIL_STATE_API", "yes", TRUE))
    {
      g_set_error(err, 0, 0, _("unable to set the PYGTK_USE_GIL_STATE_API environment variable: %s"), g_strerror(errno));
      return FALSE;
    }

  Py_Initialize();
  PyEval_InitThreads();

  module = PyImport_AddModule("__main__");
  if (! module)
    {
      pst_set_error(err);
      goto end;
    }
  main_dict = PyModule_GetDict(module);

  pst_main_init_pygobject(&status);
  if (! status)
    {
      pst_set_error(err);
      goto end;
    }

  if (! pst_init())
    {
      status = FALSE;
      pst_set_error(err);
      goto end;
    }

  pst_main_load_all_scripts();

 end:
  PyEval_ReleaseLock();
  return status;
}

static void
pst_main_init_pygobject (gboolean *status)
{
  g_return_if_fail(status != NULL);

  *status = FALSE;
  init_pygobject();
  if (pyg_enable_threads() == 0)
    *status = TRUE;
}

static void
pst_main_load_all_scripts (void)
{
  char *private_scriptsdir;

  if (g_file_test(SCRIPTS_DIR, G_FILE_TEST_IS_DIR))
    pst_main_load_scripts(SCRIPTS_DIR);

  private_scriptsdir = g_build_filename(st_settings_get_private_dir(), "python", "scripts", NULL);
  if (g_file_test(private_scriptsdir, G_FILE_TEST_IS_DIR))
    pst_main_load_scripts(private_scriptsdir);
  g_free(private_scriptsdir);
}

static void
pst_main_load_scripts (const char *dirname)
{
  GError *err = NULL;
  GDir *dir;
  const char *filename;

  g_return_if_fail(dirname != NULL);

  if (! (dir = g_dir_open(dirname, 0, &err)))
    {
      char *secondary;
      char *normalized;

      secondary = g_strdup_printf(_("Unable to scan Python scripts directory: %s"), err->message);
      g_error_free(err);

      normalized = st_dialog_normalize(secondary);
      g_free(secondary);

      st_error_dialog(_("A script error has occurred."), "%s", normalized);
      g_free(normalized);

      return;
    }

  while ((filename = g_dir_read_name(dir)))
    {
      char *pathname;
      char *extension;

      pathname = g_build_filename(dirname, filename, NULL);

      if (g_file_test(pathname, G_FILE_TEST_IS_REGULAR)
	  && (extension = strrchr(filename, '.'))
	  && (! strcmp(++extension, "py")))
	{
	  if (! pst_main_load_script(pathname, &err))
	    {
	      char *secondary;
	      char *normalized;

	      secondary = g_strdup_printf(_("Script %s could not be loaded: %s"), pathname, err->message);
	      g_clear_error(&err);

	      normalized = st_dialog_normalize(secondary);
	      g_free(secondary);

	      st_error_dialog(_("A script error has occurred."), "%s", normalized);
	      g_free(normalized);
	    }
	}
      
      g_free(pathname);
    }

  g_dir_close(dir);
}

static gboolean
pst_main_load_script (const char *filename, GError **err)
{
  FILE *file;
  PyObject *dict;
  PyObject *result;
  gboolean status;

  g_return_val_if_fail(filename != NULL, FALSE);

  if (! (file = fopen(filename, "r")))
    {
      g_set_error(err, 0, 0, _("unable to open script: %s"), g_strerror(errno));
      return FALSE;
    }
  
  /*
   * We want a per-script namespace, so we do not share the main dict,
   * we use a copy.
   */

  dict = PyDict_Copy(main_dict);
  result = PyRun_File(file, filename, Py_file_input, dict, dict);
  Py_DECREF(dict);

  if (result)
    {
      Py_DECREF(result);
      status = TRUE;
    }
  else
    {
      pst_set_error(err);
      status = FALSE;
    }

  fclose(file);

  return status;
}
