/*-
 * Copyright (c) 2011-2012       Scott Ringwelski <sgringwe@mtu.edu>
 *
 * Originally Written by Scott Ringwelski for BeatBox Music Player
 * BeatBox Music Player: http://www.launchpad.net/beat-box
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library 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
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */

public class Noise.TopDisplay : Gtk.Grid {
    Gtk.Label label;
    Gtk.Grid scale_grid;
    Gtk.Label leftTime;
    Gtk.Label rightTime;
    Gtk.Scale scale;
    Gtk.ProgressBar progressbar;
    Gtk.Button cancelButton;

    private bool is_seeking = false;
    private uint timeout_id = 0;
    
    public signal void scale_value_changed (Gtk.ScrollType scroll, double val);
    
    public TopDisplay() {
        width_request = 400;
        column_spacing = 6;

        label = new Gtk.Label ("");
        label.hexpand = true;
        scale = new Gtk.Scale.with_range (Gtk.Orientation.HORIZONTAL, 0, 1, 1000);
        scale.hexpand = true;
        leftTime = new Gtk.Label ("0:00");
        rightTime = new Gtk.Label ("0:00");
        progressbar = new Gtk.ProgressBar ();
        cancelButton = new Gtk.Button ();
        
        scale_grid = new Gtk.Grid ();

        leftTime.margin_right = rightTime.margin_left = 3;

        scale_grid.attach (leftTime, 0, 0, 1, 1);
        scale_grid.attach (scale, 1, 0, 1, 1);
        scale_grid.attach (rightTime, 2, 0, 1, 1);
        
        scale.set_draw_value (false);
        scale.can_focus = false;
        scale.hexpand = true;
        
        label.set_justify (Gtk.Justification.CENTER);
        label.set_single_line_mode (false);
        label.ellipsize = Pango.EllipsizeMode.END;
        
        cancelButton.set_image (Icons.PROCESS_STOP.render_image (Gtk.IconSize.MENU));
        cancelButton.set_relief (Gtk.ReliefStyle.NONE);
        cancelButton.halign = cancelButton.valign = Gtk.Align.CENTER;

        cancelButton.set_tooltip_text (_(STRING_CANCEL));

        // all but cancel
        var info = new Gtk.Grid ();
        info.attach (label, 0, 0, 1, 1);
        info.attach (progressbar, 0, 1, 1, 1);
        info.attach (scale_grid, 0, 1, 1, 1);
        
        attach (info, 0, 0, 1, 1);
        attach (cancelButton, 1, 0, 1, 1);
        
        cancelButton.clicked.connect (cancel_clicked);

        scale.button_press_event.connect (scale_button_press);
        scale.button_release_event.connect (scale_button_release);
        scale.value_changed.connect (value_changed);
        scale.change_value.connect (change_value);

        App.player.player.current_position_update.connect (player_position_update);
        
        App.player.changing_player.connect (() => {
            App.player.player.current_position_update.disconnect (player_position_update);
        });
        
        App.player.player_changed.connect (() => {
            App.player.player.current_position_update.connect (player_position_update);
        });
        
        var notification_manager = NotificationManager.get_default ();
        notification_manager.progressNotification.connect ((message, progress) => {
            if (message != null && progress >= 0.0 && progress <= 1.0)
                set_label_markup (message);

            set_progress_value (progress);
        });
        
        notification_manager.songNotification.connect ((message) => {
            if (message != null)
                this.set_label_markup (message);
        });
        libraries_manager.local_library.media_updated.connect(media_updated);
    }
    
    /** label functions **/
    public void set_label_text(string text) {
        label.set_text(text);
    }
    
    public void set_label_markup(string markup) {
        label.set_markup(markup);
    }
    
    public string get_label_text() {
        return label.get_text();
    }
    
    public void set_label_showing (bool val) {
        label.set_visible (val);
    }
    
    /** progressbar functions **/
    public void set_scale_sensitivity (bool val) {
        scale.set_sensitive(val);
        scale.set_visible(val);
        leftTime.set_visible(val);
        rightTime.set_visible(val);
    }
    
    // automatically shows/hides progress bar/scale based on progress's value
    public void set_progress_value (double progress) {
        if(progress >= 0.0 && progress < 1.0) {
            if(!progressbar.visible) {
                show_progressbar();
                set_label_showing(true);
            }
            
            progressbar.set_fraction(progress);
        }
        else {
            if(!scale.visible) {
                show_scale();
            }
        }
    }
    
