# 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: Templates.pm 3043 2008-03-31 14:00:38Z josh $

package BigMed::App::Web::Templates;
use strict;
use warnings;
use utf8;
use Carp;
$Carp::Verbose = 1;
use base qw(BigMed::App::Web::CP);
use BigMed::Plugin;
use BigMed::Format;
use BigMed::Template;

sub setup {
    my $app = shift;
    $app->start_mode('main-menu');
    $app->set_cp_selected_nav('Layout');
    $app->run_modes(
        'AUTOLOAD'    => sub { $_[0]->rm_main_menu() },
        'main-menu'   => 'rm_main_menu',
        'menu'        => 'rm_menu',
        'edit'        => 'rm_edit',
        'save'        => 'rm_save',
        'ajax-delete' => 'rm_ajax_delete',
    );
    return;
}

sub cgiapp_prerun {
    my $app = shift;
    $app->SUPER::cgiapp_prerun;
    $app->require_privilege_level(5);
    return;
}

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

sub rm_main_menu {
    my $app     = shift;
    my %options = @_;
    my $site_id = $app->current_site->id;
    my @groups  = (
        {   edit_url => $app->build_url(
                script => 'bm-build.cgi',
                rm     => 'menu',
                site   => $site_id,
            ),
            label       => $app->language('BUILD_Rebuild Pages'),
            description => $app->language('BUILD_DESC_Rebuild Pages'),
        },
        {   edit_url => $app->build_url(
                script => 'bm-sections.cgi',
                rm     => 'menu',
                site   => $site_id,
            ),
            label       => $app->language('SECTIONS_Section Structure'),
            description => $app->language('SECTIONS_DESC_Section Structure'),
        },
        {   edit_url => $app->build_url(
                script => 'bm-templates.cgi',
                rm     => 'menu',
                site   => $site_id,
            ),
            label       => $app->language('TEMPLATE_Edit Templates'),
            description => $app->language('TEMPLATE_DESC_Edit Templates'),
        },
        {   edit_url => $app->build_url(
                script => 'bm-themes.cgi',
                rm     => 'edit',
                site   => $site_id,
            ),
            label       => $app->language('THEME_Edit Theme CSS'),
            description => $app->language('THEME_DESC_Edit Theme CSS'),
        },
        {   edit_url => $app->build_url(
                script => 'bm-themes.cgi',
                rm     => 'menu',
                site   => $site_id,
            ),
            label       => $app->language('THEMES_New Theme'),
            description => $app->language('THEMES_DESC_New Theme'),
        },
        {   edit_url => $app->build_url(
                script => 'bm-themes.cgi',
                rm     => 'save-site',
                site   => $site_id,
            ),
            label       => $app->language('THEME_Save to Theme Library'),
            description => $app->language('THEME_DESC_Save Theme'),
        },
        {   edit_url => $app->build_url(
                script => 'bm-themes.cgi',
                rm     => 'remove',
                site   => $site_id,
            ),
            label       => $app->language('THEME_Remove Design Theme'),
            description => $app->language('THEME_DESC_Remove Design Theme'),
        },
    );

    #page title and message
    my $title_unlocal = $options{head} || 'BM_CP_NAVLABEL_Layout';
    my ( $title, $message ) = $app->title_and_message(
        field_msg => $options{field_msg},
        message   => $options{message},
        title     => $title_unlocal,
    );
    $app->set_cp_breadcrumbs( { bc_label => 'BM_CP_NAVLABEL_Layout' } );

    return $app->html_template_screen(
        'screen_prefs_menu.tmpl',
        bmcp_title => $title,
        message    => $message,
        groups     => \@groups,
    );
}

