#if defined(__MINGW32__) || defined(__MINGW64__)
#define MSWIN32
#endif

#define __NINOX_H__

#define _LARGEFILE64_SOURCE
#define _FILE_OFFSET_BITS 64

#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <math.h>
#include <values.h>
#include <time.h>

#include "fft.h"

typedef unsigned int u32;
typedef int s32;
typedef float f32;

#define DIR_MAX_COUNT 100000

// Catch and redirect standard output to our internal funtion
// where we can choose the output stream
#define printf(...) Printf(__VA_ARGS__)

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

struct cfunc
	{
	char *option;
	int (*func)(char *, char *, int);
	};

#include "version.h"

#define TRUE 1
#define FALSE 0

#define CHANNEL_R	2
#define CHANNEL_G	3
#define CHANNEL_B	4
#define CHANNEL_IR	5
#define CHANNEL_CH4	6
#define CHANNEL_UV	7
#define CHANNEL_IR610	8
#define CHANNEL_IR750	9
#define CHANNEL_IR800	10
#define CHANNEL_IR807	10
#define CHANNEL_IR850	11
#define CHANNEL_IR900	12
#define CHANNEL_IR950	13
#define CHANNEL_IR1000	14

#define MAX_CHANNEL 	14
#define NUM_CHANNELS 	(MAX_CHANNEL+1)

// Parameters for use with -renumber commandline switch
#define QRENUMBER_FIRST 1
#define QRENUMBER_LAST 2

#define POPFILTER_BEFORE 1
#define POPFILTER_AFTER  2

#define SMOOTHING_BEFORE 1
#define SMOOTHING_AFTER 2

#define QTRIM_NONE 	0
#define QTRIM_SECONDS 	1
#define QTRIM_FRAMES	2

// Valid values for Image->type;
#define IMG_PPM		1
#define IMG_BMP		2
#define IMG_FIT		3
#define IMG_FIT32U	4	// 32 bit unsigned int, depth = 32
#define IMG_FIT32F	4	// 32 bit floating point, depth = 32

// StreamFilter types
#define AVG		1
#define AVG_LOW		2
#define AVG_HIGH	3
#define LOW		4
#define MEDIAN		5
#define HIGH		6
#define MAX_POP		7

#define HISTO		1
#define GRADIENT	2
#define BR_THRESH	3
#define ADD_BR_THRESH	4
#define QF_MINCOUNT	5
#define QF_SOSQ		6
#define QF_APERTURE	7
#define QF_NONE		8

// A "practical" maximum 32 bit value. Assume that brighter pixels are artifacts
#define UMAX32s ((u32)65535 * (u32)65530)

// unsigned and signed maximum values
#define UMAX32 0xffffffff
#define SMAX32 0x7fffffff

// flags for ArchiveLoadNextImage
#define ARCHIVE_LOAD 1
#define ARCHIVE_SKIP 2
#define ARCHIVE_COMPRESSED 4
#define ARCHIVE_SER 8

#define SER_HEADER_SIZE 	178

#define FITS_LOAD 1
#define FITS_SKIP 2
#define FITS_COMPRESSED 4

#define BAYER_GBG 1
#define BAYER_RGR 2
#define BAYER_BGB 3
#define BAYER_GRG 4

// Entries for DBF (DetectBrokenFrames).
// Planet means we can be more strict in locating broken frames
// by watching for sudden movement of the centre of brightness
#define DBF_PLANET 1
#define DBF_LUNAR 2

// Modes for locatig the centre of an image
#define CENTRE_BARYCENTRE	1
#define CENTRE_LEFT		2
#define CENTRE_RIGHT		3

#define IMAGECOUNT_MAX 999999

