#   Copyright (c) 2006-8 Martin Schulze <joey@infodrom.org>
#
#   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; version 2 dated June, 1991.
#
#   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, USA.

use strict;
use warnings;

package GAK::GUI;

use Glib qw/TRUE FALSE/;
use Gtk2;
use Gtk2::Gdk::Keysyms;

use GAK::Backend;

my $about = undef;
my $list = undef;
my $details = undef;
my $tooltips = undef;
my $accels = undef;
my $key_menu = undef;

sub file_menu
{
    my $menu = new Gtk2::Menu;

    my $item = new Gtk2::MenuItem (_('_Import File'));
    $item->signal_connect ('activate', \&callback_import);
    $item->show;
    $menu->append ($item);

    $item = new Gtk2::MenuItem (_('_Update Keys'));
    $item->signal_connect ('activate', \&callback_update);
    $item->show;
    $menu->append ($item);

    $item = new Gtk2::MenuItem (_('E_xit'));
    $item->signal_connect ('activate', sub {Gtk2->main_quit});
    $item->show;
    $item->add_accelerator (activate => $accels,
                                  $Gtk2::Gdk::Keysyms{'Q'},
                                  'control-mask', 'visible');
    $menu->append ($item);

    $menu->show;

    return $menu;
}

sub key_menu
{
    my $menu = new Gtk2::Menu;

    my $item = new Gtk2::MenuItem (_('_Properties...'));
    $item->signal_connect ('activate', \&callback_properties);
    $item->show;
    $menu->append ($item);

    $item = new Gtk2::MenuItem (_('_Delete'));
    $item->signal_connect ('activate', \&callback_delete);
    $item->show;
    $menu->append ($item);

    $menu->show;

    return $menu;
}

sub help_menu
{
    my $menu = new Gtk2::Menu;

    my $item = new Gtk2::MenuItem (_('_About'));
    $item->signal_connect ('activate', \&callback_about);
    $item->show;
    $menu->append ($item);

    $menu->show;

    return $menu;
}

sub menubar
{
    my $menubar = new Gtk2::MenuBar;

    my $file_menu = file_menu;
    my $file_item = new Gtk2::MenuItem (_('_File'));
    $file_item->show;
    $file_item->set_submenu ($file_menu);

    $key_menu = key_menu;
    my $key_item = new Gtk2::MenuItem (_('_Key'));
    $key_item->show;
    $key_item->set_submenu ($key_menu);

    my $help_menu = help_menu;
    my $help_item = new Gtk2::MenuItem (_('_Help'));
    $help_item->set_right_justified (TRUE);
    $help_item->show;
    $help_item->set_submenu ($help_menu);

    $menubar->append ($file_item);
    $menubar->append ($key_item);
    $menubar->append ($help_item);
    $menubar->show;

    return $menubar;
}

sub fill_store
{
    my ($name, $expiry);
    foreach (keylist) {
	if ($_->[1] eq '-') {
	    if ($_->[2]) {
		$expiry = sprintf (_('valid until %s'), $_->[2]);
	    } else {
		$expiry = _('no expiration');
	    }
	} elsif ($_->[1] eq 'e') {
	    $expiry = sprintf (_('expired %s'), $_->[2]);
	} else {
	    $expiry = _('unknown expiration');
	}
	$name = $_->[3];
	$name =~ s/\s*<.*>//;

	$list->get_model->set ($list->get_model->append, 0 => $_->[0], 1 => $name, 2 => $expiry);
    }
}

