/*
 * SwamiguiPythonView.c - Python source view script editor and shell.
 *
 * Swami
 * Copyright (C) 1999-2014 Element Green <element@elementsofsound.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; version 2
 * of the License only.
 *
 * 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 or point your web browser to http://www.gnu.org.
 */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

/* FIXME - Hardcoded for now until... */
#define SCRIPT_PATH  "/home/josh/.swami-1/scripts"

#include <gtk/gtk.h>
#include <gdk/gdkkeysyms.h>
#include <libswami/libswami.h>
#include <Python.h>
#include <string.h>

#ifdef GTK_SOURCE_VIEW_SUPPORT
#include <gtksourceview/gtksourcebuffer.h>
#include <gtksourceview/gtksourceview.h>
#include <gtksourceview/gtksourcelanguagesmanager.h>
#endif

#include "SwamiguiPythonView.h"
#include "swami_python.h"
#include "util.h"
#include "i18n.h"

static void swamigui_python_view_refresh_scripts(void);
static void swamigui_python_view_class_init(SwamiguiPythonViewClass *klass);
static void swamigui_python_view_set_property(GObject *object,
        guint property_id,
        const GValue *value,
        GParamSpec *pspec);
static void swamigui_python_view_get_property(GObject *object,
        guint property_id,
        GValue *value,
        GParamSpec *pspec);
static void swamigui_python_view_init(SwamiguiPythonView *pyview);
static void swamigui_python_view_scripts_combo_changed(GtkComboBox *combo,
        gpointer user_data);
static gboolean swamigui_python_view_cb_key_press(GtkWidget *widget,
        GdkEventKey *event,
        gpointer user_data);
static void swamigui_python_view_python_output_func(const char *output,
        gboolean is_stderr);
static void swamigui_python_view_cb_execute_clicked(GtkButton *button,
        gpointer user_data);

/* view to send Python output to */
static SwamiguiPythonView *output_view = NULL;


static GtkListStore *scriptstore = NULL;	/* list store for scripts */

/* refresh the list of python scripts */
static void
swamigui_python_view_refresh_scripts(void)
{
    const char *fname;
    GtkTreeIter iter;
    GDir *dir;

    if(scriptstore)
    {
        gtk_list_store_clear(scriptstore);
    }
    else
    {
        scriptstore = gtk_list_store_new(1, G_TYPE_STRING);
    }

    dir = g_dir_open(SCRIPT_PATH, 0, NULL);

    while((fname = g_dir_read_name(dir)))
    {
        gtk_list_store_append(scriptstore, &iter);
        gtk_list_store_set(scriptstore, &iter, 0, fname, -1);
    }

    g_dir_close(dir);
}

GType
swamigui_python_view_get_type(void)
{
    static GType obj_type = 0;

    if(!obj_type)
    {
        static const GTypeInfo obj_info =
        {
            sizeof(SwamiguiPythonViewClass), NULL, NULL,
            (GClassInitFunc) swamigui_python_view_class_init, NULL, NULL,
            sizeof(SwamiguiPythonView), 0,
            (GInstanceInitFunc) swamigui_python_view_init,
        };

        obj_type = g_type_register_static(GTK_TYPE_VBOX, "SwamiguiPythonView",
                                          &obj_info, 0);
    }

    return (obj_type);
}

static void
swamigui_python_view_class_init(SwamiguiPythonViewClass *klass)
{
    GObjectClass *obj_class = G_OBJECT_CLASS(klass);

    obj_class->set_property = swamigui_python_view_set_property;
    obj_class->get_property = swamigui_python_view_get_property;

    swamigui_python_view_refresh_scripts();
}

static void
swamigui_python_view_set_property(GObject *object, guint property_id,
                                  const GValue *value, GParamSpec *pspec)
{
    //  SwamiguiPythonView *pyview = SWAMIGUI_PYTHON_VIEW (object);

    switch(property_id)
    {
    default:
        G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
        break;
    }
}

static void
swamigui_python_view_get_property(GObject *object, guint property_id,
                                  GValue *value, GParamSpec *pspec)
{
    //  SwamiguiPythonView *pyview = SWAMIGUI_PYTHON_VIEW (object);

    switch(property_id)
    {
    default:
        G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
        break;
    }
}

static void
swamigui_python_view_init(SwamiguiPythonView *pyview)
{
    GtkWidget *frame;
    GtkWidget *btn;
    GtkCellRenderer *renderer;
#ifdef GTK_SOURCE_VIEW_SUPPORT
    GtkSourceLanguagesManager *lm;
    GtkSourceLanguage *lang;
#endif

    pyview->glade_widg = swamigui_util_glade_create("PythonEditor");
    gtk_container_add(GTK_CONTAINER(pyview), pyview->glade_widg);

    pyview->comboscripts = swamigui_util_glade_lookup(pyview->glade_widg,
                           "ComboScripts");
    gtk_combo_box_set_model(GTK_COMBO_BOX(pyview->comboscripts),
                            GTK_TREE_MODEL(scriptstore));
    gtk_combo_box_entry_set_text_column(GTK_COMBO_BOX_ENTRY(pyview->comboscripts), 0);

    g_signal_connect(pyview->comboscripts, "changed",
                     G_CALLBACK(swamigui_python_view_scripts_combo_changed),
                     pyview);

    renderer = gtk_cell_renderer_text_new();
    gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(pyview->comboscripts), renderer, TRUE);
    gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(pyview->comboscripts), renderer,
                                   "text", 0, NULL);

    frame = swamigui_util_glade_lookup(pyview->glade_widg, "ScrollScriptEditor");