#define SER_COLORID_MONO	0
#define SER_COLORID_BAYER_RGGB	8
#define SER_COLORID_BAYER_GRGB	9
#define SER_COLORID_BAYER_GBRG	10
#define SER_COLORID_BAYER_BGGR	11
#define SER_COLORID_BAYER_CYYM	16
#define SER_COLORID_BAYER_YCMY	17
#define SER_COLORID_BAYER_YMCY	18
#define SER_COLORID_BAYER_MYYC	19

/* Flags for DrawString */
#define DRAW_BLACK_PIXELS 	1

/*
 * RowBoost definitions
 */
#define RB_ODD_MULT		1
#define RB_ODD_ADD 		2
#define RB_EVEN_MULT		3
#define RB_EVEN_ADD		4

/*
 * BMP file format header
 */

/*
 * Note that we ignore the last 5 fields 
 */

typedef struct
	{
	int filesz;	/* size of BMP file */
	short r1;	/* reserved - must be 0 */
	short r2;	/* reserved - must be 0 */
	int offset;	/* offset to image data */
	int size;	/* size of remaining header (must be 40) */
	int width;	/* image width in pixels */
	int height;	/* image height in pixels */
	short planes;	/* must be 1 */
	short bitcount;	/* bits per pixel - 1,2,4,8,16,24,32 */
	int compression;/* must be 0 for uncompressed image */
	int sizeimage;	/* image size - may be 0 for uncompressed image */
	int xppm;	/* X pixels per metre (ignore) */
	int yppm;	/* Y pixels per metre (ignore) */
	int cmapentries;/* Number of colourmap entries */
	int clrimportant; /* number of important colours */
	} bmp_header;

struct Region
	{
	int x1,y1;
	int x2,y2;
	};

struct QRegion
	{
	struct Region r;
	int histo_low;
	int histo_high;
	};

struct morph_point
	{
	int active;		// is this point in use?
	int x,y;		// Location of control point (centre)
	int w,h;		// width and height of control area
	int x_offset;		// translation
	int y_offset;		// translation
	double scale;		// lensing
	};

struct image_quality
        {
        int bucket;  // 0..6
        char *newname;
        double val;
        };

struct merge_info {
	double avg;
	};

struct Image
        {
        char *src_fname;	// Name of source file
	char *dst_fname;	// Name of destination file
	int type;		// IMG_*
        unsigned char *data;	// Image data bytes from file
	void *info;		// Image-specific info
	int width, height;	// Width, Height of source image
	int xpos, ypos;		// (x,y) position of top left corner on ccd
	int sub_x,sub_y;	// centre of interest
	int dst_width;		// Width of destination image
	int dst_height;		// Height of destination image
        int depth;
	double histo_stretch;	// If the image was histo-stretched on load, record the value here
	int auto_black;		// if AutoBlack is enabled, this is the amount subtracted
	double tm_sec;		// floating point timestamp in seconds
	unsigned long long tm_tsc; // timestamp in cpu ticks

	struct merge_info m;	// Info for merging
	struct Region cutout;	// Region to cut from source image
	struct image_quality *q;	// Image quality info
	int histo_warning;	// Set to 1 if image contains overbright pixels
        };

// Struct for FITS image type
struct fits_info
	{
	u32 bzero;
	double bscale;
	int naxis;		// NAXIS from header
	int naxis1;
	int naxis2;
	int naxis3;
	unsigned char *header;	// Primary header from source
	};

struct bmp_info
	{
	int cmap_entries;
	unsigned char *cmap;
	};

struct ppm_info
	{
	char ppm_type[3];	// "P6" etc
	int maxval;
	};

struct weight
        {
        short active;                   // set to 1 when in use
        struct morph_point *ptr;        // control point
        double wgt;                     // fractional weight (0..1)
        };

