/*
 * Copyright (c) 2003, 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 <Python.h>
#define NO_IMPORT_PYGOBJECT
#include <pygobject.h>
#include <glib/gi18n.h>
#include "streamtuner.h"
#include "pst-category.h"
#include "pst-handler-config.h"
#include "pst-handler-field.h"
#include "pst-handler.h"
#include "pst-helpers.h"
#include "pst-stream.h"
#include "pst-transfer-session.h"

#define PST_API_MAJOR_VERSION		2
#define PST_API_MINOR_VERSION		0

/*** st-action-api.h *********************************************************/

static PyObject *pst_action_register (PyObject *dummy, PyObject *args);
static PyObject *pst_action_run (PyObject *dummy, PyObject *args);

/*** st-dialog-api.h *********************************************************/

static PyObject *pst_notice (PyObject *dummy, PyObject *args);
static PyObject *pst_info_dialog (PyObject *dummy, PyObject *args);
static PyObject *pst_error_dialog (PyObject *dummy, PyObject *args);
static PyObject *pst_search_dialog (PyObject *dummy, PyObject *args);

/*** st-handlers-api.h *******************************************************/

static PyObject *pst_handlers_add (PyObject *dummy, PyObject *args);

/*** st-m3u-api.h ************************************************************/

static PyObject *pst_m3u_mktemp (PyObject *dummy, PyObject *args);

/*** st-pls-api.h ************************************************************/

static PyObject *pst_pls_parse (PyObject *dummy, PyObject *args);

/*** st-state-api.h **********************************************************/

static PyObject *pst_is_aborted (PyObject *dummy, PyObject *args);

/*** st-settings-api.h *******************************************************/

static PyObject *pst_settings_get_private_dir (PyObject *dummy, PyObject *args);
static PyObject *pst_settings_get_music_dir (PyObject *dummy, PyObject *args);

/*** st-sgml-ref-api.h *******************************************************/

static PyObject *pst_sgml_ref_expand (PyObject *dummy, PyObject *args);

/*** st-transfer-api.h *******************************************************/

static PyObject *pst_transfer_escape (PyObject *dummy, PyObject *args);

/*** st-util-api.h ***********************************************************/

static PyObject *pst_format_bitrate (PyObject *dummy, PyObject *args);
static PyObject *pst_format_samplerate (PyObject *dummy, PyObject *args);
static PyObject *pst_format_channels (PyObject *dummy, PyObject *args);
static PyObject *pst_format_audio_properties (PyObject *dummy, PyObject *args);
static PyObject *pst_hig_section_new (PyObject *dummy, PyObject *args);
static PyObject *pst_set_tooltip (PyObject *dummy, PyObject *args);

/*** st-version-api.h ********************************************************/

static PyObject *pst_check_api_version (PyObject *dummy, PyObject *args);

/*** Python-specific API *****************************************************/

static PyObject *pst_find_icon (PyObject *dummy, PyObject *args);
static PyObject *pst_gettext (PyObject *dummy, PyObject *args);
static PyObject *pst_ngettext (PyObject *dummy, PyObject *args);

