/*  Gnometab -- a guitar tablature editor for GNOME
    Copyright (C) 2001  William L. Guelker

    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 <math.h>
#include <string.h>
#include <libxml/tree.h>
#include <libxml/parser.h>
#include <gnome.h>

#include "tab_canvas.h"
#include "interface.h"
#include "chord_builder.h"
#include "dialogs.h"
#include "tab_objects.h"
#include "chord_canvas.h"

GnomeCanvasGroup *chord_objects;

static gboolean
validate_chord_coords(double x, double y)
{
    if (x < 0 || x > 98) return FALSE;
    if ((y + 12) < 0 || (y + 12) > 84) return FALSE;
    
    return TRUE;
}

static gint 
chord_object_event(GnomeCanvasItem *grid_object, GdkEvent *event, 
                                    GtabChordBuilder *gtab_dialog)
{
    double item_x, item_y;
    double new_x, new_y;
    static double x, y;
    static double x_bounds_old, y_bounds_old;
    gchar *x_prop, *y_prop;
    static int dragging;
    GdkCursor *fleur;
    static xmlNodePtr node;
    double x1, y1, x2;
        
    item_x = event->button.x;
    item_y = event->button.y;

    switch (event->type)    {
        case GDK_BUTTON_PRESS:
            switch (event->button.button)    {
                case 2:
                    
                
                    node = (xmlNodePtr ) g_object_get_data(G_OBJECT(grid_object), "node"); 
                    /* xmlUnlinkNode(node);        No way to remove nodes?!?! */
                    if (node)    {
                        xmlSetProp(node, "active", "false");     /* this sucks */
                    }
                        
                    gtk_object_destroy(GTK_OBJECT(grid_object));
                                    
                    break;
                case 1:
                    x = item_x;
                    y = item_y;
                    fleur = gdk_cursor_new(GDK_FLEUR);
                    gnome_canvas_item_get_bounds(grid_object, &x_bounds_old, 
                                                    &y1, &x2, &y_bounds_old);
                    node = (xmlNodePtr ) g_object_get_data(G_OBJECT(grid_object), "node");
                    gnome_canvas_item_grab(grid_object,
                                            GDK_POINTER_MOTION_MASK |
                                            GDK_BUTTON_RELEASE_MASK,
                                            fleur,
                                            event->button.time);
                    gdk_cursor_destroy(fleur);
                    dragging = TRUE;
                    break;
                
                default:
                    if (GNOME_IS_CANVAS_ITEM(gtab_dialog->highlights)) {
                        gtk_object_destroy(GTK_OBJECT(gtab_dialog->highlights));
                        gtab_dialog->highlights = NULL;
                    }
                    gtab_dialog->highlights = GNOME_CANVAS_GROUP(
                                                gnome_canvas_item_new(
                                                    gtab_dialog->chord_objects,
                                                    gnome_canvas_group_get_type(),
                                                    NULL));
                    
                    highlight_object(grid_object, gtab_dialog->highlights);
                    g_object_set_data(G_OBJECT(gtab_dialog->popup->menu), 
                                        "chord_obj", 
                                        grid_object);
                                        
                    gtk_menu_popup(GTK_MENU(gtab_dialog->popup->menu), 
                                        NULL, NULL, NULL, NULL, 1, 0);
                    
                    break;
                    
            }
            
            break;
        case GDK_MOTION_NOTIFY:
            if (dragging && (event->motion.state & GDK_BUTTON1_MASK))    {
                new_x = item_x;
                new_y = item_y;
                gnome_canvas_item_move(grid_object, new_x - x, new_y - y);
                
                /* this mess is needed to keep track */
                /* of where objects have been moved to */
                
                x_bounds_old = x_bounds_old + (new_x - x);        
                y_bounds_old = y_bounds_old + (new_y - y);        
                
                xmlSetProp(node, "x_bounds", float_to_char(x_bounds_old));
                xmlSetProp(node, "y_bounds", float_to_char(y_bounds_old));
                x_prop = get_prop(node, "x_create");
                y_prop = get_prop(node, "y_create");
                x1 = atof(x_prop);
                y1 = atof(y_prop);
                x1 = x1 + (new_x - x);
                y1 = y1 + (new_y - y);
                xmlSetProp(node, "x_create", float_to_char(x1));
                xmlSetProp(node, "y_create", float_to_char(y1));
                x = new_x;
                y = new_y;
                g_free(x_prop);
                g_free(y_prop);
            }

            break;
        case GDK_BUTTON_RELEASE:
            gnome_canvas_item_ungrab(grid_object, event->button.time);
            dragging = FALSE;
            
            break;
        default:
            break;
    }        
    
    return(TRUE);
}