struct __attribute__ ((__packed__)) ser_info
	{
	int LuID;			// int32 camera id
	int ColorID;			// int32 LU_COLOR_X
	int LittleEndian;		// 0 = 16bit big-endian, 1 = 16bit little-endian
	int ImageWidth;
	int ImageHeight;
	int PixelDepth;			// <=8: 1 byte, >8: 2 byte
	int FrameCount;			// Number of frames in the file
	char Observer[40];
	char Instrument[40];
	char Telescope[40];
	unsigned long long dt;		// date of image stream start (100ns ticks since Jan 1 0001)
	unsigned long long dt_utc;	// As above, but UTC
	unsigned long long *ts;		// Array of timestamps as read in from the file
					// be careful here, this field is not in the SER spec, when we write out the header
					// then we have to exclude it (ie write sizeof(unsigned long long *)  bytes short)
	};


#ifndef __GLOBALS_H__
#include "globals.h"
#endif
	
void Usage(void);
int isDirectory(char *);
int smooth_image(struct Image *img,int scale);
int smooth_image_16(unsigned char *data,int width,int height,int scale);
int scale_image(struct Image *img, int n);
int pop_filter(struct Image *);

// fileio.c
int load_image_header(FILE *in, char *tmp, struct Image *img);
int ReadByte(FILE *in);
int Fread(unsigned char *buffer, int size, int count, FILE *in);
off64_t Tell(int fd);
off64_t FTell(FILE *in);
struct Image * CreateImage(void);
struct Image * ConvertImage(struct Image *src, int type, int depth);
int SetCutoutRegion(struct Image *img, int x1, int y1, int x2, int y2);
struct Image * CreateFitsImage(char *dst_fname, int width, int height, int depth,
                unsigned char *data, u32 bzero, double bscale);
void SetChannel(int);
struct Image * LoadImage(char *src_fname, char *dst_fname);
int write_image_header(FILE *out,struct Image *img);
int write_image_data(FILE *out,struct Image *img);
int WriteImage(struct Image *img);
int InvertImage(struct Image *);
int MirrorImage(struct Image *);
struct Image * ArchiveLoadNextImage(FILE *in, int *err, int flags);
struct Image * ArchiveLoadNextImage_SER(FILE *in, int *err, int flags);
FILE * OpenArchive(char *name);
int ExtractArchive(char *archive_name, char *dstdir);
struct Image *ConvertToType(struct Image *, int newtype, int newdepth);
int ArchiveNextFilename(char *this, char *next);
int SfxToChannel(char *sfx);
FILE * OpenSerForWriting(char *filename, int width, int height, int depth, char *Obs, char *Inst, char *Tel);
int WriteSerFrame(struct Image *img, FILE *out);
int CloseSerFile(FILE *out);
int ShowHistogram_img(struct Image *img, int print_to_stdout);
int ShowHistogram_16(unsigned short *ptr, int npix, int print_to_stdout);
int ShowHistogram_8(unsigned char *ptr, int npix, int print_to_stdout);
void ApplyRowCorrection(struct Image *img);
void ApplyColumnCorrection(struct Image *img);
int ApplyRowBoost(struct Image *img);
int AutoRowBalance(struct Image *img);

// align.c
void Mkdir(char *dirname);
int Align(char *);
int SubtractDarkFrame(struct Image *);
char * GenerateDstFilename(char *);

// process.c
extern int BlankImageCount;

int FindCentre(struct Image *img, int *x_avg, int *y_avg);
int CalculateCutout(struct Image *img);
int CutOut(struct Image *img);
int ApplyGamma(struct Image *img, double gamma);
int ProcessDir(char *dir);
int process(struct Image *img);
double input_filter(struct Image *img);
int Clip(int w, int h, int *x1, int *y1, int *x2, int *y2);

// stack.c
int stack_max_channels(void);
int stack_channel_has_data(int channel);
int stack_init(void);
int stack_reset(void);
int stack_frame(struct Image *img);
int write_stack_data(char *fname);
int merge_data(char *mfile, struct Image *img);

// quality.c
void Mark_Trim(int before, int after);
void Delete_Trim(void);
void QualitySort(void);
void QAssociate(struct Image *img, double quality);
int  LoadQFile(char *fname);
void WriteQFile(char *fname);
int SubSample(unsigned char *ptr, int img_wid, int bpp, int x_size, int y_size);
double QualityEstimate(struct Image *img);
void Qrenumber(int);