sub details
{
    my $dialog = new Gtk2::Dialog;

    $dialog->set_default_size (300, 200);
    $dialog->signal_connect ('delete_event', sub { $_[0]->hide; return TRUE; });

    my $button = new_from_stock Gtk2::Button ('gtk-close');
    $button->signal_connect ('clicked', sub { $details->hide });
    $dialog->action_area->add ($button);
    $button->show;

    my $frame = new Gtk2::Frame ('dummy');
    $frame->set_border_width (5);

    my $text = new Gtk2::TextView;
    $text->set_editable (FALSE);
    $text->set_cursor_visible (FALSE);
    $text->set_border_width (5);
    my $buffer = $text->get_buffer;
    $buffer->insert_at_cursor ('nothing');
    $text->show;

    # Warning: This is a little bit crude...
    $dialog->{'text'} = $text;
    $dialog->{'frame'} = $frame;

    $frame->add ($text );
    $frame->show;
    $dialog->vbox->add ($frame);

    return $dialog;
}

sub callback_import
{
    my $chooser = new Gtk2::FileChooserDialog (_('Select keyring file'),
					       undef, 'open',
					       'gtk-cancel' => 'cancel',
					       'gtk-ok' => 'ok');

    if ($chooser->run eq 'ok') {
	if (do_add ($chooser->get_filename)) {
	    $list->get_model->clear;
	    fill_store;
	}
    }

    $chooser->destroy;
}

#
# Callback from the File menu
#
sub callback_properties
{
    my $iter = $list->get_selection->get_selected;
    return unless $iter;

    my $key = $list->get_model->get ($iter, 0);
    return unless $key;

    open_details_dialog ($key);
}

#
# Callback from the File menu
#
sub callback_delete
{
    my $iter = $list->get_selection->get_selected;
    return unless $iter;

    my $key = $list->get_model->get ($iter, 0);
    return unless $key;

    do_delete ($key);

    $list->get_model->clear;
    fill_store;
}

#
# Callback from the main window
#
sub callback_delete_list
{
    my $iter = $list->get_selection->get_selected;
    return unless $iter;

    my $key = $list->get_model->get ($iter, 0);
    return unless $key;

    do_delete ($key);
    $list->get_model->clear;
    fill_store;
}

sub callback_about
{
    $about = new Gtk2::AboutDialog;
    $about->set_name (_('APT Key Manager'));
    $about->set_website_label ('http://www.infodrom.org/projects/gak/');
    $about->set_authors ('Joey Schulze <joey@infodrom.org>');
    $about->set_copyright ('(c) 2006-8 Joey Schulze <joey@infodrom.org>');
    $about->set_license (q{Copyright (c) 2006-8 Martin Schulze <joey@infodrom.org>

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; version 2 dated June, 1991.

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, USA.});
    $about->set_translator_credits (q{Andre Luis Lopes <andrelop@debian.org>
Arif E. Nugroho <arif_endro@yahoo.com>
Attila Szervac <sas@321.hu>
Bart Cornelis <cobaco@skolelinux.no>
Clytie Siddall <clytie@riverland.net.au>
Damyan Ivanov <dam@modsoftsys.com>
Daniel Nylander <po@danielnylander.se>
Eddy Petrisor <eddy.petrisor@gmail.com>
Fred Maranhao <fred.maranhao@gmail.com>
Giuseppe Sacco <eppesuig@debian.org>
Hans Fredrik Nordhaug <hans@nordhaug.priv.no>
Jacobo Tarrio <jtarrio@debian.org>
Jarek Kaminski <jarek@vilo.eu.org>
Javier Fernandez-Sanguino <jfs@debian.org>
Joey Schulze <joey@infodrom.org>
Jordi Mallach <jordi@debian.org>
Jussi Aalto <jta_wdo@dnainternet.net>
Kaare Olsen <kaare@nightcall.dk>
Kartik Mistry <kartik.mistry@gmail.com>
Kenshi Muto <kmuto@debian.org>
Khoem Sokhem <khoemsokhem@khmeros.info>
Miguel Figueiredo <elmig@debianpt.org>
Ming Hua <minghua-guest@users.alioth.debian.org>
Miroslav Kure <kurem@debian.cz>
Peter Mann <Peter.Mann@tuke.sk>
Petter Reinholdtsen <pere@hungry.com>
Piarres Beobide <pi@beobide.net>
Recai Oktaas <roktas@debian.org>
Safir Secerovic <sapphire@linux.org.ba>
Stefano Canepa <sc@linux.it>
Steve Petruzzello <dlist@bluewin.ch>
Theppitak Karoonboonyanan <thep@linux.thai.net>
Woo-il Song <bemess@gmail.com>
Yuri Kozlov <kozlov.y@gmail.com>});

    $about->run;
    $about->destroy;
}

