/******************************************************************
 * DPUSER - The Next Generation
 *
 * File:     libfits/fits_mem.cpp
 * Purpose:  Fits class methods for memory allocation
 * Author:   Thomas Ott
 *
 * Revision history
 * ================
 * 13.08.1999: file created
 ******************************************************************/

#include "fits.h"

/*
 * Initialize all memory pointers
 */

void Fits::initializeMemory() {
	int i;

	FileName = (char *)calloc(257, sizeof(char));
    columnName = (char *)calloc(73, sizeof(char));
	dataptr = NULL;
	setCasts();
    n_elements = 0;
	for (i = 0; i <= MAXNAXIS; i++) {
        naxis[i] = 0;
	}
	bscale = 1.0;
	bzero = 0.0;
//	type = IMAGE;
//	bitpix = 0;
	filebits = membits = R4;
    bytesPerPixel = 0;
	bytesAllocated = 0;
    extensionType = UNKNOWN;
}

/*!
Update all casts to memory
*/

void Fits::setCasts() {
//	data = (float *)dataptr;
	cdata = (dpCOMPLEX *)dataptr;
	r8data = (double *)dataptr;
	r4data = (float *)dataptr;
	i1data = (unsigned char *)dataptr;
	i2data = (short *)dataptr;
	i4data = (int *)dataptr;
}

/*!
(Re)allocate of memory and update the pointers to data.
*/

bool Fits::allocateMemory(dpint64 s) {
	dpint64 memNecessary;
	int i;

	bytesPerPixel = abs(membits) / 8;
	n_elements = 1;
	
//	bitpix = membits;
	for (i = 1; i <= naxis[0]; i++) n_elements *= naxis[i];
	memNecessary = bytesPerPixel * n_elements;
	if (s) {
		memNecessary = s;
		n_elements = s / bytesPerPixel;
	}
	if (bytesAllocated == memNecessary) return TRUE;

// Paranoia, just to make sure we have no dangling NULL pointer
    if (memNecessary == 0) memNecessary = 2 * sizeof(double);
	if ((dataptr = realloc(dataptr, memNecessary)) == NULL) {
		initializeMemory();
		if (memNecessary > 0)
			return fits_error("Could not allocate enough memory");
		else
			return TRUE;
	}
	setCasts();
	bytesAllocated = memNecessary;
	return TRUE;
}

/*
 * Change the type of data we are handling
 */