// debayer.c
struct Image * DeBayer(struct Image *img, int p);
int FixBayer8(struct Image *img);

// morph.c
int smooth_image3x3(struct Image *img);
int smooth_image5x5(struct Image *img);
int translate_image(struct Image *img, int dx, int dy);
int morph_image(struct Image *img, int level);

// subsample.c
struct Image ** GenerateSubSampledImages(struct Image *img, struct Region *r, int *xsizes, int *ysizes, int depth, int count);
int Test_Subsample(struct Image *img);

// util.h
char * VStrdup(char *);
void * Realloc(void *ptr, int nbytes);
void * Malloc(int nbytes);
void * ZeroMalloc(int nbytes);
char * TypeName(int type);
double d_Random(void);
int Random(int);
int Srandom(void);
FILE * OpenLogfile(char *fname, char *mode);
int AllowWrite(char *fname);
int isSupportedFile(char *fname);
int Usleep(int);
void ShowImage(struct Image *img);
FILE *Select(FILE *f);
int Print(char *fmt,...);
int Printf(char *fmt,...);
int ApplyAntiGhost(struct Image *);
int ApplyAntiGhost_8(struct Image *);
int ApplyAntiGhost_16(struct Image *);
int ApplyAntiGhost_24(struct Image *);
void PrintInt64(long long v);
void PrintUInt64(unsigned long long v);
unsigned long long FileSize(char *fname);
char * SerTime_utc(unsigned long long stm);
unsigned long long SerTimeStamp_Unix_ms(unsigned long long t);
unsigned long long SerTimeStamp_FromUnix_ms(unsigned long long t);
char * UnixTime_ms_utc(time_t tm, int *year, int *mon, int *day, int *hr, int *min, double *sec);
unsigned long long DateTime_to_Unix_ms(int year,int month,int day,int hour,int min,double sec);
time_t my_timegm(struct tm *tm);

// tables.h
double * create_weight_buffer_decrease_lr(int w, int h);
double * create_weight_buffer_increase_lr(int w, int h);
double * create_weight_buffer_decrease_ud(int w, int h);
double * create_weight_buffer_increase_ud(int w, int h);
double * create_weight_buffer_decrease_tl(int w, int h);
double * create_weight_buffer_decrease_tr(int w, int h);
double * create_weight_buffer_decrease_bl(int w, int h);
double * create_weight_buffer_decrease_br(int w, int h);
int map_control_points(struct morph_point *m, int npoints, struct Image *img);
int draw_point(struct Image *img, int x, int y, unsigned int val);

//streamfilter.c
void init_streamfilter(void);
struct Image *CloneImage(struct Image *);
int do_StreamFilter(struct Image *img);

//rotate.c
int RotateImage(struct Image *img, double angle);

// fftutil.c
int fft_filter(struct Image *img, double lpf_r1, double lpf_r2, double lpf_p);
int fft_register_pad(struct Image *ref, struct Image *img, double lpf_r1, double lpf_r2, double lpf_p, int region, int *dx, int *dy);
int fft_register(struct Image *ref, struct Image *img, double lpf_r1, double lpf_r2, double lpf_p, int region, int *dx, int *dy);

// hotpixel.c
int do_DetectHotpixels(struct Image *img);
int WriteHotPixelFile(char *fname);

// font.c
int DrawString(struct Image *img, int y, int x, char *str, int flags);

//ftacompress.c
int _ftz_decode_frame(struct Image *img, char *buffer,int zbytes);

// switches.c
int LoadConfigFile(char *fname, char *sname, char **params, char **vals);
int SetVariable(char *str);
int Interact(void);

// darkframe.c
int LoadDarkFrameRef(char *name);
int SubtractDarkFrame(struct Image *img);
