/*
    This file is part of libtermui.

    libtermui is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    libtermui 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 libtermui.  If not, see <http://www.gnu.org/licenses/>.

    Copyright 2006, Alexandre Becoulet <alexandre.becoulet@free.fr>

*/

#ifndef TERMUI_TERM_H_
#define TERMUI_TERM_H_

#include <termui/types.h>
#include <termui/term_io.h>
#include <termui/termui_config.h>

/************************************************************************/
/* terminal methods */

/** @this specifies cursor move direction */
enum termui_term_direction_e
  {
    termui_term_dir_any,
    termui_term_dir_up,
    termui_term_dir_down,
    termui_term_dir_right,
    termui_term_dir_left
  };

/** @this specifies terminal character display attributes */
enum termui_term_attrib_e
  {
    /* base attributes */
    termui_term_attr_none		= 0,
    termui_term_attr_bright		= 1,
    termui_term_attr_under		= 4,
    termui_term_attr_blink		= 5,
    termui_term_attr_reverse		= 7,

    /* colors */
    termui_term_attr_black		= 30,
    termui_term_attr_red		= 31,
    termui_term_attr_green		= 32,
    termui_term_attr_yellow		= 33,
    termui_term_attr_blue		= 34,
    termui_term_attr_magenta		= 35,
    termui_term_attr_cyan		= 36,
    termui_term_attr_white		= 37,
  };

struct				termui_term_s;
struct				termui_term_behavior_s;

/** @multiple @this defines terminal methods prototypes */
#define	TERMUI_TERM_FCN_RESET(f)	\
  termui_err_t f(struct termui_term_s *tm)

#define TERMUI_TERM_FCN_GETSIZE(f)	\
  termui_err_t f(struct termui_term_s *tm, termui_cursor_pos_t *x, termui_cursor_pos_t *y)

#define	TERMUI_TERM_FCN_MOVE(f)	\
  termui_err_t f(struct termui_term_s *tm, enum termui_term_direction_e dir, termui_cursor_pos_t n)

#define	TERMUI_TERM_FCN_SETPOS(f)	\
  termui_err_t f(struct termui_term_s *tm, termui_cursor_pos_t x, termui_cursor_pos_t y)

#define	TERMUI_TERM_FCN_GETPOS(f)	\
  termui_err_t f(struct termui_term_s *tm, termui_cursor_pos_t *x, termui_cursor_pos_t *y)

#define TERMUI_TERM_FCN_ATTRIB(f)	\
  termui_err_t f(struct termui_term_s *tm, enum termui_term_attrib_e attr)

#define TERMUI_TERM_FCN_ERASE(f)	\
  termui_err_t f(struct termui_term_s *tm, enum termui_term_direction_e dir)

#define TERMUI_TERM_FCN_BEEP(f)	\
  termui_err_t f(struct termui_term_s *tm)

#define TERMUI_TERM_FCN_ERASELINE(f)	\
  termui_err_t f(struct termui_term_s *tm, enum termui_term_direction_e dir)

#define TERMUI_TERM_FCN_DELCHAR(f)	\
  termui_err_t f(struct termui_term_s *tm, termui_cursor_pos_t n)

#define TERMUI_TERM_FCN_INSSTR(f)	\
  termui_err_t f(struct termui_term_s *tm, const char * str, termui_strlen_t n)

#define TERMUI_TERM_FCN_WRITESTR(f)	\
  termui_err_t f(struct termui_term_s *tm, const char * str, termui_strlen_t n)

#define TERMUI_TERM_FCN_WRITECHAR(f)	\
  termui_err_t f(struct termui_term_s *tm, const char c, termui_cursor_pos_t n)

#define TERMUI_TERM_FCN_NEWLINE(f)	\
  termui_err_t f(struct termui_term_s *tm)

#define TERMUI_TERM_FCN_READKEY(f)	\
  termui_key_t f(struct termui_term_s *tm)

/** This function resets the terminal. @csee #TERMUI_TERM_FCN_RESET */
typedef	TERMUI_TERM_FCN_RESET(termui_term_reset_t);

/** This function gets the terminal size. @csee #TERMUI_TERM_FCN_GETSIZE */
typedef TERMUI_TERM_FCN_GETSIZE(termui_term_getsize_t);

/** This function moves the cursor in the given direction multiple
    times. @csee #TERMUI_TERM_FCN_MOVE */
typedef	TERMUI_TERM_FCN_MOVE(termui_term_move_t);

/** This function set the cursor position to specified
    coordinates. @csee #TERMUI_TERM_FCN_SETPOS */
typedef	TERMUI_TERM_FCN_SETPOS(termui_term_setpos_t);

/** This function get the current cursor position
    coordinates. @csee #TERMUI_TERM_FCN_GETPOS */
typedef	TERMUI_TERM_FCN_GETPOS(termui_term_getpos_t);

/** This function changes attributes used to write new
    characters. @csee #TERMUI_TERM_FCN_ATTRIB */
typedef TERMUI_TERM_FCN_ATTRIB(termui_term_attrib_t);

/** This function erase lines on the terminal.
    @csee #TERMUI_TERM_FCN_ERASE */
typedef TERMUI_TERM_FCN_ERASE(termui_term_erase_t);

/** This function request a bell signal emission. 
    @csee #TERMUI_TERM_FCN_BEEP */
typedef TERMUI_TERM_FCN_BEEP(termui_term_beep_t);

/** This function erase characters from current line.
    @csee #TERMUI_TERM_FCN_ERASELINE */
typedef TERMUI_TERM_FCN_ERASELINE(termui_term_eraseline_t);

