/*  GtkExText	
* This is my first GtkWidget
*  GtkExText is Copyright (C) 1999 by:
* Mikael Hermansson <mikeh@bahnhof.se>
*
*  This program 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 2 of the License, or
*  (at your option) any later version.
*
*  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 Library General Public License for more details.
*
*  You should have received a copy of the GNU Library General Public License
*  along with this program; if not, write to the Free Software
*  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/

#ifndef GTK_EXTEXT_H__
#define GTK_EXTEXT_H__
#ifdef __cplusplus
extern "C" {
#endif

#include <gdk/gdk.h>
#include <gtk/gtkadjustment.h>
#include <gtk/gtkeditable.h>

#define WITH_REGEX

#ifdef WITH_REGEX
#include <sys/types.h>
#include <vdkb/regex.h>
#endif
 
#define GTK_TYPE_EXTEXT                  (gtk_extext_get_type ())
#define GTK_EXTEXT(obj)                  (GTK_CHECK_CAST ((obj), GTK_TYPE_EXTEXT, GtkExText))
#define GTK_EXTEXT_CLASS(klass)          (GTK_CHECK_CLASS_CAST ((klass), GTK_TYPE_EXTEXT, GtkExTextClass))
#define GTK_IS_EXTEXT(obj)               (GTK_CHECK_TYPE ((obj), GTK_TYPE_EXTEXT))
#define GTK_IS_EXTEXT_CLASS(klass)       (GTK_CHECK_CLASS_TYPE ((klass), GTK_TYPE_EXTEXT))

#define LINE_DATA_LENGTH(cur) cur->lineptr->length
#define LINE_DATA_USERDATA(cur) cur->lineptr->user_data
#define LINE_DATA_WIDTH(cur) cur->lineptr->width
#define LINE_DATA_HEIGHT(cur) cur->lineptr->height


#define PROPERTY_INSERT 0
#define PROPERTY_REMOVEALL 1
#define PROPERTY_MERGE 2

typedef struct _GtkExText GtkExText;
typedef struct _GtkExTextClass GtkExTextClass;

typedef struct _GtkExTextMatch {
  gint startpos;
  gint endpos;
} GtkExTextMatch;

/* GtkExTextStyle Setup font and bg/fg colors */
/* to use in textdocument */
#define STYLE_FONT 0x0001
#define STYLE_FG 0x0002
#define STYLE_BG 0x0004

typedef struct _GtkExTextStyle
{
	GdkFont *font;				/* font */
	GdkColor fg_color;    /* bg_color */
	GdkColor bg_color;   /* fg_color */

    gchar key[32];

      guint16 flags;
	gint rbearing;
	gint lbearing;
	gint ascent;
	gint descent;

}GtkExTextStyle;

/* Line struct */
/* holds all lines */
/* all lines ends with "\n" character */
typedef struct _Lines /* 20 bytes */
{
  guint16 length;
  guint16 flags;      /* unused at the moment */
  guint16 width;    
  guint16 height;

  gpointer user_data;   /* possible for the user to set */

  struct _Lines *next;
  struct _Lines *prev;
} Lines;

/* Property is used  to set a property mark in the textdoc*/
typedef struct _GtkExTextProperty
{
  guint startpos;				/* startpos from begining of text */ 
  guint endpos;		/* endpos from begining of text */

  /*User data */
  gpointer user_data;            
	
	/* private user should NOT change this */
  struct _GtkExTextProperty *next;
  struct _GtkExTextProperty *prev;

 /* pointer to GtkExTextStyle */
  GtkExTextStyle *style;

} GtkExTextProperty;

/* this is a wrapped and should be public for the user */
/* this calculates startpos and endpos */
/* and the return it to the user */
/* structure is READONLY for the user */
typedef struct _GtkExTextLineData
{
  /* in text startpos */
  gint startpos;

  /* in text endpos */
  gint endpos;

  /* the line number */
  gint line_number;

  /* first line property nearest backward  */
  GtkExTextProperty *property_first;

  /* the real lineptr */
  Lines *lineptr;

} GtkExTextLineData;

/* GtkExText UndoBuffert cache */
enum {	
  EXTEXT_UNDO_INSERT,	
  EXTEXT_UNDO_REMOVE
};	

typedef struct _UndoBuffert	{
 gint type;
  gint startpos;
  gint endpos;		
  guchar *buffert;
} UndoBuffert;

typedef struct _extext_cursor	{
  gboolean hide;
  gint offsetx;
  gint x;
  gint y;
  gint w;
  gint h;
} extext_cursor;

struct _GtkExText 
{
  GtkEditable editable;

