#------------------------------------------------------------
# Copyright (C) 2006 RoyaltyShare, Inc.   All Rights Reserved
#------------------------------------------------------------
package BookPub::Price::Command::SearchExceptions;
use strict;
use warnings;

use lib '/app/tools/bookpub/lib';
use lib '/app/tools/common/lib';
use RSApache::Response::XSLT;
use Common::Preference;
use Common::Assert;

use BookPub::DB::Item::File;
use BookPub::DB::Item::SalePriceExceptionSearch;
use BookPub::Catalog::ImprintList;
use BookPub::Catalog::ContributorRoleList;
use BookPub::Price::SalePriceException;
use BookPub::Price::SalePriceException::ExceptionsDisplay;
use BookPub::Price::SalePriceException::Count;
use BookPub::Price::PriceValidationServiceList;
use BookPub::Price::SalePriceExceptionRule;
use BookPub::Price::PriceTypeList;
use BookPub::Price::FilesWithExceptionsList;

use BookPub::SearchCommand;

use base 'BookPub::SearchCommand';

sub cmd      { return 'exceptions'; }
sub area     { return 'price'; }
sub pageName { return 'Manage Price Exceptions'; }

use constant kTemplate => "/app/tools/bookpub/templates/price/exceptions.xsl";

sub pageSizePrefName { 'pe_pagesize' }

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

    my $pagesize = $self->setPagesize();

    $self->save() if ( $self->isSubmit() );

    $self->{xml}{ValidatedServices} = BookPub::Price::PriceValidationServiceList->new();
    $self->{xml}{OpenFiles}         = BookPub::Price::FilesWithExceptionsList->new();
    $self->{xml}{PriceTypes}        = BookPub::Price::PriceTypeList->new();

    $self->{xml}{Counts} = BookPub::Price::SalePriceException::Count->new( searchArgs => { $self->_searchArguments() } );

    Common::Preference::StoreCookies();

    my $response = $self->SUPER::execute(
        dbClass    => 'BookPub::DB::Item::SalePriceExceptionSearch',
        xmlClass   => 'BookPub::Price::SalePriceException::ExceptionsDisplay',
        xmlTag     => 'Exception',
        collection => $self->_getCollection(),
        pageSize   => $pagesize
    );
    return $response if $response;

    $response = RSApache::Response::XSLT->new( $self->{xml}, kTemplate );
    return $response;
}

sub save {
    my $self       = shift;
    my $action     = lc( $self->getParam('submit') );
    my $approved   = 0;
    my $unapproved = 0;
    my $id;
    my $value;

    assert( $action eq 'submit' || $action eq 'approve' || $action eq 'unapprove' );

    my $fileID = $self->getParam('File');

    my $params = $self->getParams();

    foreach my $key ( grep( /Approved_/, keys(%$params) ) ) {
        ( undef, $id ) = split( /_/, $key );
        $value = $params->{$key};

        # Approve Exceptions, but only if we are being asked to approve it.
        if ( ( $action eq 'submit' || $action eq 'approve' ) && $value ) {
            $approved++ if ( $self->_approveException( $id, $fileID ) );
        }

        # Unapprove Exceptions, but only if we are being asked to remove an approval
        if ( ( $action eq 'submit' || $action eq 'unapprove' ) && $value ) {
            $unapproved++ if ( $self->_unapproveException( $id, $fileID ) );
        }
    }

    $self->{xml}{ExceptionsApproved}   = $approved;
    $self->{xml}{ExceptionsUnapproved} = $unapproved;

    if ($fileID) {
        BookPub::DB::Item::File->updatePriceValidationCounts( file_id => $fileID );
    } else {
        my $serviceID = $self->getParam('Service');

        if ($serviceID) {
            BookPub::DB::Item::File->updatePriceValidationCounts( service_id => $serviceID );
        }
    }
}

sub isSubmit {
    my $self    = shift;
    my $command = $self->getParam('submit');

    return defined($command);
}

sub _getCollectionSize {
    my $self       = shift;
    my $collection = shift;
    my $counts     = $self->{xml}{Counts};

    assert($counts);

    return $counts->totalDisplayedExceptions();
}

sub _getCollection {
    my $self = shift;
    return BookPub::DB::Item::SalePriceExceptionSearch->Search( $self->_searchArguments() );
}

