package Cpanel::Easy::Apache::UI::CLI;

# cpanel - Cpanel/Easy/Apache/UI/CLI.pm           Copyright(c) 2014 cPanel, Inc.
#                                                           All rights Reserved.
# copyright@cpanel.net                                         http://cpanel.net
# This code is subject to the cpanel license. Unauthorized copying is prohibited

use base 'Cpanel::Easy::Apache::UI::Utils';

use Term::ANSIColor;
use File::Spec;

sub perldoc {
    my ( $self, $easy, $file ) = @_;
    die 'Invalid perldoc arg' if !-f $file;
    exec( qw( perldoc -F ), $file );
}

sub restore_backup {
    my ( $self, $easy ) = @_;

    require Cpanel::Easy::Apache::Utils::ArchiveRestore;
    Cpanel::Easy::Apache::Utils::ArchiveRestore::run(
        $easy,
        sub {
            my ( $easy, $backups_data_ar ) = @_;

            my @backups_data = @{$backups_data_ar};

            pipe READ, WRITE;

            if ( fork == 0 ) {
                close READ;
                require Curses::UI;
                local $ENV{'TERM'} = $ENV{'TERM'} =~ /^(xterm|xterm-256color)$/i ? 'xterm-color' : $ENV{'TERM'};    # case 2336
                my $cui = Curses::UI->new( '-clear_on_exit' => 1, '-color_support' => 0, '-mouse_support' => 1 );
                require Cpanel::Easy::Apache::UI::CLI::Config;
                my $wid = 'archive_restore';
                my $win = Cpanel::Easy::Apache::UI::CLI::Config::__get_window( $cui, $wid, 'Please choose an archive to restore' );
                my $y   = @backups_data;

                my $exit;

                $exit = $cui->dialog(
                    '-title'           => 'BETA Functionality Disclaimer',
                    '-message'         => "This interface is for restoring archived apache builds. It is BETA and may have unexpected results. Do not use this if you are unsure of what will happen. Do not use this if you are unable to resolve any problems that may arise from restoring an old apache build.\n\nAre you sure you want to continue?",
                    '-selected'        => 0,
                    '-buttonalignment' => 'middle',
                    '-buttons'         => [
                        {
                            '-label'   => '[No]',
                            '-value'   => 1,
                            '-onpress' => sub {
                                $exit = 1;
                            },
                        },
                        {
                            '-label' => '[Yes]',
                            '-value' => 0,
                        },
                    ],
                );
                if ($exit) {
                    print WRITE "exit exit\n";
                    close WRITE;
                    exit;
                }

                my $radio = $win->add(
                    'mylistbox', 'Listbox',
                    '-x'        => 2,
                    '-y'        => 1,
                    '-height'   => $y,
                    '-selected' => 0,
                    '-values'   => [ map { $_->[0] } @backups_data, ],
                    '-labels'   => { map { $_->[0] => $_->[1] } @backups_data, },
                    '-radio'    => 1,
                );
                $radio->focus();
                $radio->{'-focus'} = 1;
                $win->onFocus( sub { $radio->focus() } );

                $y += 2;
                $win->add(
                    $wid . 'finalchoice',
                    'Buttonbox',
                    '-y'               => $y,
                    '-buttonalignment' => 'middle',
                    '-selected'        => 0,
                    '-buttons'         => [
                        {
                            '-label'   => '[Restore]',
                            '-onpress' => sub {
                                my $ok = Cpanel::Easy::Apache::UI::CLI::Config::_confirmation_box( $cui, 'Confirm Archive Choice', 'Are you sure you want to replace your apache with this archive?' );
                                my $path = $ok ? $backups_data[ $radio->id ]->[0] : '';
                                if ($path) {
                                    print WRITE "$path\n";
                                    close WRITE;
                                    exit;
                                }
                            },
                        },
                        {
                            '-label'   => '[Exit]',
                            '-onpress' => sub {
                                print WRITE "exit exit\n";
                                close WRITE;
                                exit;
                            },
                        },
                    ],
                );
                Cpanel::Easy::Apache::UI::CLI::Config::__line_of_text( $win, 'Tab key toggles between menu & button', $y, 0 );
                $y++;

                Cpanel::Easy::Apache::UI::CLI::Config::__line_of_text( $win, 'Press q to exit without any changes', $y, 0 );
                $y++;

                Cpanel::Easy::Apache::UI::CLI::Config::__line_of_text( $win, $easy->{'powered_by_line'}, $y, 0 );

                $win->modalfocus();
                $cui->delete($wid);
            }

            close WRITE;
            my $path;
            while (<READ>) {
                chomp;
                exit if $_ eq 'exit exit';
                $path = $_;
            }

            return $path;
        },
    );

    exit;
}

