#!/usr/bin/perl -w
#

################################################################################
# Location: ............. <user defined location>eBay/API/XML/Tools/CodeGen/XSD
# File: ................. CodeGenApiCall.pm
# Original Author: ...... Milenko Milanovic
# Last Modified By: ..... Robert Bradley / Jeff Nokes
# Last Modified: ........ 03/30/2007 @ 23:08
################################################################################

package eBay::API::XML::Tools::CodeGen::XSD::CodeGenApiCall;

use lib '../../../../../../';  # To get access to all packages in XSD directory
use strict;
use warnings;
use Exporter;

use eBay::API::XML::Tools::CodeGen::XSD::BaseCodeGenDataType;


# Global Variables
our $VERSION = '0.01';    # The version of this module.

our @ISA = (
       'Exporter',
       'eBay::API::XML::Tools::CodeGen::XSD::BaseCodeGenDataType',
    );

use Data::Dumper;

sub new {
	
   my $classname = shift;	
   my %args = @_;

   my $self = {};
   bless($self, $classname);

      # 
      #  initialize properties
      # 

     # 1. 
   $self->{'requestCodeGen'}  = $args{'requestCodeGen'};
   $self->{'responseCodeGen'} = $args{'responseCodeGen'};

     # 2. name
   my $name = $args{'callName'};
   $self->setName($name);
   
     # 3. fullPackageName
   my $fullPackageName = $self->_determineFullPackageName();
   $self->setFullPackageName ( $fullPackageName );   

   return $self;
}

sub _determineFullPackageName {

   my $self = shift;

   my $str = $self->getRootPackageName()
                     . '::' . 'Call'
                     . '::' . $self->getName();
   return $str;
}

sub _getSuperClassFullPackageName {
   my $self = shift;

   my $str = $self->getRootPackageName()
                     . '::' . 'BaseCall';
   return $str;
}
		  
sub _getClassBody {
	
  my $self = shift;
  my %args = @_;

  my $sCallName    = $self->getName();
  my $pRequestGen  = $self->{'requestCodeGen'};
  my $pResponseGen = $self->{'responseCodeGen'};

  my $sSuperClassPackage  = $self->_getSuperClassFullPackageName();
  
  my $sRequestFullPackageName = $pRequestGen->getFullPackageName();
  my $sResponseFullPackageName = $pResponseGen->getFullPackageName();
				   
  my $imports = "use $sRequestFullPackageName;\n";
  $imports   .= "use $sResponseFullPackageName;\n";

    # Find element names that exists both for Request and Response
    # In case we have an element that exists for both Request and Response
    #   we will add a 'Request' and 'Response' prefix respectivly to that name
    #    (in order to avoid conflict in those names)
  my %hSameNames = ();  # for Api Calls we generate only setters for Request
                        #  and getters for Response, so we do not need to add prefix

     ## create input/output properties
  my $inputProperties = $self->getApiGettersSetters (
	                            'pCodeGenClass' => $pRequestGen
                               ,'sRequestOrResponse'=> 'Request'
                               ,'rhSameNames' => \%hSameNames
                               ,'createSetters'=> 1
                               ,'createGetters'=> 0
	                                     );
  my $outputProperties = $self->getApiGettersSetters (
	                            'pCodeGenClass' => $pResponseGen
                               ,'sRequestOrResponse'=> 'Response'
                               ,'rhSameNames' => \%hSameNames
                               ,'createSetters'=> 0
                               ,'createGetters'=> 1
	                                     );

  my $packageBody = <<"PACKAGE_BODY";

use $sSuperClassPackage;
our \@ISA = ("$sSuperClassPackage");

$imports

=head1 Subroutines:

=cut

sub getApiCallName {
   return '$sCallName';
}
sub getRequestDataTypeFullPackage {
   return '$sRequestFullPackageName';
}
sub getResponseDataTypeFullPackage {
   return '$sResponseFullPackageName';
}

#
# input properties
#

$inputProperties

#
# output properties
#

$outputProperties

PACKAGE_BODY

  return $packageBody;

}

