The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
package Google::Checkout::Notification::Factory;

=head1 NAME

Google::Checkout::Notification::Factory

=head1 DESCRIPTION

Given a notification XML, return the corresponding notification
object that's capable of handing the notification.

=head1 COPYRIGHT

Copyright 2006 Google. All rights reserved.

=cut

use strict;
use warnings;

use Exporter;
our @ISA = qw/Exporter/;
our @EXPORT_OK = qw/get_notification_object/;

use Google::Checkout::General::Error;
use Google::Checkout::XML::Constants;
use Google::Checkout::General::MerchantCalculationCallback;
use Google::Checkout::Notification::ChargeAmount;
use Google::Checkout::Notification::ChargebackAmount;
use Google::Checkout::Notification::NewOrder;
use Google::Checkout::Notification::OrderStateChange;
use Google::Checkout::Notification::RefundAmount;
use Google::Checkout::Notification::RiskInformation;
use Google::Checkout::General::Util qw/is_gco_error/;

sub get_notification_object
{
  my %args = @_;

  #--
  #-- no XML is an error
  #--
  return Google::Checkout::General::Error->new(-1, "No XML") unless $args{xml};

  #--
  #-- get the root element of the XML. no 'real' XML
  #-- parse and verification. i want this to be quick
  #--
  my $root_element = _get_root_element(\%args);

  return Google::Checkout::General::Error->new(-1, "Invalid XML") if is_gco_error($root_element);

  return _map_xml_to_notification_object($root_element, \%args);
}

sub _get_root_element
{
  my ($args) = @_;

  my $xml = '';

  #--
  #-- XML can either be in a file or in memory.
  #-- we are going to make the assumption that
  #-- if $args->{xml} starts with '<', it's not
  #-- in a file. otherwise, we load it from file
  #--
  if ($args->{xml} !~ /^</)
  {
    open(XML, $args->{xml}) || 
      return Google::Checkout::General::Error->new(-1, "Unable to open $args->{xml}: $!");

    #--
    #-- got a couple of lines. that's all we need 
    #-- to determine the type of the notification
    #--
    while (<XML>)
    {
      $xml .= $_;

      last if $. > 2;
    }

    close(XML);
  }
  else
  {
    $xml = $args->{xml};
  }

  if ($xml =~ /^<.+?<(\S+)/ms)
  { 
    return $1;
  }
  else 
  {
    return '';
  }
}

sub _map_xml_to_notification_object
{
  my ($root_element, $args) = @_;

  if ($root_element eq Google::Checkout::XML::Constants::CHARGE_AMOUNT_NOTIFICATION)
  {
    return Google::Checkout::Notification::ChargeAmount->new(xml => $args->{xml});
  } 
  elsif ($root_element eq Google::Checkout::XML::Constants::CHARGE_BACK_NOTIFICATION) 
  {
    return Google::Checkout::Notification::ChargebackAmount->new(xml => $args->{xml});
  }
  elsif ($root_element eq Google::Checkout::XML::Constants::MERCHANT_CALCULATION_CALLBACK)
  {
    return Google::Checkout::General::MerchantCalculationCallback->new(xml => $args->{xml});
  }
  elsif ($root_element eq Google::Checkout::XML::Constants::NEW_ORDER_NOTIFICATION)
  {
    return Google::Checkout::Notification::NewOrder->new(xml => $args->{xml});
  }
  elsif ($root_element eq Google::Checkout::XML::Constants::ORDER_STATE_CHANGE_NOTIFICATION)
  {
    return Google::Checkout::Notification::OrderStateChange->new(xml => $args->{xml});
  }
  elsif ($root_element eq Google::Checkout::XML::Constants::REFUND_AMOUNT_NOTIFICATION)
  {
    return Google::Checkout::Notification::RefundAmount->new(xml => $args->{xml});
  } 
  elsif ($root_element eq Google::Checkout::XML::Constants::RISK_INFORMATION_NOTIFICATION)
  {
    return Google::Checkout::Notification::RiskInformation->new(xml => $args->{xml});
  }
  else
  {
    return Google::Checkout::General::Error->new(-1, "Unknown notification: $root_element");
  }
}

1;