#------------------------------------------------------------
# Copyright (C) 2010 RoyaltyShare, Inc.   All Rights Reserved
#------------------------------------------------------------
package BookPub::Dashboard::Module::SalesTrends;

use strict;
use warnings;

use File::Temp;
use File::Basename;

use lib '/app/tools/common/lib';
use Common::Assert;

use lib '/app/tools/bookpub/lib';
use BookPub::Catalog::ImprintList;
use BookPub::Catalog::ServiceList::OnlyAggSales;
use BookPub::DB::Item::AggMProductSales;

use lib '/app/tools/raptor/lib';
use Raptor::DB::Item::PeriodMonth;

use lib '/usr/local/chart_director/lib';
use perlchartdir;

use Common::FormObject;
use base 'Common::LandingPage::Module';

sub DisplayOrder { 6 }
sub Stylesheet   { "/app/tools/bookpub/templates/dashboard/module/sales_trends.xsl" }
sub Template     { "dashboardSalesTrends" }
sub Title        { "Digital Sales Trends" }
sub Class        { "bodyModule" }

use constant kBarColor  => 0x026EAD;
use constant kLineColor => 0xF2F2F2;
use constant kTextColor => 0xA8A0A0;

use constant kChartFileExt    => ".png";
use constant kChartFilePrefix => "bpdo_trend";

use constant BASE_URL => "/bookpub/dashboard";

use constant kChartFileDir => "/app/data/charts/dashboard";
use constant kChartImgDir  => "/images/charts/dashboard";

sub relatedCommands {
    qw(
      bookpub/tracker/main
    );
}

sub _init {
    my $self = shift;
    my %args = @_;

    my $timeframe = $args{timeframe};

    if ( $timeframe && $timeframe eq 'ytd' ) {
        $self->{_yearToDate} = 1;
    } elsif ( $timeframe && $timeframe =~ /^\d+$/ ) {
        $self->{_months} = $timeframe;
    } else {
        $self->{_months} = 3;
    }

    $self->{_serviceID} = $args{service};
    $self->{_imprintID} = $args{imprint};

    return $self->SUPER::_init(%args);
}

sub _initProperties {
    my $self = shift;

    $self->_generateChartImage();
    Common::Log::Debug("Chart File: $self->{ChartSource}");

    $self->{ImprintList} = BookPub::Catalog::ImprintList->new();
    $self->{ServiceList} = BookPub::Catalog::ServiceList::OnlyAggSales->new();

    return $self->SUPER::_initProperties(@_);
}

