# DynamicPreview - (c) 2014-2017 Juxtaposition. All Rights Reserved.
# This code cannot be redistributed without permission from juxtaposition.jp
# For more information, consult your DynamicPreview license.
#
package DynamicPreview::Extra;

use strict;
use warnings;
use utf8;
use MT;
use MT::Template;
use MT::Util;
use Data::Dumper;

sub split_items {
    my ($line) = shift;
    my @items = map { $_ =~ s!^\s*(.+)\s*$!$1!; $_ =~ s!\\,!,!g; $_ } split /(?<!\\),/, $line;
    return @items;
}

sub _app {
    return MT->instance;
}

sub _base_url {
    my ($plugin, $blog_id, $html, $doc_file, $obj, $base_url) = @_;
    my $blog = MT::Blog->load($blog_id)
        or return;
    my $type;
    my $blog_path = $blog->site_path;
    my $blog_url = $blog->site_url;
    if ($obj->isa('MT::Entry')) {
        if ($obj->is_entry && $blog->archive_path) {
            $blog_path = $blog->archive_path;
            $blog_url = $blog->archive_url;
        }
    }
    elsif ($obj->isa('MT::Template')) {
        if (($obj->type eq 'individual') && $blog->archive_path) {
            $blog_path = $blog->archive_path;
            $blog_url = $blog->archive_url;
        }
    }
    elsif ($obj->isa('MT::ContentData')) {
        # Do nothing
    }
    else {
        return;
    }
    my ($rel_path) = $doc_file =~ m!^$blog_path/?(.+)$!;
    require File::Spec;
    my ($vol, $dir, $file) = File::Spec->splitpath($rel_path);

    if ($base_url) {
        $blog_url = $base_url;
    }
    require MT::Util;
    my $return_base_url = MT::Util::caturl($blog_url, $dir);
    return $return_base_url;
}

sub _insert_base_tag {
    my ($plugin, $blog_id, $html, $doc_file, $obj, $base_url) = @_;
    
    my $pattern = '<head[^>]*>';
    my $replacement = "\n<base href=\"" . $base_url . "\">\n";
    $html =~ s!($pattern)!$1$replacement!;

    # set X-XSS-Protection to 0
    _app()->set_header('X-XSS-Protection' => 0);

    return $html;
}

sub _insert_default_base_tag {
    my ($plugin, $blog_id, $html, $doc_file, $obj) = @_;
    return _insert_base_tag(@_, _base_url(@_));
}

sub insert_base_tag {
    my ($plugin, $blog_id, $html, $doc_file, $obj) = @_;
    return $html unless $blog_id && $doc_file && $obj;
    my $app = MT->instance
        or return $html;

    my $base_url;
    my $base_urls = $plugin->dynamic_preview_base_url($blog_id)
        or return _insert_default_base_tag(@_);

    my @lines = split /\r?\n/, $base_urls;
    return _insert_default_base_tag(@_) unless @lines;

    my $default_base_url;
    my %base_url_map = ();
    foreach my $line (@lines) {
        my ($url, $name) = split_items($line);
        if($url && $name) {
            $base_url_map{$name} = $url;
        }
        elsif($url) {
            $default_base_url = $url;
        }
    }

    my $mode = $app->param('__mode')
        or return _insert_default_base_tag(@_);
    my $tmpl_id = $app->param('tmpl_id');
    if($mode eq 'dynamic_preview_template' || $mode eq 'dynamic_preview_cd_template') {
        $tmpl_id = $app->param('id');
    }
    my $tmpl = MT::Template->load($tmpl_id)
        or return _insert_default_base_tag(@_);
    $base_url = $base_url_map{$tmpl->name} || $default_base_url;
    return _insert_default_base_tag(@_) unless $base_url;
    return _insert_base_tag(@_, _base_url(@_, $base_url));
}

sub replace_url {
    my ($plugin, $blog_id, $html, $doc_file) = @_;
    my $replace_url = $plugin->dynamic_preview_replace_url($blog_id)
        or return $html;
    my @lines = split /\r?\n/, $replace_url;
    return $html unless @lines;

    my @patterns = ();
    foreach my $line (@lines) {
        # my @pair = map { $_ =~ s!^\s*(.+)\s*$!$1!; $_ } split /,/, $line;
        my @items = split_items($line);
        if(@items >= 2 && length $items[0] > 0) {
            if(@items == 2) {
                push @items, 'all';
            }
            push @patterns, \@items;
        }
    }
    return $html unless @patterns;
    
    my $app = MT->instance
        or return $html;
    my $mode = $app->param('__mode')
        or return $html;
    my $tmpl_id = $app->param('tmpl_id');
    if($mode eq 'dynamic_preview_template' || $mode eq 'dynamic_preview_cd_template') {
        $tmpl_id = $app->param('id');
    }
    my $tmpl = MT::Template->load($tmpl_id)
        or return $html;

    my $replace = sub {
        my ($url, $pattern, $replacement) = @_;
        $url =~ s!$pattern!$replacement!;
        return $url;
    };

    foreach my $items (@patterns) {
        my ($pattern, $replacement, $tmpl_name) = @$items;
        next unless $tmpl_name eq $tmpl->name || $tmpl_name eq 'all';
        # $plugin->doLog('replace_url: pattern: ' . $pattern . ', replacement: ' . $replacement);
        $html =~ s!(<[^>]+(?:href|src|action|content)\s*=\s*")([^"]+)(")!$1.$replace->($2, $pattern, $replacement).$3!ge;
    }

    return $html;
}

