#------------------------------------------------------------
# Copyright (C) 2006 RoyaltyShare, Inc.   All Rights Reserved
#------------------------------------------------------------
package Support::MultiClientReport;

use strict;
use warnings;
use Carp;

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

use lib '/app/tools/support/lib';
use Support::DB::Item::DistributionService;

use Common::FormObject;
use base 'Common::XMLObject';

use POSIX qw(ceil);

sub databaseClass  { die "Must be overloaded!" }
sub databaseMethod { die "Must be overloaded!" }
sub selectFields   { }

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

    $self->{_clientID}     = $args{clientID};
    $self->{_clientTypeID} = $args{clientTypeID};
    $self->{_limit}        = $args{limit};
    $self->{_page}         = $args{page} || 1;

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

sub run {
    my $self = shift;
    my $skipClient;

    eval "require " . $self->databaseClass();
    die $@ if ($@);

    my $class  = $self->databaseClass;
    my $method = $self->databaseMethod;

    assert($class);
    assert($method);

    $self->{_rowCount} = 1;

    foreach my $client ( $self->clients() ) {

        # Switch clients
        my $app = Common::RSApp->new_temporary( clientID => $client );

        Common::Log::Debug("Switching client context to ID: $client");
        $self->_runQuery( $class, $method, @_ );
    }

    $self->_setPagination();
}

sub _setPagination {
    my $self = shift;

    $self->{PageSize}    = $self->{_limit};
    $self->{PageIndex}   = $self->{_page};
    $self->{PageCount}   = ceil( $self->{_totalSize} / $self->{_limit} ) if ( $self->{_limit} );
    $self->{IsPaginated} = $self->{PageCount} > 1 if ( $self->{PageCount} );
    $self->{TotalSize}   = $self->{_totalSize};
}

sub clients {
    my $self = shift;
    my @clients;
    my @results;
    my $client;

    if ( $self->{_clientID} ) {
        @clients = ( $self->{_clientID} );
    } elsif (Common::RSApp::IsProductionServer) {
        @clients = Common::RSDB::GetAllRPSClientIDs;
    } else {
        @clients = Common::RSDB::GetLocalRPSClientIDs;
    }

    return @clients unless ( $self->{_clientTypeID} );

    ## If we are filtering by client type
    for my $clientID (@clients) {
        $client = Common::DB::Item::Client->Lookup( client_id => $clientID );
        Common::Log::Debug( "CID: $clientID Type Filter: $self->{_clientTypeID}, Type: " . $client->type_mask );
        push( @results, $clientID ) if ( $self->{_clientTypeID} & $client->type_mask );
    }

    return @results;
}

sub fields {
    my $self   = shift;
    my $dbItem = shift;

    return @{ $self->{_selectFields} } if ( $self->{_selectFields} );

    my @fields;

    if ( $self->selectFields() ) {
        @fields = $self->selectFields();
    } else {
        assert( $dbItem, "DB Item required to get dynamic field list" );
        foreach my $key ( keys( %{$dbItem} ) ) {
            push( @fields, $key ) if ( $key !~ /^_/ );
        }
    }

    $self->{_selectFields} = \@fields;
    return @fields;
}

sub _withinUpperBound {
    my $self     = shift;
    my $rowCount = shift;

    return 1 unless ( defined $self->{_limit} );

    my $limit = $self->{_page} * $self->{_limit};

    Common::Log::Debug("Upper LIMIT: $limit, PAGE: $self->{_page}, ROW: $rowCount");

    return $limit >= $rowCount;
}

sub _withinLowerBound {
    my $self     = shift;
    my $rowCount = shift;

    return 1 unless ( defined $self->{_limit} );

    my $limit = $self->{_page} * $self->{_limit} - $self->{_limit};

    Common::Log::Debug("Lower LIMIT: $limit, PAGE: $self->{_page}, ROW: $rowCount");

    return $limit < $rowCount;
}

sub _runQuery {
    my $self   = shift;
    my $class  = shift;
    my $method = shift;

    my $collection = $class->$method(@_);

    $self->{_totalSize} += $collection->totalSize();

    unless ( $self->_withinLowerBound( $self->{_rowCount} + $collection->totalSize() ) ) {
        Common::Log::Debug("We haven't reached the lower limit yet");

        $self->{_rowCount} += $collection->totalSize();
        return;
    }

    while ( $collection->hasNext() && $self->_withinUpperBound( $self->{_rowCount} ) ) {
        my $row = $collection->next();
        if ( $self->_withinLowerBound( $self->{_rowCount} ) ) {
            Common::Log::Debug("In range: row = $self->{_rowCount}");
            $self->_pushRow($row);
        }
        $self->{_rowCount}++;
    }
}

sub _pushRow {
    my $self = shift;
    my $row  = shift;

    $self->{List}->{Item} = [] unless ( $self->{List} );

    push( @{ $self->{List}->{Item} }, $self->_initRow($row) );
}

sub _initRow {
    my $self = shift;
    my $row  = shift;

    my @fields = $self->fields($row);
    my %result;

    foreach my $field (@fields) {
        $result{$field} = $row->{$field};
    }

    $result{client_id} = Common::RSApp::GetClientID();

    return \%result;
}

1;
