// Author: Wim Lavrijsen, Aug 2007

// Bindings
#include "PyROOT.h"
#include "TPyDispatcher.h"
#include "RootWrapper.h"

// ROOT
#include "TClass.h"
#include "TObject.h"

// Standard
#include <stdarg.h>


//______________________________________________________________________________
//                         Python callback dispatcher
//                         ==========================
//
// The TPyDispatcher class acts as a functor that can be used for TFn's and GUIs
// to install callbacks from CINT.


//- data ---------------------------------------------------------------------
ClassImp(TPyDispatcher)


//- constructors/destructor --------------------------------------------------
TPyDispatcher::TPyDispatcher( PyObject* callable ) : fCallable( 0 )
{
// Construct a TPyDispatcher from a callable python object. Applies python
// object reference counting.
   Py_XINCREF( callable );
   fCallable = callable;
}

//____________________________________________________________________________
TPyDispatcher::TPyDispatcher( const TPyDispatcher& other ) : TObject ( other )
{
// Copy constructor. Applies python object reference counting.
   Py_XINCREF( other.fCallable );
   fCallable = other.fCallable;
}

//____________________________________________________________________________
TPyDispatcher& TPyDispatcher::operator=( const TPyDispatcher& other )
{
// Assignment operator. Applies python object reference counting.
   if ( this != &other ) {
      this->TObject::operator=( other );

      Py_XDECREF( fCallable );
      Py_XINCREF( other.fCallable );
      fCallable = other.fCallable;
   }

   return *this;
}

//____________________________________________________________________________
TPyDispatcher::~TPyDispatcher() {
// Destructor. Reference counting for the held python object is in effect.
   Py_XDECREF( fCallable );
}


//- public members -----------------------------------------------------------
PyObject* TPyDispatcher::DispatchVA( const char* format, ... )
{
// Dispatch the arguments to the held callable python object, using format to
// interpret the types of the arguments. Note that format is in python style,
// not in C printf style. See: https://docs.python.org/2/c-api/arg.html .
   PyObject* args = 0;

   if ( format ) {
      va_list va;
      va_start( va, format );

      args = Py_VaBuildValue( (char*)format, va );

      va_end( va );

      if ( ! args ) {
         PyErr_Print();
         return 0;
      }

      if ( ! PyTuple_Check( args ) ) {    // if only one arg ...
         PyObject* t = PyTuple_New( 1 );
         PyTuple_SET_ITEM( t, 0, args );
         args = t;
      }

   }

   PyObject* result = PyObject_CallObject( fCallable, args );
   Py_XDECREF( args );

   if ( ! result ) {
      PyErr_Print();
      return 0;
   }

   return result;
}

//____________________________________________________________________________
PyObject* TPyDispatcher::DispatchVA1( const char* clname, void* obj, const char* format, ... )
{
   PyObject* pyobj = PyROOT::BindCppObject( obj, Cppyy::GetScope( clname ), kFALSE /* isRef */ );
   if ( ! pyobj ) {
      PyErr_Print();
      return 0;
   }

   PyObject* args = 0;

   if ( format ) {
      va_list va;
      va_start( va, format );

      args = Py_VaBuildValue( (char*)format, va );

      va_end( va );

      if ( ! args ) {
         PyErr_Print();
         return 0;
      }

      if ( ! PyTuple_Check( args ) ) {    // if only one arg ...
         PyObject* t = PyTuple_New( 2 );
         PyTuple_SET_ITEM( t, 0, pyobj );
         PyTuple_SET_ITEM( t, 1, args );
         args = t;
      } else {
         PyObject* t = PyTuple_New( PyTuple_GET_SIZE( args ) + 1 );
         PyTuple_SET_ITEM( t, 0, pyobj );
         for ( int i = 0; i < PyTuple_GET_SIZE( args ); i++ ) {
            PyObject* item = PyTuple_GET_ITEM( args, i );
            Py_INCREF( item );
            PyTuple_SET_ITEM( t, i+1, item );
         }
         Py_DECREF( args );
         args = t;
      }
   } else {
      args = PyTuple_New( 1 );
      PyTuple_SET_ITEM( args, 0, pyobj );
   }

   PyObject* result = PyObject_CallObject( fCallable, args );
   Py_XDECREF( args );

   if ( ! result ) {
      PyErr_Print();
      return 0;
   }

   return result;
}

