#!/usr/bin/perl -T -w
#
# Zymonic Business Process and Information Management System
# Copyright Zednax Limited 2008 -
# For Authors and Changelog see the subversion history
use strict;

# Library path
BEGIN
{
    use vars qw($location $script_name $script_location $utils);
    use Zymonic::Utils qw(clean debug death_handler debug_exception rethrow_exception deep_replace_card_numbers);
    $main::SIG{__DIE__} = \&death_handler;
}

# Load Zymonic and clear globals
use Zymonic;
$Zymonic::session = '';
$Zymonic::system  = '';

# Config Vars
my $saxon = 0;

# XML out
my $xmlout = {};

# Global objects
my $db;
my $auth;

# Modules
use Zymonic::Config;
use Zymonic::Session;
use Zymonic::DB;
use Zymonic::Auth;
use XML::Simple;

my $protocol = ( ( defined( $ENV{HTTPS} ) and $ENV{HTTPS} eq 'on' ) ? 'https' : 'http' );

# Clean path
$ENV{PATH} = "/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/sbin:/bin:/usr/bin:/sbin:/usr/sbin";

# set binmode for STDOUT and STDERR to handle unicode
binmode STDOUT, ':utf8';
binmode STDERR, ':utf8';

# setup the field factory
$Zymonic::field_factory = Zymonic::FieldFactory->new();

# enable cache for table includes and relationship permissions
$Zymonic::object_cache = { 'Zymonic::TableInclude' => {}, 'Zymonic::RelationshipPermissions' => {}, };

# reset tabindex for this request
$Zymonic::tabindex = 0;

# Create a session (CGI only)
$ENV{SERVER_NAME} = clean( $ENV{SERVER_NAME}, "-_" );
$Zymonic::session = Zymonic::Session->new(
    ip_address      => clean( $ENV{REMOTE_ADDR} ),
    x_forwarded_for => clean( $ENV{HTTP_X_FORWARDED_FOR} ) || '',
    protocol        => $protocol
);

$Zymonic::system = $Zymonic::session->system_name( $ENV{SERVER_NAME}, "/etc/zymonic" );

# Get any flags
my $no_display_attributes = $Zymonic::session->no_display_attributes;

debug("Zymonic starting... system: $Zymonic::system");

$Zymonic::ZCONFIG{$Zymonic::system} = Zymonic::Config->new(
    system_name => $Zymonic::system,
    config_dir  => "/etc/zymonic",
    protocol    => $protocol,
);

my $redirect_url = '';

$db = Zymonic::DB->new( config => $Zymonic::ZCONFIG{$Zymonic::system} );
$Zymonic::session->{DB} = $db;

$auth = Zymonic::Auth->new(
    config      => $Zymonic::ZCONFIG{$Zymonic::system},
    session     => $Zymonic::session,
    DB          => $db,
    user        => '',
    credentials => '',
    logged_in   => '',
    ip_address  => $Zymonic::session->{ip_address}
);

# Initialise the session fully
$Zymonic::session->initialise_session(
    {
        config => $Zymonic::ZCONFIG{$Zymonic::system},
        auth   => $auth,
        DB     => $db
    }
);

# check if servside xslt is required
$saxon = $Zymonic::session->server_side_xslt();

# build documentation if needed
if ( $Zymonic::session->build_documentation )
{
    eval {
        $Zymonic::ZCONFIG{$Zymonic::system}->build_documentation($auth);
        1;
    } or do
    {

        # don't let any exceptions here bring the system down
        # debug it but ignore it
        my $exception = $@;
        if ($exception)
        {
            if ( ref($exception) and $exception->isa('Zymonic::Exception') )
            {
                debug_exception($exception);
            }
            else
            {
                debug( 'Unknown Exception (or a die): ' . Dumper($exception) );
            }
        }
    };
}

eval {
    $xmlout = $Zymonic::session->view_control($no_display_attributes);
    1;
}
  or do
{
    my $exception = $@;
    if ( $exception and ref($exception) and $exception->isa('Zymonic::Exception::State::Redirect') )
    {
        $redirect_url = $exception->redirect_url;
    }
    else
    {
        rethrow_exception($exception);
    }
};

unless ( $no_display_attributes or ( defined( $xmlout->{css} ) and $xmlout->{css} ) )

{
    $xmlout->{css} = "/ZymonicDefault.css";
}

# check for custom xsl
my $zz_xsl = $Zymonic::session->clean_param( 'ZZxsl', '/\\-._' );
my $xsl = $zz_xsl || $Zymonic::session->xsl();
my $xsl_with_path = $Zymonic::ZCONFIG{$Zymonic::system}->{htmlroot};
unless ($xsl)
{
    if ( ref( $xmlout->{currentpage} ) && $xmlout->{currentpage}->{xsl} )
    {
        $xsl = $xmlout->{currentpage}->{xsl};
    }
    else
    {
        $xsl = $Zymonic::ZCONFIG{$Zymonic::system}->{xslt};
    }
}

my $language = $Zymonic::session->language;

if (  -f $Zymonic::ZCONFIG{$Zymonic::system}->{htmlroot} . "/"
    . $language->{lang_code} . "-"
    . $language->{subset} . "/"
    . $xsl )
{
    $xsl = "/" . $language->{lang_code} . "-" . $language->{subset} . "/" . $xsl;
}

if ($redirect_url)
{
    print $Zymonic::session->redirect($redirect_url);
}
else
{

    # Output the XML
    my $output_xml_string = XMLout(
        $xmlout,
        KeyAttr       => [],
        RootName      => "Zymonic",
        NoEscape      => 1,
        SuppressEmpty => 1
    );
    if (   $Zymonic::ZCONFIG{$Zymonic::system}->{debug_io_xml}
        && $Zymonic::ZCONFIG{$Zymonic::system}->{debug_io_xml} eq 'true' )
    {
        debug( "Outgoing XML: " . deep_replace_card_numbers($output_xml_string), 'true' );
    }

    # if no ZZxsl and param to suppress XSL or API mode, then don't output XSL info
    if ( !$zz_xsl && ( $Zymonic::session->clean_param("notransform") or $no_display_attributes ) )
    {
        print $Zymonic::session->header;
        print $output_xml_string;
    }
    elsif ( !$saxon )
    {
        print $Zymonic::session->header;
        print "<?xml-stylesheet href=\"" . $xsl . "\" type=\"text/xsl\"?>\n";
        print $output_xml_string;
    }
    else
    {
        open( XT, ">/tmp/xml.$$" );
        print XT $output_xml_string;
        close(XT);

        debug("Server Side XSLT: /usr/local/bin/saxon /tmp/xml.$$ $xsl_with_path/$xsl");
        print $Zymonic::session->header( type => 'text/html' );
        print `/usr/local/bin/saxon /tmp/xml.$$ $xsl_with_path/$xsl`;
    }
}
