#ifndef __MAQVIEW_RJ
#define __MAQVIEW_RJ
#ifdef __APPLE__
#include "GLUT/glut.h"
#else
#include <GL/gl.h>
#include <GL/glu.h>
#include "GL/glut.h"
#ifdef HAVE_FREEGLUT
#include "GL/freeglut_ext.h"
#endif
#endif
#include <unistd.h>
#include <sys/types.h>
#include <stdint.h>
#include "maqmap.h"
#include "zrio.h"
#include "maqmap_index.h"
#include "caches.h"

#define MAX_BASE_Q 30

/**
 * Stack
 */

typedef struct Stack {
	void **elements;
	int offset;
	int ptr;
	int capacity;
} Stack;

#define check_alloc(ptr) if(ptr == NULL){fprintf(stderr, "Cannot alloc memeory at %s line %d", __FILE__, __LINE__);exit(1);}

#define stack_init(stack, n) stack=(Stack*)malloc(sizeof(Stack));\
	check_alloc(stack);\
	(stack)->offset=0;\
	(stack)->ptr=0;\
	(stack)->capacity=n;\
	(stack)->elements=(void**)malloc(sizeof(void*)*(stack)->capacity);\
	check_alloc(stack->elements)
#define stack_free(stack) free((stack)->elements);free(stack)
#define stack_push(stack,e) if(((stack)->ptr + (stack)->offset) >= (stack)->capacity){\
		if((stack)->offset){\
			memmove((stack)->elements, (stack)->elements + (stack)->offset, (stack)->offset * sizeof(void*));\
			(stack)->offset = 0;\
		} else {\
			(stack)->capacity = (int)(((stack)->capacity)*1.5) + 1;\
			(stack)->elements=(void**)realloc((stack)->elements, sizeof(void*) * ((stack)->capacity));\
			check_alloc((stack)->elements);\
		}\
	}\
	(stack)->elements[(stack)->ptr++] = (void*)(e)
#define stack_pop(stack) ((stack)->elements[--(stack)->ptr + (stack)->offset])
#define stack_shift(stack, value) value = (stack)->element[(stack)->offset ++]; (stack)->ptr--
#define stack_unshift(stack, value) if((stack)->offset == 0){\
		if((stack)->ptr + 4 > (stack)->capacity){\
			(stack)->capacity = (stack)->ptr + 4;\
			(stack)->elements=(void**)realloc((stack)->elements, sizeof(void*) * ((stack)->capacity));\
			check_alloc((stack)->elements);\
			memmove((stack)->elements + 4, (stack)->elements, 4 * sizeof(void*));\
			(stack)->offset = 4;\
		}\
	}\
	(stack)->elements[--(stack)->offset] = value;\
	(stack)->ptr ++

#define stack_peer(stack,i) (stack)->elements[(stack)->offset + (stack)->ptr - (i)]
#define stack_get(stack, i) (stack)->elements[(stack)->offset + (i)]
#define stack_clear(stack) (stack)->ptr = 0
#define stack_size(stack) (stack->ptr)

#define stack_clone(stack, clone) stack_init(clone, stack_size(stack));\
	memcopy((clone)->elements, (stack)->elements, sizeof(void*) * stack_size(stack));\
	(clone)->ptr = (stack)->ptr

typedef struct RGBColor {
	float rgb[3];
} Color;

typedef struct Bounds {
	int x;
	int y;
	int w;
	int h;
} Bounds;

#define SELECT_TYPE_NAVIGATION	1
#define SELECT_TYPE_REFSEQ		2
#define SELECT_TYPE_READ		3

typedef struct SelectObject {
	int id_start;
	int id_end;
	void *ptr;
	int type;
	struct SelectObject *next;
} SelectObject;

typedef struct {
	int center_x;
	int center_y;
	int square_size;

	int arrow_x;
	int arrow_y;
	int arrow_size;

	int state; /* 0: not selected; 1: selected */

} Navigation;

struct View;

#define NOTIFY (*notify)(void *observer, struct View *src, int event, int64_t last_x, int off_y)

typedef struct {
	void **objects;
	void (**notify)(void *observer, struct View *src, int event, int64_t last_x, int off_y);
	int n_ob;
} Observer;

#define VIEW_MODE_CHARACTER	0
#define VIEW_MODE_SQUARE	1
#define VIEW_MODE_LINE		2

#define TOOLTIP_SIZE 4096

#define VIEW_EVENT_CLOSE		0
#define VIEW_EVENT_RESIZE		1
#define VIEW_EVENT_MOVE			2
#define VIEW_EVENT_GOTO			3
#define VIEW_EVENT_MARK_COL		4
#define VIEW_EVENT_MARK_REF		5
#define VIEW_EVENT_SELECT_READ	6

