/*
 ******************************************************************************
 *
 *	ParcPlace Systems, Inc.
 *	Copyright (c) 1990, ParcPlace Systems, Inc. USA   All rights reserved.
 *
 ****************************************************************************
 *
 *	File:	plystr.H
 *
 *	Functions(s):
 *
 *	Description:
 *		OI_string class header
 *		OI_string is the implementation for all displayable text
 *		strings in the OI.  It allows multiple character set data,
 *		such as multi-lingual text, to be displayed in varying fonts
 *		with various types of emphasis: reverse video, underlined,
 *		etc.
 *
 *	RCSid = "$Id: plystr.H,v 4.7.1.1 1993/06/01 22:56:02 mth Exp $"
 *
 ****************************************************************************
 */

#ifndef OI_plystr_H
#define OI_plystr_H

#ifdef ultrix
#include <stdlib.h>		/* for malloc() and free() */
#endif

#ifndef OI_font_H
#include <OI/font.H>
#endif /* OI_font_H */

	class OI_d_tech;
	class OI_string;

// OI_char needs to be a class with conversion and comparison operations, etc.
	typedef	XChar2b		OI_char;

// The OI_tabstops information is used to determine how to handle tab chars in the text.
	class	OI_tabstops {	/* tab stop information */
	public:
		OI_number	*ht;		// ptr to vector of tabstop settings, values in range: inc_ht to (inc_ht * mx_ht)
		OI_number	mx_ht;		// maximum # of tabstops in ht
		OI_number	inc_ht;		// default increment between tabstops, # chars
		OI_bool		cstm;		// OI_YES => ht is vector of custom tabstops
	public:
				OI_tabstops()	{ht = NULL; mx_ht = 0; inc_ht = 0; cstm = OI_NO; }
				~OI_tabstops() ;
		void		set_regular(OI_number max_ch, OI_number inc);
		void		set_custom(OI_number *tab, OI_number n_tab, OI_number inc);
		OI_number*	extend_stops();
	};

// The OI_enhance_info class is used to determine how to handle font and foreground/background enhancements.
	class OI_enhance_info {	// extended enhancement information
		PIXEL		fg_pxl;
		PIXEL		bg_pxl;
		OI_charset	chrset;		/* charset of font */
		OI_font		*fntp;
	public:
				OI_enhance_info()	{ fg_pxl = bg_pxl = OI_UNKNOWN_PIXEL; fntp = NULL;  chrset = OI_charset_none; }
				OI_enhance_info(OI_enhance_info*);
				~OI_enhance_info();
		PIXEL		bg_pixel()		{ return(bg_pxl); }
		OI_charset	char_set()		{ return(chrset); }
		PIXEL		fg_pixel()		{ return(fg_pxl); }
		OI_font		*font()			{ return(fntp); }
		void		set_bg_pixel(PIXEL p)	{ bg_pxl = p; }
		void		set_fg_pixel(PIXEL p)	{ fg_pxl = p; }
		void		set_font(OI_charset c, OI_font *fntp) ;
	};

// An OI_str_segment is composed of characters all in:
//	1) a single character set,
//	2) the same emphasis,
//	3) the same font.
//
// It contains enough information to display the characters
// in the desired character set with the desired emphasis
// and in the specified font (with varying size/face/slant/etc.).
//
// Each segment is double linked for ease of inserting and deleting
// other segments; also for splitting and merging segments.

