# Copyright 2002-2008 Josh Clark and Global Moxie, LLC. This code cannot be
# redistributed without permission from globalmoxie.com.  For more
# information, consult your Big Medium license.
#
# $Id: Import.pm 3043 2008-03-31 14:00:38Z josh $

package BigMed::App::Web::Import;
use strict;
use warnings;
use utf8;
use Carp;
$Carp::Verbose = 1;
use English qw( -no_match_vars );
use base qw(BigMed::App::Web::CP);
use BigMed::ImportV1;
use BigMed::DiskUtil qw(bm_file_path);

sub setup {
    my $app = shift;
    $app->set_cp_selected_nav('Settings');
    $app->start_mode('v1loc');
    $app->run_modes(
        'AUTOLOAD' => sub { $_[0]->rm_v1loc() },
        'v1loc'    => 'rm_v1loc',
        'v1prefs'  => 'rm_v1prefs',
        'import'   => 'rm_import',
        'ajax-import' => 'rm_ajax_import',
    );
    return;
}

sub cgiapp_prerun {
    my $app = shift;
    $app->SUPER::cgiapp_prerun;
    $app->require_privilege_level(6);    #admins only
    return;
}

###########################################################
# RUN MODES
###########################################################

sub rm_v1loc {                           #find and prompt moxiedata
    my ( $app, %options ) = @_;
    my $moxiedata = _find_moxiedata() || q{};

    #MOXIEDATA FIELDSET ----------------------------
    my $moxiedata_field = $app->prompt_field_ref(
        id          => 'moxiedata',
        label       => 'IMPORT_LABEL_v1 moxiedata path',
        prompt_as   => 'dir_path',
        validate_as => 'v1moxiedata_path',
        required    => 1,
        ajax_status => 1,
        description => q{IMPORT_DESC_v1 moxiedata path},
        value       => $app->escape($moxiedata),
    );

    #assemble the fieldset
    my $mdata_fs = $app->prompt_fieldset_ref(
        id        => 'bmfs_moxiedata',
        fields    => [$moxiedata_field],
        title     => 'IMPORT_LABEL_Data Directory',
        query     => $options{query},
        field_msg => $options{field_msg},
    );

    #SUBMIT FIELDSET ----------------------------
    my $submit = $app->prompt_field_ref(
        id        => 'import_submit',
        prompt_as => 'submit',
        value     => $app->language('BM_SUBMIT_LABEL_Continue'),
    );
    my $submit_fs = $app->prompt_fieldset_ref(
        id     => 'bmfs_submit',
        fields => [$submit],
    );

    #PAGE INFO AND DISPLAY ----------------------------
    my ( $title, $message ) = $app->title_and_message(
        field_msg => $options{field_msg},
        message   => $options{message} || 'IMPORT_Intro',
        title     => $options{head}
          || 'IMPORT_HEAD_Import Data from Big Medium 1.x',
    );

    $app->js_add_script( $app->env('BMADMINURL') . '/js/bm-config.js' );

    $app->_set_breadcrumbs('IMPORT_LABEL_Data Directory');

    my $form_url = $app->build_url(
        script => 'bm-import.cgi',
        rm     => 'v1prefs',
        site   => $app->current_site->id,
    );
    return $app->html_template_screen(
        'screen_cp_generic.tmpl',
        bmcp_title => $title,
        form_url   => $form_url,
        message    => $message,
        fieldsets  => [$mdata_fs, $submit_fs],
    );
}