  GdkWindow *text_area;
  GdkGC *gc;	
  GdkGC *gc_xor;	
  GdkGC *bg_gc;	
  GdkFont *font;
  GtkAdjustment *vadj;
  GtkAdjustment *hadj;
  GdkPixmap* line_wrap_bitmap;
  GdkPixmap* line_arrow_bitmap;

  guint timer;
  guint button;

	/* double buffering  */
  GdkDrawable *draw_area;

  gint freeze_count;

  /* size is how mush allocated text memory */
  gint size;

  /* length is how mush used text memory */
  gint length;
	
  gint gap_len;
  gint part1len;

	
  union {	GdkWChar *wc; guchar *ch;	} text;
  union {	GdkWChar *wc; guchar *ch;	} part2text;


  /* line_wrap */
	
  guint use_wchar : 1;
  guint line_wrap : 1;
  guint  word_wrap : 1;
  guint text_insert_delete_flag : 1;
  guint undo_flag : 1;

  /* this is set if widget is readonly */
  guint read_only : 1;


  gint line_max_chars;

  /* line cache coding see source for more info */	

  Lines * line_start;
  Lines * line_end;
  Lines *line_pos;

  gint line_count;

  /* first visible line */		
  /* number of visible lines  scroll_line_start + scroll_line_count = last visible line*/
  gint scroll_line_count;

  GtkExTextLineData *scroll_line_start;
  gint line_pos_index;
  gint line_cursor_index;

  extext_cursor cursor;
  gint cursor_timer;

	
  /* Undo coding */
  /*TODO cleanup undo code */
  GSList *undo_buffert;
  gint undo_max;
  gint undo_count;
  gint undo_last;

  /* Tabcode */
  /* TODO: fix brokenes */
  GList *tab_stops;
  gint default_tab_width;

  /* property handling */
   gint property_count;

  GtkExTextProperty  *property_start;	
  GtkExTextProperty  *property_end;	
  GtkExTextProperty *property_current;
 
  /* hash list with font/color styles */
 
 GHashTable *hash_styles;
};

struct _GtkExTextClass
{
  GtkEditableClass parent_class;

  /* SIGNAL CALLBACKS */
  void (*property_destroy)(GtkExText *text,GtkExTextProperty *prop);
  gint (*property_text_insert)(GtkExText *text,GtkExTextProperty *prop,gint startpos,gint endpos);
  gint (*property_text_remove)(GtkExText *text,GtkExTextProperty *prop,gint startpos,gint endpos);
  gint (*undo_changed)(GtkExText *text);	

  void  (*set_scroll_adjustments) (GtkExText       *text,
				   GtkAdjustment  *hadjustment,
				   GtkAdjustment  *vadjustment);


  /* Is called everytime cursor comes to a new property */
  void (*property_mark)(GtkExText *text,GtkExTextProperty *prop);

  /* line_[insert/remove] signal is sent when insert/delete a line */
  /* Use for example when you need to update line marks/breakpoints or similar */ 
  gint (*line_insert)(GtkExText *text, gint line_number);
  gint (*line_remove)(GtkExText *text, gint line_number);

	/* line_funcs */
  GtkExTextLineData *(*line_by_offset)(GtkExText *text,gint y, gint *newoffsety);
  gint (*column_by_offset)(GtkExText *text,GtkExTextLineData *data,gint x, gint *newoffsetx);
};


/* GtkWidget API */

GtkType gtk_extext_get_type();
GtkWidget *gtk_extext_new();

void gtk_extext_set_adjustments(GtkExText *text,GtkAdjustment *hadj,GtkAdjustment *vadj);

/* text API */

void gtk_extext_insert(GtkExText *text,const gchar *chars,gint len);
void gtk_extext_insert_with_style(GtkExText *text,
				const char *chars,gint len, gchar *stylekey, gpointer userdata);

gint gtk_extext_get_length(GtkExText *text);

/* Editable class Wrapper API */
#define gtk_extext_backward_delete(a,b) gtk_editable_delete_text(GTK_EDITABLE(a),gtk_editable_get_position(GTK_EDITABLE(a))-b,b)
#define gtk_extext_forward_delete(a,b) gtk_editable_delete_text(GTK_EDITABLE(a),gtk_editable_get_position(GTK_EDITABLE(a)),b)
#define gtk_extext_get_text(a,b,c)	gtk_editable_get_chars(GTK_EDITABLE(a),b,c);
#define gtk_extext_set_point(a,b)	gtk_editable_set_position(GTK_EDITABLE(a),b);
#define gtk_extext_get_point(a)	gtk_editable_get_position(GTK_EDITABLE(a));