sub print_to_screen_color {
    my ( $self, $easy, $color, $string ) = @_;
    print color "bold $color";
    print $string;
    print color 'reset';
}

sub pstconf_isbad {
    my ( $self, $easy, $rc, @text ) = @_;
    $easy->{'_'}{'restore_backup'}++ if !$easy->{'_'}{'prefs'}{'do_not_revert_on_conf_failure'};
    $easy->{'_'}{'build_ok_but_confgen_failed'}++;

    $easy->print_alert(@text) if @text;
    if ( $easy->{'_'}{'prefs'}{'do_not_revert_on_conf_failure'} ) {
        my ( $x, $y ) = ( $easy->{'_'}{'httpd.conf-template_generated'}, $easy->_get_main_httpd_conf() );
        if ( -e $x ) {
            Cpanel::FileUtils::safecopy( $x, $y )
              or $easy->print_alert_color( 'red', q{'[_1]' did not return true}, qq{safecopy($x, $y)} );
        }

        $easy->print_alert_color( 'red', $easy->do_not_revert_on_conf_failure_text );
    }
}

sub preconf_isbad {
    my ( $self, $easy, @text ) = @_;

    $easy->print_alert_color( 'red', @text );
    my $url = $easy->_get_badconf_whm_url();

    print <<"BADCONF";
In order to continue please manually rectify the problem or visit the Apache Config Editor:
  $url
Alternatively you may want to try to build using the default profile:
  $0 --build --profile=cpanel_default
BADCONF
    exit;
}

sub new {
    return bless {}, shift;
}

sub isa_ui {
    return 1;
}

sub setup {
    my ( $self, $easy ) = @_;

    # $easy->_cpanelsync();

    $easy->create_state_file();
    $easy->_create_backup();
}

sub get_param_hashref {
    my ( $self, $easy ) = @_;
    return $easy->{'param_obj'}->get_param_hashref();    # Getopt::Param already has this method
}

sub hook_help {
    my ( $self, $easy ) = @_;

    if ( $easy->get_param('help') eq 'hooks-advanced' ) {
        print <<'END_HOOK';
If a hook script's exit status is checked to determine if it worked or not (Eg, like preeasyapache is handled), you can trigger "failure" by having it not exit cleanly.

For example, in /usr/local/cpanel/scripts/preeasyaapche you could set up a script that locked easyapache from building with this:

#!/usr/bin/perl

my $file = '/etc/disable_easyapache_builds';
if (-e $file) {
   print "The admin has disabled me via $file\n";
   exit 1;
}

Every hook script will get these argument passed to it in this order:

 1) easyapache version
 2) easyapache revision (not always an integer)
 3) apache version being built ( an empty string means we don't know yet, 0 means we are not building it, 2 part version string means it has not been built yet, 3 part version string means it was built)
 4) comma separated PHP versions being built ( an empty string means we don't know yet, 0 means we are not building it)
 5) all of your --hook-args values (if any) in the order they were specified

#!/usr/bin/perl

my ($ea_version, $ea_revision, $apache, $php_csv, @hook_args) = @ARGV;

if ($ea_revision ne int($ea_revision)) {
    print "using a branch of some sort\n";
}

my @phps = split(/,/, $php_csv);

if( !$apache ) {
    if ( $apache == 0) {
        print "We are not building apache this run\n";
    }
    elsif ($apache eq '') {
        print "I must be /usr/local/cpanel/scripts/preeasyapache\n";
    }
}

Every hook script will have an environment variable called 'ea3_params_yaml' that contains a YAML data structure of the parameters to easyapache.

To avoid conflicting with any flags the Cpanel::Easy framework uses or may use in the future, use --hook-args to pass custom data to the hook scripts.

#!/usr/bin/perl

use YAML::Syck;
my $hr = YAMl::Syck::Load( $ENV{'ea3_params_yaml'} );

if ( exists $hr->{'hook-args'} && grep( /no notify/, @{ $hr->{'hook-args'} }) ) {
    print "Skipping user notification\n";
}
else {
    print "Notifying users...\n";
    notify_users($msg);
}

END_HOOK

    }
    else {
        print <<'END_HOOK';
Below is a list of hook scripts easyapache calls if they exist and are executable.

Their output is sent to the screen and the log. The output has a before and after alert to visually separate it in the output.

Unless otherwise noted the exit value is ignored.

/usr/local/cpanel/scripts/preeasyapache
   When: The very beginning of a build
   Exit: If it does not exit cleanly it will halt the build (IE exit(1);)
   Uses: (These are some general ideas you could implement how you see fit)
       - lock easyapache to keep it from building
       - alert users that apache is currently being updated

/usr/local/cpanel/scripts/posteasyapache
   When: The very end of a successful build
   Uses: (These are some general ideas you could implement how you see fit)
       - verify some customization is still working properly and alert someone if it is not
       - alert users that the apache update is complete

Here are others that are called at the point their name suggests. They use before/after instead of pre/post to help indicate they relate to specific parts instead of the entire script.

/usr/local/cpanel/scripts/before_apache_make

/usr/local/cpanel/scripts/after_apache_make_install
  Hint: This is where you should apxs in other Apache modules

/usr/local/cpanel/scripts/before_httpd_restart_tests

/usr/local/cpanel/scripts/after_httpd_restart_tests

Use --skip-hooks to build without running any hooks (or the WHM equivalent found in EasyApache's 'Help' section).

For more details:
  --help=hooks-advanced

END_HOOK

    }

    exit;
}