sub replace_string {
    my ($plugin, $blog_id, $html, $doc_file) = @_;
    my $replace_string = $plugin->dynamic_preview_replace_string($blog_id)
        or return $html;
    my @lines = split /\r?\n/, $replace_string;
    return $html unless @lines;

    my @patterns = ();
    foreach my $line (@lines) {
        my @items = split_items($line);
        if(@items >= 2 && length $items[0] > 0) {
            if(@items == 2) {
                push @items, 'all';
            }
            push @patterns, \@items;
        }
    }
    return $html unless @patterns;
    
    my $app = MT->instance
        or return $html;
    my $mode = $app->param('__mode')
        or return $html;
    my $tmpl_id = $app->param('tmpl_id');
    if($mode eq 'dynamic_preview_template' || $mode eq 'dynamic_preview_cd_template') {
        $tmpl_id = $app->param('id');
    }
    my $tmpl = MT::Template->load($tmpl_id)
        or return $html;

    foreach my $items (@patterns) {
        my ($pattern, $replacement, $tmpl_name) = @$items;
        next unless $tmpl_name eq $tmpl->name || $tmpl_name eq 'all';
        $html =~ s!$pattern!$replacement!ge;
    }

    return $html;
}

sub permissions {
    return {
        'blog.preview' => {
            group => 'auth_pub',
            inherit_from => [],
            label => 'Preview',
            order => 1000,
            permitted_action => {
                preview => 1,
            },
        },
    };
}

sub create_role {
    my ($app) = @_;
    if(!$app->user->is_superuser) {
        return $app->json_error('No Permission');
    }
    my $plugin = $app->component('DynamicPreview')
        or die 'Plugin not found';
    require MT::Role;
    my @roles = MT::Role->load({ name => $plugin->translate('Preview') });
    if(scalar @roles == 0) {
        my $role = MT::Role->new;
        $role->name($plugin->translate('Preview'));
        $role->description($plugin->translate('Can preview entries, pages, templates and send mail.'));
        $role->permissions("'preview'");
        $role->save
            or return $app->json_error('Failed to save');
    }
    return $app->json_result('ok');
}

sub default_settings {
    my ($settings) = @_;
    push @$settings, 
        (
            ['dynamic_preview_mail_subject', { Default => default_mail_subject() }],
            ['dynamic_preview_mail_template', { Default => default_mail_template() }],
        );
    return $settings;
}

sub default_mail_subject {
    if(MT->current_language eq 'ja') {
        return <<'TMPL';
<mt:if name="type" eq="entry"><mt:if tag="entriesCount">[<mt:blogName />] 記事内容確認のお願い - <mt:entryTitle /><mt:else>[<mt:blogName />] <mt:categoryLabel />カテゴリ内容確認のお願い</mt:if><mt:else>[<mt:blogName />] <mt:contentTypeName />内容確認のお願い - <mt:contentLabel /></mt:if>
TMPL
    }
    return <<'TMPL';
[<mt:blogName />] Request for check - <mt:if name="type" eq="entry"><mt:if tag="entriesCount"><mt:entryTitle /><mt:else><mt:categoryLabel /> category</mt:if><mt:else><mt:contentTypeName /> : <mt:contentLabel /></mt:if>
TMPL
}

sub default_mail_template {
    if(MT->current_language eq 'ja') {
        return <<'TMPL';
<mt:if name="type" eq="entry">
<mt:if tag="entriesCount">
記事「<mt:entryTitle />」（<mt:blogName />）の内容確認をお願いいたします。

プレビューURL: <mt:var name="preview_url" />

タイトル: <mt:entryTitle />
公開日: <mt:entryDate mail="1" />
メッセージ:
<mt:var name="message" />
<mt:else>
カテゴリ「<mt:categoryLabel />」（<mt:blogName />）の内容確認をお願いいたします。

プレビューURL: <mt:var name="preview_url" />

カテゴリ: <mt:categoryLabel />
メッセージ:
<mt:var name="message" />
</mt:if>
<mt:else>
<mt:contentTypeName />「<mt:contentLabel />」（<mt:blogName />）の内容確認をお願いいたします。
プレビューURL: <mt:var name="preview_url" />

ラベル: <mt:contentLabel />
公開日: <mt:contentDate mail="1" />
メッセージ:
<mt:var name="message" />
</mt:if>
---
<mt:if name="has_author"><mt:authorDisplayName /> <<mt:authorEmail />><mt:else><mt:var name="from_address" /></mt:if>

TMPL
    }
    return <<'TMPL';
<mt:if name="type" eq="entry">
<mt:if tag="entriesCount">
You have received a confirmation request of the entry '<mt:entryTitle />' (<mt:blogName />).

Preview URL: <mt:var name="preview_url" />

Title: <mt:entryTitle />
Publish Date: <mt:entryDate mail="1" />
Message: 
<mt:var name="message" />
<mt:else>
You have received a confirmation request of the category '<mt:categoryLabel />' archive (<mt:blogName />).

Preview URL: <mt:var name="preview_url" />

Category: <mt:categoryLabel />
Message:
<mt:var name="message" />
</mt:if>
<mt:else>
You have received a confirmation request of <mt:contentTypeName> '<mt:contentLabel />' (<mt:blogName />).

Preview URL: <mt:var name="preview_url" />

Label: <mt:contentLabel />
Publish Date: <mt:contentDate mail="1" />
Message:
<mt:var name="message" />
</mt:if>

---
<mt:if name="has_author"><mt:authorDisplayName /> <<mt:authorEmail />><mt:else><mt:var name="from_address" /></mt:if>

TMPL
}