sub _generateChartImage {
    my $self = shift;

    my $currencySymbol = Common::Client::Current()->Locale()->currencyFormat()->symbol();
    my $thousands      = Common::Client::Current()->Locale()->numericFormat()->thousands();
    my $decimal        = Common::Client::Current()->Locale()->numericFormat()->decimal();

    my $chartSource;

    my $chartData = $self->_getChartData();
    my $c = new XYChart( 680, 350 );

    # Set the plotarea at (30, 20) and of size 400 x 200 pixels
    $c->setPlotArea( 85, 20, 590, 290);
    $c->getPlotArea->setGridColor(kLineColor);

    # Add a bar chart layer using the given data
    my $layer = $c->addBarLayer( $chartData->{data} );

    # Add totals above the bars
    #$layer->setAggregateLabelStyle("arialbd.ttf", 8, $layer->yZoneColor(0, 0xcc3300, 0x3333ff));

    # Set minimum size for hot spots
    $layer->setMinImageMapSize(30);

    # Force the y-axis to start at zero
    $c->yAxis->setLinearScale( 0, $perlchartdir::NoValue );
    $c->setClipping();

    # Add extra fields for tool tips.
    # Order matters!
    $c->addExtraField( $chartData->{percentChange} );
    $c->addExtraField( $chartData->{revenueChange} );

    # Need this to make the link into analytics.
    $c->addExtraField( $chartData->{periodIDs} );

    # Set the colors
    $c->setColor( $perlchartdir::DataColor, kBarColor );
    $c->setColor( $perlchartdir::LineColor, kLineColor );
    $c->setColor( $perlchartdir::TextColor, kTextColor );

    # Set the labels on the x axis.
    $c->xAxis()->setLabels( $chartData->{labels} );

    $c->yAxis()->setLabelStyle("arialbd.ttf ", 9);
    $c->xAxis()->setLabelStyle("arialbd.ttf ", 9);
    $c->xAxis()->setLabelGap(20);
    $c->yAxis()->setLabelGap(10);

    # Set the y axis label formatting.
    $c->yAxis()->setLabelFormat( $currencySymbol . "{value|0" . $thousands . $decimal . "}" );

    # I think we're going to need this name to be very unique.
    my $chartName = $self->_getChartFilename();

    $self->{ChartSource} = sprintf( "%s/%s", kChartImgDir, basename($chartName) );

    # Output the chart
    my $result = $c->makeChart($chartName);

    my $baseURL     = "/bookpub/analytics";
    my $extraParams = "period={field2|0}&period_type=m";

    my $serviceID = $self->{_serviceID};
    my $imprintID = $self->{_imprintID};
    my $command   = "&c=m";

    if ($serviceID) {
        $extraParams .= "&service=$serviceID";
        $command = "&c=s";
    }

    if ($imprintID) {
        $extraParams .= "&imprint=$imprintID";
    }

    $extraParams .= $command;

    # Create the image map
    $self->setImageMap( $c->getHTMLImageMap( $baseURL, $extraParams, 'class="SalesChart-area js-tooltip" title="%%{value|2}%%{field0|1}%%{field1|2}%%"' ) );

    return $chartSource;
}

sub _getChartFilename {
    my $self = shift;

    mkdir(kChartFileDir) unless ( -d kChartFileDir );

    my $tmp = new File::Temp(
        UNLINK   => 0,
        DIR      => kChartFileDir,
        SUFFIX   => kChartFileExt,
        TEMPLATE => kChartFilePrefix . '_XXXXXXXXXXX'
    );

    die "Failed to create temp file: $tmp: $!" unless ( -e "$tmp" );

    Common::Log::Debug("Temp file: $tmp");
    return "$tmp";

}

sub _getChartData {
    my $self    = shift;
    my @periods = $self->_getPeriods();
    my @data;
    my @labels;
    my %revenue;

    my @percentChange;
    my @revenueChange;
    my @periodIDs;

    my $collection = BookPub::DB::Item::AggMProductSales->GetTotalsByPeriod(
        periods    => $self->_periodsIDs( \@periods ),
        service_id => $self->{_serviceID},
        imprint_id => $self->{_imprintID}
    );

    while ( my $item = $collection->next() ) {
        $revenue{ $item->month_id } = $item->revenue;
    }

    foreach my $period (@periods) {
        my $r = $revenue{ $period->month_id } ? $revenue{ $period->month_id } : 0;
        my ( $revDelta, $percent ) = $self->_getPercentageChange( revenue => \%revenue, month_id => $period->month_id );

        push( @data,          $r );
        push( @labels,        uc $self->_monthToString( $period-> month ) );
        push( @percentChange, $percent );
        push( @revenueChange, $revDelta );
        push( @periodIDs,     $period->month_id );
    }

    Common::Log::Debug( "Revenue data: " . join( ', ', @data ) );
    Common::Log::Debug( "Labels: " . join( ', ', @labels ) );

    return {
        data          => \@data,
        labels        => \@labels,
        percentChange => \@percentChange,
        revenueChange => \@revenueChange,
        periodIDs     => \@periodIDs
    };
}

sub _periodsIDs {
    my $self = shift;
    my $periods = shift || return ();
    my @result;

    foreach my $period (@$periods) {
        push( @result, $period->month_id );
    }
    return \@result;
}

sub _getPeriods {
    my $self       = shift;
    my $collection = Raptor::DB::Item::PeriodMonth->GetLatestByRange(
        months => $self->{_months},
        ytd    => $self->{_yearToDate}
    );
    my @periods;

    while ( my $period = $collection->next() ) {
        push( @periods, $period );
    }

    return @periods;
}