static PyMethodDef methods[] = {
  { "action_register", pst_action_register, METH_VARARGS },
  { "action_run", pst_action_run, METH_VARARGS },

  { "notice", pst_notice, METH_VARARGS },
  { "info_dialog", pst_info_dialog, METH_VARARGS },
  { "error_dialog", pst_error_dialog, METH_VARARGS },
  { "search_dialog", pst_search_dialog, METH_NOARGS },

  { "handlers_add", pst_handlers_add, METH_VARARGS },

  { "m3u_mktemp", pst_m3u_mktemp, METH_VARARGS },

  { "pls_parse", pst_pls_parse, METH_VARARGS },

  { "is_aborted", pst_is_aborted, METH_NOARGS },

  { "settings_get_private_dir", pst_settings_get_private_dir, METH_NOARGS },
  { "settings_get_music_dir", pst_settings_get_music_dir, METH_NOARGS },

  { "sgml_ref_expand", pst_sgml_ref_expand, METH_VARARGS },

  { "transfer_escape", pst_transfer_escape, METH_VARARGS },

  { "format_bitrate", pst_format_bitrate, METH_VARARGS },
  { "format_samplerate", pst_format_samplerate, METH_VARARGS },
  { "format_channels", pst_format_channels, METH_VARARGS },
  { "format_audio_properties", pst_format_audio_properties, METH_VARARGS },
  { "HIGSection", pst_hig_section_new, METH_VARARGS },
  { "set_tooltip", pst_set_tooltip, METH_VARARGS },

  { "check_api_version", pst_check_api_version, METH_VARARGS },

  { "find_icon", pst_find_icon, METH_VARARGS },
  { "_", pst_gettext, METH_VARARGS },
  { "gettext", pst_gettext, METH_VARARGS },
  { "ngettext", pst_ngettext, METH_VARARGS },
  
  { NULL, NULL, 0, NULL },
};

static char *private_icons_dir = NULL;

gboolean
pst_init (void)
{
  PyObject *module;

  if (! private_icons_dir)
    private_icons_dir = g_build_filename(st_settings_get_private_dir(),
					 "streamtuner-python",
					 "icons",
					 NULL);

  module = Py_InitModule("ST", methods);
  
  PyModule_AddIntConstant(module, "MAJOR_VERSION", st_major_version);
  PyModule_AddIntConstant(module, "MINOR_VERSION", st_minor_version);
  PyModule_AddIntConstant(module, "MICRO_VERSION", st_micro_version);

  PyModule_AddIntConstant(module, "API_MAJOR_VERSION", PST_API_MAJOR_VERSION);
  PyModule_AddIntConstant(module, "API_MINOR_VERSION", PST_API_MINOR_VERSION);

  return pst_category_register(module)
    && pst_handler_config_register(module)
    && pst_handler_field_register(module)
    && pst_handler_register(module)
    && pst_stream_register(module)
    && pst_transfer_session_register(module);
}

/*** st-action-api.h *********************************************************/

static PyObject *
pst_action_register (PyObject *dummy, PyObject *args)
{
  const char *id;
  const char *label;
  const char *command = NULL;

  if (! PyArg_ParseTuple(args, "ss|z", &id, &label, &command))
    return NULL;

  st_action_register(id, label, command);

  return pst_none();
}

static PyObject *
pst_action_run (PyObject *dummy, PyObject *args)
{
  const char *id;
  const char *uri;
  
  gboolean status;
  GError *err = NULL;

  if (! PyArg_ParseTuple(args, "ss", &id, &uri))
    return NULL;

  Py_BEGIN_ALLOW_THREADS
  status = st_action_run(id, uri, &err);
  Py_END_ALLOW_THREADS

  if (! status)
    {
      PyErr_SetString(PyExc_RuntimeError, err->message);
      g_error_free(err);

      return NULL;
    }
  
  return pst_none();
}

/*** st-dialog-api.h *********************************************************/

static PyObject *
pst_notice (PyObject *dummy, PyObject *args)
{
  const char *message;
  
  if (! PyArg_ParseTuple(args, "s", &message))
    return NULL;
  
  st_notice("%s", message);
  
  return pst_none();
}

static PyObject *
pst_info_dialog (PyObject *dummy, PyObject *args)
{
  const char *primary;
  const char *secondary;

  const char *fmt;
  
  if (! PyArg_ParseTuple(args, "zz", &primary, &secondary))
    return NULL;
  
  Py_BEGIN_ALLOW_THREADS
  fmt = secondary ? "%s" : NULL; /* work around GCC warning for null format string */
  st_info_dialog(primary, fmt, secondary);
  Py_END_ALLOW_THREADS
  
  return pst_none();
}