sub callback_list
{
    my ($list, $event) = @_;

    if ($event->type eq '2button-press') {
        # my $row = $list->get_selection->get_selected_rows->to_string;

	my $iter = $list->get_selection->get_selected;
	my $key = $list->get_model->get ($iter, 0);

	open_details_dialog ($key);
    } elsif ($event->button == 3) {
	$key_menu->popup(
			 undef, # parent menu shell
			 undef, # parent menu item
			 undef, # menu pos func
			 undef, # data
			 $event->button,
			 $event->time
			 );
    }
}

sub callback_add
{
    my $button_or_entry = shift;
    my $entry;

    if ($button_or_entry->isa('Gtk2::Button')) {
	$entry = $button_or_entry->{'entry'};
    } elsif ($button_or_entry->isa('Gtk2::Entry')) {
	$entry = $button_or_entry;
    } else {
	die "Unknown argument for callback_add()";
    }

    my $key = $entry->get_text;
    if ((my $result = fetchkey ($key))) {
	my $dialog = Gtk2::MessageDialog->new (undef,
					       'destroy-with-parent',
					       'question', # message type
					       'ok-cancel', # which set of buttons?
					       _("Key ID") . " " . $result->{keyid} . "\n" .
					       _("Fingerprint:") . "\n" .
					       $result->{fingerprint} . "\n\n" .
					       _("Add this key to the keyring?"));
	if ($dialog->run eq 'ok') {
	    if (do_add ($result->{fname})) {
		$entry->set_text ('');
		$list->get_model->clear;
		fill_store;
	    }
	}
	$dialog->destroy;
    } else {
	my $dialog = Gtk2::MessageDialog->new (undef,
					       'destroy-with-parent',
					       'error', # message type
					       'ok', # which set of buttons?
					       sprintf(_("The key with ID %s could not be imported."), $key));
	$dialog->run;
	$dialog->destroy;
    }
}

sub callback_update
{
    do_update;

    $list->get_model->clear;
    fill_store;
}

sub callback_entry
{
    my $entry = shift;
    my $text = $entry->get_text;

    if (length($text) > 7 && $text =~ /^(0x)?[a-f0-9]*$/i) {
	$entry->{'button'}->set_sensitive (TRUE);
    } else {
	$entry->{'button'}->set_sensitive (FALSE);
    }
}

sub keywindow
{
    my $scroll = new Gtk2::ScrolledWindow (undef, undef);
    $scroll->set_policy ('automatic', 'automatic' );
    $scroll->set_shadow_type ('etched-in');

    my $store = new Gtk2::ListStore (('Glib::String')x3);

    $list = new_with_model Gtk2::TreeView ($store);
    $list->get_selection->set_mode ('single');
    $list->signal_connect ('button_press_event', \&callback_list);
    $scroll->add_with_viewport ($list);

    my $column = new_with_attributes Gtk2::TreeViewColumn (_('Keys'), Gtk2::CellRendererText->new, 'text' => 1);
    $column->set_min_width (250);
    $column->set_resizable (TRUE);
    $list->append_column ($column);
    $column = new_with_attributes Gtk2::TreeViewColumn (_('Expiration'), Gtk2::CellRendererText->new, 'text' => 2);
    $column->set_min_width (70);
    $column->set_resizable (TRUE);
    $list->append_column ($column);

    fill_store;

    return $scroll;
}