//____________________________________________________________________________
PyObject* TPyDispatcher::Dispatch( TPad* selpad, TObject* selected, Int_t event )
{
   PyObject* args = PyTuple_New( 3 );
   PyTuple_SET_ITEM( args, 0, PyROOT::BindCppObject( selpad, Cppyy::GetScope( "TPad" ) ) );
   PyTuple_SET_ITEM( args, 1, PyROOT::BindCppObject( selected, Cppyy::GetScope( "TObject" ) ) );
   PyTuple_SET_ITEM( args, 2, PyInt_FromLong( event ) );

   PyObject* result = PyObject_CallObject( fCallable, args );
   Py_XDECREF( args );

   if ( ! result ) {
      PyErr_Print();
      return 0;
   }

   return result;
}

//____________________________________________________________________________
PyObject* TPyDispatcher::Dispatch( Int_t event, Int_t x, Int_t y, TObject* selected )
{
   PyObject* args = PyTuple_New( 4 );
   PyTuple_SET_ITEM( args, 0, PyInt_FromLong( event ) );
   PyTuple_SET_ITEM( args, 1, PyInt_FromLong( x ) );
   PyTuple_SET_ITEM( args, 2, PyInt_FromLong( y ) );
   PyTuple_SET_ITEM( args, 3, PyROOT::BindCppObject( selected, Cppyy::GetScope( "TObject" ) ) );

   PyObject* result = PyObject_CallObject( fCallable, args );
   Py_XDECREF( args );

   if ( ! result ) {
      PyErr_Print();
      return 0;
   }

   return result;
}

//____________________________________________________________________________
PyObject* TPyDispatcher::Dispatch( TVirtualPad* pad, TObject* obj, Int_t event )
{
   PyObject* args = PyTuple_New( 3 );
   PyTuple_SET_ITEM( args, 0, PyROOT::BindCppObject( pad, Cppyy::GetScope( "TVirtualPad" ) ) );
   PyTuple_SET_ITEM( args, 1, PyROOT::BindCppObject( obj, Cppyy::GetScope( "TObject" ) ) );
   PyTuple_SET_ITEM( args, 2, PyInt_FromLong( event ) );

   PyObject* result = PyObject_CallObject( fCallable, args );
   Py_XDECREF( args );

   if ( ! result ) {
      PyErr_Print();
      return 0;
   }

   return result;
}

//____________________________________________________________________________
PyObject* TPyDispatcher::Dispatch( TGListTreeItem* item, TDNDData* data )
{
   PyObject* args = PyTuple_New( 2 );
   PyTuple_SET_ITEM( args, 0, PyROOT::BindCppObject( item, Cppyy::GetScope( "TGListTreeItem" ) ) );
   PyTuple_SET_ITEM( args, 1, PyROOT::BindCppObject( data, Cppyy::GetScope( "TDNDData" ) ) );

   PyObject* result = PyObject_CallObject( fCallable, args );
   Py_XDECREF( args );

   if ( ! result ) {
      PyErr_Print();
      return 0;
   }

   return result;
}

//____________________________________________________________________________
PyObject* TPyDispatcher::Dispatch( const char* name, const TList* attr )
{
   PyObject* args = PyTuple_New( 2 );
   PyTuple_SET_ITEM( args, 0, PyBytes_FromString( name ) );
   PyTuple_SET_ITEM( args, 1, PyROOT::BindCppObject( (void*)attr, Cppyy::GetScope( "TList" ) ) );

   PyObject* result = PyObject_CallObject( fCallable, args );
   Py_XDECREF( args );

   if ( ! result ) {
      PyErr_Print();
      return 0;
   }

   return result;
}

