/*
    DeaDBeeF - The Ultimate Music Player
    Copyright (C) 2009-2013 Alexey Yakovenko <waker@users.sourceforge.net>

    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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
*/
#include <string.h>
#include "ddbvolumebar.h"
#include "drawing.h"
#include "gtkui.h"
#include "interface.h"
#include "support.h"

#define min(x,y) ((x)<(y)?(x):(y))

G_DEFINE_TYPE (DdbVolumeBar, ddb_volumebar, GTK_TYPE_WIDGET);

static void
ddb_volumebar_send_configure (DdbVolumeBar *darea)
{
  GtkWidget *widget;
  GdkEvent *event = gdk_event_new (GDK_CONFIGURE);

  widget = GTK_WIDGET (darea);

  event->configure.window = g_object_ref (gtk_widget_get_window(widget));
  event->configure.send_event = TRUE;
  GtkAllocation a;
  gtk_widget_get_allocation (widget, &a);
  event->configure.x = a.x;
  event->configure.y = a.y;
  event->configure.width = a.width;
  event->configure.height = a.height;
  
  gtk_widget_event (widget, event);
  gdk_event_free (event);
}

static void
ddb_volumebar_size_allocate (GtkWidget     *widget,
				GtkAllocation *allocation)
{
  g_return_if_fail (DDB_IS_VOLUMEBAR (widget));
  g_return_if_fail (allocation != NULL);

  gtk_widget_set_allocation (widget, allocation);

  if (gtk_widget_get_realized (widget))
    {
      if (gtk_widget_get_has_window (widget))
        gdk_window_move_resize (gtk_widget_get_window(widget),
                                allocation->x, allocation->y,
                                allocation->width, allocation->height);

      ddb_volumebar_send_configure (DDB_VOLUMEBAR (widget));
    }
}

gboolean
on_volumebar_draw (GtkWidget    *widget, cairo_t *cr);

gboolean
on_volumebar_expose_event                 (GtkWidget       *widget,
                                        GdkEventExpose  *event);

gboolean
on_volumebar_motion_notify_event       (GtkWidget       *widget,
                                        GdkEventMotion  *event);

gboolean
on_volumebar_button_press_event        (GtkWidget       *widget,
                                        GdkEventButton  *event);

gboolean
on_volumebar_button_release_event      (GtkWidget       *widget,
                                        GdkEventButton  *event);

gboolean
on_volumebar_scroll_event              (GtkWidget       *widget,
                                        GdkEventScroll        *event);

gboolean
on_volumebar_configure_event (GtkWidget *widget, GdkEventConfigure *event);

static void
ddb_volumebar_class_init(DdbVolumeBarClass *class)
{
  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
  widget_class->size_allocate = ddb_volumebar_size_allocate;
#if GTK_CHECK_VERSION(3,0,0)
  widget_class->draw = on_volumebar_draw;
#else
  widget_class->expose_event = on_volumebar_expose_event;
#endif
  widget_class->button_press_event = on_volumebar_button_press_event;
  widget_class->button_release_event = on_volumebar_button_release_event;
  widget_class->motion_notify_event = on_volumebar_motion_notify_event;
  widget_class->scroll_event = on_volumebar_scroll_event;
  widget_class->configure_event = on_volumebar_configure_event;
}

GtkWidget * ddb_volumebar_new() {
    return g_object_new (DDB_TYPE_VOLUMEBAR, NULL);
}

static void
ddb_volumebar_init(DdbVolumeBar *volumebar)
{
    char s[100];
    int db = deadbeef->volume_get_db ();
    snprintf (s, sizeof (s), "%s%ddB", db < 0 ? "" : "+", db);
    gtk_widget_set_tooltip_text (GTK_WIDGET (volumebar), s);
    gtk_widget_set_has_window (GTK_WIDGET (volumebar), FALSE);
    gtk_widget_set_events (GTK_WIDGET (volumebar), GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_MOTION_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK);
}

