#!/usr/bin/perl
#
# DW::Controller::Admin::ThemeMetadata
#
# Theme metadata admin page.
#
# Authors:
#      Andrea Nall <anall@andreanall.com>
#
# Copyright (c) 2010 by Dreamwidth Studios, LLC.
#
# This program is free software; you may redistribute it and/or modify it under
# the same terms as Perl itself. For a copy of the license, please reference
# 'perldoc perlartistic' or 'perldoc perlgpl'.
#

package DW::Controller::Admin::ThemeMetadata;

use strict;
use warnings;
use DW::Controller;
use DW::Routing;
use DW::Template;
use DW::Controller::Admin;

DW::Routing->register_string( "/admin/themes/index", \&index_controller );
DW::Controller::Admin->register_admin_page(
    '/',
    path     => 'themes/',
    ml_scope => '/admin/themes/index.tt',
    privs    => ['siteadmin:themes']
);

DW::Routing->register_string( "/admin/themes/theme",    \&theme_controller );
DW::Routing->register_string( "/admin/themes/category", \&category_controller );

my %system_cats = ( featured => 1, );

sub index_controller {
    my ( $ok, $rv ) = controller( privcheck => ["siteadmin:themes"] );
    return $rv unless $ok;

    my $pub = LJ::S2::get_public_layers();

    my @themes = grep { $_ !~ /^\d+$/ && $pub->{$_}->{type} eq 'theme' } keys %$pub;
    my %layers = ();
    foreach my $uniq (@themes) {
        my ( $lay, $theme ) = split( '/', $uniq );
        push @{ $layers{$lay} }, $theme;
    }

    my $vars = {
        %$rv,

        layers     => \%layers,
        categories => [ LJ::S2Theme->all_categories( all => 1, special => 1 ) ],
    };

    return DW::Template->render_template( 'admin/themes/index.tt', $vars );
}

sub _validate_category {
    return 1 if $_[0] =~ /^[a-zA-Z0-9 ]+$/;
    return 0;
}

sub theme_controller {
    my ( $ok, $rv ) = controller( privcheck => ["siteadmin:themes"] );
    return $rv unless $ok;

    my $r = DW::Request->get;

    my $args = $r->did_post ? $r->post_args : $r->get_args;
    my $uniq = $args->{theme};

    my $pub   = LJ::S2::get_public_layers();
    my $s2lid = $pub->{$uniq}->{s2lid};
    return $r->redirect("/admin/themes/") unless $s2lid;

    my $theme = LJ::S2Theme->new( themeid => $s2lid );
    return $r->redirect("/admin/themes/") unless $theme;

    if ( $r->method eq 'POST' ) {
        return $r->redirect("/admin/themes/theme?theme=$uniq")
            unless LJ::check_form_auth( $args->{lj_form_auth} );

        # FIXME: This should be in S2Themes
        my $cats     = $theme->metadata->{cats};
        my %kwid_map = map { $_->{kwid} => $_ } values %$cats;
        my @kwids    = keys %kwid_map;

        my %change_act;
        my %delete;

        foreach my $kwid (@kwids) {
            my $act_db = $kwid_map{$kwid}->{active};
            if ( $args->{"cat_remove_$kwid"} ) {
                $delete{$kwid} = 1;
            }
            else {
                $change_act{$kwid} = 1
                    if $args->{"cat_act_$kwid"} && !$act_db;
                $change_act{$kwid} = 0
                    if !$args->{"cat_act_$kwid"}
                    && $act_db
                    && exists $kwid_map{$kwid};
            }
        }

        foreach my $kw ( split( ',', $args->{cat_add} ) ) {
            $kw = LJ::trim($kw);
            next unless _validate_category($kw);
            my $kwid = LJ::get_sitekeyword_id( $kw, 1, allowmixedcase => 1 );
            next if $delete{$kwid};
            my $add = 1;
            $add = 0 if $kwid_map{$kwid} && $kwid_map{$kwid}->{active};
            $change_act{$kwid} = 1 if $add;
        }

        my $dbh = LJ::get_db_writer();

        if (%change_act) {
            my @bind;
            my @vals;

            foreach my $kwid ( keys %change_act ) {
                push @vals, "(?,?,?)";
                push @bind, ( $s2lid, $kwid, $change_act{$kwid} );
            }

            $dbh->do(
                "REPLACE INTO s2categories ( s2lid, kwid, active ) "
                    . "VALUES "
                    . join( ',', @vals ),
                undef, @bind
            ) or die $dbh->errstr;
        }

        if (%delete) {
            $dbh->do(
                "DELETE FROM s2categories where s2lid = ? "
                    . "AND kwid IN ( "
                    . join( ',', map { $dbh->quote($_) } keys %delete ) . " )",
                undef, $s2lid
            ) or die $dbh->errstr;
        }

        $theme->clear_cache;
        LJ::S2Theme->clear_global_cache;
        return $r->redirect("/admin/themes/theme?theme=$uniq");
    }

    my %cats = %{ $theme->metadata->{cats} };

    my @cat_keys = sort {
        my $ah = $cats{$a};
        my $bh = $cats{$b};
        return
               ( $ah->{order} || 0 ) <=> ( $bh->{order} || 0 )
            || ( $bh->{active} || 0 ) <=> ( $ah->{active} || 0 )
            || $ah->{keyword} cmp $bh->{keyword}
    } keys %cats;

    my $vars = {
        %$rv,

        theme_arg => $uniq,
        theme     => $theme,
        cats      => \%cats,
        cat_keys  => \@cat_keys,
    };

    return DW::Template->render_template( 'admin/themes/theme.tt', $vars );
}

