// -*- C -*-
%module psLibSwig

%include "p_psSwig.i"

%{
#  include "pslib.h"
#if 0
#  include "Private/p_psMemory.h"	/* not available from prototype psLib include files (in src dir) */
#else
#  define P_PS_MEMMAGIC (void *)0xdeadbeef // Magic number in psMemBlock header
#endif
#  include "psLibForSwig.h"
%}

/************************************************************************************************************/
/*
 * Typemaps
 */
%typemap(in) FILE * {
#if defined(SWIGPERL)
   if (!SvOK($input)) {
      $1 = NULL;      
   } else {
      $1 = PerlIO_findFILE(IoIFP(sv_2io($input)));
   }
#elif defined(SWIGPYTHON)
    if ($input == Py_None) {
	$1 = NULL;
    } else if (!PyFile_Check($input)) {
	PyErr_SetString(PyExc_TypeError, "Need a file!");
	goto fail;
    } else {
	$1 = PyFile_AsFile($input);
    }
#endif
}

/************************************************************************************************************/

%typemap(in) psMemBlock ***arr (psMemBlock **arr) {
#if defined(SWIGPERL)
   if (!SvOK($input)) {
      $1 = NULL;
   } else {
      arr = NULL;
      $1 = &arr;
   }

#elif defined(SWIGPYTHON)
    if ($input == Py_None) {
	$1 = NULL;
    } else {
	if (!PyList_Check($input)) {
	    SWIG_exception(SWIG_RuntimeError, "\"$1_name\" isn't a list");
	}
	
	arr = NULL;
	$1 = &arr;
    }
#endif
}

%typemap(in) psMetadata ** (psMetadata *) {
    if
#if defined(SWIGPYTHON)
       ($input == Py_None)
#else
       ($input == NULL)
#endif
    {
	$1 = NULL;
    } else {
        static $*1_type arr[1];
        if ((SWIG_ConvertPtr($input, (void **) &$1, $*1_descriptor, 1)) == -1) return NULL;
	arr[0] = ($*1_type)$1;
	$1 = arr;
    }
}

/*
 * Return a (psMemBlock ***) as a list of tuples; they are _appended_ to the pre-existing list. E.g.
 *
 *     arr = []; IPP.psMemCheckLeaks(0, arr, None, False)
 *     for el in arr:
 *         print el
 */
%typemap(argout) psMemBlock ***arr {
    if ($1 != NULL) {
	psMemBlock **arr = *$1;
	
	for (int i = 0; i < result; i++) {
	    const psMemBlock *m = arr[i];
#if defined(SWIGPERL)
	    SV *sv = newSVpvf("%d:%ld:%s:%ld:%d:%d:%ld",
			      (m->startblock == P_PS_MEMMAGIC) ? 1 : 0, (long)m->id,
			      m->file, (long)m->lineno, (int)m->refCounter,
			      (m->endblock == P_PS_MEMMAGIC) ? 1 : 0, (long)(m + 1));

	    if (SvROK($input)) {
	       AV *av = (AV *)SvRV($input);
	       if (SvTYPE(av) != SVt_PVAV) {
		  SWIG_croak("Type error in argument $argnum of $symname; Expected an array of psMemBlock");
	       }

	       av_push(av, sv);
	    } else {
	       SWIG_croak("Type error in argument $argnum of $symname; Expected a reference to an array of psMemBlock");
	    }
#elif defined(SWIGPYTHON)
	    const int nel = 7;
	    PyObject *ty = PyTuple_New(nel);
	    int j = 0;
	    PyTuple_SET_ITEM(ty, j++, PyInt_FromLong(m->startblock == P_PS_MEMMAGIC));
	    PyTuple_SET_ITEM(ty, j++, PyInt_FromLong(m->id));
	    PyTuple_SET_ITEM(ty, j++, PyString_FromString(m->file));
	    PyTuple_SET_ITEM(ty, j++, PyInt_FromLong(m->lineno));
	    PyTuple_SET_ITEM(ty, j++, PyInt_FromLong(m->refCounter));
	    PyTuple_SET_ITEM(ty, j++, PyInt_FromLong(m->endblock == P_PS_MEMMAGIC));
	    PyTuple_SET_ITEM(ty, j++, PyInt_FromLong((long)(m + 1)));
	    assert (j == nel);
	    
	    PyList_Append($input, ty);
#endif
	}
	
	psFree(arr);
    }
}