sub edit_category_param {
    my ($cb, $app, $param, $tmpl) = @_;

    my $blog_id = $app->param('blog_id')
        or return 1;
    my $plugin = $app->component('DynamicPreview')
        or die 'Plugin not found';
    my $enabled = $plugin->dynamic_preview_enabled($blog_id)
        or return 1;

    # NOTE: CategorySet's category is not supported.
    if(defined $param->{category_set_id} && $param->{category_set_id}) {
        return 1;
    }
    
    require MT::Template;
    require MT::TemplateMap;
    my ($arch_tmpl) = MT::Template->load(
        undef,
        {
            'join' => MT::TemplateMap->join_on(
                'template_id',
                {
                    archive_type => 'Category',
                    blog_id => $blog_id,
                    is_preferred => 1,
                    build_type   => { not => MT::PublishOption::DISABLED() },
                },
            ),
            sort => 'name',
            direction => 'ascend',
        },
    ) or return 1;

    $param->{tmpl_id} = $arch_tmpl->id;

    # 右上widgetにリンクを追加する
    my $node = $tmpl->getElementById('useful-links')
        or return 1;
    my $html = $node->innerHTML();
    my $replacement = <<TMPL;
<li><a href="<mt:var name="script_url">?__mode=dynamic_preview&amp;blog_id=<mt:var name="blog_id" escape="url">&amp;tmpl_id=<mt:var name="tmpl_id">&amp;cat_id=<mt:var name="id">" class="preview" target="dynamic_preview"><__trans_section component="DynamicPreview"><__trans phrase="Preview this category's archive"></__trans_section></a></li>
</ul>
TMPL
    $html =~ s!</ul>!$replacement!;
    $node->innerHTML($html);

    # プレビューボタンを画面下に追加する
    my $action_buttons = $tmpl->getElementsByName('action_buttons')
        or return 1;
    my $action_button_node = $action_buttons->[0]
        or return 1;
    my $action_button_html = $action_button_node->innerHTML();
    my $button_tag = quotemeta('</button>');
    my $preview_button = <<TMPL;
    <button type="submit" title="<__trans_section component="DynamicPreview"><__trans phrase="Preview this category's archive" /></__trans_section>" class="preview action button btn btn-default"><__trans_section component="DynamicPreview"><__trans phrase="Preview" /></__trans_section></button>
TMPL
    $action_button_html =~ s!($button_tag)!$1$preview_button!;
    $action_button_node->innerHTML($action_button_html);

    # headerにscriptを追加する
    my $js_script = <<SCRIPT;
<script type="text/javascript">
var isDirty = false;
</script>
SCRIPT
    my $js_script_node = $tmpl->createElement('setvarblock');
    $js_script_node->setAttribute('name', 'js_include');
    $js_script_node->setAttribute('append', '1');
    $js_script_node->innerHTML($js_script);

    my $target;
    my $includes = $tmpl->getElementsByTagName('include');
    foreach my $t (@$includes) {
        if(lc($t->getAttribute('name') || '') eq 'layout/default.tmpl') {
            $target = $t;
            last;
        }
    }
    $tmpl->insertBefore($js_script_node, $target);

    # footerにjquery scriptを追加する
    my $jq_script = <<SCRIPT;
  jQuery(':input:visible').on('keydown change', function(){
    isDirty = true;
  });
  var openPreview = function(url) {
    if(isDirty) {
        url += '&dirty=1';
    }
    window.open(url, 'dynamic_preview');
  };
  jQuery('button.preview').click(function() {
    var url = '<mt:var name="script_url">?__mode=dynamic_preview&blog_id=<mt:var name="blog_id" escape="url">&tmpl_id=<mt:var name="tmpl_id">&cat_id=<mt:var name="id">';
    openPreview(url);
    return false;
  });
  jQuery('a.preview').click(function() {
    var url = jQuery(this).attr('href');
    openPreview(url);
    return false;
  });
SCRIPT
    my $script_node = $tmpl->createElement('setvarblock');
    $script_node->setAttribute('name', 'jq_js_include');
    $script_node->setAttribute('append', '1');
    $script_node->innerHTML($jq_script);

    $tmpl->insertBefore($script_node, $target);

    return 1;
}


1;
__END__