guchar gtk_extext_get_char_at_pos(GtkExText *text,gint pos);

/* Line and column API */

GtkExTextLineData *gtk_extext_get_line_data(GtkExText *text,gint line,GtkExTextLineData *old);

gint gtk_extext_set_line(GtkExText *text,gint pos);
gint gtk_extext_get_line(GtkExText *text);

GtkExTextLineData * gtk_extext_get_first_visible_line(GtkExText *text);
GtkExTextLineData * gtk_extext_get_line_by_char_pos(GtkExText *text,gint pos);
GtkExTextLineData* gtk_extext_get_line_by_offset(GtkExText *text,gint y,gint *newoffsety);

void gtk_extext_set_line_userdata(GtkExText *text,gint line,gpointer userdata);

void gtk_extext_set_word_wrap(GtkExText *text,gboolean set);
void gtk_extext_set_line_wrap(GtkExText *text,gboolean set);
void gtk_extext_set_line_max_chars(GtkExText *text,gint col);

gint gtk_extext_set_column(GtkExText *text,gint col);
gint gtk_extext_get_column(GtkExText *text);
gint gtk_extext_get_column_by_offset(GtkExText *text,GtkExTextLineData *linedataptr,gint x,gint *newx);

void gtk_extext_set_position(GtkEditable *editable,gint pos);
gint gtk_extext_get_position(GtkEditable *editable);
gboolean gtk_extext_get_editable(GtkExText *text);

/* search routines */

gboolean gtk_extext_search(GtkExText *text,gchar *search,gint pos,gboolean iscase,gboolean forward,GtkExTextMatch *m);

/* Undo funcs */

void gtk_extext_undo_set_max(GtkExText *text,gint max);
gboolean gtk_extext_undo_is_empty(GtkExText *text);
gboolean gtk_extext_redo_is_empty(GtkExText *text);
void gtk_extext_undo_clear_all(GtkExText *text);
void gtk_extext_undo(GtkExText *text);
void gtk_extext_redo(GtkExText *text);

/* Style functions */

GtkExTextStyle* gtk_extext_style_insert(GtkExText *text,gchar *stylename,GdkFont *font,GdkColor *fg,GdkColor *bg);
GtkExTextStyle *gtk_extext_style_get(GtkExText *text,gchar *key);
void gtk_extext_style_remove(GtkExText *textclass,gchar *key);

/* Property functions */

GtkExTextProperty * gtk_extext_property_insert(GtkExText *text,gchar*key,gint startpos, gint endpos,gpointer data,gint typ,GtkExTextProperty *prev);
GtkExTextProperty * gtk_extext_property_remove(GtkExText *text,GtkExTextProperty *remove);
GtkExTextProperty *gtk_extext_property_get_at_pos(GtkExText *text,gint pos,GtkExTextProperty *cur);
GtkExTextProperty * gtk_extext_property_move_all(GtkExText *text,gint pos, gint diff,GtkExTextProperty *cur);
GtkExTextProperty * gtk_extext_property_remove_all(GtkExText *text,gint start, gint end,GtkExTextProperty *cur);
GtkExTextProperty * gtk_extext_property_nearest_forward(GtkExText *text,gint pos,GtkExTextProperty *cur);
GtkExTextProperty * gtk_extext_property_nearest_backward(GtkExText *text,gint pos,GtkExTextProperty *cur);
GtkExTextProperty *gtk_extext_property_get_current(GtkExText *text);

/* utils returns true if found and the startpos and endpos will be updated */
/* you must initiate the startpos with some value */
/* for example startpos=gtk_editable_get_current_position() */

gboolean gtk_extext_get_current_word(GtkExText *text,gint *startpos,gint *endpos);
gboolean gtk_extext_get_next_word(GtkExText *text,gint *startpos,gint *endpos);
gboolean gtk_extext_get_previous_word(GtkExText *text,gint *startpos,gint *endpos);

void gtk_extext_freeze(GtkExText *text);
void gtk_extext_thaw(GtkExText *text);

GtkType gtk_extext_get_type(void);

#define GTK_EXTEXT_INDEX(extext,index)	(index < extext->part1len ? \
		extext->text.ch[index] : extext->part2text.ch[index])  


#ifdef WITH_REGEX
/* Regex functions */
typedef struct _Regex {
  struct re_pattern_buffer buf;
  struct re_registers reg;
} Regex;
gint gtk_extext_regex_search(GtkExText *text,gint start,Regex *regex,gboolean forward,GtkExTextMatch *m);
gint gtk_extext_regex_match(GtkExText *text,gint pos,Regex *regex);
#endif
#ifdef __cplusplus
}
#endif

#endif