#define OI_SEG_MEMORY		(1 << 0)		/* true if chars ptr is to malloced memory */
#define OI_SEG_TAB		(1 << 1)		/* true if segment is a tab char */

	class	OI_str_segment {
	private:
		OI_str_segment	*nextp;							// pointer to next segment in chain
		OI_str_segment	*prevp;							// pointer to previous segment in chain
		OI_char		*chars;							// pointer to wide-character string
		OI_number	maxchars;						// maximum number of chars in this segment
		OI_number	nchars;							// current number of chars in this segment
		OI_charset	chrset;							// character set for this segment
		OI_enhance	enhc;							// enhancement for this segment
		OI_font_list	*flistp;						// ptr to font info to paint this segment
		OI_tabstops	*tabs;							// pointer to tab stops info
		OI_number	pwidth;							// pixel width of this segment -- optimization
		OI_number	dsp_col;						// display column (tabs expanded) where this segment begins
		OI_number	dsp_pix;						// display pixel (tabs expanded) where this segment begins
		OI_number	dsp_len;						// display length (tabs expanded) of this segment
		unsigned short 	flags;							// bits give information about the segment
		OI_enhance_info	*enh_info;						// extended enhancement information for fg/bg, etc.

	private:
		void		init() ;
	public:
		// constructor & destructor
				OI_str_segment();
				OI_str_segment(int nchs);
				OI_str_segment(OI_bool copy_chars, OI_char *chp, int nchs, OI_charset chset, OI_font_bounds *fntbndp, OI_tabstops *tabp);
				~OI_str_segment();
		void		delete_all();							// delete all segments in the chain

		void		dump();								// Dump the contents of the class

		// list maintenance functions
		OI_str_segment	*insert_seg(OI_str_segment *seg);				// insert the segment before seg
		OI_str_segment	*append_seg(OI_str_segment *seg);				// append the segment after seg
		void		remove_seg();							// remove the segment from the chain
		void		delete_seg()	{ remove_seg(); delete this; }			// remove the segment from the chain and delete it
		void		join_seg(OI_str_segment *seg);					// join the following segment with this one
		OI_str_segment	*split_seg(OI_number pos);					// split the segment into two segments at pos
		void		insert_chain(OI_str_segment *seg);				// insert the chain of segments before seg
		void		append_chain(OI_str_segment *seg);				// append the chain of segments after seg

		// list query functions
 		OI_number	which_char(int offset);						// determine which char the (x) offset lies within
		OI_bool		match(OI_str_segment*);						// Check if two segments match

		// misc segment functions
		OI_str_segment	*check_join(OI_str_segment *prev, OI_str_segment *next);	// check possibility of joining segment with neighbor(s)
		OI_str_segment	*clone_seg(OI_str_segment *seg, OI_font_bounds *fbp, OI_tabstops *tabp);
						// make a cloned copy of seg
		OI_str_segment	*copy_seg(OI_str_segment *seg, OI_number pos, OI_number nch);	// copy nchs of srcp starting at pos to the OI_str_segment
		void		reset_seg(OI_bool copy_chars, OI_char *chp, int nchs, OI_charset chset, OI_enhance enhance,
						OI_font_bounds *fntbndp, OI_tabstops *tabp);
						// overwrite the values of the segment
		void		resize_seg(int nchs);						// resize the length of the segment
		void		set_unused();							// set the segment to an initial state
		void		trunc_seg(OI_number pos);					// truncate the segment after pos
		void		update_font_list(OI_font_bounds *fbp);

		// text metric functions
		void		text_extents(int *font_ascent, int *font_descent, XCharStruct *overall);
						// return the bounding box of this segment
		int		text_width(OI_number pos, OI_number nch);			// return the pixel width of this (sub)segment
		int		set_text_width(OI_number *colp, OI_number pix);			// set the pixel width of this segment

		// drawing functions
		void		draw_segment(int ht, Window win, OI_d_tech *dtp, int x, int y, OI_number pos = 0, OI_number nch = -1,
					OI_bool en_enhance = OI_YES);
						// draw the segment text on a given drawable

		// character functions
		void		copy_chars(OI_number pos, OI_number len, const OI_char *chp);
		void		delete_chars(OI_number pos, OI_number nch);
		void		move_chars(OI_number pos, OI_number len, OI_number nch);
		void		replace_chars(OI_number pos, OI_number nch, OI_char *charp, OI_charset chset, OI_font_bounds *fbndp);
		OI_bool		find_chars(OI_number *posp, OI_number nch, const OI_str_segment *srcp, OI_bool reverse);

		// enhancement functions
		void		clear_enhance();
		OI_str_segment	*chg_enhance(OI_string *strp, OI_bool is_set, OI_number pos, OI_number len, OI_enhance enhance, PIXEL fg, PIXEL bg,
					OI_font *fntp);

		// font interface functions
		OI_number	font_base()	{ return (flistp->font()->y_reference()); }	// baseline of this segment
		OI_number	font_ascent()	{ return (flistp->font()->ascent()); }		// pixel ascent of this segment
		OI_number	font_descent()	{ return (flistp->font()->descent()); }		// pixel descent of this segment

		// interface functions
		OI_str_segment	*next()		{ return (nextp); }				// pointer to next segment
		OI_str_segment	*prev()		{ return (prevp); }				// pointer to previous segment
		PIXEL		bg_pixel()	{ return (enhc & OI_enhance_background ? enh_info->bg_pixel() : OI_UNKNOWN_PIXEL); }
						// background pixel of the segment
		OI_charset	charset()	{ return (chrset); }				// charset of the segment
		OI_enhance	enhance()	{ return (enhc); }				// enhancement of the segment
		OI_number	dsp_column()	{ return (dsp_col); }				// display column of the segment
		OI_number	dsp_length()	{ return (dsp_len); }				// number of display characters in the segment
		OI_font		*enh_font()	{ return (enhc & OI_enhance_font_change ? enh_info->font() : NULL); }
						// enhancement font of the segment
		PIXEL		fg_pixel()	{ return (enhc & OI_enhance_foreground ? enh_info->fg_pixel() : OI_UNKNOWN_PIXEL); }
						// foreground pixel of the segment
		OI_font_list	*font_list()	{ return (flistp); }				// pointer to the font list for this segment
		char		*font_name()	{ return (flistp->font()->font_name()); }	// name of the font for this segment
		OI_bool		has_memory()	{ return ((OI_bool)((flags & OI_SEG_MEMORY) != 0)); }
						// OI_YES if segment has ptr to malloced memory
		OI_bool		has_tab()	{ return ((OI_bool)((flags & OI_SEG_TAB) != 0)); }	// OI_YES if is a tab segment
		OI_number	length()	{ return (nchars); }				// number of characters in the segment
		OI_number	max_length()	{ return (maxchars); }				// maximum number of characters in the segment
		OI_font		*oi_font()	{ return (flistp->font()); }			// OI_font info for this segment
		OI_tabstops	*tabstops()	{ return (tabs); }				// pointer to the tabstops in the segment
		OI_number	width()		{ return (pwidth); }				// width (in pixels) of the characters in the segment
		OI_char		*w_chars()	{ return (chars); }				// pointer to the characters in the segment
		XFontStruct	*x_font()	{ return (flistp->font()->font()); }		// X font info for this segment
		// action interface functions
		void		reset_has_memory()	{ flags &= ~OI_SEG_MEMORY; }		// reset the malloced memory flag
		void		reset_has_tab()		{ flags &= ~OI_SEG_TAB; }		// reset the tab segment flag
		void		set_has_memory()	{ flags |= OI_SEG_MEMORY; }		// set the malloced memory flag
		void		set_has_tab()	{ flags |= OI_SEG_TAB; }			// set the tab segment flag
		void		set_length(int len)	{ nchars = len; }			// set the length of the segment
		void		set_max_length(int len)	{ maxchars = len; }			// set the maximum length of the segment
		void		set_next(OI_str_segment *next)	{ nextp = next; }		// set the next field of the segment
		void		set_prev(OI_str_segment *prev)	{ prevp = prev; }		// set the prev field of the segment
		void		set_tabstops(OI_tabstops *tabp)	{ tabs = tabp; }		// set the tabs field of the segment
		void		set_w_chars(OI_char *chp)	{ chars = chp; }		// set the char pointer of the segment
		void		set_font_list(OI_font_list *fp)	{ flistp = fp; }
	};

