#------------------------------------------------------------
# Copyright (C) 2006 RoyaltyShare, Inc.   All Rights Reserved
# $Id$
#------------------------------------------------------------
package RPS::DateRange;

use strict;
use warnings;
use Date::Calc;

use lib '/app/tools/common/lib';
use Common::Util qw(decodeDateMysql);
use Common::RSApp;
use Common::Assert;

use lib '/app/tools/rps/lib';
use Common::FormObject;
use RPS::DB::Item::Client;
use base 'Common::FormObject';

# these should probably go in the client XMLObject eventually
#
use constant kPeriodMonth      => 'M';
use constant kPeriodQuarter    => 'Q';
use constant kPeriodSemiAnnual => 'S';
use constant kPeriodAnnual     => 'A';

sub _init {
    my ( $self, %args ) = @_;

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

sub _initWithHashRef {
    my ( $self, $href ) = @_;

    $self->{CurrentDate}  = Common::FormObject::Scalar::String->new( value => $href->{currentDate} );
    $self->{StartDate}    = Common::FormObject::Scalar::String->new( value => $href->{startDate} );
    $self->{EndDate}      = Common::FormObject::Scalar::String->new( value => $href->{endDate} );
    $self->{PreviousDate} = Common::FormObject::Scalar::String->new( value => $href->{previousDate} );
    $self->{NextDate}     = Common::FormObject::Scalar::String->new( value => $href->{nextDate} );
    $self->{Type} = Common::FormObject::Scalar->new( value => $href->{type} );
}

# Static method to return proper date range calss
#
sub GetMechanicalDateRangeObject {
    my ($date) = @_;

    # get client db obj
    #
    my $clientObj = RPS::DB::Item::Client->Lookup( client_id => Common::RSApp::GetClientID() );
    return undef if ( !defined $clientObj );

    return GetDateRangeObject( date => $date, type => $clientObj->royalty_period_mechanical );
}

sub GetDateRangeObject {
    my (%args) = @_;

    my $date = $args{date};
    my $type = $args{type};

    # validate date
    #
    my ( $year, $month, $day );
    if (   !( ( $year, $month, $day ) = Date::Calc::Decode_Date_US($date) )
        && !( ( $year, $month, $day ) = Date::Calc::Decode_Date_EU($date) )
        && !( ( $year, $month, $day ) = decodeDateMysql($date) ) ) {
        return undef;
    }

    my $dateRangeObj;
    if ( RPS::DateRange::kPeriodMonth() eq uc $type ) {
        $dateRangeObj = RPS::DateRange::Month->new( year => $year, month => $month, day => $day );
    } elsif ( RPS::DateRange::kPeriodQuarter() eq uc $type ) {
        $dateRangeObj = RPS::DateRange::Quarter->new( year => $year, month => $month, day => $day );
    } elsif ( RPS::DateRange::kPeriodSemiAnnual() eq uc $type ) {
        $dateRangeObj = RPS::DateRange::SemiAnnual->new( year => $year, month => $month, day => $day );
    } elsif ( RPS::DateRange::kPeriodAnnual() eq uc $type ) {
        $dateRangeObj = RPS::DateRange::Annual->new( year => $year, month => $month, day => $day );
    } else {

        # just default to month range for now
        #
        $dateRangeObj = RPS::DateRange::Month->new( year => $year, month => $month, day => $day );
    }

    return $dateRangeObj;
}

# utility to parse either a "date" parameter
# or a "year" "month" and "day" parameters.
#
sub _parseDate {
    my %args = @_;

    my ( $year, $month, $day );

    if ( $args{date} ) {
        if (   !( ( $year, $month, $day ) = Date::Calc::Decode_Date_US( $args{date} ) )
            && !( ( $year, $month, $day ) = Date::Calc::Decode_Date_EU( $args{date} ) )
            && !( ( $year, $month, $day ) = decodeDateMysql( $args{date} ) ) ) {
            return undef;
        }

    } elsif ( $args{year} && $args{month} && $args{day} ) {
        $year  = $args{year};
        $month = $args{month};
        $day   = $args{day} || 1;
    }

    return ( $year, $month, $day );
}

package RPS::DateRange::Month;
use base 'RPS::DateRange';

sub _init {
    my ( $self, %args ) = @_;

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

    my ( $year, $month, $day ) = RPS::DateRange::_parseDate(%args);

    my $href = {};
    if ( $year && $month && $day ) {
        $href->{currentDate} = sprintf( "%04d-%02d-%02d", $year, $month, $day );
        $href->{startDate}   = sprintf( "%04d-%02d-%02d", $year, $month, 1 );
        $href->{endDate}     = sprintf( "%04d-%02d-%02d", $year, $month, Date::Calc::Days_in_Month( $year, $month ) );

        # we need the next and previous dates, too
        #
        $href->{previousDate} = sprintf( "%04d-%02d-%02d", Date::Calc::Add_Delta_YM( $year, $month, $day, 0, -1 ) );
        $href->{nextDate}     = sprintf( "%04d-%02d-%02d", Date::Calc::Add_Delta_YM( $year, $month, $day, 0, 1 ) );
        $href->{type}         = RPS::DateRange::kPeriodMonth;

        $self->SUPER::_initWithHashRef($href);
    }

    return $self;
}

package RPS::DateRange::Quarter;
use base 'RPS::DateRange';

sub _init {
    my ( $self, %args ) = @_;

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

    my ( $year, $month, $day ) = RPS::DateRange::_parseDate(%args);

    my $href = {};
    if ( $year && $month && $day ) {
        $href->{currentDate} = sprintf( "%04d-%02d-%02d", $year, $month, $day );

        my ( $startMonth, $endMonth );

        if ( ( $month % 3 ) != 1 ) {

            # if $startMonth is 2, 5, 8, 11 (mod 3 == 2),
            # 	then substract 1
            # else $startMonth is 3, 6, 9, or 12 (mod 3 == 0)
            # 	so substract 2.
            $startMonth = ( $month % 3 ) ? $month - 1 : $month - 2;
        } else {

            # $startMonth is 1, 4, 7, or 10,
            # so it's already the first month
            # of the quarter.
            #
            $startMonth = $month;
        }
        $endMonth = $startMonth + 2;

        $href->{startDate} = sprintf( "%04d-%02d-%02d", $year, $startMonth, 1 );
        $href->{endDate} = sprintf( "%04d-%02d-%02d", $year, $endMonth, Date::Calc::Days_in_Month( $year, $endMonth ) );

        # we need the next and previous dates, too
        #
        $href->{previousDate} = sprintf( "%04d-%02d-%02d", Date::Calc::Add_Delta_YM( $year, $month, $day, 0, -3 ) );
        $href->{nextDate}     = sprintf( "%04d-%02d-%02d", Date::Calc::Add_Delta_YM( $year, $month, $day, 0, 3 ) );
        $href->{type}         = RPS::DateRange::kPeriodQuarter;

        $self->SUPER::_initWithHashRef($href);
    }

    return $self;
}

package RPS::DateRange::SemiAnnual;
use base 'RPS::DateRange';

sub _init {
    my ( $self, %args ) = @_;

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

    my ( $year, $month, $day ) = RPS::DateRange::_parseDate(%args);

    my $href = {};
    if ( $year && $month && $day ) {
        $href->{currentDate} = sprintf( "%04d-%02d-%02d", $year, $month, $day );

        my ( $startMonth, $endMonth );

        if ( $month >= 7 ) {
            $startMonth = 7;
            $endMonth   = 12;
        } else {
            $startMonth = 1;
            $endMonth   = 6;
        }

        $href->{startDate} = sprintf( "%04d-%02d-%02d", $year, $startMonth, 1 );
        $href->{endDate} = sprintf( "%04d-%02d-%02d", $year, $endMonth, Date::Calc::Days_in_Month( $year, $endMonth ) );

        # we need the next and previous dates, too
        #
        $href->{previousDate} = sprintf( "%04d-%02d-%02d", Date::Calc::Add_Delta_YM( $year, $month, $day, 0, -6 ) );
        $href->{nextDate}     = sprintf( "%04d-%02d-%02d", Date::Calc::Add_Delta_YM( $year, $month, $day, 0, 6 ) );
        $href->{type}         = RPS::DateRange::kPeriodSemiAnnual;

        $self->SUPER::_initWithHashRef($href);
    }

    return $self;
}

package RPS::DateRange::Annual;
use base 'RPS::DateRange';

sub _init {
    my ( $self, %args ) = @_;

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

    my ( $year, $month, $day ) = RPS::DateRange::_parseDate(%args);

    my $href = {};
    if ( $year && $month && $day ) {
        $href->{currentDate} = sprintf( "%04d-%02d-%02d", $year, $month, $day );

        $href->{startDate} = sprintf( "%04d-%02d-%02d", $year, 1,  1 );
        $href->{endDate}   = sprintf( "%04d-%02d-%02d", $year, 12, 31 );

        # we need the next and previous dates, too
        #
        $href->{previousDate} = sprintf( "%04d-%02d-%02d", Date::Calc::Add_Delta_YM( $year, $month, $day, -1, 0 ) );
        $href->{nextDate}     = sprintf( "%04d-%02d-%02d", Date::Calc::Add_Delta_YM( $year, $month, $day, 1,  0 ) );
        $href->{type}         = RPS::DateRange::kPeriodAnnual;

        $self->SUPER::_initWithHashRef($href);
    }

    return $self;
}

###
1;    #
###
