/*
 * # Licensed Materials - Property of IBM
 * # Copyright IBM Corp. 2015,2016
 */

<%SPL::CodeGen::implementationPrologue($model);%>

<%
 my $cmnDir = $model->getContext()->getToolkitDirectory()."/opt/.splpy/common/";

 require "splpy_operator.pm";
 require $cmnDir."/splpy.pm";

 my $module = splpy_Module();
 my $functionName = splpy_FunctionName();
 my $paramStyle = splpy_ParamStyle();
 my $fixedParam = splpy_FixedParam();
 my @packages = splpy_Packages();
 spl_pip_packages(splpy_PyMajor(), $model, \@packages);
 
 my $iport = $model->getInputPortAt(0);

 my $inputAttrs2Py = $iport->getNumberOfAttributes();
 if ($fixedParam != -1) {
    $inputAttrs2Py = $fixedParam;
 }

 if ($fixedParam > $iport->getNumberOfAttributes()) {
   SPL::CodeGen::exitln('%s requires at least %i attributes in input port but schema is %s',
           $model->getContext()->getKind(), $fixedParam, $iport->getSPLTupleType());
 }
 
  my $oport = $model->getOutputPortAt(0);
  my $oport_submission = 1;
  my $otupleType = $oport->getSPLTupleType();
  my @onames = SPL::CodeGen::Type::getAttributeNames($otupleType);
  my @otypes = SPL::CodeGen::Type::getAttributeTypes($otupleType);
  my %cpp_tuple_types;
 
  my $skip_set_callable = 0;
%>

#if SPLPY_OP_STATE_HANDLER == 1
#include "splpy_sh.h"
#endif

MY_OPERATOR::MY_OPERATOR() :
   pyop_(NULL),
   pyInNames_(NULL),
   pyOutNames_0(NULL)
{
   PyObject * callable;
@include  "../../opt/.splpy/common/py_constructor.cgt"
   
   {
      SplpyGIL lock;
      pyOutNames_0 = Splpy::pyAttributeNames(getOutputPortAt(0));

<% if ($paramStyle eq 'dictionary') { %>
      pyInNames_ = Splpy::pyAttributeNames(
               getInputPortAt(0));
<% } %>
   }

#if SPLPY_OP_STATE_HANDLER == 1
   this->getContext().registerStateHandler(*this);
#endif
}

MY_OPERATOR::~MY_OPERATOR() 
{
   {
   SplpyGIL lock;
   Py_CLEAR(pyInNames_);
   Py_CLEAR(pyOutNames_0);
   }

   delete pyop_;
}

void MY_OPERATOR::prepareToShutdown() 
{
    pyop_->prepareToShutdown();
}

<%
  my $call_error_action = "";
%>

void MY_OPERATOR::process(Tuple const & tuple, uint32_t port)
{
 @include  "../../opt/.splpy/common/py_splTupleCheckForBlobs.cgt"

#if SPLPY_OP_STATE_HANDLER == 1
 SPL::AutoMutex am(mutex_);
#elif SPLPY_CALLABLE_STATEFUL == 1
 SPL::AutoPortMutex am(mutex_, *this);
#endif
 try {
 // GIL is released across submission
 SplpyGIL lock;

 @include  "../../opt/.splpy/common/py_splTupleToFunctionArgs.cgt"

 @include  "../../opt/.splpy/common/py_functionReturnToTuples.cgt"
 } catch (const streamsx::topology::SplpyExceptionInfo& excInfo) {
    SPLPY_OP_HANDLE_EXCEPTION_INFO_GIL(excInfo);
 }
}

// Create member function that converts Python tuple to SPL tuple
@include  "../../opt/.splpy/common/py_valueToTuples.cgt"
@include  "../../opt/.splpy/common/py_pyTupleTosplTuple.cgt"

void MY_OPERATOR::process(Punctuation const & punct, uint32_t port)
{
    forwardWindowPunctuation(punct);
}

<%SPL::CodeGen::implementationEpilogue($model);%>
