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

BEGIN
{
    use Zymonic::Utils qw(death_handler clean rethrow_exception);
    $main::SIG{__DIE__} = \&death_handler;

    # Warnings will cause the debugger to drop 'stop' so further
    # debugging can be done.
    no warnings;    # DB::single is only needed in -d mode
    $SIG{__WARN__} = sub { print STDERR join( " ", @_ ); $DB::single = 1 };
}

use strict;
use warnings;

use Zymonic;
use Zymonic::Toolkit;
use Zymonic::DB::none;
use Zymonic::Session;

package main;

# need to setup caches as with MP/cgi handlers
$Zymonic::object_cache = { 'Zymonic::TableInclude' => {}, 'Zymonic::RelationshipPermissions' => {}, };

my $usage =
"Usage:\nzymonic_toolkit_curses.pl [MODULE] [COMMAND] [COMMAND ARGUMENTS]\nOR\nzymonic_toolkit_curses.pl [CONFIGFILE]\n";

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

my $module = $ARGV[0] || '';

my $mo;
my $DB;

open my $log_fh, '>>', '/dev/null';
*STDERR = $log_fh;

# Load requested module (to be able to get args)
if ( !$module )
{
    print $usage;
    print "No module or configfile found on command line - add a module name to get further help.\n";
    print "\nAvailable modules:\n";
    foreach my $toolkit_module ( Zymonic::Toolkit::get_available_toolkit_modules() )
    {
        my $toolkit_description = '';
        eval {
            my $toolkit_def = "Zymonic::Toolkit::$toolkit_module"->definition();
            $toolkit_description =
              ( $toolkit_def && $toolkit_def->{ShortDescription} ? $toolkit_def->{ShortDescription}->{content} : '' );
        };
        print "* $toolkit_module - $toolkit_description\n";
    }
    exit(0);
}
else
{
    # Create a command line session object and Field Factory
    $Zymonic::field_factory = Zymonic::FieldFactory->new();

    # Use a 'none' DB object to start with
    $DB = Zymonic::DB::none->new();

    my $session = Zymonic::Session->new(
        module         => 'Curses',
        ident          => '',
        DB             => $DB,
        request_source => 'zymonic_toolkit_curses.pl',
        ident          => 'zzsession',
    );
    $Zymonic::session = $session;

    # load toolkit, from configfile if set
    $mo = Zymonic::Toolkit->new(
        ( -f $module ? ( configfile => $module ) : ( module => $module ) ),
        DB      => $DB,
        session => $session,
        ident   => 'zz' . $module,

    );

    $Zymonic::session->get_field("debugfile")->validate();
    $Zymonic::session->session_debugs();

    $Zymonic::session->{config} = $mo->get_config_stub($DB);

    # check whether modules/method are set from within it
    $module = $mo->get_module();

    unless ( ref($mo) eq 'Zymonic::Toolkit::' . $module )
    {
        print $usage;
        print "Module $module not found.\n";
        exit(0);
    }

    my @commands = $mo->commands;

    # map the commands into a form that the session can use as a menu.
    my $menu = {
        $module => {
            map {
                my $method = $_;
                $_ => {
                    do => sub { show_command( $mo, $method ); }
                  }
              }
              grep { $_ ne 'help' } @commands
        }
    };

    # call the session's setup_menu method with the hashref created above.
    $Zymonic::session->setup_menu($menu);

    # Get Zymonic::Session to start the mainloop.
    $Zymonic::session->run();

}

sub show_command
{
    my $mo     = shift;
    my $method = shift;

    $Zymonic::session->close_all_forms();
    $Zymonic::session->create_form( $method . '.options', 'current' );

    # Call show fields
    $mo->show_fields($method);

    # Add a button using a new Zymonic::Session show_confirm method
    # that is labelled as per the command name ($method)
    # bind the action / button to command_handler( $method )
    # pass in a 'Cancel' as the cancel label and and anonymous sub that closes the
    # options form
    $Zymonic::session->show_confirm(
        $method, sub { command_handler( $mo, $method ) },

        'Cancel', sub { $Zymonic::session->close_form( $method . '.options' ); }
    );

}

sub command_handler
{
    my $mo       = shift;
    my $method   = shift;
    my $btn_name = shift;

    #filename variable to get the module and method and then concatinate
    #together
    my $filename = $mo->{module} . "_" . $method . ".txt";

    # Create an output form
    $Zymonic::session->create_form( $method . '.output', 'current' );
    $Zymonic::session->add_session_errors_to_current_form();

    my $save_file_btn = $Zymonic::session->last_page_of_current_form->{container}->add(
        "save_choose",
        "Buttonbox",
        -buttons => [
            {
                -label   => "Select file",
                -onpress => sub {
                    my $file = $Zymonic::session->_cursesUI->savefilebrowser();
                    $filename = $file;
                }
            }
        ],
        -border => 1,
        -width  => 15,
        -y      => $Zymonic::session->{button_y},
        -x      => $Zymonic::session->tab_x_value(3),
    );

    #add file browser buttons save to and save to file
    my $save_btn = $Zymonic::session->last_page_of_current_form->{container}->add(
        "save_new",
        "Buttonbox",
        -buttons => [
            {
                -label   => "Save",
                -onpress => sub {
                    my $fh;

                    unless ( open $fh, '>>', $filename )
                    {
                        $Zymonic::session->_cursesUI->dialog( -message => 'failed to open' . $filename );
                    }
                    else
                    {
                        my %seh = $Zymonic::session->session_errors;
                        print $fh join( "\n", map { $_->{content} } @{ $seh{session_errors} } ) . "\n";
                        close $fh;
                        $Zymonic::session->_cursesUI->dialog( -message => 'successfully written to' . $filename );
                    }
                }
            }
        ],
        -border => 1,
        -width  => 10,
        -y      => $Zymonic::session->{button_y},
        -x      => $Zymonic::session->tab_x_value(2),
    );
    $save_btn->focus();

    # Adds an OK button with a handler that closes
    # the options and output windows.
    $Zymonic::session->show_confirm(
        'OK',
        sub {
            $Zymonic::session->close_form( $method . '.output' );
        }
    );

    # Ensure the user values are reset (this is interactive)
    $Zymonic::field_factory->clear_user_values();

    $mo->{method} = $method;

    if ( $mo->validate_fields($method) )
    {
        $Zymonic::session->session_debugs();
        eval {

            $mo->$method();
            $Zymonic::session->close_form( $method . '.options' );

            1;
        } or do
        {
            my $exception = $@;
            $mo->log( $mo->ll_exception($exception) );
            if ( ref($exception) && $exception->isa('Zymonic::Exception::Toolkit::ForceStop') )
            {
                # for force stop errors, print out the message to the user
                # use record_session_error not print

                $Zymonic::session->record_session_error( $mo->ll_exception($exception) );
            }

            else
            {
                #otherwise rethrow for death handler
                my $err = death_handler( $exception, '', 'return_error' );
                $Zymonic::session->record_session_error( $err->{message}->{content} );

            }
        };

        my $completed_message = $mo->get_completed_message();

        #  use record_session_error not print
        #$Zymonic::session->record_session_error("$completed_message") if $completed_message;

    }
    else
    {

        $mo->usage_and_errors($method);
        $Zymonic::session->close_form( $method . '.options' );

    }

}

# Explicitly destroy session to trigger closing methods
$Zymonic::session = undef;
