/*
 * imgtoolsDecl.h --
 *
 *      Declarations of stuff used in the other files, but not visible ouside the 
 *      package.
 *
 * Copyright (c) 2016-2017 by Simon Bachmann <simonbachmann@bluewin.ch>
 * All rights reserved.
 *
 * Permission is hereby granted, without written agreement and without
 * license or royalty fees, to use, copy, modify, and distribute this
 * software and its documentation for any purpose, provided that the
 * above copyright notice and the following two paragraphs appear in
 * all copies of this software.
 * 
 */

#ifndef IMGTOOLS_DECL
#define IMGTOOLS_DECL

#include <tk.h>
/* 
 * === Structures and Constants ===
 */
enum Color {
    RED,
    GREEN,
    BLUE,
    ALPHA
};

enum Orient {
    VERTICAL,
    HORIZONTAL
};

enum Clipping {
    ALL,
    KEEP,
    NONE
};

enum AllowLargerFlag {
    WITHIN_IMAGE,
    ALLOW_LARGER
};

enum RegionSizeFlag {
    SIZE_IS_MAX,
    SIZE_IS_INCREMENT
};

/*
 * Custom struct for image data
 * Actually just a wrapper around Tk_PhotoImageBlock
 * In most cases we won't copy the data, pixelPtr will
 * Point to the data of a Tk_PhotoImageBlock
 * 
 * pixelPtr is for allocating and freeing memory
 * for all other operations startPtr should be used 
 * Currently, this is not the case everywhere - legacy from older
 * versions where we used Tk_PhotoImageBlock.
 * 
 * Internally, Imgtools should be able to handle unusual values 
 * for pitch and pixel size (swapped values, even negative values)
 * 
 * we don't have an offset array, as the RGBA values are always 
 * stored in adjacent bytes in exactly that order.
 */
typedef struct {
    unsigned char *pixelPtr;    /* beginning of allocated memory block */
    unsigned char *startPtr;    /* Start reading data here. DO NOT use for free() */
    int width;
    int height;
    int pitch;
    int pixelSize;              /* not really a good name, but keep the one from the Tk struct */
                                /* think of it as "distance from a pixel to the next one in the x direction" */
    int memOwner;               /* Flag that tells if we are the owner of pixelPtr, */
                                /* and may safely call Tcl_Free() on it. */
} Imgtools_Image;

/*
 * Structs for coords and sizes
 */
typedef struct {
    int x;
    int y;
} Imgtools_IntCoords;

/*
 * Despite the name, we use doubles here.
 * Turnds out, float might not be precise enough
 */
typedef struct {
    double x;
    double y;
} Imgtools_FloatCoords;

/*
 * FilterType enum, filter names and number of filters
 * We need this enum here for the commonOpts struct below
 */
enum FilterType {
    NEAREST_NEIGHBOR,
    LINEAR,
    CATROM,
    LANCZOS2,
    LANCZOS3
#ifdef IMGTOOLS_EXACT
    ,CATROM_E,
    LANCZOS2_E,
    LANCZOS3_E
#endif
};

extern const char *const filterNames[]; /* defined in imgtools.ch */

#ifdef IMGTOOLS_EXACT
    #define FILTER_COUNT 9
#else
    #define FILTER_COUNT 5
#endif

// filterWidth is defined in interplatedOpts.c

/*
 * Data for common options
 */
typedef struct {
    int options;    /* bitfield */
    int composite;
    int shrink;
    enum FilterType filter;
    unsigned char background[3]; /*rgb values*/
    float alpha;    /* value between 0 an 1 */
    Imgtools_IntCoords fromCorners[2]; /* coords of the two corners */
    Imgtools_IntCoords toCorners[2];   /* negative values if not passed */
    enum Orient orient;
    enum Clipping clipping;
    Imgtools_IntCoords followPixel;     /* debug tool */
} Imgtools_CommonOpts;

extern const char *const optionNames[]; /* defined in imgtools.c */

// The order of these constants must match the order of option 
// names defined in imgtools.c
#define OPT_COMPOSITE   1
#define OPT_SHRINK      2
#define OPT_FILTER      4
#define OPT_BACKGROUND  8
#define OPT_ALPHA       0x10
#define OPT_FROM        0x20
#define OPT_TO          0x40
#define OPT_ORIENT      0x80
#define OPT_CLIPPING    0x100
#define OPT_FOLLOWPIXEL 0x200

extern const char *const optionNames[];

/*
 * === Prototypes ===
 */
int Imgtools_PutImage (Tcl_Interp *interp, const int composite, const int shrink, 
    const Imgtools_Image *sourceData, const Imgtools_IntCoords startPos, 
    const Imgtools_IntCoords putSize, const char *destName, Tk_PhotoHandle destHandle);
int Imgtools_GetImage (Tcl_Interp *interp, Tk_PhotoHandle sourceHandle, Imgtools_Image *destPtr);
int Imgtools_ApplySubregion (Tcl_Interp *interp, const Imgtools_IntCoords corners[2], 
    Imgtools_Image *img);
void Imgtools_FreeImage (Imgtools_Image *image);

int Imgtools_NormalizeImage (Imgtools_Image *imgPtr);

int Imgtools_ParseCommonOpts (Tcl_Interp *interp, int objc, Tcl_Obj *const objv[], 
    const int allowedOpts, Imgtools_CommonOpts *commonOpts);
Tcl_Obj * Imgtools_GetAllowedOptsList(int allowedOpts, const char *const optionNames[]);

int Imgtools_FindPhoto (Tcl_Interp *interp, Tcl_Obj *name, Tk_PhotoHandle *handle);

int Imgtools_GetSizesFromSpec(Tcl_Interp *interp, Tcl_Obj *spec, const Imgtools_IntCoords sourceSize, Imgtools_IntCoords *destSize);int Imgtools_GetAlphaVal (Tcl_Interp *interp, Tcl_Obj *alphaStr, char *optName, double *alphaPtr);
void Imgtools_RemovePercent(Tcl_Obj **objPtrPtr, int *changedPtr);

int Imgtools_GetAlphaVal (Tcl_Interp *interp, Tcl_Obj *alphaStr, char *optName, double *alphaPtr);
int Imgtools_ReduceAngle (Tcl_Interp *interp, double angle, double *resultPtr);
int Imgtools_GetAngle (Tcl_Interp *interp, Tcl_Obj *angleObj, double *resultPtr);
int Imgtools_GetColor(Tcl_Interp *interp, Tcl_Obj *colorStr, unsigned char *result);
int Imgtools_GetRegion(Tcl_Interp *interp, const Imgtools_IntCoords imgSize, 
    const Imgtools_IntCoords corners[2], const enum AllowLargerFlag allowLarger, 
    const enum RegionSizeFlag sizeMode, Imgtools_IntCoords *resStartPtr, 
    Imgtools_IntCoords *resEndPtr);
void Imgtools_GetSizeFromCorners (const Imgtools_IntCoords topLeftCorner, 
    const Imgtools_IntCoords bottomRightCorner,
    Imgtools_IntCoords *sizePtr);

/*
 * Make sure we have a M_PI macro
 */
#ifndef M_PI
    #define M_PI 3.14159265358979323846264338327
#endif

/*
 * MIN and MAX: just don't use them with increment operators/other function calls
 * ==> double evaluation!
 */
#define MIN(a, b) ( ((a) < (b)) ? (a) : (b) )
#define MAX(a, b) ( ((a) > (b)) ? (a) : (b) )

#endif 