//____________________________________________________________________________
PyObject* TPyDispatcher::Dispatch( TSlave* slave, TProofProgressInfo* pi )
{
   PyObject* args = PyTuple_New( 2 );
   PyTuple_SET_ITEM( args, 0, PyROOT::BindCppObject( slave, Cppyy::GetScope( "TSlave" ) ) );
   PyTuple_SET_ITEM( args, 1, PyROOT::BindCppObject( pi, Cppyy::GetScope( "TProofProgressInfo" ) ) );

   PyObject* result = PyObject_CallObject( fCallable, args );
   Py_XDECREF( args );

   if ( ! result ) {
      PyErr_Print();
      return 0;
   }

   return result;
}
 TPyDispatcher.cxx:1
 TPyDispatcher.cxx:2
 TPyDispatcher.cxx:3
 TPyDispatcher.cxx:4
 TPyDispatcher.cxx:5
 TPyDispatcher.cxx:6
 TPyDispatcher.cxx:7
 TPyDispatcher.cxx:8
 TPyDispatcher.cxx:9
 TPyDispatcher.cxx:10
 TPyDispatcher.cxx:11
 TPyDispatcher.cxx:12
 TPyDispatcher.cxx:13
 TPyDispatcher.cxx:14
 TPyDispatcher.cxx:15
 TPyDispatcher.cxx:16
 TPyDispatcher.cxx:17
 TPyDispatcher.cxx:18
 TPyDispatcher.cxx:19
 TPyDispatcher.cxx:20
 TPyDispatcher.cxx:21
 TPyDispatcher.cxx:22
 TPyDispatcher.cxx:23
 TPyDispatcher.cxx:24
 TPyDispatcher.cxx:25
 TPyDispatcher.cxx:26
 TPyDispatcher.cxx:27
 TPyDispatcher.cxx:28
 TPyDispatcher.cxx:29
 TPyDispatcher.cxx:30
 TPyDispatcher.cxx:31
 TPyDispatcher.cxx:32
 TPyDispatcher.cxx:33
 TPyDispatcher.cxx:34
 TPyDispatcher.cxx:35
 TPyDispatcher.cxx:36
 TPyDispatcher.cxx:37
 TPyDispatcher.cxx:38
 TPyDispatcher.cxx:39
 TPyDispatcher.cxx:40
 TPyDispatcher.cxx:41
 TPyDispatcher.cxx:42
 TPyDispatcher.cxx:43
 TPyDispatcher.cxx:44
 TPyDispatcher.cxx:45
 TPyDispatcher.cxx:46
 TPyDispatcher.cxx:47
 TPyDispatcher.cxx:48
 TPyDispatcher.cxx:49
 TPyDispatcher.cxx:50
 TPyDispatcher.cxx:51
 TPyDispatcher.cxx:52
 TPyDispatcher.cxx:53
 TPyDispatcher.cxx:54
 TPyDispatcher.cxx:55
 TPyDispatcher.cxx:56
 TPyDispatcher.cxx:57
 TPyDispatcher.cxx:58
 TPyDispatcher.cxx:59
 TPyDispatcher.cxx:60
 TPyDispatcher.cxx:61
 TPyDispatcher.cxx:62
 TPyDispatcher.cxx:63
 TPyDispatcher.cxx:64
 TPyDispatcher.cxx:65
 TPyDispatcher.cxx:66
 TPyDispatcher.cxx:67
 TPyDispatcher.cxx:68
 TPyDispatcher.cxx:69
 TPyDispatcher.cxx:70
 TPyDispatcher.cxx:71
 TPyDispatcher.cxx:72
 TPyDispatcher.cxx:73
 TPyDispatcher.cxx:74
 TPyDispatcher.cxx:75
 TPyDispatcher.cxx:76
 TPyDispatcher.cxx:77
 TPyDispatcher.cxx:78
 TPyDispatcher.cxx:79
 TPyDispatcher.cxx:80
 TPyDispatcher.cxx:81
 TPyDispatcher.cxx:82
 TPyDispatcher.cxx:83
 TPyDispatcher.cxx:84
 TPyDispatcher.cxx:85
 TPyDispatcher.cxx:86
 TPyDispatcher.cxx:87
 TPyDispatcher.cxx:88
 TPyDispatcher.cxx:89
 TPyDispatcher.cxx:90
 TPyDispatcher.cxx:91
 TPyDispatcher.cxx:92
 TPyDispatcher.cxx:93
 TPyDispatcher.cxx:94
 TPyDispatcher.cxx:95
 TPyDispatcher.cxx:96
 TPyDispatcher.cxx:97
 TPyDispatcher.cxx:98
 TPyDispatcher.cxx:99
 TPyDispatcher.cxx:100
 TPyDispatcher.cxx:101
 TPyDispatcher.cxx:102
 TPyDispatcher.cxx:103
 TPyDispatcher.cxx:104
 TPyDispatcher.cxx:105
 TPyDispatcher.cxx:106
 TPyDispatcher.cxx:107
 TPyDispatcher.cxx:108
 TPyDispatcher.cxx:109
 TPyDispatcher.cxx:110
 TPyDispatcher.cxx:111
 TPyDispatcher.cxx:112
 TPyDispatcher.cxx:113
 TPyDispatcher.cxx:114
 TPyDispatcher.cxx:115
 TPyDispatcher.cxx:116
 TPyDispatcher.cxx:117
 TPyDispatcher.cxx:118
 TPyDispatcher.cxx:119
 TPyDispatcher.cxx:120
 TPyDispatcher.cxx:121
 TPyDispatcher.cxx:122
 TPyDispatcher.cxx:123
 TPyDispatcher.cxx:124
 TPyDispatcher.cxx:125
 TPyDispatcher.cxx:126
 TPyDispatcher.cxx:127
 TPyDispatcher.cxx:128
 TPyDispatcher.cxx:129
 TPyDispatcher.cxx:130
 TPyDispatcher.cxx:131
 TPyDispatcher.cxx:132
 TPyDispatcher.cxx:133
 TPyDispatcher.cxx:134
 TPyDispatcher.cxx:135
 TPyDispatcher.cxx:136
 TPyDispatcher.cxx:137
 TPyDispatcher.cxx:138
 TPyDispatcher.cxx:139
 TPyDispatcher.cxx:140
 TPyDispatcher.cxx:141
 TPyDispatcher.cxx:142
 TPyDispatcher.cxx:143
 TPyDispatcher.cxx:144
 TPyDispatcher.cxx:145
 TPyDispatcher.cxx:146
 TPyDispatcher.cxx:147
 TPyDispatcher.cxx:148
 TPyDispatcher.cxx:149
 TPyDispatcher.cxx:150
 TPyDispatcher.cxx:151
 TPyDispatcher.cxx:152
 TPyDispatcher.cxx:153
 TPyDispatcher.cxx:154
 TPyDispatcher.cxx:155
 TPyDispatcher.cxx:156
 TPyDispatcher.cxx:157
 TPyDispatcher.cxx:158
 TPyDispatcher.cxx:159
 TPyDispatcher.cxx:160
 TPyDispatcher.cxx:161
 TPyDispatcher.cxx:162
 TPyDispatcher.cxx:163
 TPyDispatcher.cxx:164
 TPyDispatcher.cxx:165
 TPyDispatcher.cxx:166
 TPyDispatcher.cxx:167
 TPyDispatcher.cxx:168
 TPyDispatcher.cxx:169
 TPyDispatcher.cxx:170
 TPyDispatcher.cxx:171
 TPyDispatcher.cxx:172
 TPyDispatcher.cxx:173
 TPyDispatcher.cxx:174
 TPyDispatcher.cxx:175
 TPyDispatcher.cxx:176
 TPyDispatcher.cxx:177
 TPyDispatcher.cxx:178
 TPyDispatcher.cxx:179
 TPyDispatcher.cxx:180
 TPyDispatcher.cxx:181
 TPyDispatcher.cxx:182
 TPyDispatcher.cxx:183
 TPyDispatcher.cxx:184
 TPyDispatcher.cxx:185
 TPyDispatcher.cxx:186
 TPyDispatcher.cxx:187
 TPyDispatcher.cxx:188
 TPyDispatcher.cxx:189
 TPyDispatcher.cxx:190
 TPyDispatcher.cxx:191
 TPyDispatcher.cxx:192
 TPyDispatcher.cxx:193
 TPyDispatcher.cxx:194
 TPyDispatcher.cxx:195
 TPyDispatcher.cxx:196
 TPyDispatcher.cxx:197
 TPyDispatcher.cxx:198
 TPyDispatcher.cxx:199
 TPyDispatcher.cxx:200
 TPyDispatcher.cxx:201
 TPyDispatcher.cxx:202
 TPyDispatcher.cxx:203
 TPyDispatcher.cxx:204
 TPyDispatcher.cxx:205
 TPyDispatcher.cxx:206
 TPyDispatcher.cxx:207
 TPyDispatcher.cxx:208
 TPyDispatcher.cxx:209
 TPyDispatcher.cxx:210
 TPyDispatcher.cxx:211
 TPyDispatcher.cxx:212
 TPyDispatcher.cxx:213
 TPyDispatcher.cxx:214
 TPyDispatcher.cxx:215
 TPyDispatcher.cxx:216
 TPyDispatcher.cxx:217
 TPyDispatcher.cxx:218
 TPyDispatcher.cxx:219
 TPyDispatcher.cxx:220
 TPyDispatcher.cxx:221
 TPyDispatcher.cxx:222
 TPyDispatcher.cxx:223
 TPyDispatcher.cxx:224
 TPyDispatcher.cxx:225
 TPyDispatcher.cxx:226
 TPyDispatcher.cxx:227
 TPyDispatcher.cxx:228
 TPyDispatcher.cxx:229
 TPyDispatcher.cxx:230
 TPyDispatcher.cxx:231
 TPyDispatcher.cxx:232
 TPyDispatcher.cxx:233
 TPyDispatcher.cxx:234
 TPyDispatcher.cxx:235
 TPyDispatcher.cxx:236
 TPyDispatcher.cxx:237
 TPyDispatcher.cxx:238
 TPyDispatcher.cxx:239
 TPyDispatcher.cxx:240
 TPyDispatcher.cxx:241
 TPyDispatcher.cxx:242
 TPyDispatcher.cxx:243
 TPyDispatcher.cxx:244
 TPyDispatcher.cxx:245
 TPyDispatcher.cxx:246
 TPyDispatcher.cxx:247
 TPyDispatcher.cxx:248
 TPyDispatcher.cxx:249
 TPyDispatcher.cxx:250
 TPyDispatcher.cxx:251
 TPyDispatcher.cxx:252
 TPyDispatcher.cxx:253
 TPyDispatcher.cxx:254
 TPyDispatcher.cxx:255
 TPyDispatcher.cxx:256
 TPyDispatcher.cxx:257
 TPyDispatcher.cxx:258
 TPyDispatcher.cxx:259
 TPyDispatcher.cxx:260
 TPyDispatcher.cxx:261
 TPyDispatcher.cxx:262
 TPyDispatcher.cxx:263
 TPyDispatcher.cxx:264
 TPyDispatcher.cxx:265
 TPyDispatcher.cxx:266
 TPyDispatcher.cxx:267
 TPyDispatcher.cxx:268
 TPyDispatcher.cxx:269
 TPyDispatcher.cxx:270
 TPyDispatcher.cxx:271
 TPyDispatcher.cxx:272
 TPyDispatcher.cxx:273