bool Fits::setType(FitsBitpix newbits, double nbscale, double nbzero) {
    dpint64 i;
    dpint64 n;
	FitsBitpix oldbits = membits;

// return if nothing to be done
	if (membits == newbits) return TRUE;

	membits = newbits;
	if (abs(oldbits) < abs(membits)) {
		if (!allocateMemory()) return FALSE;
		setCasts();
	}

	switch (newbits) {
		case I1: switch (oldbits) {
			case C16: for (n = 0; n < n_elements; n++) i1data[n] = (unsigned char)((cdata[n].r - nbzero) / nbscale); break;
			case R8:  for (n = 0; n < n_elements; n++) i1data[n] = (unsigned char)((r8data[n] - nbzero) / nbscale); break;
			case R4:  for (n = 0; n < n_elements; n++) i1data[n] = (unsigned char)(((double)r4data[n] - nbzero) / nbscale); break;
			case I4:  for (n = 0; n < n_elements; n++) i1data[n] = (unsigned char)(((double)i4data[n] * bscale + bzero - nbzero) / nbscale); break;
			case I2:  for (n = 0; n < n_elements; n++) i1data[n] = (unsigned char)(((double)i2data[n] * bscale + bzero - nbzero) / nbscale); break;
			default: break;
		}
			bzero = nbzero;
			bscale = nbscale;
			break;
		case I2: switch (oldbits) {
			case C16: for (n = 0; n < n_elements; n++) i2data[n] = (short)((cdata[n].r - nbzero) / nbscale); break;
			case R8:  for (n = 0; n < n_elements; n++) i2data[n] = (short)((r8data[n] - nbzero) / nbscale); break;
			case R4:  for (n = 0; n < n_elements; n++) i2data[n] = (short)(((double)r4data[n] - nbzero) / nbscale); break;
			case I4:  for (n = 0; n < n_elements; n++) i2data[n] = (short)(((double)i4data[n] * bscale + bzero - nbzero) / nbscale); break;
            case I1:  for (i = n_elements - 1; i >= 0; i--) i2data[i] = (short)(((double)i1data[i] * bscale + bzero - nbzero) / nbscale); break;
			default: break;
		}
			bzero = nbzero;
			bscale = nbscale;
			break;
		case I4: switch (oldbits) {
			case C16: for (n = 0; n < n_elements; n++) i4data[n] = (int)((cdata[n].r - nbzero) / nbscale); break;
			case R8:  for (n = 0; n < n_elements; n++) i4data[n] = (int)((r8data[n] - nbzero) / nbscale); break;
			case R4:  for (n = 0; n < n_elements; n++) i4data[n] = (int)(((double)r4data[n] - nbzero) / nbscale); break;
            case I2:  for (i = n_elements - 1; i >= 0; i--) i4data[i] = (int)(((double)i2data[i] * bscale + bzero - nbzero) / nbscale); break;
            case I1:  for (i = n_elements - 1; i >= 0; i--) i4data[i] = (int)(((double)i1data[i] * bscale + bzero - nbzero) / nbscale); break;
			default: break;
		}
			bzero = nbzero;
			bscale = nbscale;
			break;
		case R4: switch (oldbits) {
			case C16: for (n = 0; n < n_elements; n++) r4data[n] = (float)(cdata[n].r); break;
			case R8:  for (n = 0; n < n_elements; n++) r4data[n] = (float)r8data[n]; break;
			case I4:  for (n = 0; n < n_elements; n++) r4data[n] = (float)(i4data[n] * bscale + bzero); break;
            case I2:  for (i = n_elements - 1; i >= 0; i--) r4data[i] = (float)(i2data[i] * bscale + bzero); break;
            case I1:  for (i = n_elements - 1; i >= 0; i--) r4data[i] = (float)(i1data[i] * bscale + bzero); break;
			default: break;
		}
			bzero = 0.0;
			bscale = 1.0;
			break;
		case R8: switch (oldbits) {
			case C16: for (n = 0; n < n_elements; n++) r8data[n] = cdata[n].r; break;
            case R4:  for (i = n_elements - 1; i >= 0; i--) r8data[i] = (double)r4data[i]; break;
            case I4:  for (i = n_elements - 1; i >= 0; i--) r8data[i] = (double)i4data[i] * bscale + bzero; break;
            case I2:  for (i = n_elements - 1; i >= 0; i--) r8data[i] = (float)i2data[i] * bscale + bzero; break;
            case I1:  for (i = n_elements - 1; i >= 0; i--) r8data[i] = (float)i1data[i] * bscale + bzero; break;
			default: break;
		}
			bzero = 0.0;
			bscale = 1.0;
			break;
		case C16: switch (oldbits) {
            case R8: for (i = n_elements - 1; i >= 0; i--) {
				cdata[i].r = r8data[i];
				cdata[i].i = 0.0;
			}
				break;
            case R4: for (i = n_elements - 1; i >= 0; i--) {
				cdata[i].r = (double)r4data[i];
				cdata[i].i = 0.0;
			}
				break;
            case I4: for (i = n_elements - 1; i >= 0; i--) {
				cdata[i].r = (double)i4data[i] * bscale + bzero;
				cdata[i].i = 0.0;
			}
				break;
            case I2: for (i = n_elements - 1; i >= 0; i--) {
				cdata[i].r = (float)i2data[i] * bscale + bzero;
				cdata[i].i = 0.0;
			}
				break;
            case I1: for (i = n_elements - 1; i >= 0; i--) {
				cdata[i].r = (float)i1data[i] * bscale + bzero;
				cdata[i].i = 0.0;
			}
				break;
			default: break;
		}
			bzero = 0.0;
			bscale = 1.0;
			break;
		default: break;
	}
	if (abs(oldbits) > abs(membits)) {
		if (!allocateMemory()) return FALSE;
		setCasts();
	}

	return TRUE;
}

