/* Copyright (C) 2013 G.P. Halkes
   This program is free software: you can redistribute it and/or modify
   it under the terms of the GNU General Public License version 3, as
   published by the Free Software Foundation.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef WINDOW_H
#define WINDOW_H

/** @defgroup t3window_win Window manipulation functions. */

#include <stdlib.h>
#include <limits.h>
#include <stdint.h>
#include "common.h"

/** @typedef attr_t
    @brief Type to hold attributes used for terminal display.

    The value of a ::attr_t should be a bitwise or of ATTR_* attribute values. When the
    terminal only supports setting colors by color pair, the ::ATTR_FG macro can be used to
    specify the color pair to activate.
*/
#if INT_MAX < 2147483647L
typedef long attr_t;
#else
typedef int attr_t;
#endif

/** @name Attributes */
/*@{*/
/** Draw characters with invisibility. */
#define ATTR_INVISIBLE ((attr_t) (1L << 0))
/** Draw characters with underlining. */
#define ATTR_UNDERLINE ((attr_t) (1L << 1))
/** Draw characters with bold face/bright appearance. */
#define ATTR_BOLD ((attr_t) (1L << 2))
/** Draw characters with reverse video. */
#define ATTR_REVERSE ((attr_t) (1L << 3))
/** Draw characters blinking. */
#define ATTR_BLINK ((attr_t) (1L << 4))
/** Draw characters with dim appearance. */
#define ATTR_DIM ((attr_t) (1L << 5))
/** Draw characters with alternate character set (for line drawing etc). */
#define ATTR_ACS ((attr_t) (1L << 6))
/** Draw characters with stand-out. */
#define ATTR_STAND_OUT ((attr_t) (1L << 7))

/** Bit number of the least significant color attribute bit. */
#define ATTR_COLOR_SHIFT 8
/** Convert a color number to a foreground color attribute. */
#define ATTR_FG(x) (((((attr_t) (x)) & 0xff) + 1) << ATTR_COLOR_SHIFT)
/** Convert a color number to a background color attribute. */
#define ATTR_BG(x) (((((attr_t) (x)) & 0xff) + 1) << (ATTR_COLOR_SHIFT + 9))
/** Bitmask to leave only the foreground color in a ::attr_t value. */
#define ATTR_FG_MASK (0x1ff << ATTR_COLOR_SHIFT)
/** Bitmask to leave only the background color in a ::attr_t value. */
#define ATTR_BG_MASK (0x1ff << (ATTR_COLOR_SHIFT + 9))

/** Foreground color unspecified. */
#define ATTR_FG_DEFAULT ((attr_t) 0L)
/** Foreground color black. */
#define ATTR_FG_BLACK ATTR_FG(0)
/** Foreground color red. */
#define ATTR_FG_RED ATTR_FG(1)
/** Foreground color green. */
#define ATTR_FG_GREEN ATTR_FG(2)
/** Foreground color yellow. */
#define ATTR_FG_YELLOW ATTR_FG(3)
/** Foreground color blue. */
#define ATTR_FG_BLUE ATTR_FG(4)
/** Foreground color magenta. */
#define ATTR_FG_MAGENTA ATTR_FG(5)
/** Foreground color cyan. */
#define ATTR_FG_CYAN ATTR_FG(6)
/** Foreground color white. */
#define ATTR_FG_WHITE ATTR_FG(7)

/** Background color unspecified. */
#define ATTR_BG_DEFAULT ((attr_t) 0L)
/** Background color black. */
#define ATTR_BG_BLACK ATTR_BG(0)
/** Background color red. */
#define ATTR_BG_RED ATTR_BG(1)
/** Background color green. */
#define ATTR_BG_GREEN ATTR_BG(2)
/** Background color yellow. */
#define ATTR_BG_YELLOW ATTR_BG(3)
/** Background color blue. */
#define ATTR_BG_BLUE ATTR_BG(4)
/** Background color magenta. */
#define ATTR_BG_MAGENTA ATTR_BG(5)
/** Background color cyan. */
#define ATTR_BG_CYAN ATTR_BG(6)
/** Background color white. */
#define ATTR_BG_WHITE ATTR_BG(7)
/*@}*/

