#------------------------------------------------------------
# Copyright (C) 2006 RoyaltyShare, Inc.   All Rights Reserved
# $Id$
#------------------------------------------------------------
package Raptor::Matcher::Command::Base;
use strict;
use warnings;
use String::Similarity;

use lib '/app/tools/common/lib';
use RSApache::Response::XSLT;
use Common::Assert;
use Common::Debug;
use Common::Log;
use Common::Util;

use lib '/app/tools/rps/lib';
use lib '/app/tools/data_classes/lib';
use RPS::File::File;
use RPS::File::Sale;
use Product::ProductTrack;
use Product::ProductAlbum;
use Artist;

use lib '/app/tools/raptor/lib';

use Raptor::Command;
use base 'Raptor::Command';

# This class will serve as the base class for these commands, since there are
# a few things they have in common.
# It's not a 'real' command, as it does not implement 'execute'.
#

# !!! I'm not really very fond of this method, but I don't want to spend a lot of time
# re-working it.
#
# JPK - I'm going to add some 'secret' data, in particular the string similarity scores between
# the clean album and track titles, and the product titles.

sub showMatchOptions {
    my ( $self, $sale, $file, %args ) = @_;

    my $saleTrackNameClean = Common::Util::clean( $sale->TrackName() );
    my $saleAlbumNameClean = Common::Util::clean( $sale->AlbumName() );

    # make sure it's still unmatched
    if (
        !$sale->ProductID
        && (   $sale->ImportStatus == File::Sale::STATUS_NOMATCH
            || $sale->ImportStatus == File::Sale::STATUS_MULTIMATCH )
      ) {
        my $matches;
        my $search_param = $self->getParam("search");
        if ($search_param) {

            # user search for matches
            my $search_type_param = $self->getParam("search_type");
            $matches = $sale->GetSearchMatches( search => $search_param, search_type => $search_type_param );
        } else {

            # our suggested matches
            my $file = RPS::File::File->new( file_id => $sale->FileID );
            $matches = $sale->GetMatches( search_only => $args{search_only} || 0, service_id => $file->ServiceID );
        }

        # this sale record already has a match
        if ( !defined $matches ) {
            $self->addMessageXML( type => "error", code => "no_matches" );
        } elsif ( ref($matches) eq 'ARRAY' ) {
            foreach my $prod_id (@$matches) {
                my $albumName;
                my $trackName;
                my $prod;
                if ( $sale->IsAlbum() ) {
                    $prod = new Product::ProductAlbum( product_id => $prod_id );
                    $albumName = $prod->AlbumName();
                } elsif ( $sale->IsTrack() ) {
                    $prod      = new Product::ProductTrack( product_id => $prod_id );
                    $albumName = $prod->AlbumName();
                    $trackName = $prod->TrackName();
                } else    # what am i?
                {
                    $self->addMessageXML( type => "error", code => "unknown_product_type" );
                    Common::Log::Print( 'unknown prod-type: ' . $sale->ProductType );
                    next;
                }

                my $xml = $prod->GetObjectXML();

                # !!! Add some stuff for debugging.
                #
                if ($albumName) {
                    $xml->{AlbumNameScore} = String::Similarity::similarity( $saleAlbumNameClean, Common::Util::clean($albumName) );
                }
                if ($trackName) {
                    $xml->{TrackNameScore} = String::Similarity::similarity( $saleTrackNameClean, Common::Util::clean($trackName) );
                }

                push @{ $self->{xml}->{Products}->{Product} }, $xml;

                last if ( $. > 10 );
            }
        }

        # we found a match internally
        elsif ( $matches == 1 ) {
            if ( $args{search_only} ) {
                my $xml = _get_product_xml($sale);
                unless ($xml) {
                    $self->addMessageXML( type => 'error', code => 'unknown_product_type' );
                    return;
                }
                push @{ $self->{xml}->{Products}->{Product} }, $xml;
                return;
            }

            # just kidding, we really did have a match for this one.
            # just go to the next one
            $file->UpdateRemainingExceptions();
            my $tmp_sale_id = $sale->GetNextUnfixedID() || $sale->GetPreviousUnfixedID;

            if ($tmp_sale_id) {
                return $tmp_sale_id;
            } else {

                # recalculate remaining exceptions (just for sanity's sake)
                $file->RecalculateRemainingExceptions();

                ## all done with exceptions here...
            }
        }
    }

    # otherwise show what the match is
    else {
        my $xml = _get_product_xml($sale);
        unless ($xml) {
            $self->addMessageXML( type => 'error', code => 'unknown_product_type' );
            return undef;
        }
        push @{ $self->{xml}->{Products}->{Product} }, $xml;
    }

    return undef;
}

sub _get_product_xml {
    my ($sale) = @_;

    my $prod;

    if ( $sale->IsAlbum() ) {
        $prod = new Product::ProductAlbum( product_id => $sale->ProductID );
    } elsif ( $sale->IsTrack() ) {
        $prod = new Product::ProductTrack( product_id => $sale->ProductID );
    } else    # what am i?
    {
        Common::Log::Print( 'unknown prod-type: ' . $sale->ProductType );
        return undef;
    }

    return $prod->GetObjectXML();
}

sub setNavLinks {
    my ( $self, $sale ) = @_;

    # previous error
    my $tmp_sale_id = $sale->GetPreviousErrorID();
    $self->{xml}->{PreviousError} = $tmp_sale_id;

    # previous unfixed error
    $tmp_sale_id = $sale->GetPreviousUnfixedID();
    $self->{xml}->{PreviousUnfixed} = $tmp_sale_id;

    # next error
    $tmp_sale_id = $sale->GetNextErrorID();
    $self->{xml}->{NextError} = $tmp_sale_id;

    # next unfixed error
    $tmp_sale_id = $sale->GetNextUnfixedID();
    $self->{xml}->{NextUnfixed} = $tmp_sale_id;
}

1;