void
volumebar_draw (GtkWidget *widget, cairo_t *cr) {
    if (!widget) {
        return;
    }

#if GTK_CHECK_VERSION(3,0,0)
    GtkAllocation allocation;
    gtk_widget_get_allocation (widget, &allocation);
    cairo_translate (cr, -allocation.x, -allocation.y);
#endif

    float range = -deadbeef->volume_get_min_db ();
    GtkAllocation a;
    gtk_widget_get_allocation (widget, &a);
    int n = a.width / 4;
    float vol = (range + deadbeef->volume_get_db ()) / range * n;
    float h = 17;

    GdkColor clr_fg;
    GdkColor clr_bg;
    gtkui_get_bar_foreground_color (&clr_fg);
    gtkui_get_bar_background_color (&clr_bg);

    for (int i = 0; i < n; i++) {
        float iy = (float)i + 3;
        int _x = i * 4;
        int _h = h * iy / n;
        int _y = a.height/2-h/2;
        _y += (h - _h);
        int _w = 3;
        if (i < vol) {
            cairo_set_source_rgb (cr, clr_fg.red/65535.f, clr_fg.green/65535.f, clr_fg.blue/65535.f);
            cairo_rectangle (cr, _x + a.x, _y + a.y, _w, _h);
            cairo_fill (cr);
        }
        else {
            cairo_set_source_rgb (cr, clr_bg.red/65535.f, clr_bg.green/65535.f, clr_bg.blue/65535.f);
            cairo_rectangle (cr, _x + a.x, _y + a.y, _w, _h);
            cairo_fill (cr);
        }
    }
#if 0
    if (DDB_VOLUMEBAR (widget)->show_dbs) {
        draw_begin ((uintptr_t)gtk_widget_get_window(widget));
        draw_init_font (widget->style);
        char s[100];
        int db = deadbeef->volume_get_db ();
        snprintf (s, sizeof (s), "%s%ddB", db < 0 ? "" : "+", db);
        draw_text (widget->allocation.x, widget->allocation.y, widget->allocation.width, 0, s);
        gtk_widget_set_tooltip_text (widget, s);
        gtk_widget_trigger_tooltip_query (widget);
        draw_end ();
    }
#endif
}

gboolean
on_volumebar_draw (GtkWidget    *widget, cairo_t *cr) {
    volumebar_draw (widget, cr);
    return FALSE;
}

#if !GTK_CHECK_VERSION(3,0,0)
gboolean
on_volumebar_expose_event                 (GtkWidget       *widget,
                                        GdkEventExpose  *event)
{
    cairo_t *cr = gdk_cairo_create (gtk_widget_get_window (widget));
    on_volumebar_draw (widget, cr);
    cairo_destroy (cr);
    return FALSE;
}
#endif

gboolean
on_volumebar_motion_notify_event       (GtkWidget       *widget,
                                        GdkEventMotion  *event)
{
    GtkAllocation a;
    gtk_widget_get_allocation (widget, &a);
    if (event->state & GDK_BUTTON1_MASK) {
        float range = -deadbeef->volume_get_min_db ();
        float volume = (event->x - a.x) / a.width * range - range;
        if (volume > 0) {
            volume = 0;
        }
        if (volume < -range) {
            volume = -range;
        }
        deadbeef->volume_set_db (volume);
        char s[100];
        int db = volume;
        snprintf (s, sizeof (s), "%s%ddB", db < 0 ? "" : "+", db);
        gtk_widget_set_tooltip_text (widget, s);
        gtk_widget_trigger_tooltip_query (widget);
        gtk_widget_queue_draw (widget);
    }
    return FALSE;
}