static gint
chord_num_entry_key_press(GtkWidget *num_entry, GdkEventKey *event, 
                                            GtabChordBuilder *gtab_dialog)
{
    double cvs_x;
    double cvs_y;
    gchar  text[6];
    xmlNodePtr chord_text_xml = NULL;
    GnomeCanvasItem *grid_item;
    PangoFontDescription *font_string;
    
    double x1, y1, x2, y2;
        
    switch (event->keyval) {
        case GDK_Return:
            
            g_snprintf(text, 3, "%s", 
                    gtk_entry_get_text(GTK_ENTRY(num_entry)));
    
            g_object_get(GTK_OBJECT(gtab_dialog->cvs_entry),
                            "x", &cvs_x,
                            "y", &cvs_y,
                            NULL);
                    
            gtk_object_destroy(GTK_OBJECT(gtab_dialog->cvs_entry));

            if (cvs_x >= 84.0)    {
                font_string = pango_font_description_from_string(gtab_dialog->tab_doc->parent->chrd_bldr_font_small);
        
            }
            else    {
                font_string = pango_font_description_from_string(gtab_dialog->tab_doc->parent->chrd_bldr_font);
            }
    
            if (strlen(text) >= 1)    {
                grid_item = gnome_canvas_item_new(gtab_dialog->chord_objects, 
                                            gnome_canvas_text_get_type(),
                                            "text", text,
                                            "x", cvs_x,
                                            "y", cvs_y,
                                            "anchor", GTK_ANCHOR_NORTH_WEST,
                                            "font_desc", font_string,
                                            "fill_color", "black",
                                            NULL);
    
                gnome_canvas_item_get_bounds(grid_item, &x1, &y1, &x2, &y2);
            
                chord_text_xml = xmlNewChild(gtab_dialog->chord->xmlRootNode, NULL, 
                                                "chord_text", NULL);
        
                xmlSetProp(chord_text_xml, "text", text);
                xmlSetProp(chord_text_xml, "x_bounds", float_to_char(x1));
                xmlSetProp(chord_text_xml, "y_bounds", float_to_char(y2));
                xmlSetProp(chord_text_xml, "x_create", float_to_char(cvs_x));
                xmlSetProp(chord_text_xml, "y_create", float_to_char(cvs_y));
                
                g_signal_connect(GTK_OBJECT(grid_item), "event", 
                                (GtkSignalFunc) chord_object_event, gtab_dialog);
                g_object_set_data(G_OBJECT(grid_item), "node", chord_text_xml);
            }    
            
            pango_font_description_free(font_string);
            gtab_dialog->cvs_entry = NULL;
            
            if (validate_chord_coords(cvs_x + 14.0, cvs_y)) {
                create_chord_text_entry_widget((cvs_x + 14.0), cvs_y, gtab_dialog);
            }
            else {
                create_chord_text_entry_widget(5.0, cvs_y, gtab_dialog);
            }
            return (TRUE);
            break;
        case GDK_Escape:
            gtk_object_destroy(GTK_OBJECT(gtab_dialog->cvs_entry));
            gtab_dialog->cvs_entry = NULL;
            
            return (TRUE);
            break;
        case GDK_Down:
            g_object_get(GTK_OBJECT(gtab_dialog->cvs_entry),
                            "x", &cvs_x,
                            "y", &cvs_y,
                            NULL);
        
            gtk_object_destroy(GTK_OBJECT(gtab_dialog->cvs_entry));
            gtab_dialog->cvs_entry = NULL;
                    
            if (validate_chord_coords(cvs_x, cvs_y + 12.0)) {
                create_chord_text_entry_widget(cvs_x, cvs_y + 12.0, gtab_dialog);
            }
            else {
                create_chord_text_entry_widget(cvs_x, cvs_y, gtab_dialog);
            }
            
            return(TRUE);
            break;
        case GDK_Up:
            g_object_get(GTK_OBJECT(gtab_dialog->cvs_entry),
                            "x", &cvs_x,
                            "y", &cvs_y,
                            NULL);
            gtk_object_destroy(GTK_OBJECT(gtab_dialog->cvs_entry));
            gtab_dialog->cvs_entry = NULL;
                        
            if (validate_chord_coords(cvs_x, cvs_y - 12.0)) {
                create_chord_text_entry_widget(cvs_x, cvs_y - 12.0, gtab_dialog);
            }
            else {
                create_chord_text_entry_widget(cvs_x, cvs_y, gtab_dialog);
            }
            
            return(TRUE);
            break;
        case GDK_Left:
            g_object_get(GTK_OBJECT(gtab_dialog->cvs_entry),
                            "x", &cvs_x,
                            "y", &cvs_y,
                            NULL);
            gtk_object_destroy(GTK_OBJECT(gtab_dialog->cvs_entry));
            gtab_dialog->cvs_entry = NULL;
        
            if (validate_chord_coords(cvs_x - 14.0, cvs_y)) {
                create_chord_text_entry_widget(cvs_x - 14.0, cvs_y, gtab_dialog);
            }
            else {
                create_chord_text_entry_widget(89.0, cvs_y, gtab_dialog);
            }
            
            return(TRUE);
            break;
        case GDK_Right:
            g_object_get(GTK_OBJECT(gtab_dialog->cvs_entry),
                            "x", &cvs_x,
                            "y", &cvs_y,
                            NULL);
            gtk_object_destroy(GTK_OBJECT(gtab_dialog->cvs_entry));
            gtab_dialog->cvs_entry = NULL;

            if (validate_chord_coords(cvs_x + 14.0, cvs_y)) {
                create_chord_text_entry_widget(cvs_x + 14.0, cvs_y, gtab_dialog);
            }
            else {
                create_chord_text_entry_widget(5.0, cvs_y, gtab_dialog);
            }
            
            return(TRUE);
            break;
        default:
            return FALSE;
            break;
    }
            
    
}