typedef struct View {
	char *map_file;
	char *cns_file;
	int width;
	int height;
	int style;

	float ch_width;  /* max characters in refer sequence are showed */
	Color *qual_color_table;
	Color *base_color_table;
	Color bgColor;
	Color default_color;
	Color ref_color;
	Color select_color;
	Color tip_color;
	Color nav_color;
	Color mismatch_color;
	Color line_forward_color;
	Color line_backward_color;

	void *font;
	void *big_font;
	float font_width;
	float font_height;
	float font_line_height;


	float base_width;
	float  base_margin;
	float base_height;
	float base_line_height;

	float line_width;
	float line_height;

	float scale_x;
	float scale_y;

	int mode;

	char default_ref_char;
	RefSeq refs;

	Navigation nav;

	int layer_offset;

	int last_x, last_y;
	int old_x, old_y;
	int state;

	int rolling;

	int step;

	int selecting;
	
	Observer *observer;
	
} View;

/**
 * Default style : 0
 */
View* createView(const char *map_file, const char *cns_file, int width, int height, int style);

void observeView(View *view, void *observer, void (*notify)(void *obj, View *src, int event, int64_t last_x, int off_y));

void removeObserverView(View *view, void *object);

void notifyView(View *view, int evt, int64_t x, int y);

int view_goto(View *view, int ref_id, int64_t pos);

int view_locate(View *view, char *ref_name, int64_t pos);

void view_resize(View *view, int width, int height);

View* view_clone(View *view);

void closeView(View *view);

#define MAX_LAYER 600

/* bit-wise flag for global_flag */

#define GF_HIDE_MAPQ  0x00000001u
#define GF_HIDE_BASEQ 0x00000002u
#define GF_IS_SINGLEQ 0x00000004u

#define VP_CMD_OPEN		1
#define VP_CMD_CMD		2

struct GList;

typedef struct ViewPanel {
	int parent_win_id;
	int win_id;
	int status_id;
	float off_x;
	float off_y;
	float width;
	float height;
	float status_width;
	float status_height;

	int64_t view_number;
	char view_string[120];
	int string_n;
	int string_f;

	char err_string[120];
	int err;

	char msg_string[120];
	int msg;

	int _x, _y, _x1, _x2, _y1, _y2; // Register

	int command;

	int show_help;

	int interval; //time for rolling

	View *view;

	u_int32_t global_flag;

	void (*resize)(struct ViewPanel *vp, int w, int h);
	void (*paint)(struct ViewPanel *vp);
	int (*pick)(struct ViewPanel *vp, float x, float y, float size, void (*handle)(struct ViewPanel *vp, SelectObject *obj, int id));
	void (*handle_left_pick)(struct ViewPanel *vp, SelectObject *obj, int id);
	void (*handle_right_pick)(struct ViewPanel *vp, SelectObject *obj, int id);
	void (*handle_mouse_over)(struct ViewPanel *vp, SelectObject *obj, int id);
	void (*paintStatusBar)(struct ViewPanel *vp);
	void (*timer)(struct ViewPanel *vp, int t);
	void (*mousePressed)(struct ViewPanel *vp, int button, int x, int y);
	void (*mouseReleased)(struct ViewPanel *vp, int button, int x, int y);
	void (*mouseDragged)(struct ViewPanel *vp, int x, int y);
	void (*mouseMoved)(struct ViewPanel *vp, int x, int y);
	void (*mouseWheel)(struct ViewPanel *vp, int wheel, int direction, int x, int y);
	void (*keyTyped)(struct ViewPanel *vp, unsigned char key, int x, int y);
	void (*specialKey)(struct ViewPanel *vp, int code, int x, int y);

	void (*synchronize)(void *observer, View *view, int event, int64_t last_x, int y);

	struct ViewPanel *owner;

	void **childs;
	int child_size;
	int child_capacity;

	struct GList* ref_menu;
} ViewPanel;

void drawString(float x, float y, char *str);

ViewPanel* createViewPanel(int pw_id, View *view, float off_x, float off_y, float width, float height);

int execute_cmd(ViewPanel *vp, char *cmd);

ViewPanel* addViewPanel(ViewPanel *owner, const char *map_file, const char *cns_file, int view_style);

void bindViewPanel(ViewPanel *self, int n);

void unbindViewPanel(ViewPanel *self, int n);

void removeViewPanel(ViewPanel *vp);

typedef void (*CHILD_REPAINT)(void *child);

void VP_addChild(ViewPanel *vp, void *child, CHILD_REPAINT repaint);

void* VP_removeChild(ViewPanel *vp, void *child);

#define WINDOW_TYPE_VIEWPANEL	1
#define WINDOW_TYPE_GLIST		2

extern void **vps;
extern int *vp_types;
extern int vps_size;

ViewPanel* getCurrentViewPanel();

ViewPanel* getViewPanel(int win_id);

void register_window(int win_id, void *obj, int win_type);

int getMaxWin_id();

void closeViewPanel(ViewPanel *vp);

void closeViewPanels();

#endif

