#---------------------------------------------------------------
# ____                   _ _         ____  _
#|  _ \ ___  _   _  __ _| | |_ _   _/ ___|| |__   __ _ _ __ ___
#| |_) / _ \| | | |/ _` | | __| | | \___ \| '_ \ / _` | '__/ _ \
#|  _ < (_) | |_| | (_| | | |_| |_| |___) | | | | (_| | | |  __/
#|_| \_\___/ \__, |\__,_|_|\__|\__, |____/|_| |_|\__,_|_|  \___|
#            |___/             |___/
#
# Copyright (C) 2011 RoyaltyShare, Inc.   All Rights Reserved
#---------------------------------------------------------------
package BookPub::Catalog::Book::Title;
use strict;
use warnings;

use Data::Dumper;

use lib '/app/tools/common/lib';
use lib '/app/tools/bookpub/lib';
use lib '/app/tools/mediaserve/lib';

use Common::Util qw(clean word_containment);
use Common::Assert;

use BookPub::Import::Importer;

use base 'Common::FormObject';

use overload( '""' => 'asString' );

sub new {
    my $class = shift;
    my $self = bless {}, $class;

    return $self->_init(@_);
}

sub _init {
    my $self = shift;
    my %args;
    my $isbn;
    my ( $title, $subtitle ) = $self->_parseArgs(@_);

    $self->{Title}    = $title;
    $self->{Subtitle} = $subtitle;

    return $self;
}

sub _parseArgs {
    my $self = shift;
    my %args;

    if ( @_ == 1 ) {
        my $param = $_[0];
        return ref($param) ? ( $param->Title, $param->Subtitle ) : $self->_parseTitle($param);
    } else {
        %args = @_;
        return defined( $args{parse} )
          ? $self->_parseTitle( $args{parse} )
          : ( $args{title}, $args{subtitle} );
    }

    die "Should never get here";
}

sub _parseTitle {
    my $self  = shift;
    my $input = shift;
    my $title;
    my $subtitle;

    return unless ( defined($input) );

    return $input =~ /:/ ? BookPub::Import::Importer::ParseTitleAndSubtitle($input) : $input;
}

sub asString { shift->Combined }

sub Combined {
    my $self = shift;
    return unless ( $self->Title );
    return $self->Title unless ( $self->Subtitle );
    return $self->Title . ": " . $self->Subtitle;
}

sub CleanTitle {
    my $title = shift->Title || return;
    return Common::Util::clean_book_title($title);
}

sub CleanSubtitle {
    my $subtitle = shift->Subtitle || return;
    Common::Util::clean_book_title($subtitle);
}

sub CleanCombined {
    my $self = shift;
    return unless ( $self->Title );
    return $self->CleanTitle unless ( $self->Subtitle );
    return $self->CleanTitle() . "_" . $self->CleanSubtitle();
}

sub exactMatch {
    my $self = shift;
    my ( $title, $subtitle ) = $self->_parseArgs(@_);

    assert( $self->Title );

    # Do we have a title match?
    return unless ( defined($title) );
    return unless ( $self->Title eq $title );

    return 1 if ( !defined( $self->Subtitle ) && !defined($subtitle) );
    return   if ( !defined( $self->Subtitle ) && defined($subtitle)
        || defined( $self->Subtitle ) && !defined($subtitle) );

    return $self->Subtitle eq $subtitle;
}

sub fuzzyMatch {
    my $self   = shift;
    my $target = ref($self)->new(@_);

    return unless ( $self->Title() );
    return unless ( $target->Title() );

    # Do we have an exact match?
    return 1 if ( $self->exactMatch( title => $target->Title, subtitle => $target->Subtitle ) );

    # If no subtitle is specified, then lets try to parse the subtitle out of the
    # title.
    unless ( defined( $target->Subtitle ) ) {
        $target = ref($self)->new( parse => $target->Title() );
    }

    # Do we have a full clean match?
    return 1 if $self->CleanCombined eq $target->CleanCombined;

    ## Insert Fuzzy Logic Here
    return 1 if ( ( $self->titleFuzzyMatch($target) && $self->subtitleFuzzyMatch($target) )
        || $self->_combinedFuzzyMatch($target) );

    return;
}

sub titleFuzzyMatch {
    my $self = shift;
    my $target;

    if ( @_ == 1 ) {
        $target = shift;
    } else {
        $target = ref($self)->new(@_);
    }

    return unless ( $self->CleanTitle() );
    return unless ( $target->CleanTitle() );

    return 1 if ( $self->CleanTitle eq $target->CleanTitle );

    # Check for substring matches
    return 1 if ( substr( $target->CleanTitle, 0, length $self->CleanTitle() ) eq $self->CleanTitle );

}

sub subtitleFuzzyMatch {
    my $self = shift;
    my $target = shift || die;

    if ( @_ == 1 ) {
        $target = shift;
    } else {
        $target = ref($self)->new(@_);
    }

    # Both undefined is a positive result
    return 1 if ( !defined( $self->CleanSubtitle() ) && !defined( $target->CleanSubtitle() ) );

    return if ( !defined( $self->CleanSubtitle() ) || !defined( $target->CleanSubtitle() ) );

    return 1 if ( $self->CleanSubtitle eq $target->CleanSubtitle );

    # Check for substring matches
    return 1 if ( substr( $target->CleanSubtitle, 0, length $self->CleanSubtitle() ) eq $self->CleanSubtitle );

}

sub _combinedFuzzyMatch {
    my $self = shift;
    my $target = shift || die;

    # Both undefined is a positive result
    return 1 if ( !defined( $self->CleanCombined() ) && !defined( $target->CleanCombined() ) );

    return 1 if ( $self->CleanCombined eq $target->CleanCombined );

    # Check for substring matches
    return 1 if ( substr( $target->CleanCombined, 0, length $self->CleanCombined() ) eq $self->CleanCombined );

}

sub contains {
    my $self   = shift;
    my $target = ref($self)->new(@_);

    my $targetCombined = $target->CleanCombined();
    my $sourceCombined = $self->CleanCombined();

    return unless ( defined($targetCombined) && defined($sourceCombined) );

    $targetCombined =~ s/_+/ /g;
    $sourceCombined =~ s/_+/ /g;

    return word_containment( $sourceCombined, $targetCombined );
}

###
1;    #
###
