<%init>
my $output = "";
my $writer = XML::Writer->new( OUTPUT => \$output, UNSAFE => 1 );
Jifty->web->response->content_type('text/xml; charset=utf-8');
$writer->xmlDecl( "UTF-8", "yes" );
$writer->startTag("response");

if (my $ext = Jifty->web->request->argument('_webservice_external_redirect')) {
    $writer->startTag("redirect");
    $writer->cdataElement(url=> $ext);
    $writer->endTag();
    $writer->endTag();
    Jifty->web->out($output);
    $m->abort;
}

FRAGMENT:
for my $fragment ( Jifty->web->request->fragments ) {
    # Set up the form if need be
    Jifty->web->form->_init;
    Jifty->web->form->is_open(1) if $fragment->in_form;

    # Set up the region stack
    local Jifty->web->{'region_stack'} = [];
    my @regions;
    do {
        push @regions, $fragment;
    } while ($fragment = $fragment->parent);

    for my $current (reverse @regions) {
        my $new = Jifty->web->get_region( join '-', grep {$_} Jifty->web->qualified_region, $current->name );

        # Arguments can be complex mapped hash values.  Get their
        # real values by mapping.
        my %defaults = %{$current->arguments || {}};
        for (keys %defaults) {
            my ($key, $value) = Jifty::Request::Mapper->map(destination => $_, source => $defaults{$_});
            delete $defaults{$_};
            $defaults{$key} = $value;
        }

        $new ||= Jifty::Web::PageRegion->new(
            name           => $current->name,
            path           => URI::Escape::uri_unescape($current->path),
            region_wrapper => $current->wrapper,
            parent         => Jifty->web->current_region,
            defaults       => \%defaults,
        );

        # It's possible that the pageregion creation could fail -- no
        # name, for instance.  In that case, bail on this fragment.
        next FRAGMENT unless $new;

        $new->enter;
    }

    # Stuff the rendered region into the XML
    $writer->startTag( "fragment", id => Jifty->web->current_region->qualified_name );
    my %args = %{ Jifty->web->current_region->arguments };
    $writer->dataElement( "argument", $args{$_}, name => $_) for sort keys %args;
    if (Jifty->config->framework('ClientTemplate') && Jifty->web->current_region->client_cacheable) {
        $writer->cdataElement( "cacheable", Jifty->web->current_region->client_cache_content, type => Jifty->web->current_region->client_cacheable );
    }
    $writer->cdataElement( "content", Jifty->web->current_region->as_string );
    $writer->endTag();

    # Clean up region stack and form
    Jifty->web->current_region->exit while Jifty->web->current_region;
    Jifty->web->form->is_open(0);
}

my %results = Jifty->web->response->results;
for (keys %results) {
    $writer->startTag("result", moniker => $_, class => $results{$_}->action_class);
    $writer->dataElement("success", $results{$_}->success);

    $writer->dataElement("message", $results{$_}->message) if $results{$_}->message;
    $writer->dataElement("error", $results{$_}->error) if $results{$_}->error;

    my %warnings = $results{$_}->field_warnings;
    my %errors   = $results{$_}->field_errors;
    my %fields; $fields{$_}++ for keys(%warnings), keys(%errors);
    for (sort keys %fields) {
        next unless $warnings{$_} or $errors{$_};
        $writer->startTag("field", name => $_);
        $writer->dataElement("warning", $warnings{$_}) if $warnings{$_};
        $writer->dataElement("error", $errors{$_}) if $errors{$_};
        $writer->endTag();
    }

    # XXX TODO: Hack because we don't have a good way to serialize
    # Jifty::DBI::Record's yet, which are technically circular data
    # structures at some level (current_user of a
    # current_user->user_object is itself)
    my $content = stripkids($results{$_}->content);
    $writer->raw(XML::Simple::XMLout($content, NoAttr => 1, RootName => "content", NoIndent => 1))
      if keys %{$content};

    $writer->endTag();
}

$writer->endTag();
Jifty->web->response->content_type('text/xml; charset=UTF-8');
Jifty->web->out($output);
</%init>
<%once>
use Scalar::Util qw(blessed);
use XML::Simple;
sub stripkids {
    my $top = shift;
    if ( not ref $top ) { return $top }
    elsif (
        blessed($top)
        and (  $top->isa("Jifty::DBI::Record")
            or $top->isa("Jifty::DBI::Collection") )
        )
    {
        return undef;
    } elsif ( ref $top eq 'HASH' ) {
        foreach my $item ( keys %$top ) {
            $top->{$item} = stripkids( $top->{$item} );
        }
    } elsif ( ref $top eq 'ARRAY' ) {
        for ( 0 .. $#{$top} ) {
            $top->[$_] = stripkids( $top->[$_] );
        }
    }
    return $top;
}
</%once>