/*
 * E.S.O. - VLT project 
 * $Id: tRtdEvtTemplate.icc,v 1.1.1.1 2009/03/31 14:11:52 cguirao Exp $
 *
 * tRtdEvtTemplate.icc - data type dependent class for tRtd
 *          
 * 
 * who             when       what
 * --------------  --------   ----------------------------------------
 * pbiereic        05/02/03   Created
 */

/************************************************************************
 *
 *   DESCRIPTION
 *     Type dependent class for tRtdEvt.C. The routines are included
 *     by tRtdEvtData.C with the following definitions:
 *
 *     CLASS_NAME - class name
 *     DATA_TYPE  - data type (short, float...)
 *     SWAP       - bytes swapping routine for non-native byte order
 *
 *   The definitions are undef'd at the end of this file.
 */

#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "define.h"
#include "tRtdEvtData.h"

/*
 * --------------------------------
 * Template Class definitions
 * --------------------------------
 */
class CLASS_NAME : tRtdEvtData {
    friend class tRtdEvtData;

public:
    // public member functions
    CLASS_NAME(DATA_TYPE valmin, DATA_TYPE valmax);
    void genRef(char *p, int width, int height, int ref);
    void genImage(char *p, int width, int height, int count);
    void copyArrayToImage(char *array, char *image, int xs, int ys, int width);
    void copyImageToArray(char *image, char *array, int xs, int ys, int width);

    void initArea(char *ptr, int xs, int ys, int winsize, int width, int height);
    void jitterArea(int starjitter);
    void restoreArea();

    DATA_TYPE valmin_;
    DATA_TYPE valmax_;

    char *array_;
    char *array2_;
    char *aptr_;
    int  awinsize_;
    int  awidth_;
    int  aheight_;
    int  axs_;
    int  ays_;
};

/* 
 * --------------------------------
 * Template Class code
 * --------------------------------
 */

// constructor
CLASS_NAME::CLASS_NAME(DATA_TYPE valmin, DATA_TYPE valmax) :
    valmin_(valmin),
    valmax_(valmax)
{};

/*
 * generate a reference pixel
 */
void CLASS_NAME::genRef(char *ptr, int width, int height, int ref) 
{
    DATA_TYPE *p = (DATA_TYPE *)ptr;
    int refPixel = ref_pixel() / 2;

    // generate a n x n area around the reference pixel
    if (ref <= refPixel || width < ref + refPixel || height < ref + refPixel)
	return;

    ref--;  // for indexing
    for (int k = ref - refPixel; k <= ref + refPixel; k++)
	for (int i = ref - refPixel; i <= ref + refPixel; i ++)
	    *(p + k * width + i) = (DATA_TYPE)SWAP(valmax_);
  
    *(p + ref * width + ref) = (DATA_TYPE)SWAP(valmin_);
}

/*
 * generate some dummy image data based on the given count.
 */
void CLASS_NAME::genImage(char *ptr, int width, int height, int count)
{
    DATA_TYPE *p = (DATA_TYPE *)ptr;
    DATA_TYPE lineBuffer[MAX_NX * 3];

    // generate a line with color values
    DATA_TYPE *ptmp = lineBuffer;
    DATA_TYPE v = -width / 2;

    if (abs(v) != width /2)  // for unsigned short
	v = width / 2;

    for (int i = 0; i < MAX_NX * 3; i++, v++)
	*ptmp++ = SWAP(v);

    for (int k = 0; k < height; k++) {
	int cnt = (count + COUNT_INC) % width;
	memcpy(p + k * width, lineBuffer + cnt, width * sizeof(DATA_TYPE));
    }

    // we need some reference pixels for tests
    genRef(ptr, width, height, ref_pixel());
    genRef(ptr, width, height, count);
    genRef(ptr, width, height, width - count);
}

void CLASS_NAME::copyArrayToImage(char *ptr1, char *ptr2, int xs, int ys, int width)
{
    DATA_TYPE *array = (DATA_TYPE *)ptr1;
    DATA_TYPE *image = (DATA_TYPE *)ptr2;
    DATA_TYPE *s1, *s2;

    for (int idx = 0; idx < awinsize_; idx++) {
	s1 = array + idx * awinsize_;
	s2 = image + (ys - 1 + idx) * width + xs - 1;
	memcpy(s2, s1, awinsize_ * sizeof(DATA_TYPE));
    }
}

void CLASS_NAME::copyImageToArray(char *ptr1, char *ptr2, int xs, int ys, int width)
{
    DATA_TYPE *image = (DATA_TYPE *)ptr1;
    DATA_TYPE *array = (DATA_TYPE *)ptr2;
    DATA_TYPE *s1, *s2;

    for (int idx = 0; idx < awinsize_; idx++) {
	s1 = array + idx * awinsize_;
	s2 = image + (ys - 1 + idx) * width + xs - 1;
	memcpy(s1, s2, awinsize_ * sizeof(DATA_TYPE));
    }
}

void CLASS_NAME::initArea(char *ptr, int xs, int ys, int awinsize, int width, int height)
{
    awinsize_ = awinsize;
    axs_      = xs;
    ays_      = ys;
    awidth_   = width;
    aheight_  = height;
    aptr_     = ptr;

    // allocate buffers for saving and copying data
    int arraySize = awinsize * awinsize * sizeof(DATA_TYPE);
    array_  = (char *)malloc(arraySize);
    array2_ = (char *)malloc(arraySize);
    if (array_ == NULL || array2_ == NULL)
	errexit("not enough memory for malloc()");
    
    // save the rectangular around the star into array
    copyImageToArray(ptr, array_, xs, ys, width);
}

void CLASS_NAME::jitterArea(int starjitter)
{
    int y = ays_ + getRandomShift(starjitter);
    int x = axs_ + getRandomShift(starjitter);
    
    // copy array starting at xs,ys to the area starting at XS, YS
    copyImageToArray(aptr_, array2_, x, y, awidth_);
    copyArrayToImage(array2_, aptr_, axs_, ays_, awidth_);
}

void CLASS_NAME::restoreArea()
{
    // restore the area starting at xs, ys
    copyArrayToImage(array_, aptr_, axs_, ays_, awidth_);
}