sub cleanup {
    my ( $self, $easy ) = @_;
    return 1 if $easy->get_param('makecpphp');

    $easy->reinstate_restrictions_imposed_by_apache_make_install();
    $easy->unhide_imap_libraries() if ( $easy->{'_'}{'hide_imap_libraries'} );

    $easy->run_commands('pre-confgen-commands');

    $easy->post_httpd_conf_handler() if !$easy->{'_'}{'restore_backup'};    # no need to do it if we've already died
    $easy->_restore_backup_if_needed();

    $easy->archive_last_success_profile();

    $easy->run_commands('post-confgen-commands');

    $easy->update_runlog_entry( { 'status' => $easy->{'_'}{'restore_backup'} ? 0 : 1, } );

    $easy->report_errors();

    if ( !$easy->{'_'}{'restore_backup'} ) {
        my $phpconfigurator_text = <<'END_PHPC';

You can change how PHP is configured.
As root, simply execute:
    /usr/local/cpanel/bin/rebuild_phpconf --help
for more information.
END_PHPC

        $easy->print_alert_color( 'yellow', $phpconfigurator_text );
        $easy->print_alert_color( 'green',  'Build Complete!' );
        $easy->hook_script('/usr/local/cpanel/scripts/posteasyapache');
    }
    else {
        $easy->print_alert_color( 'yellow', 'Feel free to submit a support ticket at https://tickets.cpanel.net/submit/index.cgi?reqtype=tickets' );
    }
}

sub pid_file_failed {
    my ( $self, $easy, $pid_file_rc ) = @_;

    if ( !defined $pid_file_rc ) {
        my $cur_run = <<'END_UNAVAIL';
        Easyapache is currently running. You will need to wait for the other
        instance to finishing running. If a build is currently running you will
        need to wait for the build to complete before using this interface.
        This process can take 30 minutes or longer depending on
        what you've selected to build and the server's current state.

END_UNAVAIL
        print $easy->maketext($cur_run);
    }
    elsif ( $pid_file_rc == 0 ) {
        print $easy->maketext( 'Error reading or writing pidfile: [_1]', $! ) . "\n";
    }
    else {
        print $easy->maketext( q{Unknown/invalid pid_file_rc passed '[_1]'}, $pid_file_rc ) . "\n";
    }
}

sub output {
    my ( $self, $easy, $indent_level, @maketext ) = @_;
    my $string = "\t" x int($indent_level) . $easy->maketext(@maketext) . "\n";
    $easy->print_to_log_and_screen($string);
}

sub print_to_screen {
    my ( $self, $easy, $string ) = @_;
    print $string;
}

sub get_twiddler_new_hashref {
    my ($self) = @_;

    # use's main obj's lang_obj
    return {
        'output_ns' => 'Cpanel::CPAN::Text::Twiddler::CLI',

        # just use defaults or set these ?
        # 'start' => '',
        # 'text'  => '',
        # 'end'   => '',
    };
}

sub alert_over_last_twiddle {
    my ( $self, $easy, @maketext ) = @_;

    print "\b" x $easy->{'twiddler'}->get_longest() if $easy->{'twiddler'};

    $easy->print_alert(@maketext);

    $easy->print_to_screen("\n");
    print ' ' x $easy->{'twiddler'}->get_longest() if $easy->{'twiddler'};
}

sub configure_profile {
    require Cpanel::Easy::Apache::UI::CLI::Config;
    goto &Cpanel::Easy::Apache::UI::CLI::Config::main;
}

sub install_profile {
    my ( $self, $easy, $profile ) = @_;
    $easy->check_apache_stopfile();

    # Do 'skip-bg' for Easy::Apache HTML ??
    if ( $easy->get_param('skip-bg') ) {
        my $rc = $easy->install_profile($profile);
        $self->{'_'}{'restore_backup'}++ if !$rc;
    }
    else {
        my ( $file, $spid ) = $easy->run_install_in_bg($profile);

        $easy->tail_file_while_pid(
            {
                'file' => $file,
                'pid'  => $spid,
            }
        );
    }
}

1;
