package Jifty::Plugin::SetupWizard::View;
use strict;
use warnings;
use Jifty::View::Declare -base;

template '/__jifty/admin/setupwizard' => page {
    my $appname = Jifty->config->framework('ApplicationName');
    h1 { _("Welcome to %1!", $appname) };

    render_region(
        name      => 'WizardStep',
        path      => "/__jifty/admin/setupwizard/step",
        arguments => {
            step => 0,
        },
    );
};

template '/__jifty/admin/setupwizard/step' => sub {
    my $step = get('step');
    my $steps = Jifty->find_plugin('Jifty::Plugin::SetupWizard')->steps;
    my $step_info = $steps->[$step] or die "Invalid step index";

    div {
        class is 'setupwizard-step';

        form {
            h3 { _('%1. %2', $step+1, $step_info->{header}) } if $step_info->{header};

            show "/__jifty/admin/setupwizard/$step_info->{template}";

            unless ($step_info->{hide_button}) {
                form_submit(
                    label => _('Next'),
                    onclick => {
                        # Submit all actions
                        submit => undef,

                        # Advance to the next step
                        refresh_self => 1,
                        arguments => {
                            step => $step + 1,
                        },
                    },
                );
            }
        };
    };

    div {
        class is 'setupwizard-links';

        span { 'Skip to: ' };

        for my $i (0 .. @$steps - 1) {
            # Separator
            if ($i > 0) {
                span { ' | ' }
            }

            step_link(
                index   => $i,
                label   => "%1",
                current => $i == $step,
            );
        }
    };
};

sub step_link {
    my %args = (
        index   => 0,
        label   => "%1",
        current => 0,
        @_,
    );

    my $index = $args{index};

    my $steps = Jifty->find_plugin('Jifty::Plugin::SetupWizard')->steps;
    return unless $index >= 0 && $index < @$steps;

    my $info = $steps->[$index];
    my $name = $info->{link} || $info->{header} || $info->{template};

    if ($args{current}) {
        b { _($args{label}, $name) },
    }
    else {
        hyperlink(
            label => _($args{label}, $name),
            onclick => {
                replace_self => 1,
                arguments => {
                    step => $index,
                },
            },
        );
    }
}

sub config_field {
    my %args = @_;

    my $action = new_action('AddConfig');

    my %value_args = %{ $args{value_args} || {} };

    # Grab a sensible default, the current value of config
    if (!exists($value_args{default_value})) {
        $value_args{default_value} = Jifty->config->contextual_get($args{context}, $args{field});
    }

    # Grab sensible label, the value of field
    if (!exists($value_args{label})) {
        $value_args{label} = $args{field};
    }

    outs_raw($action->form_field('value' => %value_args));

    for my $field (qw/field context target_file message empty_is_undef/) {
        outs_raw($action->form_field(
            $field,
            render_as => 'hidden',
            (exists($args{$field}) ? (default_value => $args{$field}) : ()),
        ));
    }

    return $action;
}

template '/__jifty/admin/setupwizard/welcome' => sub {
    my $appname = Jifty->config->framework('ApplicationName');

    p {
        _("This installer will help you configure %1 by walking you through the following steps.", $appname)
    }

    ol {
        for my $i (0 .. @{ Jifty->find_plugin('Jifty::Plugin::SetupWizard')->steps } - 1) {
            li {
                step_link(
                    index   => $i,
                    label   => "%1",
                    current => $i == get('step'),
                );
            }
        }
    }

    p {
        _("At any time you may close the wizard; your progress will be saved for next time. You may also skip around, doing these steps in whatever order suits you.");
    }

    p {
        outs_raw _("This setup wizard was activated by the presence of <tt>SetupMode: 1</tt> in one of your configuration files. If you are seeing this erroneously, you may restore normal operation by adjusting the <tt>etc/site_config.yml</tt> file to have <tt>SetupMode: 0</tt> set under <tt>framework</tt>.");
    };

    form_submit(
        label => _('Begin'),
        onclick => {
            # Advance to the next step
            refresh_self => 1,
            arguments => {
                step => get('step') + 1,
            },
        },
    );
};

template '/__jifty/admin/setupwizard/language' => sub {
    p { _("You may select a different language.") };
};

template '/__jifty/admin/setupwizard/database' => sub {
    # XXX: We've got to add a sane way to unquote stuff in onfoo handlers...
    my $onchange = 'Jifty.update('
                 . Jifty::JSON::encode_json({
                    actions          => {},
                    action_arguments => {},
                    fragments        => [
                        {
                            mode => 'Replace',
                            path => '/__jifty/admin/setupwizard/database/PLACEHOLDER',
                            region => Jifty->web->qualified_region('database_details'),
                        },
                    ],
                    continuation     => undef,

                 })
                 . ', this)';

    $onchange =~ s/PLACEHOLDER/"+this.value+"/;

    # Only show them drivers they have available
    my (@available_drivers, @unavailable_drivers);
    my @all_drivers = (
        { display => 'SQLite',     value => 'SQLite' },
        { display => 'MySQL',      value => 'mysql' },
        { display => 'PostgreSQL', value => 'Pg' },
        #{ display => 'Oracle', value => 'Oracle' },
    );
    for (@all_drivers) {
        if (Jifty->handle->is_available_driver($_->{value})) {
            push @available_drivers, $_;
        }
        else {
            push @unavailable_drivers, $_;
        }
    }

    my $current_driver = Jifty->config->framework('Database')->{Driver};
    my $appname = Jifty->config->framework('ApplicationName');

    p { _("You may choose a database engine.") };

    p { _("%1 works with a number of different databases. MySQL, PostgreSQL, and SQLite are all supported. You should choose the database that you or your local database administrator knows best.", $appname) };

    p { _("SQLite is a small database engine that does not need a server or any configuration. We recommend it for testing, demonstration, and development, but it is not quite right for a high-volume production server.") };

    p { _("MySQL and PostgreSQL are well-supported production-quality database engines. ") };

    if (@unavailable_drivers) {
        my @drivers = map { "DBD::$_->{value}" } @unavailable_drivers;
        my $drivers = join ', ', @drivers;

        $drivers =~ s/, (?!.*,)/ or /;

        p { _("If your preferred database is not listed in the dropdown below, that means we could not find a database driver for it. You may be able to remedy this by using CPAN to download and install $drivers.") };
    }

    config_field(
        field      => 'Driver',
        context    => '/framework/Database',
        value_args => {
            label            => _('Database Engine'),
            render_as        => 'select',
            available_values => \@available_drivers,
            onchange         => [$onchange],
        },
    );

    config_field(
        field      => 'Database',
        context    => '/framework/Database',
        value_args => {
            label     => _('Database Name'),
        },
    );

    render_region(
        name => 'database_details',
        path => "/__jifty/admin/setupwizard/database/$current_driver",
    );

    render_region(
        name => 'test_connectivity',
        path => '/__jifty/admin/setupwizard/database/test_connectivity_button',
    );
};

