%# BEGIN BPS TAGGED BLOCK {{{
%# 
%# COPYRIGHT:
%#  
%# This software is Copyright (c) 1996-2005 Best Practical Solutions, LLC 
%#                                          <jesse@bestpractical.com>
%# 
%# (Except where explicitly superseded by other copyright notices)
%# 
%# 
%# LICENSE:
%# 
%# This work is made available to you under the terms of Version 2 of
%# the GNU General Public License. A copy of that license should have
%# been provided with this software, but in any event can be snarfed
%# from www.gnu.org.
%# 
%# This work 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., 675 Mass Ave, Cambridge, MA 02139, USA.
%# 
%# 
%# CONTRIBUTION SUBMISSION POLICY:
%# 
%# (The following paragraph is not intended to limit the rights granted
%# to you to modify and distribute this software under the terms of
%# the GNU General Public License and is only of importance to you if
%# you choose to contribute your changes and enhancements to the
%# community by submitting them to Best Practical Solutions, LLC.)
%# 
%# By intentionally submitting any modifications, corrections or
%# derivatives to this work, or any other work intended for use with
%# Request Tracker, to Best Practical Solutions, LLC, you confirm that
%# you are the copyright holder for those contributions and you grant
%# Best Practical Solutions,  LLC a nonexclusive, worldwide, irrevocable,
%# royalty-free, perpetual, license to use, copy, create derivative
%# works based on those contributions, and sublicense and distribute
%# those contributions and any derivatives thereof.
%# 
%# END BPS TAGGED BLOCK }}}
%# REST/1.0/Forms/ticket/default
%#
<%ARGS>
$id
$changes => {}
$fields => undef
</%ARGS>
<%perl>
use MIME::Entity;

my @comments;
my ($c, $o, $k, $e) = ("", [], {}, 0);
my %data   = %$changes;
my $ticket = new RT::Ticket $session{CurrentUser};
my @dates  = qw(Created Starts Started Due Resolved Told);
my @people = qw(Requestors Cc AdminCc);
my @create = qw(Queue Requestor Subject Cc AdminCc Owner Status Priority
                InitialPriority FinalPriority TimeEstimated TimeWorked
                TimeLeft Starts Started Due Resolved);
my @simple = qw(Subject Status Priority Disabled TimeEstimated TimeWorked
                TimeLeft InitialPriority FinalPriority);
my %dates  = map {lc $_ => $_} @dates;
my %people = map {lc $_ => $_} @people;
my %create = map {lc $_ => $_} @create;
my %simple = map {lc $_ => $_} @simple;

# Are we dealing with an existing ticket?
if ($id ne 'new') {
    $ticket->Load($id);
    if (!$ticket->Id) {
        return [ "# Ticket $id does not exist.", [], {}, 1 ];
    }
    elsif (!$ticket->CurrentUserHasRight('ShowTicket') ||
           (%data && !$ticket->CurrentUserHasRight('ModifyTicket')))
    {
        my $act = %data ? "modify" : "display";
        return [ "# You are not allowed to $act ticket $id.", [], {}, 1 ];
    }
}
else {
    if (%data == 0) {
        # GET ticket/new: Return a suitable default form.
        # We get defaults from queue/1 (XXX: What if it isn't there?).
        my $due = new RT::Date $session{CurrentUser};
        my $queue = new RT::Queue $session{CurrentUser};
        my $starts = new RT::Date $session{CurrentUser};
        $queue->Load(1);
        $due->SetToNow;
        $due->AddDays($queue->DefaultDueIn) if $queue->DefaultDueIn;
        $starts->SetToNow;

        return [
            "# Required: Queue, Requestor, Subject",
            [ qw(id Queue Requestor Subject Cc AdminCc Owner Status Priority
                 InitialPriority FinalPriority TimeEstimated Starts Due Text) ],
            {
                id               => "ticket/new",
                Queue            => $queue->Name,
                Requestor        => $session{CurrentUser}->Name,
                Subject          => "",
                Cc               => [],
                AdminCc          => [],
                Owner            => "",
                Status           => "new",
                Priority         => $queue->InitialPriority,
                InitialPriority  => $queue->InitialPriority,
                FinalPriority    => $queue->FinalPriority,
                TimeEstimated    => 0,
                Starts           => $starts->ISO,
                Due              => $due->ISO,
                Text             => "",
            },
            0
        ];
    }
    else {
        # We'll create a new ticket, and fall through to set fields that
        # can't be set in the call to Create().
        my (%v, $text);

        foreach my $k (keys %data) {
            if (exists $create{lc $k}) {
                $v{$create{lc $k}} = delete $data{$k};
            }
            elsif (lc $k eq 'text') {
                $text = delete $data{$k};
            }
        }

        if ($text) {
            $v{MIMEObj} =
                MIME::Entity->build(
                    From => $session{CurrentUser}->EmailAddress,
                    Subject => $v{Subject},
                    Data => $text
                );
        }

        $ticket->Create(%v);
        unless ($ticket->Id) {
            return [ "# Could not create ticket.", [], {}, 1 ];
        }

        delete $data{id};
        $id = $ticket->Id;
        push(@comments, "# Ticket $id created.");
        goto DONE if %data == 0;
    }
}