FitsBitpix Fits::getType() {
    return membits;
}

// bool Fits::setBitpix(int newb) {
// 	int i, oldbitpix;
// 	ULONG n;
// 
// // return if nothing to be done
// 	if (bitpix == newb) return TRUE;
// 
// // Allocate the new amount of memory if the new bitpix requires more
// 	oldbitpix = bitpix;
// 	if (abs(newb) > abs(bitpix)) {
// 		bitpix = newb;
// 		if (!allocateMemory()) return FALSE;
// 	}
// 	setCasts();
// 
// 	switch (oldbitpix) {
// 		case T_I1: {
// 			switch (newb) {
// 				case T_I2:
// 					for (i = (int)n_elements - 1; i >= 0; i--)
// 						i2data[i] = (unsigned short)i1data[i];
// 				break;
// 				case T_I4:
// 					for (i = (int)n_elements - 1; i >= 0; i--)
// 						i4data[i] = (unsigned int)i1data[i];
// 				break;
// 				case T_R4:
// 					for (i = (int)n_elements - 1; i >= 0; i--)
// 						r4data[i] = (float)i1data[i] * bscale + bzero;
// 					bscale = 1.0;
// 					bzero = 0.0;
// 				break;
// 				case T_R8:
// 					for (i = (int)n_elements - 1; i >= 0; i--)
// 						r8data[i] = (double)i1data[i] * bscale + bzero;
// 					bscale = 1.0;
// 					bzero = 0.0;
// 				break;
// 				case T_C16:
// 					for (i = (int)n_elements - 1; i >= 0; i--) {
// 						c16data[i].r = (double)i1data[i] * bscale + bzero;
// 						c16data[i].i = 0.0;
// 					}
// 					bscale = 1.0;
// 					bzero = 0.0;
// 				break;
// 				default: return FALSE;
// 				break;
// 			}
// 		}
// 		break;
// 		case T_I2: {
// 			switch (newb) {
// 				case T_I1:
// 					for (n = 0; n < n_elements; n++)
// 						i1data[n] = (unsigned char)i2data[n];
// 				break;
// 				case T_I4:
// 					for (i = (int)n_elements - 1; i >= 0; i--)
// 						i4data[i] = (unsigned int)i2data[i];
// 				break;
// 				case T_R4:
// 					for (i = (int)n_elements - 1; i >= 0; i--)
// 						r4data[i] = (float)i2data[i] * bscale + bzero;
// 					bscale = 1.0;
// 					bzero = 0.0;
// 				break;
// 				case T_R8:
// 					for (i = (int)n_elements - 1; i >= 0; i--)
// 						r8data[i] = (double)i2data[i] * bscale + bzero;
// 					bscale = 1.0;
// 					bzero = 0.0;
// 				break;
// 				case T_C16:
// 					for (i = (int)n_elements - 1; i >= 0; i--) {
// 						c16data[i].r = (double)i2data[i] * bscale + bzero;
// 						c16data[i].i = 0.0;
// 					}
// 					bscale = 1.0;
// 					bzero = 0.0;
// 				break;
// 				default: return FALSE;
// 				break;
// 			}
// 		}
// 		break;
// 		case T_I4: {
// 			switch (newb) {
// 				case T_I1:
// 					for (n = 0; n < n_elements; n++)
// 						i1data[n] = (unsigned char)i4data[n];
// 				break;
// 				case T_I2:
// 					for (n = 0; n < n_elements; n++)
// 						i2data[n] = (unsigned short)i4data[n];
// 				break;
// 				case T_R4:
// 					for (n = 0; n < n_elements; n++)
// 						r4data[n] = (float)i4data[n] * bscale + bzero;
// 					bscale = 1.0;
// 					bzero = 0.0;
// 				break;
// 				case T_R8:
// 					for (n = 0; n < n_elements; n++)
// 						r8data[n] = (double)i4data[n] * bscale + bzero;
// 					bscale = 1.0;
// 					bzero = 0.0;
// 				break;
// 				case T_C16:
// 					for (i = (int)n_elements - 1; i >= 0; i--) {
// 						c16data[i].r = (double)i4data[i] * bscale + bzero;
// 						c16data[i].i = 0.0;
// 					}
// 					bscale = 1.0;
// 					bzero = 0.0;
// 				break;
// 				default: return FALSE;
// 				break;
// 			}
// 		}
// 		break;
// 		case T_R4: {
// 			switch (newb) {
// 				case T_I1:
// 					for (n = 0; n < n_elements; n++)
// 						i1data[n] = (unsigned char)r4data[n];
// 				break;
// 				case T_I2:
// 					for (n = 0; n < n_elements; n++)
// 						i2data[n] = (unsigned short)r4data[n];
// 				break;
// 				case T_I4:
// 					for (n = 0; n < n_elements; n++)
// 						i4data[n] = (unsigned int)r4data[n];
// 				break;
// 				case T_R8:
// 					for (i = (int)n_elements - 1; i >= 0; i--)
// 						r8data[i] = (double)r4data[i];
// 				break;
// 				case T_C16:
// 					for (i = (int)n_elements - 1; i >= 0; i--) {
// 						c16data[i].r = (double)r4data[i];
// 						c16data[i].i = 0.0;
// 					}
// 				break;
// 				default: return FALSE;
// 				break;
// 			}
// 		}
// 		break;
// 		case T_R8: {
// 			switch (newb) {
// 				case T_I1:
// 					for (n = 0; n < n_elements; n++)
// 						i1data[n] = (unsigned char)r8data[n];
// 				break;
// 				case T_I2:
// 					for (n = 0; n < n_elements; n++)
// 						i2data[n] = (unsigned short)r8data[n];
// 				break;
// 				case T_I4:
// 					for (n = 0; n < n_elements; n++)
// 						i4data[n] = (unsigned int)r8data[n];
// 				break;
// 				case T_R4:
// 					for (n = 0; n < n_elements; n++)
// 						r4data[n] = (float)r8data[n];
// 				break;
// 				case T_C16:
// 					for (i = (int)n_elements - 1; i >= 0; i--) {
// 						c16data[i].r = r8data[i];
// 						c16data[i].i = 0.0;
// 					}
// 				break;
// 				default: return FALSE;
// 				break;
// 			}
// 		}
// 		break;
// 		case T_C16: {
// 			switch (newb) {
// 				case T_I1:
// 					for (n = 0; n < n_elements; n++)
// 						i1data[n] = (unsigned char)c16data[n].r;
// 				break;
// 				case T_I2:
// 					for (n = 0; n < n_elements; n++)
// 						i2data[n] = (unsigned short)c16data[n].r;
// 				break;
// 				case T_I4:
// 					for (n = 0; n < n_elements; n++)
// 						i4data[n] = (unsigned int)c16data[n].r;
// 				break;
// 				case T_R4:
// 					for (n = 0; n < n_elements; n++)
// 						r4data[n] = (float)c16data[n].r;
// 				break;
// 				case T_R8:
// 					for (n = 0; n < n_elements; n++)
// 						r8data[n] = c16data[n].r;
// 				break;
// 				default: return FALSE;
// 				break;
// 			}
// 		}
// 		break;
// 		default: return FALSE;
// 		break;
// 	}
// 
// // If the new memory is smaller, adjust
// 	if (abs(newb) < abs(bitpix)) {
// 		bitpix = newb;
// 		if (!allocateMemory()) return FALSE;
// 	}
// 	setCasts();
// 
// // update bitpix variable
// 	bitpix = newb;
// 
// 	return TRUE;
// }