/** This function deletes some characters at cursor position and shift
    remaining characters on the same line. @csee
    #TERMUI_TERM_FCN_DELCHAR */
typedef TERMUI_TERM_FCN_DELCHAR(termui_term_delchar_t);

/** This function inserts some characters at cursor position and shift
    trailing characters on the same line. @csee
    #TERMUI_TERM_FCN_INSSTR */
typedef TERMUI_TERM_FCN_INSSTR(termui_term_insstr_t);

/** This function overwrites characters at cursor position.
    @csee #TERMUI_TERM_FCN_INSSTR */
typedef TERMUI_TERM_FCN_WRITESTR(termui_term_writestr_t);

/** This function writes the same character multiple times overwriting
    characters at cursor position. @csee #TERMUI_TERM_FCN_INSSTR */
typedef TERMUI_TERM_FCN_WRITECHAR(termui_term_writechar_t);

/** This function requests a new line */
typedef TERMUI_TERM_FCN_NEWLINE(termui_term_newline_t);

/** This function reads the next incoming character from terminal */
typedef TERMUI_TERM_FCN_READKEY(termui_term_readkey_t);

/** @multiple @this is a shortcut to associated terminal method */
#define termui_term_reset(tm)          (tm)->t_reset    (tm)
#define termui_term_move(tm, ...)      (tm)->t_move     (tm, __VA_ARGS__)
#define termui_term_setpos(tm, ...)    (tm)->t_setpos   (tm, __VA_ARGS__)
#define termui_term_getpos(tm, ...)    (tm)->t_getpos   (tm, __VA_ARGS__)
#define termui_term_attrib(tm, ...)    (tm)->t_attrib   (tm, __VA_ARGS__)
#define termui_term_erase(tm, ...)     (tm)->t_erase    (tm, __VA_ARGS__)
#define termui_term_beep(tm)           (tm)->t_beep     (tm)
#define termui_term_eraseline(tm, ...) (tm)->t_eraseline(tm, __VA_ARGS__)
#define termui_term_delchar(tm, ...)   (tm)->t_delchar  (tm, __VA_ARGS__)
#define termui_term_insstr(tm, ...)    (tm)->t_insstr   (tm, __VA_ARGS__)
#define termui_term_writestr(tm, ...)  (tm)->t_writestr (tm, __VA_ARGS__)
#define termui_term_writechar(tm, ...) (tm)->t_writechar(tm, __VA_ARGS__)
#define termui_term_newline(tm)        (tm)->t_newline  (tm)
#define termui_term_readkey(tm)        (tm)->t_readkey  (tm)
TERMUI_TERM_FCN_GETSIZE(termui_term_getsize);

#define TERMUI_TYPESTR_MAXLEN	16

/** @internal */
struct termui_term_s
{
  /** @multiple terminal driver function */
  termui_term_reset_t		*t_reset; /* mandatory */
  termui_term_getsize_t		*t_getsize;
  termui_term_move_t		*t_move;
  termui_term_setpos_t		*t_setpos;
  termui_term_getpos_t		*t_getpos;
  termui_term_attrib_t		*t_attrib;
  termui_term_erase_t		*t_erase;
  termui_term_beep_t		*t_beep;  
  termui_term_eraseline_t	*t_eraseline;
  termui_term_delchar_t		*t_delchar;
  termui_term_insstr_t		*t_insstr;
  termui_term_writestr_t	*t_writestr; /* mandatory */
  termui_term_writechar_t	*t_writechar; /* mandatory */
  termui_term_newline_t		*t_newline; /* mandatory */
  termui_term_readkey_t		*t_readkey; /* mandatory */

  /** @multiple terminal io termio function */
  termui_termio_getsize_t	*s_getsize;
  termui_termio_gettype_t	*s_gettype;
  termui_termio_write_t		*s_write;
  termui_termio_read_t		*s_read;
  termui_termio_pollfd_t	*s_pollfd;
  termui_termio_cleanup_t	*s_cleanup;

  /** IO error flag */
  termui_err_t			ioerr;

  /** user private data */
  void				*priv;

  char				type[16];

  union {
#ifdef CONFIG_LIBTERMUI_FILEIO
    struct termui_term_fileio_s	io_file;
#endif

#ifdef CONFIG_LIBTERMUI_RAWFD
    struct termui_term_rawfd_s	io_rawfd;
#endif

#ifdef CONFIG_LIBTERMUI_TERMIOS
    struct termui_term_tty_s	io_tty;
#endif

#ifdef CONFIG_LIBTERMUI_TELNET
    struct termui_term_telnet_s	io_telnet;
#endif

#ifdef CONFIG_LIBTERMUI_LIBSSH
    struct termui_term_libssh_s	io_ssh;
#endif

    /* user defined termio private data */
    void			*io_pv;
  };
};

/** @this read a key from terminal and take action according to given behavior.
 @return error code or event function return value. */
termui_err_t termui_term_process(struct termui_term_behavior_s *bhv);

termui_ssize_t termui_term_printf(struct termui_term_s *tm, const char *fmt, ...);

termui_ssize_t termui_term_puts(struct termui_term_s *tm, const char *str);

/** @this returns a pollable fd to detect terminal activity */
static inline int32_t termui_io_pollfd(struct termui_term_s *tm)
{
  return tm->s_pollfd ? tm->s_pollfd(tm) : -1;
}

/** @this get term user private pointer */
static inline void *termui_term_get_private(struct termui_term_s *tm)
{
  return tm->priv;
}

/** @this set term user private pointer */
static inline void termui_term_set_private(struct termui_term_s *tm, void *pv)
{
  tm->priv = pv;
}

#endif