static gint 
grid_event(GnomeCanvasItem *grid, GdkEventButton *event, 
                            GtabChordBuilder *gtab_dialog)
{
    double grid_x1;
    double grid_y1;
    double grid_x2;
    double grid_y2;
    double new_x;
    GtabDialogBar *bar_dlg;
    
    if (event->type != GDK_BUTTON_PRESS)    {
        return(FALSE);
    }

    if (event->button != 1)    return(FALSE);
    
    gnome_canvas_item_get_bounds(grid, &grid_x1, &grid_y1, &grid_x2, &grid_y2);
    
    /* moves x to leftmost part of current position */
    new_x = (floor((event->x)/14))*14 + 5;    

    switch (gtab_dialog->current_tool)    {
        
        case TOOL_NUM:
            /* make sure we don't get more than one num_entry on the canvas */
            if (GNOME_IS_CANVAS_ITEM(gtab_dialog->cvs_entry)) return(TRUE); 
            
            create_chord_text_entry_widget(new_x, grid_y1, gtab_dialog);
            
            break;
        
        case TOOL_BAR:
            popup_holder_x2 = new_x;
            popup_holder_y2 = grid_y1;
            
            bar_dlg = create_chord_bar_size_popup(gtab_dialog);
            gtk_widget_show(bar_dlg->dialog);
            break;
                
        default:
            break;
    }
                                        
    return(TRUE);
}

void
create_chord_text_entry_widget(double x, double y, GtabChordBuilder *gtab_dialog)
{
    GtkWidget *num_entry;
    
    num_entry = gtk_entry_new();
    gtk_entry_set_max_length(GTK_ENTRY(num_entry), 2);
    
    gtab_dialog->cvs_entry = gnome_canvas_item_new(gtab_dialog->chord_objects,
                            gnome_canvas_widget_get_type(),
                            "widget", num_entry,
                            "x", x,
                            "y", y,
                            "anchor", GTK_ANCHOR_NORTH_WEST,
                            "width", 20.0,
                            "height", 20.0,
                            "size_pixels", TRUE,
                            NULL);
    
    gtk_entry_set_has_frame(GTK_ENTRY(num_entry), FALSE);
    g_signal_connect(GTK_OBJECT(num_entry), "key_press_event", 
                        (GtkSignalFunc) chord_num_entry_key_press, gtab_dialog);
    
    gtk_widget_show(num_entry);
        
    gtk_widget_grab_focus(num_entry);

}