static PyObject *
pst_error_dialog (PyObject *dummy, PyObject *args)
{
  const char *primary;
  const char *secondary;

  const char *fmt;
  
  if (! PyArg_ParseTuple(args, "zz", &primary, &secondary))
    return NULL;
  
  Py_BEGIN_ALLOW_THREADS
  fmt = secondary ? "%s" : NULL; /* work around GCC warning for null format string */
  st_error_dialog(primary, fmt, secondary);
  Py_END_ALLOW_THREADS
  
  return pst_none();
}

static PyObject *
pst_search_dialog (PyObject *dummy, PyObject *args)
{
  char *str;

  Py_BEGIN_ALLOW_THREADS
  str = st_search_dialog();
  Py_END_ALLOW_THREADS

  return pst_string_take_string_or_null(str);
}

/*** st-handlers-api.h *******************************************************/

static PyObject *
pst_handlers_add (PyObject *dummy, PyObject *args)
{
  PSTHandler *phandler;

  if (! PyArg_ParseTuple(args, "O!", &PSTHandler_Type, &phandler))
    return NULL;
  
  st_handlers_add(phandler->handler);

  return pst_none();
}

/*** st-m3u-api.h ************************************************************/

static PyObject *
pst_m3u_mktemp (PyObject *dummy, PyObject *args)
{
  const char *prefix;
  GSList *uri_list;

  GError *err = NULL;
  char *filename;

  if (! PyArg_ParseTuple(args, "sO&", &prefix, pst_strings_as_gslist, &uri_list))
    return NULL;
  
  Py_BEGIN_ALLOW_THREADS
  filename = st_m3u_mktemp(prefix, uri_list, &err);
  Py_END_ALLOW_THREADS

  /* free the list */
  g_slist_foreach(uri_list, (GFunc) g_free, NULL);
  g_slist_free(uri_list);

  if (! filename)
    {
      PyErr_SetString(PyExc_RuntimeError, err->message);
      g_error_free(err);

      return NULL;
    }
      
  return pst_string_take_string(filename);
}

/*** st-pls-api.h ************************************************************/

static PyObject *
pst_pls_parse (PyObject *dummy, PyObject *args)
{
  const char *playlist;
  
  GSList *url_list;
  PyObject *tuple;

  if (! PyArg_ParseTuple(args, "s", &playlist))
    return NULL;

  url_list = st_pls_parse(playlist);
  tuple = pst_strings_from_gslist(url_list);
  
  /* free the list */
  g_slist_foreach(url_list, (GFunc) g_free, NULL);
  g_slist_free(url_list);

  return tuple;
}

/*** st-state-api.h **********************************************************/

static PyObject *
pst_is_aborted (PyObject *dummy, PyObject *args)
{
  return PyBool_FromLong(st_is_aborted());
}

/*** st-settings-api.h *******************************************************/

static PyObject *
pst_settings_get_private_dir (PyObject *dummy, PyObject *args)
{
  return PyString_FromString(st_settings_get_private_dir());
}

static PyObject *
pst_settings_get_music_dir (PyObject *dummy, PyObject *args)
{
  return pst_string_take_string_or_null(st_settings_get_music_dir());
}

/*** st-sgml-ref-api.h *******************************************************/

static PyObject *
pst_sgml_ref_expand (PyObject *dummy, PyObject *args)
{
  const char *str;

  if (! PyArg_ParseTuple(args, "s", &str))
    return NULL;

  return pst_string_take_string(st_sgml_ref_expand(str));
}

/*** st-transfer-api.h *******************************************************/

static PyObject *
pst_transfer_escape (PyObject *dummy, PyObject *args)
{
  const char *url;

  if (! PyArg_ParseTuple(args, "s", &url))
    return NULL;

  return pst_string_take_string(st_transfer_escape(url));
}

/*** st-util-api.h ***********************************************************/

