#------------------------------------------------------------
# Copyright (C) 2007 RoyaltyShare, Inc.   All Rights Reserved
# $Id$
#------------------------------------------------------------
#
#------------------------------------------------------------
# Validation Album Sequential Object.  Extends the Validate
# Rule class.  This object contains the method to do
# validation on piece of data.
#
# Test the target field to ensure all rows contain sequential
# data with no duplicates.
#
#
# Base Class:
#   Validation::Rule
#
# Public methods:
#   + Metadata::Rule::Album::Sequential new();
#   + $fail_status         ok();
#   + $scalar              AUTOLOAD( $scalar );
#------------------------------------------------------------
package Metadata::Rule::Album::Sequential;
use strict;

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

use lib '/app/tools/metadata/lib';
use base 'Metadata::Rule::Album';

use Validate::Util qw( is_sequence );

use vars qw($AUTOLOAD);

###
# Default failure message if the OK method fails.
###
use constant kFailureMessage => "numbers missing or not in order";

use constant kClassAttributes => qw( additional_field allow_duplicates maximum minimum deviation );

#------------------------------------------------------------
# Public Methods
#------------------------------------------------------------

#------------------------------------------------------------
# Constructor
#------------------------------------------------------------
sub new {
    my ( $class, %args ) = @_;
    my $self = bless {}, $class;

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

#------------------------------------------------------------
# $fail_status ok( $target_data )
#
# Check for multually exclusive fields.
#
# Parameters:
#   $target_data - Data we will be testing.
#
# Return:
#   $fail_status - kStatusOK (0) if the test passes, any
#                  non-zero should be considered a failure.
#------------------------------------------------------------
sub ok {
    my ( $self, $target, %args ) = @_;
    my $fail =
      defined( $self->{_fail_status} )
      ? $self->{_fail_status}
      : Validate::kStatusDefault;
    my $success = Validate::kStatusOK;
    my $result  = $success;
    my $status;
    my $count = 0;

    my @sequence;
    my ( $minimum, $maximum );

    my $additional_field = $self->additional_field();

    my $dbo = Common::RSApp::GetClientDB();
    my $target_select =
      $self->allow_duplicates()
      ? "DISTINCT(" . $self->target_field() . ")"
      : $self->target_field;

    $target_select .= " as target ";
    $target_select .= ", " . $additional_field . " as add_field "
      if ($additional_field);

    my $order_by;
    $order_by = $additional_field . ", "
      if ($additional_field);

    #$order_by .= ", " if( $self->additional_field && $self->target_field );
    $order_by .= $self->target_field if ( $self->target_field );

    return undef unless ( $self->is_configured() );

    return $success unless ( defined($target) && length($target) );

    my $sql =
        "SELECT $target_select " . "FROM "
      . Metadata::DB::Item::ContentImportData::kTable . " "
      . "WHERE "
      . $self->unifying_field() . " = "
      . $dbo->DBQuote($target) . " " . " AND "
      . $self->target_field()
      . " IS NOT NULL "
      . "ORDER BY $order_by ";

    my $sth = $dbo->DoCmd($sql);

    my $add_field_value;
    while ( my $row = $sth->fetchrow_hashref() ) {
        next unless ( $row->{target} && $row->{target} =~ /^\d+$/ );
        $count++;

        if ( $add_field_value && $row->{add_field} && $add_field_value ne $row->{add_field} ) {
            $status = is_sequence(
                list    => \@sequence,
                minimum => $self->minimum(),
                maximum => $self->maximum()
            ) ? $success : $fail;
            $result = $result < $status ? $status : $result;

            @sequence = ();
            $minimum  = undef;
            $maximum  = undef;
        }

        $add_field_value = $row->{add_field};
        push( @sequence, $row->{target} );

        if ( defined($minimum) ) {
            $minimum = $row->{target} < $minimum ? $row->{target} : $minimum;
        } else {
            $minimum = $row->{target};
        }

        if ( defined($maximum) ) {
            $maximum = $row->{target} > $maximum ? $row->{target} : $maximum;
        } else {
            $maximum = $row->{target};
        }

    }

    $status = is_sequence(
        list    => \@sequence,
        minimum => $self->minimum(),
        maximum => $self->maximum()
    ) ? $success : $fail;

    return $success unless ($count);

    $result = $result < $status ? $status : $result;
    Common::Log::Debug("Status: $status Result: $result");

    return $result;
}

#------------------------------------------------------------
# Private Methods
#------------------------------------------------------------

#------------------------------------------------------------
# Validate::Rule _init()
# Initialize the object.
#
# - Build accessor method hash
# - set internal private data ( message, fail_status, and
#   parameter ). See the base class for parameter defintions.
#------------------------------------------------------------
sub _init {
    my ( $self, %args ) = @_;

    # Build a hash with our valid class attributes
    foreach ( (kClassAttributes) ) {
        $self->{_attributes}->{$_}++;
    }

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

    $self->message( $args{message} ? $args{message} : kFailureMessage );

    return $self;
}
1;
