#!/usr/bin/perl
# vim: set ts=4 sw=4 et :

use strict;
use Gtk2;
use Gtk2::Gdk::Keysyms;
use Cache::Memcached;
use Data::Dumper;

$Data::Dumper::Terse = 1;

my @cmds = ();
my $cmd_cur = -1;

my $mc = new Cache::Memcached {
    'servers' => [ "127.0.0.1:11211" ]
};

Gtk2->init;
my $win = Gtk2::Window->new("toplevel");
$win->signal_connect(delete_event => sub { Gtk2->main_quit });
$win->set_border_width(10);

my $vb = Gtk2::VBox->new(0, 5);
my $display = Gtk2::TextView->new;
my $buffer = $display->get_buffer;
$display->set_editable(0);
my $scroll = Gtk2::ScrolledWindow->new;
$scroll->set_policy('automatic', 'automatic');
$scroll->set_shadow_type('in');
$scroll->add($display);
$vb->pack_start($scroll, 1, 1, 0);

$display->modify_font(Gtk2::Pango::FontDescription->from_string("monospace"));
$buffer->create_tag("command", "foreground", "blue");
$buffer->create_tag("data", "foreground", "black");
$buffer->create_tag("error", "foreground", "red");

my $entry = Gtk2::Entry->new();
$entry->signal_connect(key_press_event => \&entry_keypress);
$entry->signal_connect(activate => \&entry_activate);
$vb->pack_start($entry, 0, 0, 0);

$win->add($vb);

$win->set_title("MemCachedClient");
$win->set_default_size(400, 500);
$win->signal_connect(show => sub { $entry->grab_focus });
$win->show_all;

Gtk2->main;

sub display {
    my ($level, $text) = @_;
    $buffer->insert_with_tags_by_name($buffer->get_end_iter, "$text\n", $level);
}

sub run_command {
    my ($text) = @_;
    
    # if we're rerunning a history command, then
    # we should pull it out of its old spot in the history.
    splice(@cmds, $cmd_cur, 1)
        if $cmd_cur >= 0 and $cmds[$cmd_cur] eq $text;
    # and in any case, add this command to the history.
    unshift(@cmds, $text);
    $cmd_cur = -1;

    display('command', $text);
    if ($text =~ /^get\s+(\S+)$/i) {
        my $str = $mc->get($1);
        if (ref $str) {
            $str = Dumper($str);
            $str =~ s/^        //gm;
        }
        if ($str) {
            display('data', $str);
        } else {
            display('error', "Not found.");
        }
    } elsif ($text =~ /^set\s+(\S+)\s+(.*)$/i) {
        my ($key, $val) = ($1, $2);
        if ($mc->set($key, $val)) {
            display('data', "Ok.");
        } else {
            display('error', "Not found.");
        }
    } elsif ($text =~ /^delete\s+(\S+)$/i) {
        $mc->delete($1);
        display('data', "Ok.");
    } else {
        display('error', "Unknown command '$text'.");
    }
}

sub entry_keypress {
    my ($entry, $ev) = @_;
    if ($ev->keyval == $Gtk2::Gdk::Keysyms{'Up'}) {
        $cmd_cur++ if $cmd_cur < @cmds-1;
        $entry->set_text($cmds[$cmd_cur]) if $cmds[$cmd_cur];
        return 1;
    } elsif ($ev->keyval == $Gtk2::Gdk::Keysyms{'Down'}) {
        $cmd_cur-- if $cmd_cur >= 0;
        if ($cmd_cur >= 0 and $cmds[$cmd_cur]) {
            $entry->set_text($cmds[$cmd_cur]);
        } else {
            $entry->set_text('');
        }
        return 1;
    }
    return 0;
}

sub entry_activate {
    my $text = $entry->get_text;
    if ($text =~ /\w/) {
        run_command($entry->get_text);
        $entry->set_text("");
    }
}

