#! /usr/bin/env perl

use strict;
use warnings;

use Proc::Fork;
use YAML::Any qw/LoadFile/;
use String::Format;
use URI;
use File::Spec;

use Glib qw/TRUE FALSE/;
use Gtk2 -init;
use Gtk2::WebKit;
use Gtk2::Gdk::Keysyms;

my %keysyms = %Gtk2::Gdk::Keysyms;

my $config = LoadFile("config.yml");

my $url = URI->new($ARGV[0] // $config->{homepage});
if (! $url->scheme) {
    my $path = $url->path;
    if (-r $path) {
        $url->path(File::Spec->rel2abs($path));
        $url->scheme('file');
    }
    else {
        $url = URI->new('http://' . $path);
    }
}

my $default_mod_mask = Gtk2::Accelerator->get_default_mod_mask;

my $win  = Gtk2::Window->new;
my $box = Gtk2::VBox->new(FALSE, FALSE);

my $entry;
if ($config->{interface}->{uri}) {
    $entry = Gtk2::Entry->new();
}
my $view = Gtk2::WebKit::WebView->new;
my $search = Gtk2::Entry->new();
my $status;
if ($config->{interface}->{status}) {
    $status = Gtk2::Statusbar->new;
}

$win->add($box);
$win->signal_connect(destroy => sub { Gtk2->main_quit });
$win->signal_connect('key-press-event', sub {
    my ($widget , $event) = @_;
    if ($event->state >= 'control-mask' && $event->keyval == $Gtk2::Gdk::Keysyms{'f'}) {
        $view->go_forward;
        return TRUE;
    }
    if ($event->state >= 'control-mask' && $event->keyval == $Gtk2::Gdk::Keysyms{'b'}) {
        $view->go_back;
        return TRUE;
    }
    if ($event->state >= 'control-mask' && $event->keyval == $Gtk2::Gdk::Keysyms{'s'}) {
        $search->grab_focus;
        return TRUE;
    }
    if ($event->state >= 'control-mask' && $event->keyval == $Gtk2::Gdk::Keysyms{'plus'}) {
        $view->zoom_in;
        return TRUE;
    }
    if ($event->state >= 'control-mask' && $event->keyval == $Gtk2::Gdk::Keysyms{'minus'}) {
        $view->zoom_out;
        return TRUE;
    }
    if ($event->state >= 'control-mask' && $event->keyval == $Gtk2::Gdk::Keysyms{'equal'}) {
        $view->set_zoom_level($config->{zoom});
        return TRUE;
    }
    if ($event->state >= 'control-mask' && $event->keyval == $Gtk2::Gdk::Keysyms{'KP_Add'}) {
        $view->zoom_in;
        return TRUE;
    }
    if ($event->state >= 'control-mask' && $event->keyval == $Gtk2::Gdk::Keysyms{'KP_Subtract'}) {
        $view->zoom_out;
        return TRUE;
    }
    if ($event->state >= 'control-mask' && $event->keyval == $Gtk2::Gdk::Keysyms{'KP_Equal'}) {
        $view->zoom_out;
        return TRUE;
    }

    return FALSE;
                     },
    );

if ($config->{interface}->{uri}) {
    $box->pack_start($entry, FALSE, FALSE, FALSE);
}
$box->pack_start_defaults($view);
if ($config->{interface}->{status}) {
    $box->pack_end($status, FALSE, FALSE, FALSE);
}
$box->pack_end($search, FALSE, FALSE, FALSE);
$box->show;

$entry->signal_connect('activate', sub {
    my ($widget, $label) = @_;
    my $text = $widget->get_text();
    $view->open($text);
                     },
    );
$entry->set_activates_default(TRUE);

my $selected_url;
my $hovering_cid;
if ($config->{interface}->{status}) {
    $view->signal_connect('hovering-over-link', sub {
        my ($widget, $unknown, $link) = @_;
        if (defined($link)) {
            if (defined($hovering_cid)) {
                $status->pop($hovering_cid);
            }
            $selected_url = $link;
            my $cid = $status->get_context_id($link);
            $status->push($cid, $link);
            $hovering_cid = $cid;
        }
        else {
            $status->pop($hovering_cid);
        }
                      },
        );
}
if ($config->{interface}->{uri}) {
    $view->signal_connect('load-finished', sub {
        my ($view , $frame) = @_;
        $entry->set_text($view->get_uri);
                          },
        );
}
$view->signal_connect('mime-type-policy-decision-requested', sub {
    my ($view, $frame, $request, $mime, $decision) = @_;
    if ($view->can_show_mime_type($mime)) {
        $decision->use;
    }
    else {
        print $mime;
        $decision->download;
    }
    return TRUE;
                      },
    );
$view->signal_connect('download-requested', sub {
    my ($view , $download) = @_;
    my $url = $download->get_uri;
    my $cmd = $config->{download}->{command};
    my $dir = $config->{download}->{directory};
    my %format = (
        'u' => $url,
        );
    $cmd = stringf($cmd, %format);
    system("cd " . $dir . "; " . $cmd);
                      },
    );
$view->signal_connect('new-window-policy-decision-requested', sub {
    my ($view, $frame, $request, $action, $decision) = @_;
    $selected_url = $request->get_uri;
    $decision->use;
    return TRUE;
                      },
    );
$view->signal_connect('create-web-view', sub {
    my ($view, $frame) = @_;
    run_fork { child { exec $0 . " " . $selected_url } };
    return undef;
                      }
    );
$view->set_zoom_level($config->{zoom});
$view->open($url->as_string);

$search->signal_connect('activate', sub {
    my ($widget, $label) = @_;
    my $text = $widget->get_text();
    if ($text) {
        $view->mark_text_matches($text, FALSE, 0);
        $view->set_highlight_text_matches(TRUE);
        $view->search_text($text, FALSE, FALSE, TRUE);
    }
    else {
        $view->unmark_text_matches();
    }
                        },
    );
$search->set_activates_default(TRUE);

$win->show_all;
Gtk2->main;