/************************************************************************************************************/
%{
typedef struct { float re, im; } swig_psC32;  ///< 32-bit complex floating point
typedef struct { double re, im; } swig_psC64; ///< 64-bit complex floating point
%}

#if 0
%include <stdint.h>			// SWIG has trouble with nested typedefs in this file
					// at least on Darwin machines
#else
typedef unsigned char  uint8_t;
typedef unsigned short uint16_t;
typedef unsigned int   uint32_t;
typedef unsigned long  uint64_t;
typedef char           int8_t;
typedef short          int16_t;
typedef int            int32_t;
typedef long           int64_t;
#endif

typedef int psBool;
typedef void *psPtr;
typedef uint8_t psU8;                  ///< 8-bit unsigned int
typedef uint16_t psU16;                ///< 16-bit unsigned int
typedef uint32_t psU32;                ///< 32-bit unsigned int
typedef uint64_t psU64;                ///< 64-bit unsigned int
typedef int8_t psS8;                   ///< 8-bit signed int
typedef int16_t psS16;                 ///< 16-bit signed int
typedef int32_t psS32;                 ///< 32-bit signed int
typedef int64_t psS64;                 ///< 64-bit signed int
typedef float psF32;                   ///< 32-bit floating point
typedef double psF64;                  ///< 64-bit floating point
typedef struct { float re, im; } swig_psC32;  ///< 32-bit complex floating point
typedef struct { double re, im; } swig_psC64; ///< 64-bit complex floating point

%typemap(in) psC32 = float;
%typemap(in) psC64 = double;

typedef enum {
    PS_TYPE_S8 = 0x0101,               ///< Character.
    PS_TYPE_S16 = 0x0102,              ///< Short integer.
    PS_TYPE_S32 = 0x0104,              ///< Integer.
    PS_TYPE_S64 = 0x0108,              ///< Long integer.
    PS_TYPE_U8 = 0x0301,               ///< Unsigned character.
    PS_TYPE_U16 = 0x0302,              ///< Unsigned short integer.
    PS_TYPE_U32 = 0x0304,              ///< Unsigned integer.
    PS_TYPE_U64 = 0x0308,              ///< Unsigned long integer.
    PS_TYPE_F32 = 0x0404,              ///< Single-precision Floating point.
    PS_TYPE_F64 = 0x0408,              ///< Double-precision floating point.
    PS_TYPE_C32 = 0x0808,              ///< Complex numbers consisting of single-precision floating point.
    PS_TYPE_C64 = 0x0810              ///< Complex numbers consisting of double-precision floating point.
} psElemType;

typedef enum {
    PS_DIMEN_SCALAR,            ///< Scalar.
    PS_DIMEN_VECTOR,            ///< Vector.
    PS_DIMEN_TRANSV,            ///< Transposed vector.
    PS_DIMEN_IMAGE,             ///< Image.
    PS_DIMEN_OTHER              ///< Something else that's not supported for arithmetic.
} psDimen;

typedef struct {
    psElemType type;            ///< Primitive type.
    psDimen dimen;              ///< Dimensionality.
}
psType;

%include "psErrorCodes.h"
%include "psLogMsg.h"
%include "psMemory.h"
%ignore psTraceFree;
%include "psTrace.h"

EXPORT_TYPE(psList);
%include "psList.h"

EXPORT_TYPE(psImage);
EXPORT_TYPE(psRegion);
%typemap(memberin) psImage * {
   psFree($1);
   $1 = $input;
#if defined(SWIGPERL)
   p_psMemIncrRefCounter($1, "memberin(psImage *)", 0);
#endif
}
NEWOBJECT(psImageReadSection);
NEWOBJECT(psImageSubset);
NEWOBJECT(psImageSubsection);
NEWOBJECT(psImageCopy);
NOTNULL(psImageTrim);
%include "psImage.h"
%include "psImageIO.h"
%include "psImageExtraction.h"