sub controlbox
{
    my $box = new Gtk2::HBox (FALSE, 0);

    my $label = new Gtk2::Label (_('Key ID'));
    $label->show;

    my $entry = new_with_max_length Gtk2::Entry (25);
    $entry->signal_connect ('activate', \&callback_add);
    $entry->signal_connect ('changed', \&callback_entry);
    $entry->show;

    my $button = new_from_stock Gtk2::Button ('gtk-add');
    # Warning: This is a little bit crude...
    $button->{'entry'} = $entry;
    $entry->{'button'} = $button;
    $button->signal_connect ('clicked', \&callback_add);
    $button->set_sensitive (FALSE);
    $tooltips->set_tip ($button, _('Add key to the keyring'));
    $button->show;

    my $update = new_from_stock Gtk2::Button ('gtk-refresh');
    $update->signal_connect ('clicked', \&callback_update);
    $tooltips->set_tip ($update, _('Update keys using the keyring package'));
    $update->show;

    my $hbox = new Gtk2::HBox (TRUE, 6);
    # $hbox->pack_start ($update, FALSE, FALSE, 2);
    $hbox->add ($update);
    $hbox->show;

    $box->pack_start ($label, FALSE, FALSE, 2);
    $box->pack_start ($entry, FALSE, FALSE, 2);
    $box->pack_start ($button, FALSE, FALSE, 2);
    $box->pack_end ($hbox, TRUE, FALSE, 2);
    $box->show;

    return $box;
}

sub open_details_dialog
{
    my $key = shift;

    $details = details unless defined $details;

    $details->set_title (_('Key Details'));
    $details->{'frame'}->set_label (sprintf (_('Details of 0x%s'), substr ($key, length($key)-8, 8)));
    $details->{'key'} = $key;

    my @keys = keydetails ($key);
    my @k = @{$keys[0]};

    my $name = $k[9];
    my $mail = $k[9];
    $name =~ s/\s*<.*>//;
    $mail =~ s/.*<(.*)>/$1/;

    my $info = $name . "\n";
    $info .= _('Owner').': ' . $mail . "\n";
    $info .= _('Key ID').': 0x' . substr ($k[4], length ($k[4])-8, 8) . "\n";
    if ($k[1] eq 'e') {
	$info .= sprintf (_('Key expired on %s'), $k[6]) . "\n";
    } elsif ($k[1] eq '-' && $k[6]) {
	$info .= sprintf (_('Key valid until %s'), $k[6]) . "\n";
    }
    $info .= _('Full ID: ') . substr ($k[4], 0, 4) . 
	" " . substr ($k[4], 4, 4) . 
	" " . substr ($k[4], 8, 4) . 
	" " . substr ($k[4], 12, 4) . "\n";
    $info .= _('Fingerprint:') . "\n" .
	fingerprint ($key);

    my $buffer = $details->{'text'}->get_buffer;
    my ($start, $end) = $buffer->get_bounds;
    $buffer->delete ($start, $end);
    $buffer->insert_at_cursor ($info);

    $details->show;
}

sub new
{
    $tooltips = new Gtk2::Tooltips;
    $tooltips->enable;

    $accels = new Gtk2::AccelGroup;

    my $window = new Gtk2::Window;
    $window->add_accel_group ($accels);
    $window->set_title (_('APT Key Manager'));
    $window->set_default_size (600, 210);

    $window->signal_connect ('destroy', sub {Gtk2->main_quit} );

    my $mainbox = new Gtk2::VBox (FALSE, 0);

    my $menubar = menubar;
    my $keylist = keywindow;
    my $control = controlbox;

    $mainbox->pack_start ($menubar, FALSE, FALSE, 0);
    $mainbox->add ($keylist);
    $mainbox->pack_end ($control, FALSE, FALSE, 0);

    $mainbox->show;
    $window->add ($mainbox);

    return $window;
}

#
# Make Perl happy
#
1;