void 
create_grid(GtabChordBuilder *gtab_dialog)
{
    GnomeCanvasGroup *chord_canvas = NULL;                                        
    GnomeCanvasItem  *background = NULL;
    GnomeCanvasPoints *points;
      /* static GnomeCanvasItem *grid = NULL; */
    double x = 0;
      double y = 0;
       
    chord_canvas = gnome_canvas_root(GNOME_CANVAS(gtab_dialog->canvas));
    
    points = gnome_canvas_points_new(4);
    points->coords[0] = 0.0;
    points->coords[1] = 0.0;
    points->coords[2] = 98.0;
    points->coords[3] = 0.0;
    points->coords[4] = 98.0;
    points->coords[5] = 84.0;
    points->coords[6] = 0.0;
    points->coords[7] = 84.0;
    
    background = gnome_canvas_item_new(chord_canvas,
                                       gnome_canvas_polygon_get_type(),
                                       "points", points,
                                       "width_pixels", 1,
                                       "fill_color", "white",
                                       "outline_color", "white",
                                       NULL);
    
    gnome_canvas_points_unref(points);
                                    
    for (x = 7; x <= 84; x = x + 14)    {
        /* this draws invisible grid for the top row X's and 0's */ 
        GnomeCanvasItem *grid1;
        
        points = gnome_canvas_points_new(4);
        points->coords[0] = x;
        points->coords[1] = 0.0;
        points->coords[2] = x + 14.0;
        points->coords[3] = 0.0;
        points->coords[4] = x + 14.0;
        points->coords[5] = 12.0;
        points->coords[6] = x;
        points->coords[7] = 12.0;
        grid1 = gnome_canvas_item_new(chord_canvas,
                                        gnome_canvas_polygon_get_type(),
                                        "points", points,
                                        "width_pixels", 1,
                                        "fill_color", "white",
                                        "outline_color", "white",
                                        NULL);
        
        gnome_canvas_points_unref(points);
        g_signal_connect(GTK_OBJECT(grid1), "event", 
                            (GtkSignalFunc) grid_event, gtab_dialog);
    
    }                                        
        
    for (x = 7; x <= 63; x = x + 14)    {
        for (y = 12; y <= 72; y = y + 12)    {
                        
            if (x != 63)    {
                GnomeCanvasItem *grid2;
                
                points = gnome_canvas_points_new(4);
                points->coords[0] = x;
                points->coords[1] = y;
                points->coords[2] = x + 14.0;
                points->coords[3] = y;
                points->coords[4] = x + 14.0;
                points->coords[5] = y + 12.0;
                points->coords[6] = x;
                points->coords[7] = y + 12.0;
                grid2 = gnome_canvas_item_new(chord_canvas,
                                         gnome_canvas_polygon_get_type(),
                                         "points", points,
                                         "width_pixels", 1,
                                         "fill_color", "white",
                                         "outline_color", "gray",
                                         NULL);
                g_signal_connect(GTK_OBJECT(grid2), "event", 
                                    (GtkSignalFunc) grid_event, gtab_dialog);
                gnome_canvas_points_unref(points);
            }
            else    {
                GnomeCanvasItem *grid2;
                GnomeCanvasItem *grid3;
                
                /* Jump ahead to draw the white boxes on 
                    the far right for fret numbers */
                
                points = gnome_canvas_points_new(4);
                points->coords[0] = x + 14.0;
                points->coords[1] = y;
                points->coords[2] = x + 28.0;
                points->coords[3] = y;
                points->coords[4] = x + 28.0;
                points->coords[5] = y + 12.0;
                points->coords[6] = x + 14.0;
                points->coords[7] = y + 12.0;
                grid2 = gnome_canvas_item_new(chord_canvas,
                                         gnome_canvas_polygon_get_type(),
                                         "points", points,
                                         "width_pixels", 1,
                                         "fill_color", "white",
                                         "outline_color", "white",
                                         NULL);
                g_signal_connect(GTK_OBJECT(grid2), "event", 
                                    (GtkSignalFunc) grid_event, gtab_dialog);
                gnome_canvas_points_unref(points);
                
                points = gnome_canvas_points_new(4);
                points->coords[0] = x;
                points->coords[1] = y;
                points->coords[2] = x + 14.0;
                points->coords[3] = y;
                points->coords[4] = x + 14.0;
                points->coords[5] = y + 12.0;
                points->coords[6] = x;
                points->coords[7] = y + 12.0;
                grid3 = gnome_canvas_item_new(chord_canvas,
                                         gnome_canvas_polygon_get_type(),
                                         "points", points,
                                         "width_pixels", 1,
                                         "fill_color", "white",
                                         "outline_color", "gray",
                                         NULL);
                g_signal_connect(GTK_OBJECT(grid3), "event", 
                                    (GtkSignalFunc) grid_event, gtab_dialog);
                gnome_canvas_points_unref(points);
            }
            
        }
      }
    
    
      gtab_dialog->chord_objects = GNOME_CANVAS_GROUP(gnome_canvas_item_new(chord_canvas, 
                                        gnome_canvas_group_get_type(), NULL));
      gtab_dialog->current_tool = TOOL_NUM;
        
      gtab_dialog->chord = xmlNewDoc("1.0");
      gtab_dialog->chord->xmlRootNode = xmlNewDocNode(gtab_dialog->chord, NULL, 
                                        "chord_objects", NULL);
    
}