sub rm_v1prefs {
    my ( $app, %options ) = @_;

    #fetch and confirm moxiedata directory
    my %field = $app->parse_submission(
        {   id       => 'moxiedata',
            parse_as => 'dir_path',
            required => 1,
        }
    );
    return $app->rm_v1loc( field_msg => $field{_ERROR}, query => $app->query )
      if $field{_ERROR};
    if ( !is_moxiedata( $field{moxiedata} ) ) {
        $app->set_error(
            head => 'CONFIG_Missing file',
            text => 'CONFIG_Directory not moxiedata'
        );
        return $app->rm_v1loc( query => $app->query );
    }

    #fetch the user/data list to import
    my $importer = BigMed::ImportV1->new( $field{moxiedata} )
      or return $app->rm_v1loc( query => $app->query );
    my %v1_site    = $importer->v1_site_hash;
    my @v1_userids = $importer->v1_user_ids;
    if ( !%v1_site && !@v1_userids ) {
        $app->set_error(
            head => 'IMPORT_HEAD_No Data To Import',
            text => 'IMPORT_DESC_No Data To Import'
        );
        return $app->rm_v1loc( query => $app->query );
    }

    #put sites in alpha order
    my @v1_siteids =
      map  { $_->[0] }
      sort { $a->[1] cmp $b->[1] }
      map  { [$_, lc $v1_site{$_}] } keys %v1_site;

    #SELECTED SITES FIELDSET ----------------------------
    my $sites = $app->prompt_field_ref(
        id        => 'build_what',
        label     => 'IMPORT_Sites To Build',
        prompt_as => 'radio_toggle',
        value     => [
            {   label   => 'IMPORT_All sites',
                value   => 'all',
                checked => 1,
                id      => 'all_sites',
                field   => $app->prompt_field_ref(
                    id        => 'build_all',
                    prompt_as => 'hidden',
                ),
            },
            {   label => 'IMPORT_Selected sites',
                value => 'selected',
                id    => 'selected',
                field => $app->prompt_field_ref(
                    id        => 'selected_sites',
                    prompt_as => 'value_list',
                    multiple  => 8,
                    options   => \@v1_siteids,
                    labels    => \%v1_site,
                    label     => 'IMPORT_Selected sites',
                ),
            },
        ],
    );
    my $site_fs = $app->prompt_fieldset_ref(
        id        => 'bmfs_sites',
        fields    => [$sites],
        title     => 'IMPORT_LABEL_Sites',
        query     => $options{query},
        field_msg => $options{field_msg},
    );

    #NEW DIRECTORY FIELDSET ----------------------------
    my $new_dir_field = $app->prompt_field_ref(
        id           => 'newdir',
        label        => 'IMPORT_LABEL_Create New Directory?',
        option_label => 'IMPORT_LABEL_Build sites in new directories',
        value        => 1,
        prompt_as    => 'boolean',
    );
    my $newdir_fs = $app->prompt_fieldset_ref(
        id        => 'bmfs_newdir',
        pre_html  => $app->language('IMPORT_LABEL_HTML Explanation'),
        fields    => [$new_dir_field],
        title     => 'IMPORT_LABEL_HTML Directories',
        query     => $options{query},
        field_msg => $options{field_msg},
    );

    #MERGE USER FIELDSET ----------------------------
    my $merge_users = $app->prompt_field_ref(
        id           => 'merge_users',
        label        => 'IMPORT_LABEL_Merge Accounts',
        option_label => 'IMPORT_LABEL_Apply v1 privileges to v2 accounts',
        value        => 1,
        prompt_as    => 'boolean',
    );
    my $user_fs = $app->prompt_fieldset_ref(
        id        => 'bmfs_users',
        pre_html  => $app->language('IMPORT_LABEL_Merge Explanation'),
        fields    => [$merge_users],
        title     => 'IMPORT_LABEL_Duplicate User Names',
        query     => $options{query},
        field_msg => $options{field_msg},
    );

    #SUBMIT FIELDSET ----------------------------
    my $submit = $app->prompt_field_ref(
        id        => 'import_submit',
        prompt_as => 'submit',
        value     => $app->language('BM_SUBMIT_LABEL_Continue'),
    );
    my $moxiedata = $app->prompt_field_ref(
        id        => 'moxiedata',
        prompt_as => 'hidden',
        value     => $app->escape( $field{moxiedata} ),
    );
    my $submit_fs = $app->prompt_fieldset_ref(
        id     => 'bmfs_submit',
        fields => [$moxiedata, $submit],
    );

    #PAGE INFO AND DISPLAY ----------------------------
    my ( $title, $message ) = $app->title_and_message(
        field_msg => $options{field_msg},
        message   => $options{message},
        title     => $options{head} || 'IMPORT_HEAD_Import Preferences',
    );

    $app->_set_breadcrumbs('IMPORT_HEAD_Import Preferences');

    my $form_url = $app->build_url(
        script => 'bm-import.cgi',
        rm     => 'import',
        site   => $app->current_site->id,
    );
    return $app->html_template_screen(
        'screen_cp_generic.tmpl',
        bmcp_title => $title,
        form_url   => $form_url,
        message    => $message,
        fieldsets  => [$site_fs, $newdir_fs, $user_fs, $submit_fs],
    );
}

sub rm_import {

    #vet the query and, if successful, submit again to the *real*
    #importer, rm_ajax_import, via statusdriver javascript
    
    my $app = shift;
    my ($rfield, $field_err) = $app->vet_import_request();
    if (!$rfield) {
        return $app->rm_v1prefs(
            field_msg => $field_err,
            query     => $app->query,
          );
    }

    #checks out, build the progress screen and submit the url to statusdriver
    my $import_url = $app->build_url(
        script => 'bm-import.cgi',
        rm => 'ajax-import',
    );
    $import_url .= '?' . $app->query->query_string . ';BM_IFRAMEAJAX=1';
    $import_url = $app->js_escape($import_url);
    
    $app->js_add_onload(
        "new BM.StatusDriver('bmImportStatus','$import_url');" );
    $app->_set_breadcrumbs('IMPORT_Importing Data...');

    return $app->html_template_screen( 'screen_import_progress.tmpl',
        bmcp_title => $app->language('IMPORT_Importing Data...'), );
}

