/******************************************************************************
 * $Id: pyextend.i,v 1.25 2005/02/18 20:10:01 sean Exp $
 *
 * Project:  MapServer
 * Purpose:  Python-specific extensions to MapScript objects
 * Author:   Sean Gillies, sgillies@frii.com
 *
 ******************************************************************************
 *
 * Python-specific mapscript code has been moved into this 
 * SWIG interface file to improve the readibility of the main
 * interface file.  The main mapscript.i file includes this
 * file when SWIGPYTHON is defined (via 'swig -python ...').
 *
 *****************************************************************************/

/* ===========================================================================
   Python rectObj extensions
   ======================================================================== */

%extend pointObj {

%pythoncode {

    def __str__(self):
        return self.toString()

}
    
}


/* ===========================================================================
   Python rectObj extensions
   ======================================================================== */
   
%extend rectObj {

%pythoncode {

    def __str__(self):
        return self.toString()
        
    def __contains__(self, item):
        item_type = str(type(item))
        if item_type == "<class 'mapscript.pointObj'>":
            if item.x >= self.minx and item.x <= self.maxx \
            and item.y >= self.miny and item.y <= self.maxy:
                return True
            else:
                return False
        else:
            raise TypeError, \
                '__contains__ does not yet handle %s' % (item_type)
        
}

}

/******************************************************************************
 * Extensions to mapObj
 *****************************************************************************/

%extend mapObj {
  
    /* getLayerOrder() extension returns the map layerorder as a native
     sequence */

    PyObject *getLayerOrder() {
        int i;
        PyObject *order;
        order = PyTuple_New(self->numlayers);
        for (i = 0; i < self->numlayers; i++) {
            PyTuple_SetItem(order,i,PyInt_FromLong((long)self->layerorder[i]));
        }
        return order;
    } 

    int setLayerOrder(PyObject *order) {
        int i, size;
        size = PyTuple_Size(order);
        for (i = 0; i < size; i++) {
            self->layerorder[i] = (int)PyInt_AsLong(PyTuple_GetItem(order, i));
        }
        return MS_SUCCESS;
    }
    
    PyObject* getSize()
    {
        PyObject* output ;
        output = PyTuple_New(2);
        PyTuple_SetItem(output,0,PyInt_FromLong((long)self->width));
        PyTuple_SetItem(output,1,PyInt_FromLong((long)self->height));
        return output;
    }    
%pythoncode {

    def get_height(self):
        return self.getSize()[1] # <-- second member is the height
    def get_width(self):
        return self.getSize()[0] # <-- first member is the width
    def set_height(self, value):
        return self.setSize(self.getSize()[0], value)
    def set_width(self, value):
        return self.setSize(value, self.getSize()[1])
    width = property(get_width, set_width)
    height = property(get_height, set_height)
    
}    
    
}

/****************************************************************************
 * Support for bridging Python file-like objects and GD through IOCtx
 ***************************************************************************/

/******************************************************************************
 * Extensions to imageObj
 *****************************************************************************/
    
