# SPL_CGT_INCLUDE: ../../opt/.splpy/common/py_pyTupleTosplTuple.cgt
# SPL_CGT_INCLUDE: ../../opt/.splpy/common/py_functionReturnToTuples.cgt
# SPL_CGT_INCLUDE: ../../opt/.splpy/common/py_constructor.cgt
# SPL_CGT_INCLUDE: ../../opt/.splpy/common/py_splTupleToFunctionArgs.cgt
# SPL_CGT_INCLUDE: ../../opt/.splpy/common/py_splTupleCheckForBlobs.cgt
# SPL_CGT_INCLUDE: ../../opt/.splpy/common/py_valueToTuples.cgt

package Noop_cpp;
use strict; use Cwd 'realpath';  use File::Basename;  use lib dirname(__FILE__);  use SPL::Operator::Instance::OperatorInstance; use SPL::Operator::Instance::Annotation; use SPL::Operator::Instance::Context; use SPL::Operator::Instance::Expression; use SPL::Operator::Instance::ExpressionTree; use SPL::Operator::Instance::ExpressionTreeEvaluator; use SPL::Operator::Instance::ExpressionTreeVisitor; use SPL::Operator::Instance::ExpressionTreeCppGenVisitor; use SPL::Operator::Instance::InputAttribute; use SPL::Operator::Instance::InputPort; use SPL::Operator::Instance::OutputAttribute; use SPL::Operator::Instance::OutputPort; use SPL::Operator::Instance::Parameter; use SPL::Operator::Instance::StateVariable; use SPL::Operator::Instance::TupleValue; use SPL::Operator::Instance::Window; 
sub main::generate($$) {
   my ($xml, $signature) = @_;  
   print "// $$signature\n";
   my $model = SPL::Operator::Instance::OperatorInstance->new($$xml);
   unshift @INC, dirname ($model->getContext()->getOperatorDirectory()) . "/../impl/nl/include";
   $SPL::CodeGenHelper::verboseMode = $model->getContext()->isVerboseModeOn();
   print '/*', "\n";
   print ' * # Licensed Materials - Property of IBM', "\n";
   print ' * # Copyright IBM Corp. 2015,2016', "\n";
   print ' */', "\n";
   print "\n";
   SPL::CodeGen::implementationPrologue($model);
   print "\n";
   print "\n";
    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;
   print "\n";
   print "\n";
   print '#if SPLPY_OP_STATE_HANDLER == 1', "\n";
   print '#include "splpy_sh.h"', "\n";
   print '#endif', "\n";
   print "\n";
   print 'MY_OPERATOR_SCOPE::MY_OPERATOR::MY_OPERATOR() :', "\n";
   print '   pyop_(NULL),', "\n";
   print '   pyInNames_(NULL),', "\n";
   print '   pyOutNames_0(NULL)', "\n";
   print '{', "\n";
   print '   PyObject * callable;', "\n";
   print '    // Common code for the constructor of SPL Python primitive operators', "\n";
   print '    // that are created from Python functions/callables', "\n";
   print '    // Loads the Python runtime and initializes the function and module variables.', "\n";
       # Initialize splpy.pm
       splpyInit($model);
   print "\n";
   print '    pyop_ = new SplpyPyOp(this);', "\n";
   print '    ', "\n";
   print '    {', "\n";
   print '    SplpyGIL lock;', "\n";
   print "\n";
   print '    // Set the function the operator will call as a member field', "\n";
   print '    callable =', "\n";
   print '      SplpyGeneral::loadFunction("';
   print $module;
   print '", "';
   print $functionName;
   print '");   ', "\n";
   print '     ', "\n";
       if (splpy_OperatorCallable() eq 'class') {
   print "\n";
   print '   { ', "\n";
   print '     // Pass all the arguments by name in a dictionary', "\n";
   print '     // object, effectively as **kwargs. Python will', "\n";
   print '     // unpack correctly to the actual __init__ args', "\n";
   print '     PyObject *empty_tuple = PyTuple_New(0);', "\n";
   print '     PyObject *param_dict = PyDict_New();', "\n";
        for (my $i = 0; $i < $model->getNumberOfParameters(); ++$i) {
            my $tp = $model->getParameterAt($i);
   
            print '{';
            print 'PyObject * param_key = PyUnicode_DecodeUTF8((const char*)  "' . $tp->getName() . '", ((int)(sizeof("' . $tp->getName() . '")))-1 , NULL);';
   
            # cardinality == 1
            print 'PyObject * param_value = ' .
                 convertToPythonValueFromExpr(
                    $tp->getValueAt(0)->getSPLType(),
                    $tp->getValueAt(0)->getCppExpression()) . ";\n";
   
            print " PyDict_SetItem(param_dict, param_key, param_value);\n";
            print " Py_DECREF(param_key);\n";
            print " Py_DECREF(param_value);\n";
            print "}\n";
        }
   print "\n";
   print "\n";
   print '     // At this point callable is the callable class object', "\n";
   print '     // we call it to create an instance of the class', "\n";
   print '     // (which itself is callable)', "\n";
   print "\n";
   print '     // Make the operator pointer (opc) available to', "\n";
   print '     // the __init__ method.', "\n";
   print '     SplpyGeneral::callVoidFunction(', "\n";
   print '         "streamsx.ec", "_set_tl_opc", this->pyop_->opc(), NULL);', "\n";
   print "\n";
   print '     PyObject *tmp_instance = SplpyGeneral::pyObject_Call(callable, empty_tuple, param_dict);', "\n";
   print '     Py_DECREF(callable);', "\n";
   print '     if (tmp_instance == NULL) {', "\n";
   print '         SPLAPPTRC(L_ERROR, "Fatal error: cannot create instance of class " << "';
   print $functionName;
   print '" << " in module " << "';
   print $module;
   print '", "python");', "\n";
   print '        SplpyGeneral::callVoidFunction(', "\n";
   print '            "streamsx.ec", "_clear_tl_opc", NULL, NULL);', "\n";
   print '         throw SplpyGeneral::pythonException("';
   print $module;
   print '");', "\n";
   print '     }', "\n";
   print '     SplpyGeneral::callVoidFunction(', "\n";
   print '         "streamsx.ec", "_clear_tl_opc", NULL, NULL);', "\n";
   print '   ', "\n";
   print '     callable = tmp_instance;', "\n";
   print '   }', "\n";
       }
   print "\n";
    if (not $skip_set_callable) { 
   print "\n";
   print '     this->pyop_->setCallable(callable);', "\n";
   print '     this->pyop_->setup(SPLPY_CALLABLE_STATE_HANDLER);', "\n";
    } 
   print "\n";
   print "\n";
   print '    }', "\n";
   print '   ', "\n";
   print '   {', "\n";
   print '      SplpyGIL lock;', "\n";
   print '      pyOutNames_0 = Splpy::pyAttributeNames(getOutputPortAt(0));', "\n";
   print "\n";
    if ($paramStyle eq 'dictionary') { 
   print "\n";
   print '      pyInNames_ = Splpy::pyAttributeNames(', "\n";
   print '               getInputPortAt(0));', "\n";
    } 
   print "\n";
   print '   }', "\n";
   print "\n";
   print '#if SPLPY_OP_STATE_HANDLER == 1', "\n";
   print '   this->getContext().registerStateHandler(*this);', "\n";
   print '#endif', "\n";
   print '}', "\n";
   print "\n";
   print 'MY_OPERATOR_SCOPE::MY_OPERATOR::~MY_OPERATOR() ', "\n";
   print '{', "\n";
   print '   {', "\n";
   print '   SplpyGIL lock;', "\n";
   print '   Py_CLEAR(pyInNames_);', "\n";
   print '   Py_CLEAR(pyOutNames_0);', "\n";
   print '   }', "\n";
   print "\n";
   print '   delete pyop_;', "\n";
   print '}', "\n";
   print "\n";
   print 'void MY_OPERATOR_SCOPE::MY_OPERATOR::prepareToShutdown() ', "\n";
   print '{', "\n";
   print '    pyop_->prepareToShutdown();', "\n";
   print '}', "\n";
   print "\n";
     my $call_error_action = "";
   print "\n";
   print "\n";
   print 'void MY_OPERATOR_SCOPE::MY_OPERATOR::process(Tuple const & tuple, uint32_t port)', "\n";
   print '{', "\n";
   # Perl Variables that need to be set:
   #
   # $iport - input port 
   #
   # $inputAttrs2Py - number of attributes to pass as tuple style
   #
   
      #Check if a blob exists in the input schema
      for (my $i = 0; $i < $inputAttrs2Py; ++$i) {
         if (typeHasBlobs($iport->getAttributeAt($i)->getSPLType())) {
   print "\n";
   print '   PYSPL_MEMORY_VIEW_CLEANUP();', "\n";
            last;
         }
      }
   print "\n";
   print "\n";
   print '#if SPLPY_OP_STATE_HANDLER == 1', "\n";
   print ' SPL::AutoMutex am(mutex_);', "\n";
   print '#elif SPLPY_CALLABLE_STATEFUL == 1', "\n";
   print ' SPL::AutoPortMutex am(mutex_, *this);', "\n";
   print '#endif', "\n";
   print ' try {', "\n";
   print ' // GIL is released across submission', "\n";
   print ' SplpyGIL lock;', "\n";
   print "\n";
   {
   # Takes the input SPL tuple and converts it to
   # the arguments needed to be passed to a Python
   # function/callable decorated as a SPL operator.
   
   # Variables that need to be set:
   
   # $paramStyle - tuple or dictionary
   # $iport - input port 
   # $inputAttrs2Py - number of attributes to pass as tuple style
   
   my $ipt = $iport->getCppTupleType();
   my $ipv = $iport->getCppTupleName();
   
   print "\n";
   print "\n";
   print '   ';
   print $ipt;
   print ' const & ';
   print $ipv;
   print ' = static_cast< ';
   print $ipt;
   print ' const &>(tuple);', "\n";
   print "\n";
       if ($paramStyle eq 'tuple') {
   print "\n";
   print '// START-Processing passing SPL tuple as a Python tuple', "\n";
   print '// Declares: PyObject * pyTuple ', "\n";
   print '// Declares: PyObject * pyDict as NULL', "\n";
   print "\n";
   print '    PyObject *pyDict = NULL; ', "\n";
   print '    PyObject * pyTuple = PyTuple_New(';
   print $inputAttrs2Py;
   print ');', "\n";
   print '    PyObject *pyValue;', "\n";
        for (my $i = 0; $i < $inputAttrs2Py; ++$i) {
            my $la = $iport->getAttributeAt($i);
            print convertToPythonValueAsTuple($ipv, $i, $la->getSPLType(), $la->getName());
        }
   print "\n";
   print '// END-Processing passing SPL tuple as a Python tuple', "\n";
       }
   print "\n";
   print "\n";
       if ($paramStyle eq 'dictionary') {
   print "\n";
   print '// START-Processing passing SPL tuple as a Python dictionary', "\n";
   print '// All attributes are passed in the dictionary', "\n";
   print '// Declares: PyObject * pyTuple as empty tuple', "\n";
   print '// Declares: PyObject * pyDict', "\n";
   print "\n";
   print '    PyObject * pyTuple = PyTuple_New(0);', "\n";
   print '    PyObject * pyDict = PyDict_New();', "\n";
        my $ppn = '';
        if ($iport->getIndex() >= 1) {
            $ppn = $iport->getIndex();
        }
   
        for (my $i = 0; $i < $iport->getNumberOfAttributes(); ++$i) {
            my $la = $iport->getAttributeAt($i);
            print convertAndAddToPythonDictionaryObject($ipv, $i, $la->getSPLType(), $la->getName(), 'pyInNames_' . $ppn);
        }
   print "\n";
   print '// END-Processing passing SPL tuple as a Python dictionary', "\n";
       }
   }
   print "\n";
   print "\n";
   print "\n";
   print '   // Calls the Python function and', "\n";
   print '   // converts the returned value into', "\n";
   print '   // SPL Tuples and submits them.', "\n";
   print '   // Returns if the Python function returns None.', "\n";
   {
     my $ituplearg = "";
     if (defined $iport) {
        $ituplearg = ", " . $iport->getCppTupleName();
     }
   print "\n";
   print "\n";
   print '    PyObject * pyReturnVar = SplpyGeneral::pyObject_Call(pyop_->callable(), pyTuple, pyDict);', "\n";
   print "\n";
   print '    if (pyReturnVar == NULL) {', "\n";
   print '        ';
   print $call_error_action;
   print "\n";
   print '        throw SplpyExceptionInfo::pythonError("';
   print $functionName;
   print '");', "\n";
   print '    }', "\n";
   print '    else if (SplpyGeneral::isNone(pyReturnVar)) {', "\n";
   print '         Py_DECREF(pyReturnVar);', "\n";
   print '    } else {', "\n";
   print "\n";
   print '         pySubmitTuplesPort';
   print $oport->getIndex();
   print '(pyReturnVar ';
   print $ituplearg;
   print ');', "\n";
   print "\n";
   print '         Py_DECREF(pyReturnVar);', "\n";
   print '    }', "\n";
   }
   print "\n";
   print ' } catch (const streamsx::topology::SplpyExceptionInfo& excInfo) {', "\n";
   print '    SPLPY_OP_HANDLE_EXCEPTION_INFO_GIL(excInfo);', "\n";
   print ' }', "\n";
   print '}', "\n";
   print "\n";
   print '// Create member function that converts Python tuple to SPL tuple', "\n";
   #
   # Creates a function pySubmitTuplesN that takes a Python value
   # and submits tuples to the output port. The value
   # must be a Python tuple or a list[tuple].
   # Calls the generated function fromPythonToPort0
   #
   # $oport - output port to submit to
   # $iport - optional - input port to copy attributes from.
   #
   {
     my $itypeparam = "";
     my $ituplearg = "";
     if (defined $iport) {
        $itypeparam = ", " . $iport->getCppTupleType() . " const & ituple";
        $ituplearg = ", ituple";
     }
   print "\n";
   print "\n";
   print 'void MY_OPERATOR_SCOPE::MY_OPERATOR::pySubmitTuplesPort';
   print $oport->getIndex();
   print '(PyObject *value ';
   print $itypeparam;
   print ') {', "\n";
   print "\n";
   print "\n";
   print '  if (PyTuple_Check(value))', "\n";
   print '  {', "\n";
   print '    ';
   print $oport->getCppTupleType();
   print ' otuple;', "\n";
   print '    fromPythonToPort';
   print $oport->getIndex();
   print '(value, otuple ';
   print $ituplearg;
   print ');', "\n";
   print '  }', "\n";
   print '  else if (PyDict_Check(value)) {', "\n";
   print '    ';
   print $oport->getCppTupleType();
   print ' otuple;', "\n";
   print '    fromPythonDictToPort';
   print $oport->getIndex();
   print '(value, otuple ';
   print $ituplearg;
   print ');', "\n";
   print '  }', "\n";
   print '  else if (PyList_Check(value))', "\n";
   print '  {', "\n";
   print "\n";
   print '     /* Logic for if a list of tuples is returned */', "\n";
   print '     Py_ssize_t tc = PyList_GET_SIZE(value);', "\n";
   print '     for (Py_ssize_t k = 0; k < tc; k++) {    ', "\n";
   print '       PyObject *ltuple = PyList_GET_ITEM(value, k);', "\n";
   print '       if (SplpyGeneral::isNone(ltuple))', "\n";
   print '           continue;', "\n";
   print '       ';
   print $oport->getCppTupleType();
   print ' otuple;', "\n";
   print '       if (PyTuple_Check(ltuple)) {    ', "\n";
   print '           fromPythonToPort';
   print $oport->getIndex();
   print '(ltuple, otuple ';
   print $ituplearg;
   print ');', "\n";
   print '       } else if (PyDict_Check(ltuple)) {', "\n";
   print '           fromPythonDictToPort';
   print $oport->getIndex();
   print '(ltuple, otuple ';
   print $ituplearg;
   print ');', "\n";
   print '       } else {', "\n";
   print '          throw SplpyGeneral::generalException("submit",', "\n";
   print '             "Fatal error: Value submitted must be a Python tuple, dict or list of tuples or dicts: Port ';
   print $oport->getIndex();
   print '");', "\n";
   print '       }', "\n";
   print '     ', "\n";
   print '     }', "\n";
   print '  }', "\n";
   print '  else {', "\n";
   print '     throw SplpyGeneral::generalException("submit",', "\n";
   print '        "Fatal error: Value submitted must be a Python tuple, dict or a Python list of tuples or dicts: Port ';
   print $oport->getIndex();
   print '");', "\n";
   print '  }', "\n";
   print '}', "\n";
   }
   print "\n";
   # Generates functions in an operator that converts a Python
   # tuple to an SPL tuple for a given port and optional to
   # submit the tuple.
   #
   # $oport must be set on entry to required output port
   # $oport_submission must be set on entry to generate submission methods.
   # $iport can be set to automatically copy input attributes to
   # output attributes when the Python tuple does not supply a value.
   
     my $itypeparam = "";
     my $itypearg = "";
     if (defined $iport) {
        $itypeparam = ", " . $iport->getCppTupleType() . " const & ituple";
        $itypearg = ", ituple";
     }
   print "\n";
   print "\n";
    if ($oport_submission) { 
   print "\n";
   print ' ', "\n";
   print '// Python tuple to SPL tuple with submission to a port', "\n";
   print 'void MY_OPERATOR_SCOPE::MY_OPERATOR::fromPythonToPort';
   print $oport->getIndex();
   print '(PyObject *pyTuple, ';
   print $oport->getCppTupleType();
   print ' & otuple ';
   print $itypeparam;
   print ') {', "\n";
   print "\n";
   print '  try {', "\n";
   print '    MY_OPERATOR_SCOPE::MY_OPERATOR::fromPyTupleToSPLTuple(pyTuple, otuple ';
   print $itypearg;
   print ');', "\n";
   print '  } catch (const streamsx::topology::SplpyExceptionInfo& excInfo) {', "\n";
   print '    SPLPY_OP_HANDLE_EXCEPTION_INFO(excInfo);', "\n";
   print '    return;', "\n";
   print '  }', "\n";
   print "\n";
   print '  STREAMSX_TUPLE_SUBMIT_ALLOW_THREADS(otuple, ';
   print $oport->getIndex();
   print ');', "\n";
   print '}', "\n";
   print "\n";
   print '// Python dict to SPL tuple with submission to a port.', "\n";
   print 'void MY_OPERATOR_SCOPE::MY_OPERATOR::fromPythonDictToPort';
   print $oport->getIndex();
   print '(PyObject *pyDict, ';
   print $oport->getCppTupleType();
   print ' & otuple ';
   print $itypeparam;
   print ') {', "\n";
   print "\n";
   print '  try {', "\n";
   print '    MY_OPERATOR_SCOPE::MY_OPERATOR::fromPyDictToSPLTuple(pyDict, otuple ';
   print $itypearg;
   print ');', "\n";
   print '  } catch (const streamsx::topology::SplpyExceptionInfo& excInfo) {', "\n";
   print '    SPLPY_OP_HANDLE_EXCEPTION_INFO(excInfo);', "\n";
   print '    return;', "\n";
   print '  }', "\n";
   print "\n";
   print '  STREAMSX_TUPLE_SUBMIT_ALLOW_THREADS(otuple, ';
   print $oport->getIndex();
   print ');', "\n";
   print '}', "\n";
   print "\n";
   }
   print "\n";
   print "\n";
   # Ensure we generate function only once for each tuple type
   my $otype = $oport->getCppTupleType();
   if (! exists $cpp_tuple_types{$otype}) {
       $cpp_tuple_types{$otype} = 1;
   print "\n";
   print "\n";
   print '// Python tuple to SPL tuple , conversion only', "\n";
   print 'void MY_OPERATOR_SCOPE::MY_OPERATOR::fromPyTupleToSPLTuple(PyObject *pyTuple, ';
   print $oport->getCppTupleType();
   print ' & otuple  ';
   print $itypeparam;
   print ') {', "\n";
   print "\n";
   print '  Py_ssize_t frs = PyTuple_GET_SIZE(pyTuple); ', "\n";
   print '    ', "\n";
     if (defined $iport) {
       print 'bool setAttr = false;';
     }
   
     for (my $ai = 0; $ai < $oport->getNumberOfAttributes(); ++$ai) {
       
       my $attribute = $oport->getAttributeAt($ai);
       my $name = $attribute->getName();
       my $atype = $attribute->getSPLType();
       splToPythonConversionCheck($atype);
       
       if (defined $iport) {
                print 'setAttr = false;';
       }
   print "\n";
   print '    if (';
   print $ai;
   print ' < frs) {', "\n";
   print '         // Value from the Python function', "\n";
   print '         PyObject *pyAttrValue = PyTuple_GET_ITEM(pyTuple, ';
   print $ai;
   print ');', "\n";
   print '         if (!SplpyGeneral::isNone(pyAttrValue)) {', "\n";
   print '                  streamsx::topology::pySplValueFromPyObject(', "\n";
   print '                               otuple.get_';
   print $name;
   print '(), pyAttrValue);', "\n";
       if (defined $iport) {
                print 'setAttr = true;';
       }
   print "\n";
   print '      }', "\n";
   print '   }', "\n";
       if (defined $iport) {
       
       # Only copy attributes across if they match on name and type,
       # or on name and input type T and output type optional<T>
       my $matchInputAttr = $iport->getAttributeByName($name);
       if (defined $matchInputAttr) {
           my $inputType = $matchInputAttr->getSPLType();
           if (($inputType eq $atype) ||
               (hasOptionalTypesSupport() &&
                SPL::CodeGen::Type::isOptional($atype) &&
                ($inputType eq
                 SPL::CodeGen::Type::getUnderlyingType($atype)))) {
   print "\n";
   print '    if (!setAttr) {', "\n";
   print '      // value from the input attribute', "\n";
   print '      otuple.set_';
   print $name;
   print '(ituple.get_';
   print $name;
   print '());', "\n";
   print '    }', "\n";
         }
       }
      }
   print "\n";
   print '         ', "\n";
   }
    
   print "\n";
   print "\n";
   print '}', "\n";
   print "\n";
   print "\n";
   print '// Python dict to SPL tuple , conversion only', "\n";
   print 'void MY_OPERATOR_SCOPE::MY_OPERATOR::fromPyDictToSPLTuple(PyObject *pyDict, ';
   print $oport->getCppTupleType();
   print ' & otuple  ';
   print $itypeparam;
   print ') {', "\n";
   print "\n";
   print '  Py_ssize_t available = PyDict_Size(pyDict); ', "\n";
   print '    ', "\n";
     if (defined $iport) {
       print 'bool setAttr = false;';
     }
   
     for (my $ai = $oport->getNumberOfAttributes() - 1; $ai >= 0; --$ai) {
       
       my $attribute = $oport->getAttributeAt($ai);
       my $name = $attribute->getName();
       my $atype = $attribute->getSPLType();
       splToPythonConversionCheck($atype);
       
       if (defined $iport) {
                print 'setAttr = false;';
       }
   print "\n";
   print '    if (available > 0) {', "\n";
   print '         // Value from the Python function', "\n";
   print '         PyObject *pyAttrValue = PyDict_GetItem(pyDict, PyTuple_GET_ITEM(pyOutNames_';
   print $oport->getIndex();
   print ', ';
   print $ai;
   print '));', "\n";
   print '         if (pyAttrValue != NULL) {', "\n";
   print '             --available;', "\n";
   print '             if (!SplpyGeneral::isNone(pyAttrValue)) {', "\n";
   print '                  streamsx::topology::pySplValueFromPyObject(', "\n";
   print '                               otuple.get_';
   print $name;
   print '(), pyAttrValue);', "\n";
       if (defined $iport) {
                print 'setAttr = true;';
       }
   print "\n";
   print '           }', "\n";
   print '        }', "\n";
   print '   }', "\n";
       if (defined $iport) {
       
       # Only copy attributes across if they match on name and type
       my $matchInputAttr = $iport->getAttributeByName($name);
       if (defined $matchInputAttr) {
          if ($matchInputAttr->getSPLType() eq $attribute->getSPLType()) {
   print "\n";
   print '    if (!setAttr) {', "\n";
   print '      // value from the input attribute', "\n";
   print '      otuple.set_';
   print $name;
   print '(ituple.get_';
   print $name;
   print '());', "\n";
   print '    }', "\n";
         }
       }
      }
   print "\n";
   print '         ', "\n";
   }
    
   print "\n";
   print '}', "\n";
    } 
   print "\n";
   print "\n";
   print 'void MY_OPERATOR_SCOPE::MY_OPERATOR::process(Punctuation const & punct, uint32_t port)', "\n";
   print '{', "\n";
   print '    forwardWindowPunctuation(punct);', "\n";
   print '}', "\n";
   print "\n";
   SPL::CodeGen::implementationEpilogue($model);
   print "\n";
   CORE::exit $SPL::CodeGen::USER_ERROR if ($SPL::CodeGen::sawError);
}
1;