    /** scale functions **/
    public void set_scale_range(double min, double max) {
        scale.set_range (min, max);
    }
    
    public void set_scale_value (double val) {
        scale.set_value (val);
    }
    
    public double get_scale_value () {
        return scale.get_value ();
    }
    
    public virtual bool scale_button_press(Gdk.EventButton event) {
        if (event.type != Gdk.EventType.BUTTON_PRESS) {
            return true;
        }

        App.player.player.current_position_update.disconnect (player_position_update);
        is_seeking = true;
        change_value (Gtk.ScrollType.NONE, get_current_time ());

        return false;
    }
    
    public virtual bool scale_button_release (Gdk.EventButton event) {
        is_seeking = false;

        change_value (Gtk.ScrollType.NONE, get_current_time ());
        
        return false;
    }

    public double get_current_time () {
        Gtk.Allocation extents;
        double point_x = 0;
        double point_y = 0;
        Gdk.ModifierType mask;
        unowned Gdk.Display display = Gdk.Display.get_default ();
        unowned Gdk.Window scale_window = scale.get_window ();
        unowned Gdk.DeviceManager device_manager = display.get_device_manager ();
        scale_window.get_device_position_double (device_manager.get_client_pointer (), out point_x, out point_y, out mask);
        scale.get_allocation (out extents);
        point_x = point_x - extents.x;
        if (point_x < 0)
            point_x = 0;

        // get miliseconds of media
        // calculate percentage to go to based on location
        return (double)point_x / (double)extents.width * scale.get_adjustment().upper;
    }
    
    public virtual void value_changed () {
        if (!scale.visible)
            return;

        double val = scale.get_value ();
        if (val < 0.0)
            val = 0.0;

        //make pretty current time
        uint elapsed_secs = (uint)val;
        leftTime.set_text (TimeUtils.pretty_length_from_ms (elapsed_secs));

        uint media_duration_secs = (uint)App.player.media_info.media.length;

        //make pretty remaining time
        rightTime.set_text (TimeUtils.pretty_length_from_ms (media_duration_secs - elapsed_secs));
    }
    
    public virtual bool change_value (Gtk.ScrollType scroll, double val) {
        App.player.player.current_position_update.disconnect(player_position_update);
        scale.set_value(val);
        scale_value_changed(scroll, val);

        if (timeout_id > 0)
                Source.remove (timeout_id);
 
        timeout_id = Timeout.add (300, () => {
            if( !is_seeking ) {
                App.player.player.set_position((int64) TimeUtils.miliseconds_to_nanoseconds ((uint) val));
                App.player.player.current_position_update.connect(player_position_update);
            }
            return Source.remove (timeout_id);
        });
        
        return false;
    }
    
    /** other functions **/
    public void show_scale() {
        scale_grid.set_no_show_all (false);
        scale_grid.show_all ();

        progressbar.set_no_show_all (true);
        progressbar.hide ();
                
        cancelButton.set_no_show_all (true);
        cancelButton.hide ();
    }
    
    public void show_progressbar() {
        scale_grid.set_no_show_all (true);
        scale_grid.hide();

        progressbar.set_no_show_all (false);
        progressbar.show_all ();
                
        cancelButton.set_no_show_all (false);
        cancelButton.show_all ();
    }

    public void hide_scale_and_progressbar() {
        scale_grid.set_no_show_all (true);
        scale_grid.hide();

        progressbar.set_no_show_all (true);
        progressbar.hide ();
                
        cancelButton.set_no_show_all (true);
        cancelButton.hide ();
    }
    
    public virtual void player_position_update (int64 position) {
        if (App.player.media_info.media != null) {
            set_scale_value ((double) TimeUtils.nanoseconds_to_miliseconds (position));
        }
    }

    public void cancel_clicked() {
        NotificationManager.get_default ().progress_canceled ();
    }

    public void set_media (Media current_media) {
        set_scale_range (0.0, (double)(current_media.length));
    }

    void media_updated (Gee.Collection<int> ids) {
        if (App.player.media_info == null)
            return;

        var current_media = App.player.media_info.media;

        if (current_media == null)
            return;

        // update current media
        foreach (var id in ids) {
            if (id == current_media.rowid)
                set_media (current_media);
        }
    }
}