%extend imageObj {

    /* New imageObj constructor taking an optional PyFile-ish object
     * argument.
     *
     * Furthermore, we are defaulting width and height so that in case
     * anyone wants to swig mapscript with the -keyword option, they can
     * omit width and height.  Work done as part of Bugzilla issue 550. */

    imageObj(PyObject *arg1=Py_None, PyObject *arg2=Py_None, 
             PyObject *input_format=Py_None)
    {
        imageObj *image=NULL;
        outputFormatObj *format=NULL;
        int width;
        int height;
        PyObject *pybytes;
      
        unsigned char PNGsig[8] = {137, 80, 78, 71, 13, 10, 26, 10};
        unsigned char JPEGsig[3] = {255, 216, 255};

        if (PyInt_Check(arg1) && PyInt_Check(arg2)) 
        {
            /* Create from width, height, format/driver */
            width = (int) PyInt_AsLong(arg1);
            height = (int) PyInt_AsLong(arg2);
            
            if (input_format == Py_None) {
                format = msCreateDefaultOutputFormat(NULL, "GD/GIF");
                if (format == NULL)
                    format = msCreateDefaultOutputFormat(NULL, "GD/PNG");
                if (format == NULL)
                    format = msCreateDefaultOutputFormat(NULL, "GD/JPEG");
                if (format == NULL)
                    format = msCreateDefaultOutputFormat(NULL, "GD/WBMP");
            }
            else if (PyString_Check(input_format)) {
                format = msCreateDefaultOutputFormat(NULL, 
                                PyString_AsString(input_format));
            }
            else {
                if ((SWIG_ConvertPtr(input_format, (void **) &format,
                     SWIGTYPE_p_outputFormatObj,
                     SWIG_POINTER_EXCEPTION | 0 )) == -1) 
                {
                    msSetError(MS_IMGERR, "Can't convert format pointer",
                                          "imageObj()");
                    return NULL;
                }
            }
        
            if (format == NULL) {
                msSetError(MS_IMGERR, "Could not create output format",
                           "imageObj()");
                return NULL;
            }

            image = msImageCreate(width, height, format, NULL, NULL, NULL);
            return image;
        }
        
        /* Is arg1 a filename? */
        else if (PyString_Check(arg1)) 
        {
            return (imageObj *) msImageLoadGD((char *) PyString_AsString(arg1));
        }
        
        /* Is a file-like object */
        else if (arg1 != Py_None)
        {

            if (PyObject_HasAttrString(arg1, "seek"))
            {
                /* Detect image format */
                pybytes = PyObject_CallMethod(arg1, "read", "i", 8);
                PyObject_CallMethod(arg1, "seek", "i", 0);
            
                if (memcmp(PyString_AsString(pybytes),"GIF8",4)==0) 
                {
%#ifdef USE_GD_GIF
                    image = createImageObjFromPyFile(arg1, "GD/GIF");
%#else
                    msSetError(MS_MISCERR, "Unable to load GIF image.",
                               "imageObj()");
%#endif
                }
                else if (memcmp(PyString_AsString(pybytes),PNGsig,8)==0) 
                {
%#ifdef USE_GD_PNG
                    image = createImageObjFromPyFile(arg1, "GD/PNG");
%#else
                    msSetError(MS_MISCERR, "Unable to load PNG image.",
                               "imageObj()");
%#endif
                }
                else if (memcmp(PyString_AsString(pybytes),JPEGsig,3)==0) 
                {
%#ifdef USE_GD_JPEG
                    image = createImageObjFromPyFile(arg1, "GD/JPEG");
%#else
                    msSetError(MS_MISCERR, "Unable to load JPEG image.", 
                               "imageObj()");
%#endif
                }
                else
                {
                    msSetError(MS_MISCERR, "Failed to detect image format.  Likely cause is invalid image or improper filemode.  On windows, Python files should be opened in 'rb' mode.", "imageObj()");
                }

                return image;
            
            }
            else /* such as a url handle */
            {
                /* If there is no seek method, we absolutely must
                   have a driver name */
                if (!PyString_Check(arg2))
                {
                    msSetError(MS_MISCERR, "A driver name absolutely must accompany file objects which do not have a seek() method", "imageObj()");
                    return NULL;
                }    
                return (imageObj *) createImageObjFromPyFile(arg1, 
                        PyString_AsString(arg2));
            }
        }
        else 
        {
            msSetError(MS_IMGERR, "Failed to create image", 
                       "imageObj()");
            return NULL;
        }
    }
  
    /* ======================================================================
       write()

       Write image data to an open Python file or file-like object.
       Overrides extension method in mapscript/swiginc/image.i.
       Intended to replace saveToString.
    ====================================================================== */
    int write( PyObject *file=Py_None )
    {
        FILE *stream;
        gdIOCtx *ctx;
        unsigned char *imgbuffer;
        int imgsize;
        PyObject *noerr;
        int retval=MS_FAILURE;
       
        /* Return immediately if image driver is not GD */
        if ( !MS_DRIVER_GD(self->format) )
        {
            msSetError(MS_IMGERR, "Writing of %s format not implemented",
                       "imageObj::write", self->format->driver);
            return MS_FAILURE;
        }

        if (file == Py_None) /* write to stdout */
        {
            ctx = msNewGDFileCtx(stdout);
            retval = msSaveImageGDCtx(self->img.gd, ctx, self->format);
            ctx->gd_free(ctx);
        }
        else if (PyFile_Check(file)) /* a Python (C) file */
        {
            stream = PyFile_AsFile(file);
            ctx = msNewGDFileCtx(stream);
            retval = msSaveImageGDCtx(self->img.gd, ctx, self->format);
            ctx->gd_free(ctx);
        }
        else /* presume a Python file-like object */
        {
            imgbuffer = msSaveImageBufferGD(self->img.gd, &imgsize,
                                            self->format);
            if (imgsize == 0)
            {
                msSetError(MS_IMGERR, "failed to get image buffer", "write()");
                return MS_FAILURE;
            }
                
            noerr = PyObject_CallMethod(file, "write", "s#", imgbuffer,
                                        imgsize);
            gdFree(imgbuffer);
            if (noerr == NULL)
                return MS_FAILURE;
            else
                Py_DECREF(noerr);
            retval = MS_SUCCESS;
        }

        return retval;
    }

    /* Deprecated */  
    PyObject *saveToString() {
        int size=0;
        unsigned char *imgbytes;
        PyObject *imgstring; 

        imgbytes = msSaveImageBufferGD(self->img.gd, &size, self->format);
        if (size == 0)
        {
            msSetError(MS_IMGERR, "failed to get image buffer", "saveToString()");
            return NULL;
        }
        imgstring = PyString_FromStringAndSize(imgbytes, size); 
        gdFree(imgbytes);
        return imgstring;
    }

}