sub _monthToString {
    my $self   = shift;
    my $month  = shift;
    my @months = ( "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" );

    assert( $month >= 1 && $month <= 12 );

    return $months[ $month - 1 ];
}

sub setImageMap {
    my $self = shift;
    my $imageMap = shift || return;

    Common::Log::Debug($imageMap);
    $imageMap =~ s/%%([\+\-0-9\.]+)%%([\+\-0-9\.|NaN]+)%%([\+\-0-9\.]+)+%%/_formatMapTitle($1, $2, $3)/gem;

    $self->{ImageMap} = $imageMap;
}

sub _formatMapTitle {
    my ( $revenue, $unitChange, $revenueChange ) = @_;

    if ( $unitChange eq 'NaN' ) {
        return _formatMapRevenue($revenue);
    } else {
        return
            _formatMapRevenue($revenue)
          . "&lt;br&gt;"
          . _formatMapPercentage($unitChange)
          . "&lt;br&gt;"
          . _formatMapRevenueChange($revenueChange);
    }
}

sub _formatMapRevenue {
    my $value = shift;

    my $rawValue = $value;

    $value = Common::Client::Current()->Locale()->formatMoney( Common::RSMath::round( $value, 2 ) );

    if ( $rawValue < 0 ) {

        # We want to add a space between the negative sign and the number.
        $value =~ s/-//;
        $value = "- $value";
    }

    return $value;
}

sub _formatMapPercentage {
    my $value = shift;

    my $rawValue = $value;

    $value = Common::Client::Current()->Locale()->formatNumber( Common::RSMath::round( $value, 2 ) ) . "%";

    if ( $rawValue > 0 ) {
        $value = "&lt;span class='chartGain'&gt;+ " . $value . "&lt;/span&gt;";
    } elsif ( $rawValue < 0 ) {

        # We want to add a space between the negative sign and the number.
        $value =~ s/-//;
        $value = "&lt;span class='chartLoss'&gt;- $value&lt;/span&gt;";
    }

    return $value;
}

sub _formatMapRevenueChange {
    my $value = shift;

    my $rawValue = $value;

    $value = Common::Client::Current()->Locale()->formatMoney( Common::RSMath::round( $value, 2 ) );

    if ( $rawValue > 0 ) {
        $value = "&lt;span class='chartGain'&gt;+ " . $value . "&lt;/span&gt;";
    } elsif ( $rawValue < 0 ) {

        # Here too we want to add a space between the negative sign and the number.
        $value =~ s/-//;
        $value = "&lt;span class='chartLoss'&gt;- $value&lt;/span&gt;";
    }

    return $value;
}

sub _getPercentageChange {
    my $self           = shift;
    my %args           = @_;
    my $revenueByMonth = $args{revenue};
    my $currentMonth   = $args{month_id};

    assert($currentMonth);
    assert($revenueByMonth);

    my $currentRevenue = $revenueByMonth->{$currentMonth} || 0;
    my $previousRevenue;

    if ( exists $revenueByMonth->{ $currentMonth - 1 } ) {
        $previousRevenue = $revenueByMonth->{ $currentMonth - 1 };
    } else {
        my $collection = BookPub::DB::Item::AggMProductSales->GetTotalsByPeriod(
            periods    => [ $currentMonth - 1 ],
            service_id => $self->{_serviceID},
            imprint_id => $self->{_imprintID}
        );

        my $dbItem = $collection->next;

        $previousRevenue = $dbItem ? $dbItem->revenue : 0;
    }

    my $diff = $currentRevenue - $previousRevenue;

    my $percent;

    if ( $previousRevenue && $previousRevenue != 0 ) {
        $percent = ( $diff / $previousRevenue ) * 100;

        if ( ( $diff < 0 && $percent > 0 ) || ( $diff > 0 && $percent < 0 ) ) {
            $percent *= -1;
        }
    } else {
        $percent = 'NaN';
    }

    Common::Log::Debug("Current: $currentRevenue, Prev: $previousRevenue, D: $diff, P: $percent");

    return ( $diff, $percent );

}

###
1;    #
###