EXPORT_TYPE(psMetadata)
%typemap(memberin) psMetadata * {
   psFree($1);
   $1 = $input;
#if defined(SWIGPERL)
   p_psMemIncrRefCounter($1, "memberin(psMetadata *)", 0);
#endif
}

%include "psMetadata.h"

%apply int *OUTPUT { psU32 *nFail }
TYPE_INOUT(psMetadata *, md);
NEWOBJECT(psMetadataParseConfig);
NOTNULL(psMetadataLookup);
%include "psMetadataIO.h"
CLEAR_TYPE_INOUT(psMetadata *, md);

%extend psMetadataItem {
    const char *get_STR(void) {
       if (self->type != PS_META_STR) {
	  return NULL;
       } else {
	  return self->data.V;
       }
    }
}

%include "psLibForSwig.h"

EXPORT_TYPE(psHash);
%include "psHash.h"

EXPORT_TYPE(psErr);
NEWOBJECT(psErrorGet);
NEWOBJECT(psErrorLast);
%include "psError.h"

EXPORT_TYPE(psArray);
%extend psArray {
    const void *get_data(int i) {
	return self->data[i];
    }

    const psCell *get_cell(int i) {
        return (psCell *)(self->data[i]);
    }
    const psChip *get_chip(int i) {
        return (psChip *)(self->data[i]);
    }
    const psReadout *get_readout(int i) {
        return (psReadout *)(self->data[i]);
    }
}
%include "psArray.h"

// N.b. assumes e.g. %array_class(int, intArray);
%define GET_CARRAY(structType, ctype, typeName)
   %extend structType {
      ctype ## Array *get_data_ ## typeName(void) {
	 if (self->type.type == PS_TYPE_ ## typeName) {
	    return self->data.typeName;
	 } else {
	    psError(PS_ERR_BAD_PARAMETER_TYPE, 1, "psVector is of type %d, not PS_TYPE_" "typeName",
		    self->type.type);
	    return NULL;
	 }
      }
   }
%enddef

EXPORT_TYPE(psVector);
%include "psVector.h"
GET_CARRAY(psVector, float,  F32);
GET_CARRAY(psVector, double, F64);
   
EXPORT_TYPE(psObservatory);
EXPORT_TYPE(psFPA);
EXPORT_TYPE(psChip);
EXPORT_TYPE(psCell);
EXPORT_TYPE(psReadout);
EXPORT_TYPE(psExposure);
%include "psAstrometry.h"

%extend psFPA {
    void set_chip(int i, psChip *chip) {
        self->chips->data[i] = chip;
	p_psMemIncrRefCounter(chip, "set_chip", 0);
    }
}
%extend psChip {
    void set_cell(int i, psCell *cell) {
        self->cells->data[i] = cell;
	p_psMemIncrRefCounter(cell, "set_cell", 0);	
    }
}
%extend psCell {
   char *extname;
    void set_readout(int i, psReadout *readout) {
        self->readouts->data[i] = readout;
	p_psMemIncrRefCounter(readout, "set_readout", 0);	
    }
}
%{
   char *psCell_extname_get(psCell *cell) { return NULL; }
   void psCell_extname_set(psCell *cell, char *val) { return; }
%}

NEWOBJECT(psBinaryOp);
TYPE_INOUT(void *, out);
psImage *psBinaryOp(void *out, void *in1, char *op, void *in2);
CLEAR_TYPE_INOUT(void *, out);
%include "psScalar.h"

EXPORT_TYPE(psTime);
NEWOBJECT(psTimeGetTime);
%include "psTime.h"

EXPORT_TYPE(psFits);
NEWOBJECT(psFitsReadImage);
TYPE_INOUT(psImage *, out);
%include "psFits.h"
CLEAR_TYPE_INOUT(psImage *, out);

EXPORT_TYPE(psStats);
EXPORT_TYPE(psHistogram);
%include "psStats.h"
%include "psImageStats.h"