#ifdef GTK_SOURCE_VIEW_SUPPORT
    lm = gtk_source_languages_manager_new();
    lang = gtk_source_languages_manager_get_language_from_mime_type
           (lm, "text/x-python");

    if(lang)
        pyview->srcbuf
            = GTK_TEXT_BUFFER(gtk_source_buffer_new_with_language(lang));
    else
    {
        pyview->srcbuf = GTK_TEXT_BUFFER(gtk_source_buffer_new(NULL));
    }

    gtk_source_buffer_set_highlight(GTK_SOURCE_BUFFER(pyview->srcbuf), TRUE);

    pyview->srcview = gtk_source_view_new_with_buffer
                      (GTK_SOURCE_BUFFER(pyview->srcbuf));
#else
    pyview->srcbuf = gtk_text_buffer_new(NULL);
    pyview->srcview = gtk_text_view_new_with_buffer(pyview->srcbuf);
#endif

    gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(pyview->srcview), GTK_WRAP_CHAR);
    g_signal_connect(pyview->srcview, "key-press-event",
                     G_CALLBACK(swamigui_python_view_cb_key_press), pyview);
    gtk_widget_show(pyview->srcview);
    gtk_container_add(GTK_CONTAINER(frame), pyview->srcview);

    pyview->conbuf = gtk_text_buffer_new(NULL);

    pyview->conview = swamigui_util_glade_lookup(pyview->glade_widg,
                      "TxtPyConsole");
    gtk_text_view_set_buffer(GTK_TEXT_VIEW(pyview->conview), pyview->conbuf);

    btn = swamigui_util_glade_lookup(pyview->glade_widg, "BtnExecute");
    g_signal_connect(btn, "clicked",
                     G_CALLBACK(swamigui_python_view_cb_execute_clicked),
                     pyview);
}

static void
swamigui_python_view_scripts_combo_changed(GtkComboBox *combo, gpointer user_data)
{
    SwamiguiPythonView *pyview = SWAMIGUI_PYTHON_VIEW(user_data);
    char *fname, *fullname, *buf;
    GtkTreeModel *model;
    GtkTreeIter iter;

    if(!gtk_combo_box_get_active_iter(combo, &iter))
    {
        return;
    }

    model = gtk_combo_box_get_model(combo);
    gtk_tree_model_get(model, &iter, 0, &fname, -1);

    fullname = g_strconcat(SCRIPT_PATH, G_DIR_SEPARATOR_S, fname, NULL);
    g_free(fname);

    if(!g_file_get_contents(fullname, &buf, NULL, NULL))
    {
        g_free(fullname);
        return;
    }

    g_free(fullname);

    gtk_text_buffer_set_text(pyview->srcbuf, buf, -1);
    g_free(buf);
}

static gboolean
swamigui_python_view_cb_key_press(GtkWidget *widget, GdkEventKey *event,
                                  gpointer user_data)
{
    SwamiguiPythonView *pyview = SWAMIGUI_PYTHON_VIEW(user_data);
    GtkWidget *btn;
    GtkTextMark *cursor;
    GtkTextIter start_iter, end_iter;
    char *cmd;

    if(event->keyval != GDK_Return)
    {
        return (FALSE);
    }

    /* return if not in "shell mode" (ENTER executes line) */
    btn = swamigui_util_glade_lookup(pyview->glade_widg, "BtnShellMode");

    if(!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(btn)))
    {
        return (FALSE);
    }

    /* get cursor position */
    cursor = gtk_text_buffer_get_insert(pyview->srcbuf);

    /* get an iterator for the cursor (end of line) */
    gtk_text_buffer_get_iter_at_mark(pyview->srcbuf, &end_iter, cursor);

    start_iter = end_iter;	/* copy iterator */

    /* set the iterator to the beginning of the line */
    gtk_text_iter_set_line_offset(&start_iter, 0);

    cmd = gtk_text_buffer_get_text(pyview->srcbuf, &start_iter, &end_iter, FALSE);

    if(cmd && cmd[0])		/* some command to execute? */
    {
        /* set current output view and Python log function */
        output_view = pyview;
        swamigui_python_set_output_func(swamigui_python_view_python_output_func);

        PyRun_SimpleString(cmd);

        output_view = NULL;
    }

    g_free(cmd);

    return (FALSE);
}

static void
swamigui_python_view_python_output_func(const char *output,
                                        gboolean is_stderr)
{
    GtkTextIter iter;

    if(!output_view)
    {
        return;
    }

    gtk_text_buffer_get_end_iter(output_view->conbuf, &iter);
    gtk_text_buffer_insert(output_view->conbuf, &iter, output, -1);
}

/* Glade callback for Execute toolbar button */
static void
swamigui_python_view_cb_execute_clicked(GtkButton *button, gpointer user_data)
{
    SwamiguiPythonView *pyview = SWAMIGUI_PYTHON_VIEW(user_data);
    GtkTextIter start, end;
    char *script;

    gtk_text_buffer_get_bounds(pyview->srcbuf, &start, &end);
    script = gtk_text_buffer_get_text(pyview->srcbuf, &start, &end, FALSE);

    output_view = pyview;
    swamigui_python_set_output_func(swamigui_python_view_python_output_func);

    PyRun_SimpleString(script);

    output_view = NULL;

    g_free(script);
}

/**
 * swamigui_python_view_new:
 *
 * Create a new GUI python view shell widget.
 *
 * Returns: New swami GUI python view.
 */
GtkWidget *
swamigui_python_view_new(void)
{
    return (GTK_WIDGET(g_object_new(SWAMIGUI_TYPE_PYTHON_VIEW, NULL)));
}
