#------------------------------------------------------------
# Copyright (C) 2009 RoyaltyShare, Inc.   All Rights Reserved
#------------------------------------------------------------

package Common::Translator::VersionFromXML;

use base 'Common::Translator::Version';

#
# Common::Translator::VersionWithHeader
#
# This class provides an interface like Common::TranslatorVersion
# but also does header and column mapping.
#

use strict;

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

use Data::Dumper;

sub _supportedVersion { assert(0) }

sub validate {
    my $self = shift;

    unless ( ref( $self->{_parser} ) && $self->{_parser}->fileType() eq 'xml' ) {
        $self->{_error} = "Input is not a valid XML file";
    }

    return $self->error ? undef : 1;
}

sub parser {
    my $self   = shift;
    my $parser = shift;

    if ($parser) {
        $self->{_parser} = $parser;

        $self->validate();
    }

    return $self->{_parser};
}

sub getMapByColumn {
    my $self = shift;
    my $path = shift;
    assert( defined($path) );

    my $itemConfig = $self->_getItemConfig($path);
    assert($itemConfig);

    return { to => $itemConfig };
}

sub _getItemConfig {
    my $self = shift;
    my $path = shift || return;

    my $required = $self->_requiredXML();
    my $optional = $self->_optionalXML();

    return $required->{$path} if ( $required && $required->{$path} );

    return $optional->{$path} if ( $optional && $optional->{path} );
}

sub transform {
    my $self       = shift;
    my $path       = shift;
    my $destColumn = shift;
    my $value      = shift || return;
    my $config     = $self->_getItemConfig($path);
    my @configs    = ref($config) eq 'ARRAY' ? @{$config} : ($config);

    assert( $path && $destColumn );

    return unless ($value);

    foreach my $c (@configs) {

        # If this is a hash ref
        if ( ref($c) ) {
            assert( $c->{column}, "column not defined in config" );

            return $self->_transform( $value, $c ) if ( $destColumn eq $c->{column} );
        }

        # Otherwise only the destination column is defined and we simply return
        # the value if we are looking at the right config.
        else {
            return $value if ( $destColumn eq $c );
        }
    }

    Common::Log::Debug("  Transforming: $path Value: $value");

    return;
}

sub _transform {
    my $self   = shift;
    my $value  = shift;
    my $config = shift;

    if ( defined( $config->{keyPath} ) && defined( $config->{keyValue} ) ) {
        $value = $self->_transformSelect( $value, $config );
    }

    if ( defined( $config->{method} ) ) {
        $value = $config->{method}($value);
    }

    return $value;
}

sub _transformSelect {
    my $self   = shift;
    my $value  = shift;
    my $config = shift;
    my @nodes  = ref($value) eq 'ARRAY' ? @$value : ($value);

    my $key    = $config->{keyPath};
    my $match  = $config->{keyValue};
    my $select = $config->{selectPath};

    assert( defined($value) && defined($config) );

    for my $node (@nodes) {
        if ( $node->{$key} && $node->{$key} eq $match ) {
            return $node->{$select};
        }
    }

    return;
}

###
1;    # Play nicely.
###
