#!/usr/bin/perl
# Gournal - A notetaking app for TabletPCs running linux
# Version 0.4.1
# Copyright (C) 2004 Chris Debenham <chris@adebenham.com>
#
# 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 2 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, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
#
#

# Bring in what we need
use strict;
use Gtk2 -init;
use Gtk2::GladeXML;
use Gtk2::Helper;
use Gnome2::Canvas;
use Gnome2::Print;
use IO::Socket;
use Compress::Zlib;
use XML::Mini::Document;
use Data::Dumper;

# Setup constants
use constant TRUE  => 1;
use constant FALSE => 0;

# Brush Types
use constant NORMAL => 0;
use constant TEXT   => 1;
use constant DATE   => 2;
use constant HILITE => 3;
use constant ERASE  => 4;
use constant IMAGE  => 5;

# Setup variables
my ($globals);
$globals->{'basedir'}   = $ENV{HOME} . "/.gournal/";
$globals->{'sharedir'}  = "/usr/share/gournal/";
$globals->{'prefs'}     = $globals->{'basedir'} . "config";
$globals->{'gladefile'} = $globals->{'sharedir'} . "gournal.glade";

# Initialise values/defaults
$globals->{'DEBUG'}              = FALSE;
$globals->{'oldx'}               = -100;
$globals->{'oldy'}               = -100;
$globals->{'movement_flag'}      = FALSE;
$globals->{'brush_width'}        = 2;
$globals->{'brush_color'}        = 0x000000ff;
$globals->{'tool_type'}          = NORMAL;
$globals->{'canvas_text'}        = 0;
$globals->{'canvas_image'}       = 0;
$globals->{'changed_flag'}       = FALSE;
$globals->{'server_port'}        = 5505;
$globals->{'client_flag'}        = FALSE;
$globals->{'server_flag'}        = FALSE;
$globals->{'signal_freeze_flag'} = TRUE;
$globals->{'font'}               = "Sans 40";
$globals->{'pagewidth'}          = 900;
$globals->{'pageheight'}         = 1300;
$globals->{'current_page'}       = "";
$globals->{'line_spacing'}       = 40;
$globals->{'tmpdir'}             = $ENV{HOME} . "/Documents";
$globals->{'tmpfont'}            = $globals->{'font'};
$globals->{'tmpwidth'}           = $globals->{'pagewidth'};
$globals->{'tmpheight'}          = $globals->{'pageheight'};
$globals->{'tmpspacing'}         = $globals->{'line_spacing'};
$globals->{'lastid'}             = 0;
my (@xv, @yv, @line, @hosts, @favourites);
my ($io_id);

# Structures that will contain all the pages, svg and items
my ($pages, %svg, %canvasitem);

# Check commandline arguments
if ($ARGV[0]) {
    foreach (0 .. (@ARGV - 1)) {
        if ($ARGV[$_] eq "-d") {
            $globals->{'DEBUG'} = TRUE;
        }
    }
}

# Load GUI
my $mainxml = Gtk2::GladeXML->new($globals->{'gladefile'}, 'windowMain');
$mainxml->signal_autoconnect_from_package('');
$mainxml->get_widget('windowMain')
  ->signal_connect("key_press_event", \&handle_key);
my $sectionTabs = Gtk2::Notebook->new;
$sectionTabs->popup_enable;
$sectionTabs->set_scrollable(TRUE);
$sectionTabs->set_tab_pos('top');
$mainxml->get_widget('vboxMain')->add($sectionTabs);

if (!-e $globals->{'basedir'}) {
    mkdir $globals->{'basedir'}, 0777;
}

load_prefs();

$globals->{'server_port'} = $ARGV[0];
my $OUTPORT = $ARGV[1];
my $found   = "";
load_dir("");
opendir(DIR, $globals->{'svgdir'});
foreach (sort (readdir(DIR))) {
    if (!($_ =~ /^\./)) {
        if (-d $globals->{'svgdir'} . $_) {
            load_dir($_);
        }
    }
}
closedir DIR;