static PyObject *
pst_format_bitrate (PyObject *dummy, PyObject *args)
{
  int bitrate;

  if (! PyArg_ParseTuple(args, "i", &bitrate))
    return NULL;
  
  return pst_string_take_string(st_format_bitrate(bitrate));
}

static PyObject *
pst_format_samplerate (PyObject *dummy, PyObject *args)
{
  int samplerate;

  if (! PyArg_ParseTuple(args, "i", &samplerate))
    return NULL;
  
  return pst_string_take_string(st_format_samplerate(samplerate));
}

static PyObject *
pst_format_channels (PyObject *dummy, PyObject *args)
{
  int channels;

  if (! PyArg_ParseTuple(args, "i", &channels))
    return NULL;
  
  return pst_string_take_string(st_format_channels(channels));
}

static PyObject *
pst_format_audio_properties (PyObject *dummy, PyObject *args)
{
  int bitrate;
  int samplerate;
  int channels;

  if (! PyArg_ParseTuple(args, "iii", &bitrate, &samplerate, &channels))
    return NULL;
  
  return pst_string_take_string(st_format_audio_properties(bitrate, samplerate, channels));
}

static PyObject *
pst_hig_section_new (PyObject *dummy, PyObject *args)
{
  const char *title;
  GtkWidget *widget;

  if (! PyArg_ParseTuple(args, "sO&", &title, pst_convert_widget, &widget))
    return NULL;
  
  return pygobject_new(G_OBJECT(st_hig_section_new(title, widget)));
}

static PyObject *
pst_set_tooltip (PyObject *dummy, PyObject *args)
{
  GtkWidget *widget;
  const char *tooltip;

  if (! PyArg_ParseTuple(args, "O&z", pst_convert_widget, &widget, &tooltip))
    return NULL;
  
  st_set_tooltip(widget, tooltip);

  return pst_none();
}

/*** st-version-api.h ********************************************************/

static PyObject *
pst_check_api_version (PyObject *dummy, PyObject *args)
{
  unsigned int required_major_version;
  unsigned int minimum_minor_version;

  if (! PyArg_ParseTuple(args, "ii", &required_major_version, &minimum_minor_version))
    return NULL;

  /* we check against the streamtuner/python API version */
  return PyBool_FromLong(PST_API_MAJOR_VERSION == required_major_version
			 && PST_API_MINOR_VERSION >= minimum_minor_version);
}

/*** Python-specific API *****************************************************/

static PyObject *
pst_find_icon (PyObject *dummy, PyObject *args)
{
  const char *filename;

  char *pathname;

  if (! PyArg_ParseTuple(args, "s", &filename))
    return NULL;

  g_assert(private_icons_dir != NULL);

  Py_BEGIN_ALLOW_THREADS

  pathname = g_build_filename(ICONS_DIR, filename, NULL);
  if (! g_file_test(pathname, G_FILE_TEST_EXISTS))
    {
      g_free(pathname);
      pathname = g_build_filename(private_icons_dir, filename, NULL);
      if (! g_file_test(pathname, G_FILE_TEST_EXISTS))
	{
	  g_free(pathname);
	  pathname = NULL;
	}
    }

  Py_END_ALLOW_THREADS

  if (pathname)
    return pst_string_take_string(pathname);
  else
    {
      PyErr_Format(PyExc_RuntimeError, _("unable to find %s"), filename);
      return NULL;
    }
}

static PyObject *
pst_gettext (PyObject *dummy, PyObject *args)
{
  const char *msgid;

  if (! PyArg_ParseTuple(args, "s", &msgid))
    return NULL;

  return PyString_FromString(gettext(msgid));
}

static PyObject *
pst_ngettext (PyObject *dummy, PyObject *args)
{
  const char *msgid;
  const char *msgid_plural;
  long n;

  if (! PyArg_ParseTuple(args, "ssl", &msgid, &msgid_plural, &n))
    return NULL;

  return PyString_FromString(ngettext(msgid, msgid_plural, n));
}