gboolean
on_volumebar_button_press_event        (GtkWidget       *widget,
                                        GdkEventButton  *event)
{
    GtkAllocation a;
    gtk_widget_get_allocation (widget, &a);
    if (event->button == 1) {
        float range = -deadbeef->volume_get_min_db ();
        float volume = (event->x - a.x)/ a.width * range - range;
        if (volume < -range) {
            volume = -range;
        }
        if (volume > 0) {
            volume = 0;
        }
        deadbeef->volume_set_db (volume);
        char s[100];
        int db = volume;
        snprintf (s, sizeof (s), "%s%ddB", db < 0 ? "" : "+", db);
        gtk_widget_set_tooltip_text (widget, s);
        gtk_widget_trigger_tooltip_query (widget);
//        DDB_VOLUMEBAR (widget)->show_dbs = 1;
        gtk_widget_queue_draw (widget);
    }
    return FALSE;
}


gboolean
on_volumebar_button_release_event      (GtkWidget       *widget,
                                        GdkEventButton  *event)
{
    if (event->button == 1) {
//        DDB_VOLUMEBAR (widget)->show_dbs = 0;
        gtk_widget_queue_draw (widget);
    }
  return FALSE;
}

gboolean
on_volumebar_scroll_event              (GtkWidget       *widget,
                                        GdkEventScroll        *event)
{
    float range = -deadbeef->volume_get_min_db ();
    float vol = deadbeef->volume_get_db ();
    if (event->direction == GDK_SCROLL_UP || event->direction == GDK_SCROLL_RIGHT) {
        vol += 1;
    }
    else if (event->direction == GDK_SCROLL_DOWN || event->direction == GDK_SCROLL_LEFT) {
        vol -= 1;
    }
    if (vol > 0) {
        vol = 0;
    }
    else if (vol < -range) {
        vol = -range;
    }
    deadbeef->volume_set_db (vol);
    gtk_widget_queue_draw (widget);
    char s[100];
    int db = deadbeef->volume_get_db ();
    snprintf (s, sizeof (s), "%s%ddB", db < 0 ? "" : "+", db);
    gtk_widget_set_tooltip_text (widget, s);
    gtk_widget_trigger_tooltip_query (widget);
    return FALSE;
}

gboolean
on_volumebar_configure_event (GtkWidget *widget, GdkEventConfigure *event) {
    gtkui_init_theme_colors ();
    return FALSE;
}

static gboolean
on_evbox_button_press_event          (GtkWidget       *widget,
                                        GdkEventButton  *event,
                                        gpointer         user_data)
{
    return gtk_widget_event (GTK_WIDGET (user_data), (GdkEvent *)event);
}

static gboolean
on_evbox_button_release_event        (GtkWidget       *widget,
                                        GdkEventButton  *event,
                                        gpointer         user_data)
{
    return gtk_widget_event (GTK_WIDGET (user_data), (GdkEvent *)event);
}

static gboolean
on_evbox_motion_notify_event         (GtkWidget       *widget,
                                        GdkEventMotion  *event,
                                        gpointer         user_data)
{
    return gtk_widget_event (GTK_WIDGET (user_data), (GdkEvent *)event);
}

static gboolean
on_evbox_scroll_event                (GtkWidget       *widget,
                                        GdkEvent        *event,
                                        gpointer         user_data) {
    return gtk_widget_event (GTK_WIDGET (user_data), (GdkEvent *)event);
}

void
ddb_volumebar_init_signals (DdbVolumeBar *vb, GtkWidget *evbox) {
  g_signal_connect ((gpointer) evbox, "button_press_event",
                    G_CALLBACK (on_evbox_button_press_event),
                    vb);
  g_signal_connect ((gpointer) evbox, "button_release_event",
                    G_CALLBACK (on_evbox_button_release_event),
                    vb);
  g_signal_connect ((gpointer) evbox, "scroll_event",
                    G_CALLBACK (on_evbox_scroll_event),
                    vb);
  g_signal_connect ((gpointer) evbox, "motion_notify_event",
                    G_CALLBACK (on_evbox_motion_notify_event),
                    vb);
}