template '/__jifty/admin/setupwizard/database/SQLite' => sub {
    # Nothing more needed!
};

sub _configure_database_connectivity {
    my $driver = shift;

    config_field(
        field   => 'Host',
        context => '/framework/Database',
        value_args => {
            hints => _('The domain name of your database server (for example, db.example.com)'),
        },
        empty_is_undef => 1,
    );

    config_field(
        field   => 'Port',
        context => '/framework/Database',
        value_args => {
            hints => _('Leave blank to use the default value for your database'),
        },
        empty_is_undef => 1,
    );

    # Better default for postgres ("root" is Jifty's current default)
    my %user_value_args;
    $user_value_args{default_value} = 'postgres'
        if $driver eq 'Pg'
        && Jifty->config->framework('Database')->{User} eq 'root';

    config_field(
        field   => 'User',
        context => '/framework/Database',
        empty_is_undef => 1,
        value_args => \%user_value_args,
    );

    config_field(
        field   => 'Password',
        context => '/framework/Database',
        value_args => {
            render_as => 'password',
        },
        empty_is_undef => 1,
    );
}

template '/__jifty/admin/setupwizard/database/mysql' => sub {
    _configure_database_connectivity('mysql');
};

template '/__jifty/admin/setupwizard/database/Pg' => sub {
    _configure_database_connectivity('Pg');

    config_field(
        field   => 'RequireSSL',
        context => '/framework/Database',
        value_args => {
            label     => _('Use SSL?'),
            render_as => 'checkbox',
        },
    );
};

template '/__jifty/admin/setupwizard/database/test_connectivity_button' => sub {
    hyperlink(
        label     => _("Test connectivity"),
        as_button => 1,
        onclick   => {
            # Submit all actions
            submit => undef,

            # Actually test connectivity
            replace_with => '/__jifty/admin/setupwizard/database/test_connectivity',
        },
    );
};

template '/__jifty/admin/setupwizard/database/test_connectivity' => sub {
    my $db_args = Jifty->config->framework('Database');
    my $action = Jifty::Plugin::SetupWizard::Action::TestDatabaseConnectivity->new(
        arguments => {
            driver     => $db_args->{Driver},
            database   => $db_args->{Database},
            host       => $db_args->{Host},
            port       => $db_args->{Port},
            user       => $db_args->{User},
            password   => $db_args->{Password},
            requiressl => $db_args->{RequireSSL},
        },
    );
    $action->validate;
    $action->run;

    if ($action->result->success) {
        p {
            attr { class => 'popup_message' };
            outs $action->result->message;
        }
    }
    else {
        p {
            attr { class => 'popup_error' };
            outs $action->result->error;
        }
    }

    show '/__jifty/admin/setupwizard/database/test_connectivity_button';
};

template '/__jifty/admin/setupwizard/web' => sub {
    p { _("You may change web server settings.") };

    my $appname = lc Jifty->config->framework('ApplicationName');
    $appname =~ s/-//g;

    config_field(
        field      => 'BaseURL',
        context    => '/framework/Web',
        value_args => {
            hints => _('The root URL for the web server (examples: http://%1.yourcompany.com, http://business.com/%1)', $appname),
        },
    );

    config_field(
        field   => 'Port',
        context => '/framework/Web',
    );
};

template '/__jifty/admin/setupwizard/finalize' => sub {
    p { _("You may finalize your configuration.") };

    my $appname = Jifty->config->framework('ApplicationName');
    my $action = config_field(
        field      => 'SetupMode',
        context    => '/framework',
        message    => _('Setup finished. Welcome to %1!', $appname),
        value_args => {
            render_as     => 'hidden',
            default_value => 0,
        },
    );

    form_next_page url => '/';
    form_submit( label => _('Done!') );
};

1;

__END__

=head1 NAME

Jifty::Plugin::SetupWizard::View - templates for SetupWizard

=head1 FUNCTIONS

=head2 step_link

A helper function for constructing a link to a different step. Expected
arguments: the C<index> of the step and the C<label> for the link.

=head2 config_field

A helper function for constructing a mini-form for a config field. It returns
the action that was created. Expected arguments are:

=over 4

=item value_args

The arguments for the C<form_field> call for value. If there's no C<default_value>, one will be constructed using the C<context> parameter.

=item field

=item context

=item target_file

=item message

=item empty_is_undef

These parameters are for specifying defaults for each action argument.

=back

=cut