sub rm_ajax_import {
    my $app = shift;
    my $statusbar = BigMed::Status->new();

    my ($rfield, $field_err) = $app->vet_import_request();
    if (!$rfield) {
        my $send_msg;
        if ($field_err) {
            my $rerror = shift;
            my %error  = ref $rerror eq 'HASH' ? %$rerror : ();
            my @msg    = map {
                substr( $_, 0, 1 ) ne '_'
                  ? $_ . ': ' . $app->language( $error{$_} )
                  : ()
              } sort keys %error;
            $send_msg = join('<br />', @msg );
        }
        $statusbar->send_error();
    }

    my $importer = BigMed::ImportV1->new( $rfield->{moxiedata} )
      or $statusbar->send_error();

    $importer->import_v1_data(
        statusbar       => $statusbar,
        sites           => $rfield->{sites},
        newdir          => $rfield->{newdir},
        merge_usernames => $rfield->{merge_users},
      ) or $statusbar->send_error();
   
    $statusbar->mark_done();
    exit(0);
}

sub vet_import_request {
    my $app = shift;
    
    #fetch and confirm moxiedata directory
    my %field = $app->parse_submission(
        {   id       => 'moxiedata',
            parse_as => 'dir_path',
            required => 1,
        },
        {   id       => 'build_what',
            parse_as => 'radio_toggle',
            required => 1,
        },
        {   id       => 'newdir',
            parse_as => 'boolean',
        },
        {   id       => 'merge_users',
            parse_as => 'boolean',
        },
    );
    return (undef, $field{_ERROR}) if $field{_ERROR};
    
    my $rsites;
    if ( $field{build_what} eq 'selected' ) {
        my %site_field = $app->parse_submission(
            {   id       => 'selected_sites',
                parse_as => 'value_list',
                multiple => 1,
                required => 1,
            }
        );
        return ( undef, $site_field{_ERROR} ) if $site_field{_ERROR};
        $rsites = $site_field{selected_sites};    
    }
    
    if ( !is_moxiedata( $field{moxiedata} ) ) {
        $app->set_error(
            head => 'CONFIG_Missing file',
            text => 'CONFIG_Directory not moxiedata'
        );
        return $app->rm_v1prefs( query => $app->query );
    }
    
    #everything checks out
    $field{sites} = $rsites;
    return \%field;
}

sub _find_moxiedata {
    my $above       = _above_root();
    my $root        = _document_root();
    my $cgibin      = bm_file_path( $root, 'cgi-bin' );
    my $cgibin_mbin = bm_file_path( $cgibin, 'moxiebin' );
    my $mbin        = bm_file_path( $root, 'moxiebin' );
    my $cgi         = bm_file_path( $root, 'cgi' );
    my $cgi_mbin    = bm_file_path( $cgi, 'moxiebin' );

    my @base_dirs =
      ( $above, $root, $cgibin, $cgibin_mbin, $mbin, $cgi, $cgi_mbin, );
    foreach my $base (@base_dirs) {
        my $trydir = bm_file_path( $base, 'moxiedata' );
        return $trydir if is_moxiedata($trydir);
    }
    return bm_file_path( $above, 'moxiedata' );   #give something to work from
}

sub is_moxiedata {    # (ajax routine instead uses Config's ajax-verify-dir)
    my $path = shift;
    return -e bm_file_path( $path, 'sites', 'siteindex.cgi' );
}

sub _above_root {
    my $doc_root = _document_root();
    ( my $above_root = $doc_root ) =~ s{ [/\\] [^/\\]+ [/\\]?$}{}msx;
    return $above_root;
}

sub _document_root {
    my $doc_root = $ENV{DOCUMENT_ROOT};
    if ( !$doc_root && $OSNAME eq 'MSWin32' ) {
        $doc_root = 'E:\path\to\public_html_directory';
    }
    elsif ( !$doc_root ) {
        $doc_root = '/path/to/public_html_directory';
    }
    return $doc_root;
}

sub _set_breadcrumbs {
    my ( $app, $title) = @_;
    my $sid= $app->current_site->id;
    my @bc = (
        {   bc_label => 'BM_CP_NAVLABEL_Settings',
            bc_url   => $app->build_url(
                script => 'bm-prefs.cgi',
                rm     => 'main-menu',
                site   => $sid,
            ),
        },
        {   bc_label => 'BM_CP_NAVLABEL_ImportV1',
            bc_url   => $app->build_url(
                script => 'bm-import.cgi',
                rm     => 'v1loc',
                site   => $sid,
            ),
        },
        { bc_label => $title },
    );
    return $app->set_cp_breadcrumbs(@bc);
}



1;