#define ERR_SUCCESS 0
#define ERR_OUT_OF_MEMORY -1
#define ERR_NONPRINT -2
#define ERR_ERRNO -3

/** Category mask for libunistring's @c uc_is_general_category_withtable for
    finding control characters. */
#define UTF8_CONTROL_MASK (UC_CATEGORY_MASK_Cs | UC_CATEGORY_MASK_Cf | UC_CATEGORY_MASK_Co | \
	UC_CATEGORY_MASK_Cc | UC_CATEGORY_MASK_Zl | UC_CATEGORY_MASK_Zp)

#define WIDTH_TO_META(_w) (((_w) & 3) << CHAR_BIT)

#define WIDTH_MASK (3 << CHAR_BIT)
#define META_MASK (~((1 << CHAR_BIT) - 1))

#define BASIC_ATTRS (T3_ATTR_UNDERLINE | T3_ATTR_BOLD | T3_ATTR_REVERSE | T3_ATTR_BLINK | T3_ATTR_DIM | T3_ATTR_ACS)

#define INITIAL_ALLOC 80

#define _BLOCK_SIZE_TO_WIDTH(x) ((int)((x & 1) + 1))

typedef struct {
	char *data; /* Data bytes. */
	int width; /* Width in cells of the the data. */
	int length; /* Length in bytes. */
	int allocated; /* Allocated number of bytes. */
} line_data_t;

typedef enum {
	CURSOR_NORM,
	CURSOR_INVIS,
	CURSOR_VVIS
} cursor_t;

typedef struct {
	int paint_x, paint_y; /* Drawing cursor */
	int width, height; /* Height and width of the t3_window_t */
	attr_t default_attrs; /* Default attributes to be combined with drawing attributes.
	                           Mostly useful for background specification. */
	line_data_t *lines; /* The contents of the t3_window_t. */

	int saved_cursor_x, saved_cursor_y;
	int cached_pos_line;
	int cached_pos;
	int cached_pos_width;
	cursor_t cursor_state;
	td_bool cup_active;

	/* Abuse the line_data_t data structure to create an output buffer. It would be
	   nicer to have it as a separate type, but this prevents us from having to
	   duplicate code. */
	line_data_t output_buffer;
} window_t;

extern td_bool win_bce;

td_bool ensure_space(line_data_t *line, size_t n);

void init_attr_map(void);
void free_attr_map(void);

window_t *win_new(int height, int width);
window_t *win_copy(window_t *win);
void win_del(window_t *win);

attr_t get_attr(int idx);
uint32_t get_value(const char *str, size_t *bytes);
td_bool win_resize(window_t *win, int height, int width);
void win_set_paint(window_t *win, int y, int x);
int win_get_paint_x(window_t *win);
int win_get_paint_y(window_t *win);
int win_get_height(window_t *win);
int win_get_width(window_t *win);
td_bool win_compare(window_t *winA, window_t *winB, FILE *descr_out);
void win_scroll(window_t *win);
void win_scroll_back(window_t *win);

void win_set_default_attrs(window_t *win, attr_t attrs);
attr_t win_get_default_attrs(window_t *win);
int win_addnstr(window_t *win, const char *str, size_t n);
void win_clrtoeol(window_t *win);
void win_clrtobol(window_t *win);
void win_clrtobot(window_t *win);
void win_clrtotop(window_t *win);

void win_set_cursor(window_t *win, cursor_t cursor_state);

void win_save_cursor(window_t *win);
void win_restore_cursor(window_t *win);

void win_set_cup(window_t *win, td_bool cup_active);
td_bool win_get_cup(window_t *win);

/*============= in write_image.c =============*/
#ifdef HAVE_CAIRO
void win_write_image(window_t *winA, window_t *winB, const char *name);
extern int cell_width, cell_height;
extern const char *option_font;
#endif
#endif
