Index: /trunk/BookmarkApp.pm
===================================================================
--- /trunk/BookmarkApp.pm	(revision 5)
+++ /trunk/BookmarkApp.pm	(revision 5)
@@ -0,0 +1,177 @@
+package BookmarkApp;
+use strict;
+use warnings;
+use base qw{CGI::Application};
+
+use DBI;
+use Encode;
+use JSON;
+use Template;
+use Bookmarks;
+
+my $template = Template->new;
+
+my $dbname = 'new.db';
+my $dbh = DBI->connect("dbi:SQLite:dbname=$dbname", "", "", { RaiseError => 1 });
+my $bookmarks = Bookmarks->new({
+    dbh => $dbh,
+});
+
+sub setup {
+    my $self = shift;
+    $self->mode_param(path_info => 1);
+    $self->run_modes([qw{
+        list
+        view
+        edit
+    }]);
+}
+
+sub list {
+    my $self = shift;
+    my $q = $self->query;
+
+    # check for a uri param, and if there is one present,
+    # see if a bookmark for that URI already exists
+    if (defined(my $uri = $q->param('uri'))) {
+        my $bookmark = $bookmarks->get_bookmark({ uri => $uri });
+        if ($bookmark) {
+            # redirect to the view of the existing bookmark
+            $self->header_type('redirect');
+            $self->header_props(
+                -uri => $q->url . '/' . $bookmark->{id},
+            );
+            return;
+        } else {
+            # bookmark was not found; show the form to create a new bookmark
+            $bookmark->{uri} = $uri;
+            $bookmark->{title} = $q->param('title');
+            $self->header_props(
+                -type    => 'text/html',
+                -charset => 'UTF-8',
+                -status  => 404,
+            );
+            $template->process(
+                'bookmark.tt',
+                $bookmark,
+                \my $output,
+            );
+            return $output;
+        }
+    }
+
+    # list all the bookmarks 
+    my $format = $q->param('format') || 'html';
+    my $tag = $q->param('tag');
+    my @resources = $bookmarks->get_resources({ tag => $tag });
+    my @all_tags = $bookmarks->get_tags({ selected => $tag });
+    my @cotags = $bookmarks->get_cotags({ tag => $tag });
+
+    if ($format eq 'json') {
+        $self->header_props(
+            -type    => 'application/json',
+            -charset => 'UTF-8',
+        );
+        return decode_utf8(
+            encode_json({
+                resources => \@resources,
+            })
+        );
+    } else {
+        $self->header_props(
+            -type    => 'text/html',
+            -charset => 'UTF-8',
+        );
+
+        # set the base URL, adding a trailing slash if needed
+        my $base_url = $q->url;
+        $base_url .= '/' if $base_url =~ m{/bookmarks$};
+
+        $template->process(
+            'list.tt',
+            {
+                base_url     => $base_url,
+                selected_tag => $tag,
+                tags         => \@all_tags,
+                cotags       => \@cotags,
+                resources    => \@resources,
+            },
+            \my $output,
+        );
+        return $output;
+    }
+}
+
+sub view {
+    my $self = shift;
+    my $id = $self->param('id');
+    my $field = $self->param('field');
+
+    my $bookmark = $bookmarks->get_bookmark({ id => $id });
+    if ($bookmark) {
+        if ($field) {
+            # respond with just the requested field as plain text
+            $self->header_props(
+                -type    => 'text/plain',
+                -charset => 'UTF-8',
+            );
+            my $value = $bookmark->{$field};
+            return ref $value eq 'ARRAY' ? join(',', @{ $value }) : $value;
+        } else {
+            # display the bookmark form for this bookmark
+            $bookmark->{exists} = 1;
+            $bookmark->{created} = "Created " . localtime($bookmark->{ctime});
+            $bookmark->{created} .= '; Updated ' . localtime($bookmark->{mtime}) unless $bookmark->{ctime} == $bookmark->{mtime};
+            $self->header_props(
+                -type    => 'text/html',
+                -charset => 'UTF-8',
+            );
+            $template->process(
+                'bookmark.tt',
+                $bookmark,
+                \my $output,
+            );
+            return $output;
+        }
+    } else {
+        $self->header_props(
+            -type    => 'text/html',
+            -charset => 'UTF-8',
+            -status  => 404,
+        );
+        return "Bookmark $id Not Found";
+    }
+}
+
+#TODO: split this into edit and create methods
+sub edit {
+    my $self = shift;
+    my $q = $self->query;
+    #TODO: get the bookmark based on the id and edit it directly?
+    #TODO: deal with changing URIs
+    my $uri = $q->param('uri');
+    my $title = $q->param('title');
+    my @tags = split ' ', $q->param('tags');
+    $bookmarks->add({
+        uri   => $uri,
+        title => $title,
+        tags  => \@tags,
+    });
+
+=begin
+
+    my $location = URI->new($q->url);
+    $location->query_form(uri => $uri) if defined $q->url_param('uri');
+    $location->fragment('updated');
+
+=cut
+
+    # return to the form
+    $self->header_type('redirect');
+    $self->header_props(
+        -uri => $ENV{REQUEST_URI},
+        -status => 303,
+    );
+}
+
+1;
Index: /trunk/index.cgi
===================================================================
--- /trunk/index.cgi	(revision 4)
+++ /trunk/index.cgi	(revision 5)
@@ -1,161 +1,14 @@
 #!/usr/bin/perl -w
 use strict;