# If no existing pages then create a new blank one
if ($found eq "") {
    my $newpage = add_page("", "Main");
    set_page("Main", $newpage);
} else {
    my ($section, $page) = split(/\//, $found, 2);
    $page =~ s/\.svgz$//g;
    set_page($section, $page);
}
$sectionTabs->signal_connect_after(switch_page => \&switch_section, undef);
$globals->{'signal_freeze_flag'} = FALSE;
$mainxml->get_widget('buttonBlack')->set_active(TRUE);

if (!$globals->{'DEBUG'}) {
    $mainxml->get_widget('windowMain')->maximize;
}

#turn_on_server();

# Gtk event loop
Gtk2->main;

# Should never get here
exit(0);

####
## Helper functions
####

# Only show debug output if in debug mode
sub debug {
    my $text = shift;
    if ($globals->{'DEBUG'}) {
        print $text. "\n";
    }
}

####
## Interface handling functions
####

# Confirm if the user wants to close us
sub close_main {
    my $xml =
      Gtk2::GladeXML->new($globals->{'gladefile'}, 'dialogConfirmClose');
    $xml->signal_autoconnect_from_package('');
    if (!$globals->{'changed_flag'}) {
        $xml->get_widget('buttonCloseSave')->hide();
    }
    return TRUE;
}

# Check if anything has changed, if so offer to save, otherwise close
sub destroy_main {
    if ($globals->{'changed_flag'}) {
        my $xml =
          Gtk2::GladeXML->new($globals->{'gladefile'}, 'dialogConfirmClose');
        $xml->signal_autoconnect_from_package('');
        $xml->get_widget('buttonCloseCancel')->hide();
    } else {
        exit_confirmed();
    }
    return TRUE;
}

# Exit has been confirmed so quit now
sub exit_confirmed {
    my $pagenum = 0;
    while (Gtk2->events_pending) {
        Gtk2->main_iteration;
    }
    Gtk2->main_quit;
    return FALSE;
}

# Save the current page and exit
sub exit_and_save {
    save_page($globals->{'current_page'});
    exit_confirmed();
}

# Cancel current dialog
sub cancel_dialog {
    my ($widget) = @_;
    $widget->get_toplevel->destroy();
}

# Create a preferences dialog
sub setup_gournal {
    $globals->{'prefs_xml'} =
      Gtk2::GladeXML->new($globals->{'gladefile'}, 'dialogPrefs');
    $globals->{'prefs_xml'}->signal_autoconnect_from_package('');

    # Don't allow cancel if there is no existing prefs
    $globals->{'prefs_xml'}->get_widget('spinWidth')
      ->set_value($globals->{'pagewidth'});
    $globals->{'prefs_xml'}->get_widget('spinHeight')
      ->set_value($globals->{'pageheight'});
    $globals->{'prefs_xml'}->get_widget('spinSpacing')
      ->set_value($globals->{'line_spacing'});
    $globals->{'prefs_xml'}->get_widget('entryFont')
      ->set_text($globals->{'font'});
    $globals->{'prefs_xml'}->get_widget('entryDocDirectory')
      ->set_text($ENV{HOME} . "/Gournal");
    my $store = $globals->{'prefs_xml'}->get_widget('treeHosts')->get_model();
    if ($store) {
        $store->clear;
    } else {
        $store = Gtk2::ListStore->new('Glib::String');
        $globals->{'prefs_xml'}->get_widget('treeHosts')->set_model($store);
        my $renderer = Gtk2::CellRendererText->new;
        $renderer->set(editable => TRUE);
        $renderer->signal_connect(edited => \&edit_favourite);
        my $column =
          Gtk2::TreeViewColumn->new_with_attributes("Hosts", $renderer,
            text => 0);
        $globals->{'prefs_xml'}->get_widget('treeHosts')
          ->append_column($column);
    }
    foreach my $item (@favourites) {
        $store->set($store->append, 0, $item);
        deubg("Favourite $item");
    }
    my $response = $globals->{'prefs_xml'}->get_widget('dialogPrefs')->run();
    if ($response eq "ok") {
        open(PREFS, ">" . $globals->{'prefs'})
          || die("Couldn't create the config file : $!");
        print PREFS "Width = " . $globals->{'tmpwidth'} . "\n";
        print PREFS "Height = " . $globals->{'tmpheight'} . "\n";
        print PREFS "Spacing = " . $globals->{'tmpspacing'} . "\n";
        print PREFS "Font = " . $globals->{'tmpfont'} . "\n";
        print PREFS "Documents = " . $globals->{'tmpdir'} . "\n";
        foreach my $fav (@favourites) {
            print PREFS "Host = " . $fav . "\n";
        }
        close PREFS;
    }
    $globals->{'prefs_xml'}->get_widget('dialogPrefs')->destroy();
    load_prefs();
}

# Load the current preferences
sub load_prefs {
    open(PREFS, $globals->{'prefs'}) || setup_gournal();
    @favourites = ();
    while (<PREFS>) {
        chomp;
        my @line = split(/=/);
        $line[0] =~ s/ *$//g;
        $line[1] =~ s/^ *//g;
        if ($line[0] eq "Width") {
            $globals->{'width'} = $line[1];
        } elsif ($line[0] eq "Height") {
            $globals->{'height'} = $line[1];
        } elsif ($line[0] eq "Spacing") {
            $globals->{'spacing'} = $line[1];
        } elsif ($line[0] eq "Font") {
            $globals->{'font'} = $line[1];
        } elsif ($line[0] eq "Host") {
            push @favourites, $line[1];
        } elsif ($line[0] eq "Documents") {
            $globals->{'svgdir'} = $line[1];
            if (substr($globals->{'svgdir'}, -1) ne "/") {
                $globals->{'svgdir'} .= "/";
            }
        }
    }
    close PREFS;
}

# Update preferences from dialog
sub pref_changed {
    $globals->{'tmpwidth'} =
      $globals->{'prefs_xml'}->get_widget('spinWidth')->get_value_as_int();
    $globals->{'tmpheight'} =
      $globals->{'prefs_xml'}->get_widget('spinHeight')->get_value_as_int();
    $globals->{'tmpspacing'} =
      $globals->{'prefs_xml'}->get_widget('spinSpacing')->get_value_as_int();
    $globals->{'tmpfont'} =
      $globals->{'prefs_xml'}->get_widget('entryFont')->get_text();
    $globals->{'tmpdir'} =
      $globals->{'prefs_xml'}->get_widget('entryDocDirectory')->get_text();
}

# Show the help/about screen
sub show_help {
    my $tmpxml = Gtk2::GladeXML->new($globals->{'gladefile'}, 'dialogAbout');
    $tmpxml->signal_autoconnect_from_package('');

    my $response = $tmpxml->get_widget('dialogAbout')->run();
    $tmpxml->get_widget('dialogAbout')->destroy();
}

####
## Event related functions
####

# Mouse button has been pressed
sub button_press_event {
    my ($widget, $event) = @_;
    my ($x,      $y)     = $event->coords;
    my ($cx,     $cy)    = $widget->window_to_world($x, $y);

    #if ($event->button == 3) {
    #tool_erase();
    #}
    my $pagename = $widget->{'section'} . "/" . $widget->{'pagename'};
    if ($event->button == 1 || $event->button == 3) {
        my $id = time;
        if (int($globals->{'lastid'}) == $id) {
            $id = $globals->{'lastid'} + 0.1;
        }
        $globals->{'lastid'} = $id;
        if ($globals->{'tool_type'} == DATE) {
            $globals->{'changed_flag'} = TRUE;
            my @time = localtime(time);
            my $date = sprintf(
                "%d:%02d %d/%d/%02d",
                $time[2], $time[1], $time[3],
                ($time[4] + 1),
                ($time[5] - 100)
            );
            $canvasitem{$pagename}->{$id} = Gnome2::Canvas::Item->new(
                $widget->root, 'Gnome2::Canvas::Text',
                fill_color => 'black',
                x          => $cx,
                y          => $cy,
                font       => $globals->{'font'},
                text       => $date,
                anchor     => 'south-west'
            );
            my $tag = $svg{$pagename}->getElement('svg')->createChild('text');
            $tag->attribute('x',     $cx);
            $tag->attribute('y',     $cy);
            $tag->attribute('name',  $id);
            my $tmpfont=$globals->{'font'};
            $tmpfont=~s/ /_/g;
            $tag->attribute('style', "font:" . $tmpfont);
            $tag->text($date);
        } elsif ($globals->{'tool_type'} == TEXT) {
            $globals->{'changed_flag'}    = TRUE;
            $globals->{'canvas_text'}     = $id;
            $canvasitem{$pagename}->{$id} = Gnome2::Canvas::Item->new(
                $widget->root, 'Gnome2::Canvas::Text',
                x          => $cx,
                y          => $cy,
                text       => "",
                anchor     => 'south-west',
                fill_color => 'black',
                font       => $globals->{'font'}
            );
            $globals->{'text_tag'} =
              $svg{$pagename}->getElement('svg')->createChild('text');
            $globals->{'text_tag'}->attribute('x',    $cx);
            $globals->{'text_tag'}->attribute('y',    $cy);
            $globals->{'text_tag'}->attribute('name', $id);
            my $tmpfont=$globals->{'font'};
            $tmpfont=~s/ /_/g;
            $globals->{'text_tag'}
              ->attribute('style', "font:" . $tmpfont);
            $globals->{'text_tag'}->text("");
        } elsif ($globals->{'tool_type'} == ERASE) {
        } elsif ($globals->{'tool_type'} == IMAGE) {
        } else {
            $globals->{'changed_flag'} = TRUE;
            my @time = localtime(time);
            my $root = $widget->root;
            $globals->{'current_group'} = Gnome2::Canvas::Item->new(
                $root, 'Gnome2::Canvas::Group',
                x => 0,
                y => 0
            );
            draw_brush($widget, $event->coords);
            my ($x, $y) = $event->coords;
            my ($cx, $cy) = $widget->window_to_world($x, $y);
            @xv                         = ($cx);
            @yv                         = ($cy);
            $globals->{'movement_flag'} = FALSE;
        }
    }
    return TRUE;
}

# Mouse button has been released
sub button_release_event {
    my ($widget, $event) = @_;
    my $pagename = $widget->{'section'} . "/" . $widget->{'pagename'};
    debug("Action on $pagename");
    if (
        ($event->button == 1 || $event->button == 3)
        && (   $globals->{'tool_type'} == NORMAL
            || $globals->{'tool_type'} == HILITE)
      )
    {
        if (!$globals->{'movement_flag'}) {
            draw_brush($widget, $globals->{'oldx'} + 1, $globals->{'oldy'} + 1);
        }
        $globals->{'oldx'} = -100;
        $globals->{'oldy'} = -100;
        my $filename  = $widget->{user_data};
        my $path      = $svg{$pagename}->getElement('svg')->createChild('path');
        my $brush_col = $globals->{'brush_color'};
        $brush_col = int($globals->{'brush_color'} / 256);
        $brush_col = sprintf('#%06X', $brush_col);
        my $brush_trans = $globals->{'brush_color'};
        $brush_trans = (($brush_trans / 256) - (int($brush_trans / 256)));
        my $style =
          sprintf('fill:none;stroke:'
              . $brush_col
              . ';stroke-opacity:'
              . $brush_trans
              . ';stroke-linecap:round'
              . ';stroke-linejoin:round'
              . ';stroke-width:'
              . $globals->{'brush_width'}
              . ";");
        $path->attribute('style', $style);
        my $id = time;

        if (int($globals->{'lastid'}) == $id) {
            $id = $globals->{'lastid'} + 0.1;
        }
        $globals->{'lastid'} = $id;
        $path->attribute('name', $id);
        my $points = "";
        my $i      = 0;

        $points = "M " . $xv[0] . " " . $yv[0] . " ";
        for ($i = 1 ; $i < @xv ; $i++) {
            $points .= "L " . $xv[$i] . " " . $yv[$i] . " ";
        }
        $path->attribute('d', $points);
        if ($globals->{'client_flag'}) {
            send_item($path, $filename);
        }

        $globals->{'current_group'}->destroy;
        $globals->{'current_group'} = undef;
        my $root = $widget->root;
        $canvasitem{$pagename}->{$id} = Gnome2::Canvas::Item->new(
            $root, 'Gnome2::Canvas::Line',
            points          => \@line,
            cap_style       => 'round',
            join_style      => 'round',
            fill_color_rgba => $globals->{'brush_color'},
            width_units     => $globals->{'brush_width'}
        );
        $canvasitem{$pagename}->{$id}->{user_data} = $id;
        $canvasitem{$pagename}->{$id}->show();
        @line = ();

    }
    if ($event->button == 3) {
        $mainxml->get_widget('buttonBlack')->set_active(TRUE);
    }
    if ($globals->{'tool_type'} == DATE) {
        $mainxml->get_widget('buttonBlack')->set_active(TRUE);
    }
    if ($globals->{'tool_type'} == ERASE) {
        my $filename = $widget->{user_data};
        if ($globals->{'selected_item'}) {
            delete_item($filename, $globals->{'selected_item'});
        }
        $globals->{'selected_item'} = FALSE;
    } elsif ($globals->{'tool_type'} == IMAGE) {
        my ($x, $y) = $event->coords;
        my ($cx, $cy) = $widget->window_to_world($x, $y);
        my $id = time;
        if (int($globals->{'lastid'}) == $id) {
            $id = $globals->{'lastid'} + 0.1;
        }
        $globals->{'lastid'} = $id;
        $canvasitem{$pagename}->{$id} = $globals->{'canvas_image'};
        my $tag = $svg{$pagename}->getElement('svg')->createChild('image');
        $tag->attribute('x',      $cx);
        $tag->attribute('y',      $cy-$globals->{'canvas_image'}->get('height'));
        $tag->attribute('width',  $globals->{'canvas_image'}->get('width'));
        $tag->attribute('height', $globals->{'canvas_image'}->get('height'));
        $tag->attribute('name',   $id);
        $tag->attribute('xlink:href', $globals->{'canvas_image'}->{user_data});
        $mainxml->get_widget('buttonBlack')->set_active(TRUE);
    }

    return TRUE;
}

# Mouse has moved
sub motion_notify_event {
    my ($widget, $event) = @_;
    my $pagename = $widget->{'section'} . "/" . $widget->{'pagename'};

    my ($x, $y, $state);

    if ($event->is_hint) {
        (undef, $x, $y, $state) = $event->window->get_pointer;
    } else {
        $x     = $event->x;
        $y     = $event->y;
        $state = $event->state;
    }
    if (
        (grep (/button1-mask/, @$state) || grep (/button3-mask/, @$state))
        && (   $globals->{'tool_type'} == NORMAL
            || $globals->{'tool_type'} == HILITE)
      )
    {
        $globals->{'movement_flag'} = TRUE;
        draw_brush($widget, $x, $y);
    }

    if ($globals->{'tool_type'} == ERASE) {
        my $canvas = get_current_canvas();
        my $item = $canvas->get_item_at($x, $y);
        if (defined $item->{user_data}) {
            if ($globals->{'selected_item'}) {
                $canvasitem{$pagename}->{$globals->{'selected_item'}}
                  ->set(fill_color_rgba => $globals->{'selected_item_colour'});
            }
            $globals->{'selected_item'}        = $item->{user_data};
            $globals->{'selected_item_colour'} =
              $canvasitem{$pagename}->{$globals->{'selected_item'}}
              ->get('fill_color_rgba');
            $canvasitem{$pagename}->{$globals->{'selected_item'}}
              ->set(fill_color_rgba => 0xff000088);
            if (   grep (/button1-mask/, @$state)
                || grep (/button3-mask/, @$state))
            {
                delete_item($pagename, $globals->{'selected_item'});
                $globals->{'selected_item'} = FALSE;
            }
        } else {
            if ($globals->{'selected_item'}) {
                $canvasitem{$pagename}->{$globals->{'selected_item'}}
                  ->set(fill_color_rgba => $globals->{'selected_item_colour'});
                $globals->{'selected_item'} = FALSE;
            }
        }
    } elsif ($globals->{'tool_type'} == IMAGE) {
        my ($cx, $cy) = $widget->window_to_world($x, $y);
        $globals->{'canvas_image'}->set('x' => $cx);
        $globals->{'canvas_image'}->set('y' => $cy);
    }

    return TRUE;
}

# Keyboard has been used
sub handle_key {
    my ($widget, $event) = @_;
    debug("Handling key " . $event->keyval);
    if ($event->state =~ /control-mask/) {
        if ($event->keyval == 122) {
            finish_text();
            undo_last();
            return TRUE;
        } elsif ($event->keyval == 121) {
            finish_text();
            redo_last();
            return TRUE;
        }
    } else {
        if (($globals->{'tool_type'} == TEXT) && $globals->{'canvas_text'} != 0)
        {
            my $pagename = get_current_pagename();
            if ($event->keyval == 65288) {
                my $newtext = substr(
                    $canvasitem{$pagename}->{$globals->{'canvas_text'}}
                      ->get('text'),
                    0, -1
                );

                $canvasitem{$pagename}->{$globals->{'canvas_text'}}
                  ->set(text => $newtext);
            } else {
                my $char = "";
                if ($event->keyval == 65293) {
                    $char = "\n";
                } else {
                    $char = chr(Gtk2::Gdk->keyval_to_unicode($event->keyval));
                }
                $canvasitem{$pagename}->{$globals->{'canvas_text'}}->set(
                    text => $canvasitem{$pagename}->{$globals->{'canvas_text'}}
                      ->get('text') . $char);
            }
        }
        return TRUE;
    }
    return FALSE;
}

####
## Page related functions
####

# Go to the next page within current section
sub next_page {
    my $pagename = get_current_pagename();
    my ($section, $page) = split(/\//, $pagename, 2);
    $pages->{$section}->{'_notebook'}->next_page;
}

# Go to the previous page within current section
sub prev_page {
    my $pagename = get_current_pagename();
    my ($section, $page) = split(/\//, $pagename, 2);
    $pages->{$section}->{'_notebook'}->prev_page;
}

# Initial load of page
# svg/canvas not created yet, just the notebook tab
sub load_page {
    my ($section, $filename) = @_;
    my $pagename = $filename;
    $pagename =~ s/\.svgz$//g;
    debug("Loading Page $section -> $pagename");

    if (!defined $pages->{$section}->{$pagename}) {
        my $scroll = Gtk2::ScrolledWindow->new;
        $scroll->set_policy('automatic', 'automatic');
        $scroll->{'section'}  = $section;
        $scroll->{'pagename'} = $pagename;
        $scroll->show;
        $pages->{$section}->{$pagename}->{'scroll'}  = $scroll;
        $pages->{$section}->{$pagename}->{'pagenum'} =
          $pages->{$section}->{'_notebook'}->append_page($scroll, $pagename);
        $pages->{$section}->{'_notebook'}
          ->get_nth_page($pages->{$section}->{$pagename}->{'pagenum'})
          ->{'pagename'} = $pagename;
        $pages->{$section}->{'_notebook'}
          ->get_nth_page($pages->{$section}->{$pagename}->{'pagenum'})
          ->{'section'} = $section;
    }
}

# Finish loading a page
# Loads svg/canvas to existing tab
sub finish_load {
    my ($section, $pagename) = @_;
    my $gz;
    debug("Finishing loading " . $pagename);
    my $page     = $section . "/" . $pagename;
    my $filename = $page;
    $pages->{$section}->{$pagename}->{'canvas'} =
      new_canvas($section, $pagename);
    $pages->{$section}->{$pagename}->{'scroll'}
      ->add($pages->{$section}->{$pagename}->{'canvas'});
    $pages->{$section}->{$pagename}->{'scroll'}->show_all();

    if ($section eq "Main") {
        $filename = $pagename;
    }
    if ($gz = gzopen($globals->{'svgdir'} . $filename . ".svgz", "rb")) {
        my $xml = "";
        while ($gz->gzread($_)) {
            $xml .= $_;
        }
        $gz->gzclose;
        $svg{$page} = XML::Mini::Document->new();
        $svg{$page}->parse($xml);
        my $svg2             = $svg{$page}->getElement('svg');
        my $topLevelChildren = $svg2->getAllChildren();
        foreach my $child (@{$topLevelChildren}) {

            if (   $child->{'_attributes'}->{'visibility'}
                && $child->{'_attributes'}->{'visibility'} eq "hidden")
            {

                # ignore
            } else {

                load_item($section, $pagename, $child,"canvas");
            }
        }
    } else {
        $svg{$page} = XML::Mini::Document->new();
        my $header = $svg{$page}->getRoot()->header('xml');
        $header->attribute('version', '1.0');
        $svg{$page}->getRoot()->comment('Created with Gournal');
        $svg{$page}->getRoot()
          ->docType(
'svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"'
          );
        my $tmpsvg = $svg{$page}->getRoot()->createChild('svg');
        $tmpsvg->attribute('width',       $globals->{'pagewidth'});
        $tmpsvg->attribute('height',      $globals->{'pageheight'});
        $tmpsvg->attribute('xmlns',       "http://www.w3.org/2000/svg");
        $tmpsvg->attribute('xmlns:xlink', "http://www.w3.org/1999/xlink");
        $tmpsvg->attribute('version',     "1.1");
    }
}

# Save the given page to disk
sub save_page {
    my ($pagename) = @_;
    debug("Saving page");
    finish_text();
    my ($section, $page) = split(/\//, $pagename);
    if ($section eq "Main") {
        $section = "";
    } else {
        if (   (-e $globals->{'svgdir'} . $section)
            && (!-d $globals->{'svgdir'}))
        {
            debug("Error");
        } elsif (!-e $globals->{'svgdir'} . $section) {
            mkdir $globals->{'svgdir'} . $section;
        }
    }
    my $filename = $globals->{'svgdir'} . $section . "/" . $page . ".svgz";
    if ($pagename ne "") {
        debug("Saving $filename");
        my $gz = gzopen($filename, "wb");
        $gz->gzwrite($svg{$pagename}->toString);
        $gz->gzclose;
        debug("$pagename Saved");
        $globals->{'changed_flag'} = FALSE;
    }
}

# Save the current page
sub save_current_page {
    debug("Saving current pages");
    finish_text();
    my $pagename = get_current_pagename();
    save_page($pagename);
}

# Clear the current page
sub clear_page {
    my $page = get_current_pagename();
    my ($section, $pagename) = split(/\//, $page, 2);
    $pages->{$section}->{$pagename}->{'canvas'}->destroy;
    $pages->{$section}->{$pagename}->{'canvas'} =
      new_canvas($section, $pagename);
    $pages->{$section}->{$pagename}->{'scroll'}
      ->add($pages->{$section}->{$pagename}->{'canvas'});

    $svg{$page} = XML::Mini::Document->new();
    my $header = $svg{$page}->getRoot()->header('xml');
    $header->attribute('version', '1.0');
    $svg{$page}->getRoot()->comment('Created with Gournal');
    $svg{$page}->getRoot()
      ->docType(
'svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd"'
      );
    my $tmpsvg = $svg{$page}->getRoot()->createChild('svg');
    $tmpsvg->attribute('width',  $globals->{'pagewidth'});
    $tmpsvg->attribute('height', $globals->{'pageheight'});
    $globals->{'changed_flag'} = TRUE;
}

# Create a new blank page
sub add_page {
    my ($widget, $section) = @_;
    if ($section eq "") {
        $section =
          $sectionTabs->get_nth_page($sectionTabs->get_current_page)
          ->{'section'};
    }
    debug("Adding page to $section");
    my @time = localtime(time);
    my $page = sprintf(
        "%04d-%02d-%02d@%02d:%02d",
        ($time[5] + 1900),
        ($time[4] + 1),
        $time[3], $time[2], $time[1]
    );
    if (defined $pages->{$section}->{$page}) {
        $page = sprintf(
            "%04d-%02d-%02d@%02d:%02d:%02d",
            ($time[5] + 1900),
            ($time[4] + 1),
            $time[3], $time[2], $time[1], $time[0]
        );
    }
    $globals->{'signal_freeze_flag'} = TRUE;
    load_page($section, $page . ".svgz");
    set_page($section, $page);
    $globals->{'signal_freeze_flag'} = FALSE;
    return $page;
}

# Create a new canvas for given pagename
sub new_canvas {
    my ($section, $page) = @_;
    debug("Creating new canvas $section/$page");

    # Create Canvas
    my $canvas = Gnome2::Canvas->new_aa();
    $canvas->set_scroll_region(0, 0, 600, 800);
    $canvas->set_center_scroll_region(FALSE);
    $canvas->set_pixels_per_unit(1);
    $canvas->signal_connect(
        motion_notify_event => \&motion_notify_event,
        undef
    );
    $canvas->signal_connect(button_press_event => \&button_press_event, undef);
    $canvas->signal_connect(
        button_release_event => \&button_release_event,
        undef
    );
    $canvas->{'section'}  = $section;
    $canvas->{'pagename'} = $page;

    $canvas->show;
    my $root = $canvas->root;

    Gnome2::Canvas::Item->new(
        $root, 'Gnome2::Canvas::Rect',
        outline_color => 'black',
        fill_color    => 'white',
        x1            => 0,
        y1            => 0,
        x2            => $globals->{'pagewidth'} - 100,
        y2            => $globals->{'pageheight'} - 100
    );

    Gnome2::Canvas::Item->new(
        $root, 'Gnome2::Canvas::Line',
        points      => [40, 0, 40, $globals->{'pageheight'} - 100],
        fill_color  => 'blue',
        width_units => .5
    );

    for (
        my $i = 40 ;
        $i < ($globals->{'pageheight'} - 100) ;
        $i = $i + $globals->{'line_spacing'}
      )
    {
        Gnome2::Canvas::Item->new(
            $root, 'Gnome2::Canvas::Line',
            points      => [0, $i, $globals->{'pagewidth'} - 100, $i],
            fill_color  => 'blue',
            width_units => .5
        );
    }

    return $canvas;
}

# Confirm if the user wishes to delete the current page
sub delete_page {
    my $pagename = get_current_pagename();
    my $canvas   = get_current_canvas();
    my $xml      = Gtk2::GladeXML->new($globals->{'gladefile'}, 'dialogDelete');
    $xml->signal_autoconnect_from_package('');
    $xml->get_widget('labelDelete')
      ->set_text(
        "Are you sure you want to\ndelete the page named\n" . $pagename . "?");
    $xml->get_widget('dialogDelete')->{user_data} = $pagename;
}

# Deletion confirmed so delete the current page
sub do_delete_page {
    my ($widget) = @_;
    my $pagename = $widget->get_toplevel->{user_data};
    debug("Deleting " . $pagename);
    cancel_dialog($widget);
    my ($section, $page) = split(/\//, $pagename, 2);
    my $pagenum = $pages->{$section}->{$page}->{'pagenum'};
    $mainxml->get_widget('notebookMain')->remove_page($pagenum);
    $pages->{$section}->{$page}->{'canvas'}->destroy;
    delete $svg{$pagename};

    #system "rm " . $globals->{'svgdir'} . $filename . ".svgz";

    unlink $globals->{'svgdir'} . $pagename . ".svgz";
}

# Ask what the user wants to rename the page to
sub rename_page {
    my $pagename = get_current_pagename();
    my ($section, $page) = split(/\//, $pagename, 2);
    my $canvas = get_current_canvas();
    my $xml = Gtk2::GladeXML->new($globals->{'gladefile'}, 'dialogRename');
    $xml->signal_autoconnect_from_package('');
    $xml->get_widget('labelRename')
      ->set_text("What do you want to\nrename " . $page . " to?");
    $xml->get_widget('entryRename')->set_text($page);
    my $response = $xml->get_widget('dialogRename')->run();

    if ($response eq "cancel") {
        $xml->get_widget('dialogRename')->destroy();
    } else {
        my $newtext = $xml->get_widget('entryRename')->get_text();
        $canvas->{'pagename'} = $newtext;
        $pages->{$section}->{'_notebook'}
          ->set_tab_label_text($pages->{$section}->{$page}->{'scroll'},
            $newtext);
        rename($globals->{'svgdir'} . $section . "/" . $page.".svgz",
            $globals->{'svgdir'} . $section . "/" . $newtext . ".svgz");
        $xml->get_widget('dialogRename')->destroy();
        $svg{$section . "/" . $newtext} = $svg{$pagename};
        delete $svg{$pagename};
        $canvasitem{$section . "/" . $newtext} = $canvasitem{$pagename};
        delete $canvasitem{$pagename};
        $pages->{$section}->{$newtext} = $pages->{$section}->{$page};
        delete $pages->{$section}->{$page};
        $pages->{$section}->{$newtext}->{'canvas'}->{'pagename'}=$newtext;
        $pages->{$section}->{$newtext}->{'scroll'}->{'pagename'}=$newtext;
    }
}

# Get the pagename of the current page
sub get_current_pagename {
    my $scroll = get_current_scroll();
    return $scroll->{'section'} . "/" . $scroll->{'pagename'};
}

# Get the current scolled window
sub get_current_scroll {
    my $section =
      $sectionTabs->get_nth_page($sectionTabs->get_current_page)->{'section'};
    my $page =
      $pages->{$section}->{'_notebook'}
      ->get_nth_page($pages->{$section}->{'_notebook'}->get_current_page)
      ->{'pagename'};
    return $pages->{$section}->{$page}->{'scroll'};
}

# Get the current canvas
sub get_current_canvas {
    my $section =
      $sectionTabs->get_nth_page($sectionTabs->get_current_page)->{'section'};
    my $page =
      $pages->{$section}->{'_notebook'}
      ->get_nth_page($pages->{$section}->{'_notebook'}->get_current_page)
      ->{'pagename'};
    return $pages->{$section}->{$page}->{'canvas'};
}

# Jump directly to the given page
sub set_page {
    my ($section, $page) = @_;
    if (!exists $svg{$section . "/" . $page}) {
        $globals->{'current_page'} = $section . "/" . $page;
        finish_load($section, $page);
    }
    $sectionTabs->set_current_page($pages->{$section}->{'_pageid'});
    $pages->{$section}->{'_notebook'}
      ->set_current_page($pages->{$section}->{$page}->{'pagenum'});
}

# Called when page is changed
# Checks if previous page changed and asks to save
# Checks if current page is fully loaded and if not, loads
sub switch_page {
    my ($widget) = @_;
    my $pagename = get_current_pagename();
    my ($section, $page) = split(/\//, $pagename, 2);
    if ($globals->{'current_page'} ne $pagename) {
        if ($globals->{'changed_flag'}) {

            # Save changes?
            debug("Confirming save changes");
            my $xml =
              Gtk2::GladeXML->new($globals->{'gladefile'}, 'dialogSave');
            $xml->signal_autoconnect_from_package('');
            $xml->get_widget('labelSave')
              ->set_text("What do you want save the changes to "
                  . $globals->{'current_page'});
            my $response = $xml->get_widget('dialogSave')->run();

            if ($response eq "ok") {
                save_page($globals->{'current_page'});
            } else {
                # clear the changed_flag anyway
                $globals->{'changed_flag'} = FALSE;
            }
            $xml->get_widget('dialogSave')->destroy();
        }
    }
    $globals->{'current_page'} = $pagename;
    if (!$globals->{'signal_freeze_flag'}) {
        debug("Switching page");
        if (!exists $svg{$pagename}) {
            finish_load($section, $page);
        }
    }
}

# Load an item from the svg to the canvas
sub load_item {
    my ($section, $page, $child, $target,$pc) = @_;
    my $pagename = $section . "/" . $page;
    my ($root);
    if ($target eq "canvas") {
        $root     = $pages->{$section}->{$page}->{'canvas'}->root;
    }
    if ($child->{'_name'} eq "path") {
        my ($styles);
        my $tmp = $child->{'_attributes'}->{'style'};
        my @style = split(/;/, $tmp);
        foreach (@style) {
            my @tmp2 = split(/:/, $_);
            $styles->{$tmp2[0]} = $tmp2[1];
        }
        if ($target eq "canvas") {
            my $tmppoints = $child->{'_attributes'}->{'d'};
            $tmppoints =~ s/[ML] //g;
            my @points = split(/ /, $tmppoints);
            my $brush_col = $styles->{'stroke'};
            $styles->{'stroke-opacity'} =~ s/,/./g;
            $brush_col                  =~ s/#//g;
            $brush_col = (hex($brush_col) + $styles->{'stroke-opacity'}) * 256;
            $canvasitem{$pagename}->{$child->{'_attributes'}->{'name'}} =
              Gnome2::Canvas::Item->new(
                $root, 'Gnome2::Canvas::Line',
                cap_style       => 'round',
                join_style      => 'round',
                points          => \@points,
                fill_color_rgba => $brush_col,
                width_units     => $styles->{'stroke-width'}
              );
            $canvasitem{$pagename}->{$child->{'_attributes'}->{'name'}}
              ->{user_data} = $child->{'_attributes'}->{'name'};
        } elsif ($target eq "print") {
            my @points = split(/[ML]/,$child->{'_attributes'}->{'d'});
            my $firstpoint=TRUE;
            my $brush_col = $styles->{'stroke'};
            $brush_col                  =~ s/#//g;
            my @colour=split(//,$brush_col);
            my $r = hex($colour[0].$colour[1])/256;
            my $g = hex($colour[2].$colour[3])/256;
            my $b = hex($colour[4].$colour[5])/256;
            my $a = $styles->{'stroke-opacity'};
            $a =~ s/,/./g;
            $pc->setrgbcolor($r,$g,$b);
            $pc->setopacity($a);
            $pc->setlinecap(1);
            $pc->setlinejoin(1);
            $pc->setlinewidth($styles->{'stroke-width'}/2);
            foreach (@points) {
                if ($_ ne "") {
                my @point=split(/ /,$_);
                my $x=$point[1]/($globals->{'width'}/$globals->{'print_width'});
                my $y=$point[2]/($globals->{'height'}/$globals->{'print_height'});
                $y=$globals->{'print_height'}-$y;
                
                if ($point[1] ne "" ) {
                    if ($firstpoint) {
                        $pc->moveto($x,$y);
                        $firstpoint=FALSE;
                    } else {
                        $pc->lineto($x,$y);
                    }
                }
                }
            }
            $pc->stroke;
        }
    } elsif ($child->{'_name'} eq "polyline") {
        my ($styles);
        my $tmp = $child->{'_attributes'}->{'style'};
        my @style = split(/; /, $tmp);
        foreach (@style) {
            my @tmp2 = split(/: /, $_);
            $styles->{$tmp2[0]} = $tmp2[1];
        }
        my $tmppoints = $child->{'_attributes'}->{'points'};
        $tmppoints =~ s/^points: //g;
        my @points = split(/[ ,]/, $tmppoints);
        if ($target eq "canvas") {
           $canvasitem{$pagename}->{$child->{'_attributes'}->{'name'}} =
             Gnome2::Canvas::Item->new(
                $root, 'Gnome2::Canvas::Line',
                cap_style       => 'round',
                join_style      => 'round',
                points          => \@points,
                fill_color_rgba => $styles->{'stroke'},
                width_units     => $styles->{'stroke-width'}
              );
            $canvasitem{$pagename}->{$child->{'_attributes'}->{'name'}}
              ->{user_data} = $child->{'_attributes'}->{'name'};
        } else {
            debug ("Can't print polylines");
        }
    } elsif ($child->{'_name'} eq "text") {
        my ($styles);
        my @style = split(/;/, $child->{'_attributes'}->{'style'});
        foreach (@style) {
            my @tmp2 = split(/:/, $_);
            $styles->{$tmp2[0]} = $tmp2[1];
        }
        my $data = $child->{'_children'}[0]->{'_contents'};
        chomp($data);
        $styles->{'font'} =~ s/_/ /g;
        if ($target eq "canvas") {
            $canvasitem{$pagename}->{$child->{'_attributes'}->{'name'}} =
              Gnome2::Canvas::Item->new(
                $root, 'Gnome2::Canvas::Text',
                fill_color => 'black',
                x          => $child->{'_attributes'}->{'x'},
                y          => $child->{'_attributes'}->{'y'},
                font       => $styles->{'font'},
                text       => $data,
                anchor     => 'south-west'
              );
            $canvasitem{$pagename}->{$child->{'_attributes'}->{'name'}}
              ->{user_data} = $child->{'_attributes'}->{'name'};
        } elsif ($target eq "print") {
            $pc->setfont(Gnome2::Print::Font->find_closest_from_full_name($styles->{'font'}));
            $pc->setrgbcolor(0,0,0);
            my $x=$child->{'_attributes'}->{'x'}/($globals->{'width'}/$globals->{'print_width'});
            my $y=$child->{'_attributes'}->{'y'}/($globals->{'height'}/$globals->{'print_height'});
            $y=$globals->{'print_height'}-$y;
            $pc->moveto($x,$y);
            $pc->show($data);
        }
    } elsif ($child->{'_name'} eq "image") {
        my $filename = $child->{'_attributes'}->{'xlink:href'};
        my $im       =
          Gtk2::Gdk::Pixbuf->new_from_file($globals->{'svgdir'} . $section."/".$filename);
        if ($target eq "canvas") {
            $canvasitem{$pagename}->{$child->{'_attributes'}->{'name'}} =
              Gnome2::Canvas::Item->new(
                $root,    'Gnome2::Canvas::Pixbuf',
                "pixbuf", $im,
                "x",      $child->{'_attributes'}->{'x'},
                "y",      $child->{'_attributes'}->{'y'},
                "width",  $child->{'_attributes'}->{'width'},
                "height", $child->{'_attributes'}->{'height'},
                "anchor", 'south-west',
              );
        } elsif ($target eq "print") {
            my $x=$child->{'_attributes'}->{'x'}/($globals->{'width'}/$globals->{'print_width'});
            my $y=$child->{'_attributes'}->{'y'}/($globals->{'height'}/$globals->{'print_height'});
            $y=$globals->{'print_height'}-$y;
            $pc->gsave;
            $pc->translate($x,$y);
            $pc->scale ($im->get_width, $im->get_height);
            if ($im->get_has_alpha) {
                $pc->rgbaimage ($im->get_pixels, $im->get_width, $im->get_height, $im->get_rowstride);
            } else {
                $pc->rgbimage ($im->get_pixels, $im->get_width, $im->get_height, $im->get_rowstride);
            }
            $pc->grestore;
        }
    }
}

# Load a background image
sub load_bg {
    my ($widget) = @_;
    my $xml = Gtk2::GladeXML->new($globals->{'gladefile'}, 'dialogFile');
    $xml->signal_autoconnect_from_package('');
    my $response = $xml->get_widget('dialogFile')->run();
    if ($response eq "ok") {
        add_page("", "");
        my $id = time;
        if (int($globals->{'lastid'}) == $id) {
            $id = $globals->{'lastid'} + 0.1;
        }
        $globals->{'lastid'} = $id;

        my $pagename = get_current_pagename();
        my $canvas   = get_current_canvas();
        my $filename = $xml->get_widget('dialogFile')->get_filename();
        $xml->get_widget('dialogFile')->destroy();
        my $newfilename = $pagename . "@" . $id . ".png";
        system( "convert -resize "
              . ($globals->{'pagewidth'} - 100) . "x"
              . ($globals->{'pageheight'} - 100) . " \""
              . $filename . "\" \""
              . $globals->{'svgdir'}
              . $newfilename
              . "\"");
        my $im =
          Gtk2::Gdk::Pixbuf->new_from_file($globals->{'svgdir'} . $newfilename);
        $canvasitem{$pagename}->{$id} = Gnome2::Canvas::Item->new(
            $canvas->root, 'Gnome2::Canvas::Pixbuf',
            "pixbuf",      $im,
            "x",           0,
            "y",           0,
            "width",       $im->get_width,
            "height",      $im->get_height,
            "anchor",      'south-west',
        );
        my $tag = $svg{$pagename}->getElement('svg')->createChild('image');
        $tag->attribute('x',          0);
        $tag->attribute('y',          0);
        $tag->attribute('width',      $im->get_width);
        $tag->attribute('height',     $im->get_height);
        $tag->attribute('name',       $id);
        $tag->attribute('xlink:href', $newfilename);
    }
}

# Print the current page
sub print_page {
    debug("Print page");
    my $job    = Gnome2::Print::Job->new;
    my $dialog = Gnome2::Print::Dialog->new($job, "Print Current Page", 0);

    $dialog->signal_connect(delete_event => sub { $dialog->destroy; });
    $dialog->signal_connect(
        response => sub {
            my ($d, $response, $job) = @_;

            my $conf = $d->get_config;
            my $j = Gnome2::Print::Job->new($conf);

            if ($response == 1) {    # user hit 'Print'
                render_job($j);
                my $pc = Gnome2::Print::Context->new($conf);
                $j->render($pc);
                $pc->close;

                $dialog->destroy;
                my $done_dialog = Gtk2::Dialog->new("Page printing",$d,'destroy-with-parent','gtk-ok' => 'none');
                my $label = Gtk2::Label->new("Page sent to printer");
                $done_dialog->vbox->add($label);
                $done_dialog->show_all;
                $done_dialog->run;
                $done_dialog->destroy;
            } elsif ($response == 2) {    # user hit 'Preview'
                render_job($j);

                my $preview = Gnome2::Print::JobPreview->new($j, "Preview Page");
                $preview->set_property("allow-grow",   1);
                $preview->set_property("allow-shrink", 1);
                $preview->set_transient_for($d);
                $preview->show_all;
            } else {
                $d->destroy;
            }
        },
        $job
    );

    $dialog->run();
}

# Render the current printjob
sub render_job {
    my ($job)  = @_;
    my $pagename = get_current_pagename();
    my ($section,$page) = split (/\//,$pagename,2);
    my $conf = $job->get_config;
    ($globals->{'print_width'}, $globals->{'print_height'}) = $conf->get_page_size;
    my $pc = $job->get_context;

    # Begin the page
    $pc->beginpage("1");
    
    my $svg2 = $svg{$pagename}->getElement('svg');
    my $topLevelChildren = $svg2->getAllChildren();
    foreach my $child (@{$topLevelChildren}) {

        if (   $child->{'_attributes'}->{'visibility'}
            && $child->{'_attributes'}->{'visibility'} eq "hidden")
        {

            # ignore
        } else {
            load_item($section, $page, $child,"print",$pc);
        }
    }

    # Finish the page
    $pc->showpage;

    $job->close;
}

####
## Section related functions
####

# Load a directory as a section
sub load_dir {
    my ($dir) = @_;
    my $section = $dir;
    if ($section eq "") {
        $section = "Main";
    }
    if (!defined $pages->{$dir}->{'_notebook'}) {
        debug("Loading Section " . $section);
        $pages->{$section}->{'_notebook'} = Gtk2::Notebook->new;
        $pages->{$section}->{'_notebook'}->popup_enable;
        $pages->{$section}->{'_notebook'}->set_scrollable(TRUE);
        $pages->{$section}->{'_notebook'}->set_tab_pos('right');

        $pages->{$section}->{'_pageid'} =
          $sectionTabs->append_page($pages->{$section}->{'_notebook'},
            $section);
        $sectionTabs->get_nth_page($pages->{$section}->{'_pageid'})
          ->{'section'} = $section;
        $pages->{$section}->{'_notebook'}->show();
        $sectionTabs->show_all();
        opendir(DIR, $globals->{'svgdir'} . $dir);
        foreach (readdir DIR) {

            if ($_ =~ /\.svgz$/) {
                load_page($section, $_);
                $found = $section . "/" . $_;
            } elsif ($_ =~ /\.svg\.gz$/) {
                my $oldname = $_;
                my $newname = $_;
                $newname =~ s/\.svg\.gz$/\.svgz/g;
                rename $globals->{'svgdir'} . $dir . $oldname, $globals->{'svgdir'} . $dir . $newname;
                load_page($section,$newname);
                $found = $section . "/" . $newname;
            }
        }
        closedir DIR;
        $pages->{$section}->{'_notebook'}
          ->signal_connect_after(switch_page => \&switch_page, undef);
    }
}

# Called when section tab is changed
sub switch_section {
    my ($widget) = @_;
    if (!$globals->{'signal_freeze_flag'}) {
        my $section =
          $sectionTabs->get_nth_page($sectionTabs->get_current_page)
          ->{'section'};
        debug("Switching Section to $section");
        my $subwidget = $pages->{$section}->{'_notebook'};
        switch_page($subwidget);
    }
}

# Create a new time-named section
sub add_section {
    my @time    = localtime(time);
    my $section = sprintf(
        "%04d-%02d-%02d@%02d:%02d",
        ($time[5] + 1900),
        ($time[4] + 1),
        $time[3], $time[2], $time[1]
    );
    if (exists $pages->{$section}) {
        $section = sprintf(
            "%04d-%02d-%02d@%02d:%02d:%02d",
            ($time[5] + 1900),
            ($time[4] + 1),
            $time[3], $time[2], $time[1], $time[0]
        );
    }
    debug("Adding section $section");
    $globals->{'signal_freeze_flag'} = TRUE;
    load_dir($section);
    add_page("", $section);
    $globals->{'signal_freeze_flag'} = FALSE;
}

####
## Tool related functions
####

# Set the brush width to fine
sub brush_fine {
    my ($widget) = @_;
    if ($widget->get_active) {
        if (toggle_thick("buttonFine")) {
            $globals->{'brush_width'} = 1;
        }
    }
}

# Set the brush width to medium
sub brush_medium {
    my ($widget) = @_;
    if ($widget->get_active) {
        if (toggle_thick("buttonMedium")) {
            $globals->{'brush_width'} = 2;
        }
    }
}

# Set the brush width to heavy
sub brush_heavy {
    my ($widget) = @_;
    if ($widget->get_active) {
        if (toggle_thick("buttonHeavy")) {
            $globals->{'brush_width'} = 4;
        }
    }
}

# Set the brush width to fat
sub brush_fat {
    my ($widget) = @_;
    if ($widget->get_active) {
        if (toggle_thick("buttonThick")) {
            $globals->{'brush_width'} = 20;
        }
    }
}

# Set the tool to black pen
sub tool_black {
    my ($widget) = @_;
    if ($widget->get_active) {
        if (toggle_tool("buttonBlack")) {
            finish_text();
            $globals->{'brush_color'} = 0x000000ff;
            $globals->{'tool_type'}   = NORMAL;
            $mainxml->get_widget('buttonMedium')->set_active(TRUE);
        }
    }
}

# Set the tool to red pen
sub tool_red {
    my ($widget) = @_;
    if ($widget->get_active) {
        if (toggle_tool("buttonRed")) {
            finish_text();
            $globals->{'brush_color'} = 0xff0000ff;
            $globals->{'tool_type'}   = NORMAL;
            $mainxml->get_widget('buttonMedium')->set_active(TRUE);
        }
    }
}

# Set the tool to whiteout
sub tool_erase {
    my ($widget) = @_;
    if ($widget->get_active) {
        if (toggle_tool("buttonWhiteout")) {
            finish_text();
            $globals->{'brush_color'} = 0xffffffff;
            $globals->{'tool_type'}   = NORMAL;
            $mainxml->get_widget('buttonThick')->set_active(TRUE);
        }
    }
}

# Set the tool to delete
sub tool_delete {
    my ($widget) = @_;
    if ($widget->get_active) {
        if (toggle_tool("buttonDelete")) {
            finish_text();
            $globals->{'tool_type'} = ERASE;
        }
    }
}

# Set the tool to the highlighter
sub tool_hilite {
    my ($widget) = @_;
    if ($widget->get_active) {
        if (toggle_tool("buttonHighlite")) {
            finish_text();
            $globals->{'brush_color'} = 0xffff0080;
            $globals->{'tool_type'}   = HILITE;
            $mainxml->get_widget('buttonThick')->set_active(TRUE);
        }
    }
}

# Zoom into the page
sub zoom_in {
    my $canvas = get_current_canvas();
    $canvas->set_pixels_per_unit(2);
}

# Return to normal zoom
sub zoom_out {
    my $canvas = get_current_canvas();
    $canvas->set_pixels_per_unit(1);
}

# Set tool to text
sub add_text {
    my ($widget) = @_;
    if ($widget->get_active) {
        if (toggle_tool("buttonText")) {
            finish_text();
            $globals->{'tool_type'} = TEXT;
        }
    }
}

# Set tool to timestamp
sub add_date {
    if (toggle_tool("buttonTime")) {
        finish_text();
        $globals->{'tool_type'} = DATE;
    }
}

# Finish the current textitem
sub finish_text {
    if (defined $globals->{'text_tag'}) {
        my $pagename = get_current_pagename();
        $globals->{'text_tag'}->text(
            $canvasitem{$pagename}->{$globals->{'canvas_text'}}->get('text'));
        undef $globals->{'text_tag'};
    }
}

# Draw a rectangle on the screen
sub draw_brush {
    my ($widget, $x, $y) = @_;
    my ($cx2, $cy2) = $widget->window_to_world($x, $y);
    $x = $cx2;
    $y = $cy2;
    push @xv,   $x;
    push @yv,   $y;
    push @line, $x, $y;

    if (($globals->{'oldx'} == -100) && ($globals->{'oldy'} == -100)) {
        $globals->{'oldx'} = $x;
        $globals->{'oldy'} = $y;
    }

    Gnome2::Canvas::Item->new(
        $globals->{'current_group'},
        'Gnome2::Canvas::Line',
        points     => [$globals->{'oldx'}, $globals->{'oldy'}, $x, $y],
        cap_style  => 'round',
        join_style => 'round',
        fill_color_rgba => $globals->{'brush_color'},
        width_units     => $globals->{'brush_width'}
    );

    $globals->{'oldx'} = $x;
    $globals->{'oldy'} = $y;
}

# Undo the last change
sub undo_last {
    my $pagename = get_current_pagename();
    my $s        = ($canvasitem{$pagename});
    my @keys     = sort keys(%$s);
    my $lastkey  = pop(@keys);
    delete_item($pagename, $lastkey);
    $globals->{'changed_flag'} = TRUE;
}

# Redo the last undone change
sub redo_last {
    my $pagename         = get_current_pagename();
    my $svg2             = $svg{$pagename}->getElement('svg');
    my $topLevelChildren = $svg2->getAllChildren();
    my @deleted          = ();
    foreach my $child (@{$topLevelChildren}) {
        if (   $child->{'_attributes'}->{'visibility'}
            && $child->{'_attributes'}->{'visibility'} eq "hidden")
        {
            push @deleted, $child->{'_attributes'}->{'name'};
        }
    }
    my @tmp     = sort @deleted;
    my $itemnum = pop @tmp;
    if ($itemnum) {
        foreach my $child (@{$topLevelChildren}) {
            if ($child->{'_attributes'}->{'name'} eq $itemnum) {
                $child->attribute('visibility', "visible");
                $child->attribute('name',       time);
                my ($section, $page) = split(/\//, $pagename, 2);
                load_item($section, $page, $child,"canvas");
            }
        }
    }
    $globals->{'changed_flag'} = TRUE;
}

# Choose the font for the text tool
sub choose_font {
    my $xml = Gtk2::GladeXML->new($globals->{'gladefile'}, 'dialogFont');
    $xml->signal_autoconnect_from_package('');
    $xml->get_widget('dialogFont')->set_font_name($globals->{'font'});
    my $response = $xml->get_widget('dialogFont')->run();

    if ($response eq "cancel") {
        $xml->get_widget('dialogFont')->destroy();
    } else {
        $globals->{'font'} = $xml->get_widget('dialogFont')->get_font_name;
        debug("Font chosen is $globals->{'font'}");
        $xml->get_widget('dialogFont')->destroy();
    }
}

# Delete given item on page
sub delete_item {
    my ($pagename, $id) = @_;
    if (defined $canvasitem{$pagename}->{$id}) {
        $canvasitem{$pagename}->{$id}->destroy;
        delete $canvasitem{$pagename}->{$id};
        my $svg2             = $svg{$pagename}->getElement('svg');
        my $topLevelChildren = $svg2->getAllChildren();

        foreach my $child (@{$topLevelChildren}) {
            if (   $child->{'_attributes'}->{'name'}
                && $child->{'_attributes'}->{'name'} eq $id)
            {
                $child->attribute('visibility', "hidden");
                $child->attribute('name',       time);
            }
        }
    }
}

# Add an image to the page
sub add_image {
    my ($widget) = @_;
    if (toggle_tool("buttonPicture")) {
        my $xml = Gtk2::GladeXML->new($globals->{'gladefile'}, 'dialogFile');
        $xml->signal_autoconnect_from_package('');
        my $response = $xml->get_widget('dialogFile')->run();
        if ($response eq "ok") {
            my $id = time;
            if (int($globals->{'lastid'}) == $id) {
                $id = $globals->{'lastid'} + 0.1;
            }
            $globals->{'lastid'} = $id;

            my $pagename = get_current_pagename();
            my $filename    = $xml->get_widget('dialogFile')->get_filename();
            my $newfilename = $pagename . "@" . $id;
            system( "cp \""
                  . $filename . "\" \""
                  . $globals->{'svgdir'}
                  . $newfilename
                  . "\"");
            my $im =
              Gtk2::Gdk::Pixbuf->new_from_file(
                $globals->{'svgdir'} . $newfilename);
            my $canvas = get_current_canvas();
            $globals->{'canvas_image'} = Gnome2::Canvas::Item->new(
                $canvas->root, 'Gnome2::Canvas::Pixbuf',
                "pixbuf",      $im,
                "x",           0,
                "y",           0,
                "width",       $im->get_width,
                "height",      $im->get_height,
                "anchor",      'south-west',
            );
            my ($section, $page) = split(/\//, $newfilename, 2);
            $globals->{'canvas_image'}->{user_data} = $page;
            $globals->{'tool_type'} = IMAGE;
        }
        $xml->get_widget('dialogFile')->destroy();
    }
}

# Update display of brush width in toolbar
sub toggle_thick {
    my ($button) = @_;
    if ($mainxml->get_widget($button)->get_active()) {
        foreach
          my $item ('buttonFine', 'buttonMedium', 'buttonThick', 'buttonHeavy')
        {
            if ($item ne $button) {
                if ($mainxml->get_widget($item)->get_active()) {
                    $mainxml->get_widget($item)->set_active(FALSE);
                }
            }
        }
    }
    return $mainxml->get_widget($button)->get_active();
}

# Update display of current tool in toolbar
sub toggle_tool {
    my ($button) = @_;
    debug("$button chosen");
    if ($mainxml->get_widget($button)->get_active()) {
        foreach my $item (
            'buttonBlack',    'buttonWhiteout',
            'buttonHighlite', 'buttonText',
            'buttonTime',     'buttonPicture',
            'buttonDelete',   'buttonRed'
          )
        {
            if ($item ne $button) {
                if ($mainxml->get_widget($item)->get_active()) {
                    $mainxml->get_widget($item)->set_active(FALSE);
                }
            }
        }
    }
    return $mainxml->get_widget($button)->get_active();
}

####
## Network functions
####

# Handle input from network socket
sub io_handler {
    my ($sock, $tag) = @_;
    debug("Handling network");
    my $canvas   = FALSE;
    my $new_sock = $sock->accept();
    while (defined($_ = <$new_sock>)) {
        chomp;

        # Wait until the local user is finished what they are doing
        while (($globals->{'oldx'} != -100)
            && ($globals->{'oldy'} != -100)
            && (defined $globals->{'text_tag'}))
        {
            Gtk2->events_pending();
        }
        my @line = split(/"/, $_);
        my %item;
        foreach (@line) {
            my @tmp = split(/=/, $_, 2);
            $item{$tmp[0]} = $tmp[1];
        }

        if (!exists $svg{$item{'page'}}) {
            load_page($item{'page'});
            $canvas =
              $mainxml->get_widget('notebookMain')
              ->get_nth_page(
                $mainxml->get_widget('notebookMain')->get_current_page)
              ->get_child;
        } else {
            my $pagenum = 0;
            while (
                !(
                    ($canvas)
                    && ($pagenum <
                        $mainxml->get_widget('notebookMain')->get_n_pages())
                )
              )
            {
                $canvas =
                  $mainxml->get_widget('notebookMain')->get_nth_page($pagenum)
                  ->get_child;
                if ($canvas->{user_data} ne $item{'page'}) {
                    $canvas = FALSE;
                }
                $pagenum++;
            }
            if (!$canvas) {
                load_page($item{'page'});
                $canvas =
                  $mainxml->get_widget('notebookMain')
                  ->get_nth_page(
                    $mainxml->get_widget('notebookMain')->get_current_page)
                  ->get_child;
                debug("finish_load($item{'page'}, $canvas);");
            }
        }
        my $item = $svg{$item{'page'}}->getElement('svg')->createChild('path');
        foreach (keys %item) {
            if ($_ ne "page") {
                $item->attribute($_, $item{$_});
            }
        }
        load_item($item{'page'}, $canvas, $item,"canvas");
    }
    close($new_sock);

    return TRUE;
}

# Send changes over the network
sub send_item {
    my ($item, $filename) = @_;
    debug("Outport: $OUTPORT");
    foreach my $hostname (@hosts) {
        if (
            my $server = IO::Socket::INET->new(
                Proto    => "tcp",
                PeerAddr => $hostname,
                PeerPort => $OUTPORT
            )
          )
        {

            my $output = 'page=' . $filename;
            my $hash   = $item->{'_attributes'};
            foreach (keys %$hash) {
                $output .= '"' . $_ . '=' . $item->{'_attributes'}->{$_};
            }
            print $server $output . "\n";
            close($server);
        }
    }
}

# Turn on/off network client
sub toggle_client {
    my $conxml = Gtk2::GladeXML->new($globals->{'gladefile'}, 'dialogConnect');
    $conxml->signal_autoconnect_from_package('');
    my @tmp = sort @hosts;
    @hosts = @tmp;
    my $table = new Gtk2::Table((int(@hosts / 3) + 1), 3, TRUE);
    my @button = ();
    for (my $row = 0 ; $row <= int(@hosts / 3) ; $row++) {
        foreach my $col (0 .. 2) {
            my $itemnum = $row * 3 + $col;
            if (defined $hosts[$itemnum]) {
                $button[$itemnum] = Gtk2::ToggleButton->new($hosts[$itemnum]);
                $button[$itemnum]->set_active(TRUE);
                $table->attach(
                    $button[$itemnum], $col, $col + 1, $row, $row + 1,
                    ['expand', 'fill'],
                    ['expand', 'fill'],
                    0, 0
                );
            }
        }
    }
    $conxml->get_widget('vboxConnect')->pack_start($table, TRUE, TRUE, 0);
    $table->show_all();

    my $response = $conxml->get_widget('dialogConnect')->run();
    if ($response eq "ok") {
        my $found   = FALSE;
        my @tmplist = ();
        for my $itemnum (0 .. (@hosts - 1)) {
            if ($hosts[$itemnum] eq
                $conxml->get_widget('entryConnect')->get_text())
            {
                $found = TRUE;
            }
            if ($button[$itemnum]->get_active()) {
                if ($hosts[$itemnum] ne
                    $conxml->get_widget('entryConnect')->get_text())
                {
                    push @tmplist, $hosts[$itemnum];
                }
            }
        }
        if (   (!$found)
            && ($conxml->get_widget('entryConnect')->get_text() ne ""))
        {
            push @tmplist, $conxml->get_widget('entryConnect')->get_text();
        }
        @hosts = sort @tmplist;
    }
    debug(@hosts);
    if (@hosts == 0) {
        $globals->{'client_flag'} = FALSE;
    } else {
        $globals->{'client_flag'} = TRUE;
    }
    my $vbox = Gtk2::VBox->new(FALSE, 0);
    if ($globals->{'client_flag'}) {
        my $icon = Gtk2::Image->new_from_stock('gtk-cancel', 'large_toolbar');
        $vbox->pack_start($icon, TRUE, TRUE, 0);
        my $label = Gtk2::Label->new("Disconnect");
        $vbox->pack_start($label, TRUE, TRUE, 0);
    } else {
        my $icon = Gtk2::Image->new_from_stock('gtk-ok', 'large_toolbar');
        $vbox->pack_start($icon, TRUE, TRUE, 0);
        my $label = Gtk2::Label->new("Connect");
        $vbox->pack_start($label, TRUE, TRUE, 0);
    }
    $conxml->get_widget('dialogConnect')->destroy();
    my $child = $mainxml->get_widget('buttonClient')->get_child();
    $child->destroy();
    $mainxml->get_widget('buttonClient')->add($vbox);
    $mainxml->get_widget('buttonClient')->show_all;
}

# Turn on/off network server
sub toggle_server {
    my $vbox = Gtk2::VBox->new(FALSE, 0);
    if ($globals->{'server_flag'}) {
        turn_off_server();
        my $icon = Gtk2::Image->new_from_stock('gtk-no', 'large_toolbar');
        $vbox->pack_start($icon, TRUE, TRUE, 0);
        my $label = Gtk2::Label->new("Deaf");
        $vbox->pack_start($label, TRUE, TRUE, 0);
    } else {
        turn_on_server();
        my $icon = Gtk2::Image->new_from_stock('gtk-yes', 'large_toolbar');
        $vbox->pack_start($icon, TRUE, TRUE, 0);
        my $label = Gtk2::Label->new("Listening");
        $vbox->pack_start($label, TRUE, TRUE, 0);
    }
    my $child = $mainxml->get_widget('buttonServer')->get_child();
    $child->destroy();
    $mainxml->get_widget('buttonServer')->add($vbox);
    $mainxml->get_widget('buttonServer')->show_all;

}

# Turn on the nework server
sub turn_off_server {
    Gtk2::Helper->remove_watch($io_id);
    $mainxml->get_widget('buttonServer')->set_label("Deaf");
    $globals->{'server_flag'} = FALSE;
}

# Turn off the nework server
sub turn_on_server {
    debug("Turning on server");
    my $sock = new IO::Socket::INET(
        Listen    => SOMAXCONN,
        LocalPort => $globals->{'server_port'},
        Resuse    => 1,
        Proto     => 'tcp'
      )
      or die "Can't open socket: $!";
    $sock->autoflush(1);
    $io_id =
      Gtk2::Helper->add_watch($sock->fileno, 'in',
        sub { io_handler($sock, $io_id); });
    $globals->{'server_flag'} = TRUE;
}

# Edit the list of known servers
sub edit_favourite {
    my ($widget, $num, $newtext) = @_;
    my $store = $globals->{'prefs_xml'}->get_widget('treeHosts')->get_model();
    my $iter  = $store->get_iter_from_string($num);
    if ($newtext == "") {
        $store->remove($iter);
        my @newfav = ();
        foreach (0 .. (@favourites - 1)) {
            if ($_ != $num) {
                push @newfav, $favourites[$_];
            }
        }
        @favourites = @newfav;
    } else {
        $store->set($iter, 0, $newtext);
        $favourites[$num] = $newtext;
    }
    return TRUE;
}

# Add a server to the list of known servers
sub add_favourite {
    my $store   = $globals->{'prefs_xml'}->get_widget('treeHosts')->get_model();
    my $newtext = $globals->{'prefs_xml'}->get_widget('entryAddFav')->get_text;
    $store->set($store->append, 0, $newtext);
    push @favourites, $newtext;
}