// An OI_string is composed one or more segments,
// where each segment differs from the previous/next in either:
//	a) character set encoding,
//	b) enhancement,
//	c) font,
//	d) tabs are also a segment because of special handling needed.
//
// The general approach to the member functions is that they iterate thru
// the list of segments calling the segment member functions to do the actual work.
// 
// This class needs to call the Compound Text, EUC, etc. encoding and decoding functions.

#define OI_STRING_DISABLE_ENHANCEMENTS	0x01	/* 1 -> don't paint enhancements */

	class	OI_string {
	private:
		OI_str_segment	*segments;	// pointer to first segment
		OI_number	nchars;		// current number of characters in all segments
		OI_number	maxchars;	// maximum number of characters in all segments
		OI_font_bounds	*fontbnds;	// pointer to font bounds info
		OI_tabstops	*tabs;		// pointer to tab stops info
		OI_number	pwidth;		// total width of all segments, pixels
		OI_number	dsp_len;	// display length (tabs expanded) of all segment
		unsigned short 	flags;		// bits give information about the string

	private:
		void		paint_text(Bool as_image, Window win, OI_d_tech *dtp, int x, int y, OI_number pos, OI_number nch);
						// draw the text on a given drawable
		void		char_resize();	// recompute size due to char changes
		void		chg_enhance(OI_bool is_set, OI_number pos, OI_number len, OI_enhance enhance, PIXEL fg, PIXEL bg,
					const char *fontname);
		OI_bool		find_chars_forward(OI_number *posp, OI_string *strp);
		OI_bool		find_chars_reverse(OI_number *posp, OI_string *strp);

	public:
		// constructors & destructor
				OI_string(const char *etext, OI_font_bounds *fbp, OI_tabstops *tabp=NULL,
						OI_char_encode_type enctyp=OI_char_encode_ctxt);
						// Make an OI_string from an encoded string
				OI_string(int nchs, OI_font_bounds *fbp, OI_tabstops *tabp=NULL);
						// Make an OI_string with reserved space
				OI_string(int nchs, const char *etext, OI_font_bounds *fbp, OI_tabstops *tabp=NULL,
						OI_char_encode_type enctyp=OI_char_encode_ctxt);
						// Make an OI_string from an encoded string with reserved space
				~OI_string();

		// utility functions
		static	OI_bool	convert_text(OI_string **strp, char **cachep, const char *etext, OI_char_encode_type enctyp,
						OI_font_bounds *fbp, OI_tabstops *tabp);
						// Utility function to aid converting encoded text to OI_string
 		static	char	*get_text(/* REB const */ OI_string *strp, char **cachep, OI_char_encode_type enctyp);
						// Utility function to aid getting encoded text from OI_string
		static	OI_bool	force_match(OI_string **strp, OI_string *matchp);
						// Utility function to force 1st string to match 2nd, even if 2nd is NULL

		// clone functions
		OI_string	*clone() const	{return (clone(fontbnds, tabs));}		// return a cloned copy of the OI_string
		OI_string	*clone(OI_font_bounds *fbp, OI_tabstops *tabp) const;		// make a clone copy using fbp and tabp

		// misc functions
		void		dump();								// Dump the contents of the class
		void		copy(OI_string *srcp, OI_number pos, OI_number nch);		// copy nchs of srcp starting at pos to the OI_string
		void		fill(const char *etext, OI_char_encode_type enctyp);		// fill an existing OI_string from the encoded string
		OI_bool		match(OI_string *tptp);						// OI_yes if this string matches template passed
		void		truncate(OI_number pos);					// truncate the string after pos

	 	OI_str_segment	*which_seg(OI_number *pos, int *offset = NULL);			// determine which segment `pos' is in

		void		font_resize();							// recompute size due to font changes

		// text metric functions
		int		text_width(OI_number pos, OI_number nch);			// get the width of the poly string
		void		text_extents(int *max_ascent, int *max_descent, XCharStruct *overall);
						// get the bounding box of the poly string

		// drawing functions
		void		draw_text(Window win, OI_d_tech *dtp, int x, int y, OI_number pos = 0, OI_number nch = -1)
						{paint_text(False, win,dtp,x,y,pos,nch);}
						// draw the text on a given drawable
		void		draw_text(OI_d_tech *dtp, int x, int y, OI_number pos = 0, OI_number nch = -1) ;
		void		draw_image_text(Window win, OI_d_tech *dtp, int x, int y, OI_number pos = 0, OI_number nch = -1)
						{paint_text(True, win,dtp,x,y,pos,nch);}
						// draw the image text on a given drawable
		void		draw_image_text(OI_d_tech *dtp, int x, int y, OI_number pos = 0, OI_number nch = -1) ;

		// character functions
		void		insert_chars(OI_number pos, OI_number nch, const char *charp, OI_charset charset = OI_charset_latin1);
		void		insert_chars(OI_number pos, OI_number nch, const OI_char *charp, OI_charset charset = OI_charset_latin1);
		void		insert_chars(OI_number pos, OI_string *strp, OI_number psn, OI_number nch);
		void		replace_chars(OI_number pos, OI_number nch, const char *charp, OI_charset charset = OI_charset_latin1);
		void		replace_chars(OI_number pos, OI_number nch, const OI_char *charp, OI_charset charset = OI_charset_latin1);
		void		replace_chars(OI_number pos, OI_number nch, const OI_string *strp);
		void		delete_chars(OI_number pos, OI_number nch);
		void		append_chars(OI_number nch, OI_char *charp, OI_charset charset, OI_enhance enhance);

		// encoded character functions
		OI_number	insert_encoded_chars(OI_number pos, OI_number *nchp, const char *strp, OI_char_encode_type enctyp);
		OI_number	replace_encoded_chars(OI_number pos, OI_number *nchp, const char *strp, OI_char_encode_type enctyp);
		OI_bool		find_chars(OI_number *posp, OI_string *strp, OI_bool reverse = OI_NO);

		// enhancement functions
		void		clear_enhance();
		void		disable_enhancements()		{ flags |= OI_STRING_DISABLE_ENHANCEMENTS; }
		void		enable_enhancements()		{ flags &= ~OI_STRING_DISABLE_ENHANCEMENTS; }
		OI_bool		enhancements_enabled()		{ return ((OI_bool)(flags&OI_STRING_DISABLE_ENHANCEMENTS)?OI_NO:OI_YES); }
		void		remove_enhance(OI_number pos, OI_number len, OI_enhance enhance)
						{chg_enhance(OI_NO, pos, len, enhance, OI_UNKNOWN_PIXEL, OI_UNKNOWN_PIXEL, NULL);}
		void		set_enhance(OI_number pos, OI_number len, OI_enhance enhance, PIXEL fg=OI_UNKNOWN_PIXEL, PIXEL bg=OI_UNKNOWN_PIXEL,
					const char *fontname=NULL)
						{chg_enhance(OI_YES, pos, len, enhance, fg, bg, fontname);}

		// text retrieval functions
		char		*text(OI_number pos, OI_number *lenp);				// returns the plain (sub)string
		char		*encoded_text(OI_number pos, OI_number *lenp, OI_char_encode_type enctyp);
						// returns the encoded (sub)string
		char		*save_encoded_text(char **savp, OI_number pos, OI_number *lenp, OI_char_encode_type enctyp);
						// returns the encoded (sub)string and saves a copy also
		char		*compound_text(OI_number pos, OI_number *lenp);
						// returns the "Compound Text" encoded (sub)string
		char		*save_compound_text(char **savp, OI_number pos, OI_number *lenp);
						// returns the "Compound Text" encoded (sub)string and saves a copy also

		// utility functions
		OI_number	font_ascent()	{ return (fontbnds->ascent()); }		// maximum ascent (in pixels) in the string
		OI_number	font_descent()	{ return (fontbnds->descent()); }		// maximum descent (in pixels) in the string
		OI_number	font_height()	{ return (fontbnds->ascent()+fontbnds->descent()); }	// maximum height (in pixels) in the string
		OI_number	font_width()	{ return (fontbnds->width()); }			// maximum character width (in pixels) in the string
		OI_number	font_y_base()	{ return (fontbnds->y_reference()); }		// baseline (in pixels) of the string

		OI_number	dsp_length()	{ return (dsp_len); }				// the number of display characters in the string
		OI_number	length()	{ return (nchars); }				// number of characters in the string
		OI_number	max_length()	{ return (maxchars); }				// maximum number of characters in the string
		OI_number	width()		{ return (pwidth); }				// the width (in pixels) of the string

		OI_charset	charset(OI_number pos);						// charset of the character at pos
		int		ctxt_length(OI_number pos = 0, OI_number len = -1);		// number bytes in compound text encoding of string
		OI_enhance	enhance(OI_number pos);						// the enhancement of the character at pos
		XFontStruct	*font(OI_number pos);						// font used to paint the character at pos
		char		*font_name(OI_number pos);					// name of font used to paint the character at pos
		OI_font		*oi_font(OI_number pos);					// OI_font used to paint the character at pos

 		OI_number	which_char(int offset);						// determine which char the (x) offset lies within

		OI_bool		has_tab();							// OI_YES if has a tab segment
		OI_bool		is_tab(OI_number pos);						// is char at pos an ASCII tab?
		OI_bool		is_white(OI_number pos);					// is char at pos a white space character?
		OI_bool		get_char_info(OI_number pos, OI_char *chp, OI_charset *csp, OI_enhance *ep);
						// return info about the char at pos
		void		set_font_bounds(OI_font_bounds *tabp);				// set font bounds of the string
		void		consolidate_font_bounds();
		OI_font_bounds	*font_bounds()	{ return (fontbnds); }				// return the font bounds of the string
		void		set_tabstops(OI_tabstops *tabp);				// set the tabstops of the string
		OI_tabstops	*tabstops()	{ return (tabs); }				// return the tabstops of the string
	};

	extern "C" {
		void		dump_OI_str_segment(OI_str_segment *segp);
		void		dump_OI_string(OI_string *strp);
	}

#endif /* OI_plystr_H */