-
-use Encode;
-use URI;
-use CGI;
-use YAML;
-use DBI;
-use Template;
-use JSON;
-use Bookmarks;
-
-my $q = CGI->new;
-my $template = Template->new;
-
-my $method = $ENV{REQUEST_METHOD};
 
 # bookmarklet to add a bookmark via the browser
 # javascript:(function(){window.open("http://grim.ath.cx/~peter/bookmarks?uri="+document.location+"&title="+document.title,"edit_bookmark","width=800,height=250")})()
 
-my $dbname = 'new.db';
-my $dbh = DBI->connect("dbi:SQLite:dbname=$dbname", "", "", { RaiseError => 1 });
-
-my $bookmarks = Bookmarks->new({
-    dbh => $dbh,
-});
-
-=begin new style?
-
-if ($ENV{PATH_INFO} =~ m{^/(\d+)(?:/(uri|title|tags))?\b}) {
-    require Resource::Bookmark;
-    my $resource = Resource::Bookmark->new({
-        q => $q,
-        id => $1,
-        field => $2,
-        bookmarks => $bookmarks,
-    });
-    $resource->$method();
-}
-exit;
-
-=cut
-
-my %resource = (
-    GET => sub {
-        my ($q, $dbh) = @_;
-        if ($ENV{PATH_INFO} =~ m{^/(\d+)(?:/(uri|title|tags))?\b}) {
-            my $id = $1;
-            my $field = $2;
-            my $bookmark = $bookmarks->get_bookmark({ id => $id });
-            if ($bookmark) {
-                if ($field) {
-                    print $q->header(
-                        -type    => 'text/plain',
-                        -charset => 'UTF-8',
-                    );
-                    my $value = $bookmark->{$field};
-                    print ref $value eq 'ARRAY' ? join(',', @{ $value }) : $value;
-                } else {
-                    $bookmark->{exists} = 1;
-                    $bookmark->{created} = "Created " . localtime($bookmark->{ctime});
-                    $bookmark->{created} .= '; Updated ' . localtime($bookmark->{mtime}) unless $bookmark->{ctime} == $bookmark->{mtime};
-                    print $q->header(
-                        -type    => 'text/html',
-                        -charset => 'UTF-8',
-                    );
-                    $template->process(
-                        'bookmark.tt',
-                        $bookmark
-                    );
-                }
-            } else {
-                print $q->header(
-                    -type    => 'text/html',
-                    -charset => 'UTF-8',
-                    -status  => 404,
-                );
-                print "Not Found";
-            }
-        } elsif (defined(my $uri = $q->param('uri'))) {
-            my $bookmark = $bookmarks->get_bookmark({ uri => $uri });
-            if ($bookmark) {
-                #TODO: is there a better base URL to use?
-                print $q->redirect($q->url . '/' . $bookmark->{id});
-            } else {
-                # bookmark was not found; show the form to create a new bookmark
-                $bookmark->{uri} = $uri;
-                $bookmark->{title} = $q->param('title');
-                print $q->header(
-                    -type    => 'text/html',
-                    -charset => 'UTF-8',
-                    -status  => 404,
-                );
-                $template->process(
-                    'bookmark.tt',
-                    $bookmark
-                );
-            }
-        } else {
-            # list all the bookmarks 
-            my $format = $q->param('format') || 'html';
-            my $tag = $q->param('tag');
-            my @resources = $bookmarks->get_resources({ tag => $tag });
-            my @all_tags = $bookmarks->get_tags({ selected => $tag });
-            my @cotags = $bookmarks->get_cotags({ tag => $tag });
-
-            if ($format eq 'json') {
-                print $q->header(
-                    -type    => 'application/json',
-                    -charset => 'UTF-8',
-                );
-                print decode_utf8(
-                    encode_json({
-                        resources => \@resources,
-                    })
-                );
-            } else {
-                print $q->header(
-                    -type    => 'text/html',
-                    -charset => 'UTF-8',
-                );
-
-                # set the base URL, adding a trailing slash if needed
-                my $base_url = $q->url;
-                $base_url .= '/' if $base_url =~ m{/bookmarks$};
-
-                $template->process(
-                    'list.tt',
-                    {
-                        base_url     => $base_url,
-                        selected_tag => $tag,
-                        tags         => \@all_tags,
-                        cotags       => \@cotags,
-                        resources    => \@resources,
-                    },
-                );
-            }
-        }
-    },
-    POST => sub {
-        #TODO: deal with changing URIs
-        my ($q, $dbh) = @_;
-        my $uri = $q->param('uri');
-        my $title = $q->param('title');
-        my @tags = split ' ', $q->param('tags');
-        $bookmarks->add({
-            uri   => $uri,
-            title => $title,
-            tags  => \@tags,
-        });
-
-        my $location = URI->new($q->url);
-        $location->query_form(uri => $uri) if defined $q->url_param('uri');
-        $location->fragment('updated');
-        print $q->redirect($ENV{REQUEST_URI}); #$location);
-    },
+use CGI::Application::Dispatch;
+CGI::Application::Dispatch->dispatch(
+    table => [
+        '[get]'              => { app => 'BookmarkApp', rm => 'list' },
+        ':id/:field?[get]'   => { app => 'BookmarkApp', rm => 'view' },
+        ':id?[post]'         => { app => 'BookmarkApp', rm => 'edit' },
+    ],
 );
-
-$resource{$method}->($q, $dbh);
-
-