sub getApiGettersSetters {
  my $self = shift;
  my %args = @_;

  my $pCodeGenClass = $args{'pCodeGenClass'};
        # properties that exist for both Request and Response
  my $rhSameNames   = $args{'rhSameNames'} || {};  
  my $sRequestOrResponse = $args{'sRequestOrResponse'};
  my $createSetters = $args{'createSetters'};
  my $createGetters = $args{'createGetters'};

  #print "createGetters=|$createGetters|, createSetters=|$createSetters|\n";

  my $raElements   = $pCodeGenClass->getElements();
  my $raAttributes = $pCodeGenClass->getAttributes();

  my $str = '';
  my $sReGetterName = 'get' . $sRequestOrResponse . 'DataType';
  my $sReSetterName = 'set' . $sRequestOrResponse . 'DataType';
  foreach my $pElem ( @$raElements ) {

    my $name    = $pElem->getName();
    my $typeNS  = $pElem->getTypeNS();
    my $isArray = $pElem->isArray();
    my $pAnnotation = $pElem->getAnnotation();

    my $pElemGenClass = $self->getDataTypeByDataTypeWithNS($typeNS);

    my $setterVarName = "s$name";
    if ( defined $pElemGenClass ) {

       if ( ! $pElemGenClass->isScalar() ) {	    
            $setterVarName = "p$name";
       }
    }

    my $sWrapperPropertyName = $name;
    if ( exists $rhSameNames->{$name}) {
        $sWrapperPropertyName = "$sRequestOrResponse$name";
    }
    my $sGetterName = $self->getGetterName( $sWrapperPropertyName, $typeNS );
    my $sSetterName = $self->getSetterName( $sWrapperPropertyName );

    my $sInnerGetterName = $self->getGetterName( $name, $typeNS );
    my $sInnerSetterName = $self->getSetterName( $name );

    if ( $createGetters == 1)  {

       my $strComment = $self->getSetterGetterComment(
                                    'propertyType'   => $typeNS
                                   ,'isArray'        => $isArray
				                   ,'pAnnotation'    => $pAnnotation
                                   ,'methodName'     => $sGetterName
                                   ,'setterOrGetter' => 'getter'
                                                   );	  
       $str .=<<"GETTERS";
$strComment       
sub $sGetterName {
   my \$self = shift;
   return \$self->$sReGetterName()->$sInnerGetterName();
}
GETTERS
    }

    if ( $createSetters == 1)  {
	   
           # Do not generate annotation comments for a setter
           # if you have already generated them for a getter
       my $pSetterAnnotation = $pAnnotation;
       if ($createGetters == 1) {
            $pSetterAnnotation = undef;
       }
       my $strComment = $self->getSetterGetterComment(
                                    'propertyType'   => $typeNS
                                   ,'isArray'        => $isArray
				                   ,'pAnnotation'    => $pSetterAnnotation
                                   ,'methodName'     => $sSetterName
                                   ,'setterOrGetter' => 'setter'
                                                   );	  
       $str .=<<"SETTERS";
$strComment       
sub $sSetterName {
   my \$self   = shift;
   my \$$setterVarName = shift;
   \$self->$sReGetterName()->$sInnerSetterName(\$$setterVarName);
}
SETTERS
    }
    $str .= "\n";
  }

  return $str;
}

=head2 _getGetterComment()

This method is used from within 'getSetterGetterComment' method

NOTE: This method overrides the same method in BaseCodeGenDataType.pm
Why? The super method does not display annotation documentation for
getters. For API call properties we display annotation documentation 
even for getters.

=cut

sub _getGetterComment {
  my $self = shift;
  my %args = @_;

  my $propertyType   = $args{'propertyType'};
  my $isArray        = $args{'isArray'};
  my $pAnnotation    = $args{'pAnnotation'};

     # 1. annotation documentation
     #
  my $annDoc = $self->_formatDocumentation( $pAnnotation );
    
     # 2.  annotation callInfo documentation (input arguments)
     #
  my $strCallInfoOutputProps   = $self->_getGetterCallsInfo( $pAnnotation );

     # 3. type description
     #
  my $typeComment = $self->_getTypeComment(
                               'isArray' => $isArray
                              ,'propertyType'  => $propertyType
                              ,'sDescriptionKey' => 'Returns'
	                                  );

  my $strComment = $annDoc;
  
  $strComment .= $strCallInfoOutputProps;	  
  $strComment .= $typeComment;

  return $strComment;
}

=head2  getPropertyToCallInfo()

CallInfo is a package defined in Annotation.pm file.
The packageName is: Annotation::CallInfo

NOTE: This method overrides the same method in BaseCodeGenDataType.pm
It overrides it because for Api calls we do not display 
name of calls for which the property is used (since THIS generates
a property for currently generated API call. 

=cut

sub getPropertyToCallInfo {

   my $self = shift;
   my $raCallInfo = shift;

   my $str = '';
   if ( defined $raCallInfo ) {
	   
      foreach my $pCallInfo (@$raCallInfo ) {	   

        $str .= $self->getPropertyToCallInfo_Attributes( $pCallInfo );
        $str .= $self->getPropertyToCallInfo_Context( $pCallInfo );
      }
   }

   return $str;
}

1;