void 
create_chord_bar(double x, double y, gint positions, GtabChordBuilder *dialog)
{
    GnomeCanvasItem *new_bar;
    GnomeCanvasPoints *points;
    xmlNodePtr chord_bar_xml;
    double start_x;
    double start_y;
    double total_length;
    double x1, y1, x2, y2;
    
    start_x = x;
    start_y = y - 17.0;
    total_length = 12*positions;
    
    points = gnome_canvas_points_new(6);

    points->coords[0] = start_x;
    points->coords[1] = start_y;
    points->coords[2] = start_x + (total_length/5);
    points->coords[3] = start_y - 4;
    points->coords[4] = start_x + 2*(total_length/5);
    points->coords[5] = start_y - 6;
    points->coords[6] = start_x + 3*(total_length/5);
    points->coords[7] = start_y - 6;
    points->coords[8] = start_x + 4*(total_length/5);
    points->coords[9] = start_y - 4;
    points->coords[10] = start_x + 5*(total_length/5);
    points->coords[11] = start_y;
    
    new_bar = gnome_canvas_item_new(dialog->chord_objects,
                                    gnome_canvas_line_get_type(),
                                    "points", points,
                                    "fill_color", "black",
                                    "width_pixels", 1,
                                    "first_arrowhead", FALSE,
                                    "last_arrowhead", FALSE,
                                    "smooth", TRUE,
                                    "spline_steps", 8,    
                                    NULL);

    gnome_canvas_request_redraw(GNOME_CANVAS
                                (dialog->canvas),
                                ((int) start_x - 3), ((int) start_y - 8),
                                ((int) start_x + total_length + 3), 
                                ((int) start_y + 3));
                                
    gnome_canvas_points_unref(points);

    gnome_canvas_item_get_bounds(new_bar, &x1, &y1, &x2, &y2);
    
    chord_bar_xml = xmlNewChild(dialog->chord->xmlRootNode, NULL, "chord_bar", NULL);
    xmlSetProp(chord_bar_xml, "x_bounds", float_to_char(x1));
    xmlSetProp(chord_bar_xml, "y_bounds", float_to_char(y2));
    xmlSetProp(chord_bar_xml, "x_create", float_to_char(x));
    xmlSetProp(chord_bar_xml, "y_create", float_to_char(y));
    xmlSetProp(chord_bar_xml, "positions", float_to_char(positions));
    
    g_signal_connect(GTK_OBJECT(new_bar), "event", 
                        (GtkSignalFunc) chord_object_event, dialog);
    g_object_set_data(G_OBJECT(new_bar), "node", chord_bar_xml);
}

void 
create_chord_text(double x, double y, gchar *text, GtabChordBuilder *dialog)
{
    xmlNodePtr chord_text_xml = NULL;
    GnomeCanvasItem *grid_item;
    PangoFontDescription *font_string;
    double x1, y1, x2, y2;
                            
    if (strlen(text) >= 1)    {
        
        if (x >= 84.0)    {
            font_string = pango_font_description_from_string(dialog->tab_doc->parent->chrd_bldr_font_small);
            
        }
        else    {
            font_string = pango_font_description_from_string(dialog->tab_doc->parent->chrd_bldr_font);
            
        }
            
        grid_item = gnome_canvas_item_new(dialog->chord_objects, 
                                        gnome_canvas_text_get_type(),
                                        "text", text,
                                        "x", x,
                                        "y", y,
                                        "anchor", GTK_ANCHOR_NORTH_WEST,
                                        "font_desc", font_string,
                                        "fill_color", "black",
                                        NULL);
    
        gnome_canvas_item_get_bounds(grid_item, &x1, &y1, &x2, &y2);
        
        chord_text_xml = xmlNewChild(dialog->chord->xmlRootNode, NULL, 
                                            "chord_text", NULL);
    
        xmlSetProp(chord_text_xml, "text", text);
        xmlSetProp(chord_text_xml, "x_bounds", float_to_char(x1));
        xmlSetProp(chord_text_xml, "y_bounds", float_to_char(y2));
        xmlSetProp(chord_text_xml, "x_create", float_to_char(x));
        xmlSetProp(chord_text_xml, "y_create", float_to_char(y));
        
        g_signal_connect(GTK_OBJECT(grid_item), "event", 
                            (GtkSignalFunc) chord_object_event, dialog);
        g_object_set_data(G_OBJECT(grid_item), "node", chord_text_xml);
        
        pango_font_description_free(font_string);
    }    
    
    
}
