//
//  Copyright (C) 2017 Santiago León O., Adam Bieńkowski
//
//  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 3 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, see <http://www.gnu.org/licenses/>.
//

public class Gala.Plugins.PIP.SelectionArea : CanvasActor {
    public signal void captured (int x, int y, int width, int height);
    public signal void selected (int x, int y);
    public signal void closed ();

    public Gala.WindowManager wm { get; construct; }

    private Gala.ModalProxy? modal_proxy;
    private Graphene.Point start_point;
    private Graphene.Point end_point;
    private bool dragging = false;
    private bool clicked = false;

    public SelectionArea (Gala.WindowManager wm) {
        Object (wm: wm);
    }

    construct {
        start_point = { 0, 0 };
        end_point = { 0, 0 };
        visible = true;
        reactive = true;

        int screen_width, screen_height;
        wm.get_display ().get_size (out screen_width, out screen_height);
        width = screen_width;
        height = screen_height;
    }

    public override bool key_press_event (Clutter.Event e) {
        if (e.get_key_symbol () == Clutter.Key.Escape) {
            close ();
            closed ();
            return true;
        }

        return false;
    }

    public override bool button_press_event (Clutter.Event e) {
        if (dragging || e.get_button () != Clutter.Button.PRIMARY) {
            return true;
        }

        clicked = true;

        float press_x, press_y;
        e.get_coords (out press_x, out press_y);
        start_point = { (int) press_x, (int) press_y};

        return true;
    }

    public override bool button_release_event (Clutter.Event e) {
        if (e.get_button () != Clutter.Button.PRIMARY) {
            return true;
        }

        if (!dragging) {
            float event_x, event_y;
            e.get_coords (out event_x, out event_y);
            selected ((int) event_x, (int) event_y);
            close ();
            return true;
        }

        dragging = false;
        clicked = false;

        int x, y, w, h;
        get_selection_rectangle (out x, out y, out w, out h);
        close ();
        start_point = { 0, 0 };
        end_point = { 0, 0 };
        this.hide ();
        content.invalidate ();

        captured (x, y, w, h);

        return true;
    }

    public override bool motion_event (Clutter.Event e) {
        if (!clicked) {
            return true;
        }

        float press_x, press_y;
        e.get_coords (out press_x, out press_y);
        end_point = { (int) press_x, (int) press_y};
        content.invalidate ();

        if (!dragging) {
            dragging = true;
        }

        return true;
    }

    public void close () {
#if HAS_MUTTER50
        set_cursor_type (Clutter.CursorType.DEFAULT);
#else
        wm.get_display ().set_cursor (Meta.Cursor.DEFAULT);
#endif

        if (modal_proxy != null) {
            wm.pop_modal (modal_proxy);
        }
    }

    public void start_selection () {
#if HAS_MUTTER50
        set_cursor_type (Clutter.CursorType.CROSSHAIR);
#else
        wm.get_display ().set_cursor (Meta.Cursor.CROSSHAIR);
#endif
        grab_key_focus ();

        modal_proxy = wm.push_modal (this, true);
    }

    private void get_selection_rectangle (out int x, out int y, out int width, out int height) {
        x = (int) float.min (start_point.x, end_point.x);
        y = (int) float.min (start_point.y, end_point.y);
        width = (int) (start_point.x - end_point.x).abs ();
        height = (int) (start_point.y - end_point.y).abs ();
    }

    protected override void draw (Cairo.Context ctx, int width, int height) {
        ctx.save ();

        ctx.set_operator (Cairo.Operator.CLEAR);
        ctx.paint ();

        ctx.restore ();

        if (!dragging) {
            return;
        }

        int x, y, w, h;
        get_selection_rectangle (out x, out y, out w, out h);

        ctx.rectangle (x, y, w, h);
        ctx.set_source_rgba (0.1, 0.1, 0.1, 0.2);
        ctx.fill ();

        ctx.rectangle (x, y, w, h);
        ctx.set_source_rgb (0.7, 0.7, 0.7);
        ctx.set_line_width (1.0);
        ctx.stroke ();
    }
}