sub _searchArguments {
    my $self      = shift;
    my $fileID    = $self->getParam('File');
    my $approved  = $self->_optionOrPref('Approved');
    my $serviceID = $self->getParam('Service');
    my $order     = $self->_optionOrPref('Order');
    my $services  = $self->{xml}{ValidatedServices};

    assert($services);

    # Set the default service id for the search
    unless ($serviceID) {
        my $service = $services->getFirst();
        assert( $service, 'No services configured for price validation' );

        $serviceID = $service->ServiceID;
    }

    return (
        order_by       => $self->_getSortCriteria(),
        order          => $order,
        modified_sales => $self->_getModifiedSaleIDs(),
        file_id        => $fileID,
        hide_approved  => $approved,
        service_id     => $serviceID
    );

}

sub _getModifiedSaleIDs {
    my $self = shift;

    return $self->{_modifiedSaleIDs};
}

sub _getSortCriteria {
    my $self    = shift;
    my $orderBy = $self->_optionOrPref('OrderBy');

    # Set your default sort criteria, undef == no sorting
    if ( !defined($orderBy) ) {
        return undef;
    }

    elsif ( $orderBy eq 'author' ) {
        return [ 'last_name', 'book.title', 'variance' ];
    }

    elsif ( $orderBy eq 'title' ) {
        return [ 'book.title', 'last_name', 'variance' ];
    }

    elsif ( $orderBy eq 'format' ) {
        return [ 'IF( format_subtype.onix_code_id, format_subtype.description, format_type.description )', 'variance' ];
    }

    elsif ( $orderBy eq 'catalogPrice' ) {
        return [ 'price', 'variance' ];
    }

    elsif ( $orderBy eq 'units' ) {
        return [ 'SUM(sale.units)', 'variance' ];
    }

    elsif ( $orderBy eq 'saleDate' ) {
        return [ 'date_begin', 'date_end', 'variance' ];
    }

    elsif ( $orderBy eq 'salePrice' ) {
        return [ 'sale.list_price', 'variance' ];
    }

    elsif ( $orderBy eq 'variance' ) {
        return [ 'variance', 'has_price', 'book.title' ];
    }

    elsif ( $orderBy eq 'country' ) {
        return ['country_code', 'variance'];
    }

    else {
        die "Unknow sort criteria '$orderBy'";
    }
}

sub _setException {
    my $self     = shift;
    my $saleID   = shift || return;
    my $approved = shift;

    my $exception = new BookPub::Price::SalePriceException( saleID => $saleID );

    # Ignore the exceptions if nothing is going to change
    return if ( $exception->Approved  && $approved );
    return if ( !$exception->Approved && !$approved );

    $exception->setApproved($approved);
    $exception->save();

    # Save the ID so we know it's been modified.
    $self->{_modifiedSaleIDs} = [] unless ( $self->{_modifiedSaleIDs} );
    push( @{ $self->{_modifiedSaleIDs} }, $saleID );

    return 1;
}

sub _approveException {
    my $self   = shift;
    my $saleID = shift;
    my $fileID = shift;

    my $approved;
    my $related = BookPub::DB::Item::SalePriceException->GetRelated(
        sale_id => $saleID,
        file_id => $fileID
    );
    while ( my $dbItem = $related->next() ) {
        if ( $self->_setException( $dbItem->sale_id, 1 ) ) {
            my $obj = new BookPub::Price::SalePriceExceptionRule( saleID => $dbItem->sale_id );
            $obj->save() if ($obj);
            $approved = 1;
        }
    }

    return $approved;
}

sub _unapproveException {
    my $self   = shift;
    my $saleID = shift;
    my $fileID = shift;

    my $unapproved;
    my $related = BookPub::DB::Item::SalePriceException->GetRelated(
        sale_id => $saleID,
        file_id => $fileID
    );
    while ( my $dbItem = $related->next() ) {
        if ( $self->_setException( $dbItem->sale_id, 0 ) ) {
            my $obj = new BookPub::Price::SalePriceExceptionRule( saleID => $dbItem->sale_id );
            $obj->delete() if ($obj);
            $unapproved = 1;
        }
    }

    return $unapproved;
}

sub _optionOrPref {
    my $self = shift;
    my $key = shift || die;

    my $value = $self->getParam($key);

    # Unset the cookie if the passed in value is default
    if ( $value && $value eq 'default' ) {
        Common::Preference::SetPersistentCookie( "pe_$key", '' );
        return;
    }

    unless ( defined($value) ) {
        $value = Common::Preference::GetValue("pe_$key") unless ( defined($value) );
    }

    Common::Preference::SetPersistentCookie( "pe_$key", $value );

    $self->{xml}{Preferences}->{$key} = $value;

    return defined($value) && length($value) ? $value : undef;
}

1;