sub category_controller {
    my ( $ok, $rv ) = controller( privcheck => ["siteadmin:themes"] );
    return $rv unless $ok;

    my $r = DW::Request->get;

    my $args = $r->did_post ? $r->post_args : $r->get_args;
    my $cat  = $args->{category};

    $cat = undef unless _validate_category($cat);
    return $r->redirect("/admin/themes/") unless $cat;

    my $pub = LJ::S2::get_public_layers();

    my @themes = grep { $_ !~ /^\d+$/ && $pub->{$_}->{type} eq 'theme' } keys %$pub;
    my %layers = ();
    foreach my $uniq (@themes) {
        my ( $lay, $theme ) = split( '/', $uniq );
        $layers{$lay}->{$theme} = $pub->{$uniq};
    }

    my %s2lid_act = map { $_->s2lid => 1 } LJ::S2Theme->load_by_cat($cat);

    my $can_delete = 0;
    my $is_system  = $system_cats{$cat} ? 1 : 0;

    $can_delete = ( %s2lid_act ? 0 : 1 ) unless $is_system;

    if ( $r->method eq 'POST' ) {
        return $r->redirect("/admin/themes/category?category=$cat")
            unless LJ::check_form_auth( $args->{lj_form_auth} );

        my $dbh = LJ::get_db_writer();

        if ( $args->{delete} ) {
            return $r->redirect("/admin/themes/category?category=$cat")
                unless $can_delete;

            my $kwid = LJ::get_sitekeyword_id( $cat, 1, allowmixedcase => 1 );
            my $to_clear =
                $dbh->selectall_arrayref( "SELECT s2lid FROM s2categories WHERE kwid = ?",
                undef, $kwid )
                or die $dbh->errstr;

            $dbh->do( "DELETE FROM s2categories WHERE kwid = ?", undef, $kwid ) or die $dbh->errstr;

            LJ::S2Theme->new( themeid => $_->[0] )->clear_cache foreach @$to_clear;
            LJ::S2Theme->clear_global_cache;

            return $r->redirect("/admin/themes/");
        }
        else {
            my %change_act;
            foreach my $theme (@themes) {
                my $s2lid  = $pub->{$theme}->{s2lid};
                my $db_act = $s2lid_act{$s2lid};
                my $act    = $args->{"s2lid_act_$s2lid"} || 0;

                $change_act{$s2lid} = 1 if $act  && !$db_act;
                $change_act{$s2lid} = 0 if !$act && $db_act;
            }

            if (%change_act) {
                my @bind;
                my @vals;

                my $kwid = LJ::get_sitekeyword_id( $cat, 1, allowmixedcase => 1 );
                foreach my $s2lid ( keys %change_act ) {
                    push @vals, "(?,?,?)";
                    push @bind, ( $s2lid, $kwid, $change_act{$s2lid} );
                }

                $dbh->do(
                    "REPLACE INTO s2categories ( s2lid, kwid, active ) "
                        . "VALUES "
                        . join( ',', @vals ),
                    undef, @bind
                ) or die $dbh->errstr;
            }

            LJ::S2Theme->new( themeid => $_ )->clear_cache foreach keys %change_act;
            LJ::S2Theme->clear_global_cache;
            return $r->redirect("/admin/themes/category?category=$cat");
        }
    }

    my $vars = {
        %$rv,

        category   => $cat,
        layers     => \%layers,
        active     => \%s2lid_act,
        can_delete => $can_delete,
        is_system  => $is_system,
    };

    return DW::Template->render_template( 'admin/themes/category.tt', $vars );
}

1;