# Now we know we're dealing with an existing ticket.
if (%data == 0) {
    my ($time, $key, $val, @data);

    push @data, [ id    => "ticket/".$ticket->Id   ];
    push @data, [ Queue => $ticket->QueueObj->Name ] 
	if (!%$fields || exists $fields->{lc 'Queue'});
    push @data, [ Owner => $ticket->OwnerObj->Name ]
	if (!%$fields || exists $fields->{lc 'Owner'});
    push @data, [ Creator => $ticket->CreatorObj->Name ]
	if (!%$fields || exists $fields->{lc 'Creator'});

    foreach (qw(Subject Status Priority InitialPriority FinalPriority)) {
	next unless (!%$fields || (exists $fields->{lc $_}));
        push @data, [$_ => $ticket->$_ ];
    }

    foreach $key (@people) {
	next unless (!%$fields || (exists $fields->{lc $key}));
        push @data, [ $key => [ $ticket->$key->MemberEmailAddresses ] ];
    }

    $time = new RT::Date ($session{CurrentUser});
    foreach $key (@dates) {
	next unless (!%$fields || (exists $fields->{lc $key}));
        $time->Set(Format => 'sql', Value => $ticket->$key);
        push @data, [ $key => $time->AsString ];
    }

    $time = new RT::Date ($session{CurrentUser});
    foreach $key (qw(TimeEstimated TimeWorked TimeLeft)) {
	next unless (!%$fields || (exists $fields->{lc $key}));
        $val = $ticket->$key || 0;
        $val = $time->DurationAsString($val*60) if $val;
        push @data, [ $key => $val ];
    }

    my %k = map {@$_} @data;
    $o = [ map {$_->[0]} @data ];
    $k = \%k;
}
else {
    my ($get, $set, $key, $val, $n, $s);

    foreach $key (keys %data) {
        $val = $data{$key};
        $key = lc $key;
        $n = 1;

        if (ref $val eq 'ARRAY') {
            unless ($key =~ /^(?:Requestors|Cc|AdminCc)$/i) {
                $n = 0;
                $s = "$key may have only one value.";
                goto SET;
            }
        }

        if ($key =~ /^queue$/i) {
            next if $val eq $ticket->QueueObj->Name;
            ($n, $s) = $ticket->SetQueue($val);
        }
        elsif ($key =~ /^owner$/i) {
            next if $val eq $ticket->OwnerObj->Name;
            ($n, $s) = $ticket->SetOwner($val);
        }
        elsif (exists $simple{$key}) {
            $key = $simple{$key};
            $set = "Set$key";

            next if (($val eq $ticket->$key)|| ($ticket->$key =~ /^\d+$/ && $val == $ticket->$key));
            ($n, $s) = $ticket->$set("$val");
        }
        elsif (exists $dates{$key}) {
            $key = $dates{$key};
            $set = "Set$key";

            my $time = new RT::Date $session{CurrentUser};
            $time->Set(Format => 'sql', Value => $ticket->$key);
            next if ($val =~ /^not set$/i || $val eq $time->AsString);
            ($n, $s) = $ticket->$set($val);
        }
        elsif (exists $people{$key}) {
            $key = $people{$key};
            my ($p, @msgs);

            my %new  = map {$_=>1} @{ vsplit($val) };
            my %old  = map {$_=>1} $ticket->$key->MemberEmailAddresses;
            my $type = $key eq 'Requestors' ? 'Requestor' : $key;

            foreach $p (keys %old) {
                unless (exists $new{$p}) {
                    ($s, $n) = $ticket->DeleteWatcher(Type => $type,
                                                      Email => $p);
                    push @msgs, [ $s, $n ];
                }
            }
            foreach $p (keys %new) {
                # XXX: This is a stupid test.
                unless ($p =~ /^[\w.+-]+\@([\w.-]+\.)*\w+.?$/) {
                    $s = 0;
                    $n = "$p is not a valid email address.";
                    push @msgs, [ $s, $n ];
                    next;
                }
                unless ($ticket->IsWatcher(Type => $type, Email => $p)) {
                    ($s, $n) = $ticket->AddWatcher(Type => $type,
                                                   Email => $p);
                    push @msgs, [ $s, $n ];
                }
            }

            $n = 1;
            if (@msgs = grep {$_->[0] == 0} @msgs) {
                $n = 0;
                $s = join "\n", map {"# ".$_->[1]} @msgs;
                $s =~ s/^# //;
            }
        }
        elsif ($key ne 'id' && $key ne 'type' && $key ne 'creator') {
            $n = 0;
            $s = "Unknown field.";
        }

    SET:
        if ($n == 0) {
            $e = 1;
            push @comments, "# $key: $s";
            unless (@$o) {
                my %o = keys %$changes;
                delete $o{id};
                @$o = ("id", keys %o);
                $k = $changes;
            }
        }
    }
    push(@comments, "# Ticket ".$ticket->id." updated.") unless $n == 0;
}

DONE:
$c ||= join("\n", @comments) if @comments;
return [$c, $o, $k, $e];

</%perl>