sub rm_menu {
    my $app     = shift;
    my %options = @_;
    my $site    = $app->current_site or return $app->rm_login_site;
    my $site_id = $site->id;

    #load formats and identify the format type to display
    my @formats = $app->get_template_formats;
    my %check_format;
    @check_format{@formats} = ();
    my @args = $app->path_args;
    my $format = $args[0] || 'HTML';
    $format = 'HTML' if !exists $check_format{$format};

    #build tab info
    my @tabs = map {
        {   text     => $app->language( 'FORMAT_TITLE_' . $_ ),
            selected => $format eq $_,
            url      => $app->build_url(
                script => 'bm-templates.cgi',
                rm     => 'menu',
                site   => $site_id,
                args   => [$_],
            ),
        }
    } @formats;

    my $fclass = BigMed::Format->class_for_name($format)
      or croak "Format type '$format' does not map to a known class";
    my @templates  = $fclass->templates;
    my @customize  = grep { $_->{custom_sec} } @templates;
    my $tmpl       = BigMed::Template->new($site);
    my %tmpl_label =
      map { $_->{name} => $app->language( $_->{label} ) } @templates;

    #get id of section we saved if that's where we're coming from.
    my $just_saved = $app->session->param('BMTMPL_saved') || q{};
    $app->session->clear( ['BMTMPL_saved'] ) if $just_saved;

    #build sitewide default template links
    my @site_default;
    my $show_default_key;
    foreach my $t (@templates) {
        my $type   = $t->{name};
        my $source =
          $tmpl->template_source( format => $format, type => $type );
        push @site_default,
          { 'label'    => $tmpl_label{$type},
            'edit_url' => $app->build_url(
                script => 'bm-templates.cgi',
                site   => $site_id,
                rm     => 'edit',
                args   => [$format, $type, 'default'],
            ),
            'source'  => $app->template_source_label($source),
            'custom'  => $source ? "$format-$type-default" : q{},
            'tmpl_id' => "$type-default",
          };
        $show_default_key = 1 if $source;
    }

    #build section template links
    my @sections;
    my $show_section_key;
    my $icon = $app->env('BMADMINURL') . '/img/bmcp_gear.gif';
    if ( @customize > 0 ) {
        foreach my $id ( $site->all_descendants_ids ) {
            my $sec = $site->section_obj_by_id($id) or next;
            my %section = (
                indent => ( '&nbsp; &nbsp; ' x scalar $sec->parents - 1 ),
                section_name => $sec->name,
                section_id   => $id,
                display => $just_saved =~ /^\d+$/ms && $just_saved == $id,

            );
            my @sec_tmpl;
            my $custom_icon;
            foreach my $t (@customize) {
                my $type   = $t->{name};
                my $source = $tmpl->template_source(
                    format  => $format,
                    type    => $type,
                    section => $sec
                );
                my $custom_id;
                if ( $source =~ /^\d+$/ms && $source == $id ) {
                    $custom_icon = $icon;
                    $custom_id   = "$format-$type-$id";
                }
                push @sec_tmpl,
                  { 'source'   => $app->template_source_label( $source, $id ),
                    'label'    => $tmpl_label{$type},
                    'edit_url' => $app->build_url(
                        script => 'bm-templates.cgi',
                        site   => $site_id,
                        rm     => 'edit',
                        args   => [$format, $type, $id],
                    ),
                    'custom'  => $custom_id,
                    'tmpl_id' => "$type-$id",
                  };
            }
            $section{templates}   = \@sec_tmpl;
            $section{custom_icon} = $custom_icon;
            $show_section_key = 1 if $custom_icon;
            push @sections, \%section;
            $app->js_make_toggle( "bms_$id", "bmsub_$id", 'blind' );
        }
    }

    #page title and message
    my $format_title  = $app->language( 'FORMAT_TITLE_' . $format );
    my $title_unlocal = $options{head}
      || ['TEMPLATE_Template Menu', q{%BM} . $format_title . q{%}];
    my ( $title, $message ) = $app->title_and_message(
        field_msg => $options{field_msg},
        message   => $options{message},
        title     => $title_unlocal,
    );
    $app->_set_breadcrumbs( format => $format, site => $site );

    #add help links
    my @help_links = (
        {   help_title =>
              $app->language(q{TEMPLATES_HELP_TITLE_What's a template?}),
            help_text =>
              $app->language(q{TEMPLATES_HELP_TEXT_What's a template?}),
            help_id => 'whatsit',
        },
    );
    if ( @templates > 1 ) {   #show a help link to display the different types
        my $text = $app->language(
            [   'TEMPLATES_HELP_x number of templates',
                scalar @templates,
                q{%BM} . $format_title . q{%},
            ]
          )
          . '<dl>';
        foreach my $t (@templates) {
            $text .= '<dt><strong>'
              . $tmpl_label{ $t->{name} }
              . '</strong></dt>';
            $text .= '<dd>' . $app->language( $t->{description} ) . '</dd>'
              if $t->{description};
        }
        $text .= '</dl>';
        push @help_links,
          { help_title => $app->language(
                [   'TEMPLATES_HELP_TITLE_Types of templates',
                    q{%BM} . $format_title . q{%}
                ]
            ),
            help_text => $text,
            help_id   => 'tmpltypes',
          };

    }

    $app->js_make_toggle( 'whatsitHelpLink',   'whatsitHelpBox',   'blind' );
    $app->js_make_toggle( 'tmpltypesHelpLink', 'tmpltypesHelpBox', 'blind' );
    $app->js_add_script( $app->env('BMADMINURL') . '/js/bm-templates.js' );
    my $template = $options{template} || 'screen_templates_menu.tmpl';
    return $app->html_template_screen(
        $template,
        bmcp_title       => $title,
        message          => $message,
        tabs             => \@tabs,
        defaults         => \@site_default,
        sections         => \@sections,
        show_default_key => $show_default_key,
        show_section_key => $show_section_key,
        help_links       => \@help_links,
    );
}

sub rm_edit {
    my $app     = shift;
    my %options = @_;
    my $site    = $app->current_site or return $app->rm_login_site;
    my $site_id = $site->id;
    my ( $fclass, $format, $type, $section ) =
      $app->get_template_info_from_path($site);
    return $app->rm_menu if !$format;

    #fetch the escaped template and source info
    my $tmpl     = BigMed::Template->new($site);
    my $template = $app->escape(
        $tmpl->template_text(
            format  => $format,
            type    => $type,
            section => $section,
        )
    );

    # look up the template source and build source explainer if necessary
    # (no message if already customized)
    my $source = $tmpl->template_source(
        format  => $format,
        type    => $type,
        section => $section,
    );
    my ( $source_text, $inherits, $for_text );
    if ( $section && $source ne $section->id ) {    #uncustomized section
        $source_text = $app->language('TEMPLATES_SOURCE_This section');
        $for_text    = $app->language('TEMPLATES_SOURCE_the section');
        if ( $source eq 'site' ) {    #inheriting from site master
            $inherits =
              $app->language(q{TEMPLATES_SOURCE_the site's master template});
        }
        elsif ($source) {             #inheriting from another section
            my $parent = $site->section_obj_by_id($source);
            $inherits = $app->language(
                [   'TEMPLATES_SOURCE_the parent section',
                    q{%BM} . $parent->name . q{%}
                ]
            );
        }
        else {                        #inheriting from the system default
            $inherits =
              $app->language('TEMPLATES_SOURCE_the default template');
        }
    }
    elsif ( !$section && $source ne 'site' ) {    #uncustomized site master
        $source_text = $app->language('TEMPLATES_SOURCE_This site');
        $inherits = $app->language('TEMPLATES_SOURCE_the default template');
        $for_text = $app->language('TEMPLATES_SOURCE_the site');
    }
    my $source_preamble;
    $source_preamble = [
        'TEMPLATES_SOURCE_long_text', "\%BM$source_text%",
        "\%BM$inherits%",             "\%BM$for_text%"
      ]
      if $source_text;

    my %info        = $fclass->template_info($type);
    my $field_title = [
        'TEMPLATE_template_label',
        q{%BM} . $app->language( $info{label} ) . q{%}
    ];
    my $field = $app->prompt_field_ref(
        id         => 'template',
        prompt_as  => 'raw_text',
        value      => $template,
        hide_label => 1,
        width      => '98%',
        height     => '18em',
        css_class  => 'bmcpMarkup',
        label      => $field_title,
    );
    my $submit_text = $options{submit_text} || 'BM_SUBMIT_LABEL_Save';
    my $submit = $app->prompt_field_ref(
        id        => 'template_submit',
        prompt_as => 'submit',
        value     => $app->language($submit_text),
    );
    my $what_is_it = '<strong>'
      . $app->language('BM_What is it?')
      . '</strong> '
      . $app->language( $info{description} );
    my $fieldset = $app->prompt_fieldset_ref(
        id        => 'bmfs_template',
        fields    => [$field, $submit],
        title     => $field_title,
        query     => $options{query},
        field_msg => $options{field_msg},
        pre_html  => $what_is_it,
    );

    #page title and message
    my $section_title =
      $section ? $section->name : $app->language('TEMPLATE_Master Template');
    $section_title = q{%BM} . $section_title . q{%};
    my $template_title = q{%BM} . $app->language( $info{label} ) . q{%};
    my $title_unlocal  = $options{head}
      || ['TEMPLATE_Edit Title', $section_title, $template_title];
    my ( $title, $message ) = $app->title_and_message(
        field_msg => $options{field_msg},
        message   => $options{message} || $source_preamble,
        title     => $title_unlocal,
    );
    $app->_set_breadcrumbs(
        format => $format,
        site   => $site,
        title  => $title_unlocal
    );

    my $id = $section ? $section->id : 'default';
    my $form_url = $app->build_url(
        script => 'bm-templates.cgi',
        site   => $site_id,
        rm     => 'save',
        args   => [$format, $type, $id],
    );

    return $app->html_template_screen(
        'screen_cp_generic.tmpl',
        bmcp_title => $title,
        form_url   => $form_url,
        message    => $message,
        fieldsets  => [$fieldset],
    );
}

sub rm_ajax_delete {
    my $app = shift;
    $app->require_post() or return $app->ajax_system_error;

    my $site = $app->current_site or return $app->rm_ajax_login_badsite;
    my ( $fclass, $format, $type, $section ) =
      $app->get_template_info_from_path($site);
    return $app->ajax_system_error if !$format;

    my $tmpl = BigMed::Template->new($site);

    #gather IDs of sections that use this template
    my $this_tmpl = $section ? $section->id : 'site';
    my @subs = grep {
        $this_tmpl eq $tmpl->template_source(
            format  => $format,
            type    => $type,
            section => $_,
        );
    } $site->all_descendants_ids($section);

    $tmpl->delete_template(
        format  => $format,
        type    => $type,
        section => $section,
      )
      or return $app->ajax_system_error;

    #get a fresh template object (to clear cache) and get the new path info
    $tmpl = BigMed::Template->new($site);
    my $new_source = $tmpl->template_source(
        format  => $format,
        type    => $type,
        section => $section,
    );
    my $id = $section ? $section->id : q{};
    my $status = $app->template_source_label( $new_source, $id );
    my $sub_status =
      scalar @subs
      ? $app->template_source_label( $new_source, $subs[0] )
      : q{};

    return $app->ajax_json_response(
        {   valid      => 'OK',
            statusHTML => $status,
            subs       => \@subs,
            subHTML    => $sub_status,
        }
    );
}

sub rm_save {
    my $app = shift;
    my $site = $app->current_site or return $app->rm_login_site;
    my ( $fclass, $format, $type, $section ) =
      $app->get_template_info_from_path($site);
    return $app->rm_menu if !$format;

    #not required... allow a blank file.
    my %field = $app->parse_submission(
        {   id       => 'template',
            parse_as => 'raw_text',
        },
    );
    if ( $field{_ERROR} ) {
        return $app->rm_edit(
            head      => 'BM_Please_Review_Your_Entry',
            field_msg => $field{_ERROR},
            query     => $app->query,
        );
    }

    my $tmpl = BigMed::Template->new($site);
    $tmpl->save_template(
        format  => $format,
        type    => $type,
        section => $section,
        text    => $field{template}
      )
      or return $app->rm_edit( query => $app->query );

    #what level of template was it?
    my %template_info = $fclass->template_info($type);
    my $rlevel = $template_info{level};
    $rlevel = {'detail' => 1} if !%{ $rlevel }; #overflow pages etc.
    
    #leave trace for menu to know what section to leave open
    my ( $id, $url, $for_what );
    if ($section) {
        my $rm;
        if ($rlevel->{detail}) { #build all pages for section
            $rm = 'build-section';
            $for_what = ['BUILD_for the section', $section->name];
        }
        else { #build front pages for section
            $rm = 'build-front';
            $for_what = ['BUILD_front pages for the section', $section->name];
        }
        
        $id = $section->id;
        $url = $app->build_url(
            script => 'bm-build.cgi',
            rm     => $rm,
            site   => $site->id,
            args   => [ $id ],
        );
    }
    else {
        $id  = 'default';
        my ($rm, $sec);
        if ($rlevel->{detail}) { #build all pages for entire site
            $rm = 'build-all';
            $for_what = 'BUILD_all_pages';
        }
        elsif ( $rlevel->{section} ) { #build front pages for all sections
            $rm = 'build-front';
            $for_what = 'BUILD_front pages for entire site';
        }
        else { #build homepage only
            $rm = 'build-front';
            $for_what = 'BUILD_build homepage';
            $sec = 'home';
        }
        $url = $app->build_url(
            script => 'bm-build.cgi',
            rm     => $rm,
            site   => $site->id,
            args   => [ $sec ],
        );
    }
    $app->session->param( 'BMTMPL_saved', $id );
    $app->set_session_message(
        [   'TEMPLATE_Saved changes, now rebuild', $url,
            $app->language($for_what)
        ]
    );

    #success, return to menu
    my $redirect = $app->build_url(
        script => 'bm-templates.cgi',
        rm     => 'menu',
        site   => $site->id,
    );
    $app->header_type('redirect');
    $app->header_props( -url => $redirect );
    return "Redirecting to $redirect";
}

sub get_template_formats {
    BigMed::Plugin->load_formats;
    my @formats = grep { $_ ne 'HTML' } BigMed::Format->format_names;
    unshift @formats, 'HTML';
    return @formats;
}

my %source_label;

sub template_source_label {
    my $app = shift;
    my ( $source, $id ) = @_;
    my $site = $app->current_site;
    if ( !%source_label ) {
        %source_label =
          map { $_ => $app->language("TEMPLATES_SOURCE_$_") }
          qw(default site custom-site section);
    }
    if ( !$id ) {
        return $source
          ? $source_label{'custom-site'}
          : $source_label{'default'};
    }
    return $source eq 'site' ? $source_label{site}
      : $source && $source == $id ? $source_label{section}
      : $source ? $app->language(
        ['TEMPLATES_SOURCE_inherit', $site->section_obj_by_id($source)->name]
      )
      : $source_label{default};
}

sub get_template_info_from_path {
    my $app  = shift;
    my $site = shift;
    my ( $format, $type, $sec_id ) = $app->path_args;
    $format ||= 'HTML';
    $sec_id ||= 'default';
    $type   ||= q{};
    if ( !$type ) {
        $app->set_error(
            head => 'TEMPLATE_Unspecified template',
            text => 'TEMPLATE_TEXT_Unspecified template',
        );
        return ();
    }

    #load formats and identify the format to edit
    my @formats = $app->get_template_formats();
    my %check_format;
    @check_format{@formats} = ();
    if ( !exists $check_format{$format} ) {
        $app->set_error(
            head => 'TEMPLATE_Unknown template format',
            text => ['TEMPLATE_TEXT_Unknown template format', $format],
        );
        return ();
    }

    #confirm the template type
    my $fclass = BigMed::Format->class_for_name($format)
      or croak "Format type '$format' does not map to a known class";
    my @templates =
      $sec_id eq 'default' ? $fclass->templates : grep { $_->{custom_sec} }
      $fclass->templates;
    my @template_names = map { $_->{name} } @templates;
    my %check_template;
    @check_template{@template_names} = ();
    if ( !exists $check_template{$type} ) {
        $app->set_error(
            head => 'TEMPLATE_Unknown template',
            text => ['TEMPLATE_TEXT_Unknown template', $type],
        );
        return ();
    }

    #confirm the section id
    my $section;
    if ( $sec_id ne 'default' ) {
        $sec_id =~ s/\D+//msg;
        defined( $section =
              $sec_id ? $site->section_obj_by_id($sec_id) : q{} )
          or return $app->rm_menu;    #i/o error
        if ( !$section ) {            #id does not point to a valid section
            $app->set_error(
                head => 'TEMPLATE_Unknown Section',
                text => 'TEMPLATE_TEXT_Unknown Section',
            );
            return ();
        }
    }
    return ( $fclass, $format, $type, $section );

}

sub _set_breadcrumbs {
    my $app   = shift;
    my %param = @_;
    my ( $format, $title, $site ) = @param{qw(format title site)};

    #sets these breadcrumbs up to appropriate depth; no link if you're on
    #the page itself
    #1) link to the template menu for the format type
    #2) unlinked title (not shown if no title)

    my $type_name = $app->language( 'FORMAT_TITLE_' . $format );
    my $type_url;
    $type_url = $app->build_url(
        script => 'bm-templates.cgi',
        rm     => 'menu',
        args   => [$format],
        site   => $site->id,
      )
      if $title;
    my @bc = (
        {   bc_label => 'BM_CP_NAVLABEL_Layout',
            bc_url   => $app->build_url(
                script => 'bm-templates.cgi',
                rm     => 'main-menu',
                site   => $app->current_site->id,
            ),
        },
        {   bc_label => ['TEMPLATE_Template Menu', $type_name],
            bc_url   => $type_url,
        }
    );

    push @bc, { bc_label => $title } if $title;
    $app->set_cp_breadcrumbs(@bc);
    return;
}

1;

__END__

