// utf-8

/*	Copyright  (c)	Günter Woigk   2001-2003
  					mailto:kio@little-bat.de

	This file is free software

 	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.  

 	Permission to use, copy, modify, distribute, and sell this software and
 	its documentation for any purpose is hereby granted without fee, provided
 	that the above copyright notice appear in all copies and that both that
 	copyright notice and this permission notice appear in supporting
 	documentation, and that the name of the copyright holder not be used
 	in advertising or publicity pertaining to distribution of the software
 	without specific, written prior permission.  The copyright holder makes no
 	representations about the suitability of this software for any purpose.
 	It is provided "as is" without express or implied warranty.

 	THE COPYRIGHT HOLDER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
 	INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
 	EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY SPECIAL, INDIRECT OR
 	CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
 	DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
 	TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 	PERFORMANCE OF THIS SOFTWARE.


    ----------------------------------------------------------------------------

			class Var

    ----------------------------------------------------------------------------
*/


#ifndef _var_h_
#define _var_h_


#include	"ustring/sstring.h"



class   Var;
typedef Var const	cVar;
typedef	Var*		VarPtr;
typedef	cVar*		cVarPtr;

class	Vek;
typedef Vek const	cVek;



/* ----	undef defines from "Menues.h" ----
*/
#ifdef SetItem
#undef SetItem
#endif

#ifdef GetItem
#undef GetItem
#endif

#ifdef setitem
#undef setitem
#endif


/* ----	enum for Var::type ----------------------------
*/
enum vtype			// variable type & security
{
					isNumber = 28762887,// float number
					isText, 			// text string
					isList, 			// 1-dim array / list ((elements may be arrays))
					isProc 				// subroutine
};



/* ----	Struct Vek -----------------------------------------------
		array==0 && size=used=0			=> leerer vektor
		array!=0 && used<=size			=> dynamisch angelegter vektor
		array!=0 && used!=0 && size==0	=> subslice aus anderem vektor
*/
struct Vek
{
	Var**			array;				// array of Vars
	uint			size;				// allocated size (items)
	uint			used;				// used items (VScript: Size)

					Vek();				// prohibit!
					~Vek();				// prohibit!
					Vek(cVek&);			// prohibit!
	Vek&			operator=(cVek&);	// prohibit!
};




/* ====	variables class ================================
*/
class Var
{
	vtype			type;								// variable type & security
	Var*			parent;								// parent list or NULL
	uint			index;								// own index in parent's list
	String			name;								// variable's name

	long			data[sizeof(String)/sizeof(long)];	// variable data
	double&			value		( )						{ return *(double*)data; }
	String&			text		( )						{ return *(String*)data; }
	String&			proc		( )						{ return *(String*)data; }
	Vek&			list		( )						{ return *(Vek*   )data; }
	double			value		( ) const				{ return *(double*)data; }
	cString&		text		( )	const				{ return *(String*)data; }
	cString&		proc		( )	const				{ return *(String*)data; }
	cVek&			list		( )	const				{ return *(Vek*   )data; }


	bool		type_invalid	( ) const				{ return type<isNumber  || type>isProc;  }
	bool		type_valid		( ) const				{ return type>=isNumber && type<=isProc; }

	void		init_list		( );
	void		copy_list		( cVar& q );
	void		move_list		( Var& q );
	void		kill_list		( );
	void		fix_parents		( );

	void		init_data		( )						{ type=isNumber; value() = 0.0; }
	void		init_data		( vtype v );
	void		init_data		( double d )			{ type=isNumber; value() = d; }
	void		init_data		( cString& t )			{ type=isText; /*new(data)String(t);*/ text()._init(t); }
	void		init_data		( cVar& q );
	void		move_data		( Var& q );
	void		swap_data		( Var& q );
	void		kill_data		( );

	void		init_link		( )						{ parent=NULL; }
	void		init_link		( Var* par, uint idx );
	void		kill_link		( );
	void		link			( Var* par, uint idx )	{ XXXTRAP(Contains(par)); kill_link(); init_link(par,idx); }
	void		unlink			( )						{ kill_link(); init_link(); }

	void		Sort			( Var**, Var** );
	void		RSort			( Var**, Var** );
	Var&		ListOp			( Var&(Var::*fp)(double), double q );
	Var&		ListOp			( Var&(Var::*fp)(double), cVar& q  );
	void		ListOp			( void(Var::*fp)(cVar&,double), cVar& q1, double q2 );
	void		ListOp			( void(Var::*fp)(cVar&,double), cVar& q1, cVar& q2 );
	Var&		append_list		( cVar& q, String(*disass_proc)(cString&)=NULL );

public:
	void		validate		( cstr, long ) const;
	#define		Validate()		validate(__FILE__,__LINE__)

				Var				( )						{ init_link(); init_data(0.0); }
				~Var			( )						{ kill_data(); kill_link(); }

				Var				( Var* par, uint idx )	{ init_data(0.0); init_link(par,idx); }

				Var				( vtype type );
				Var				( cString& name, vtype );

				Var				( double value );
				Var				( cString& name, double value );

				Var				( cString& text );
				Var				( cString& name, cString& text );

				Var				( cVar& q )				: name(q.name) { q.Validate(); init_link(); init_data(q); }

	Var&		operator=		( cVar& q );			// source or target may be part of the other!
	Var&		operator=		( double d )			{                      kill_data(); init_data(d); return *this; }
	Var&		operator=		( cString& t )			{ XXXTRAP(&text()==&t); kill_data(); init_data(t); return *this; }

	void		CopyData		( Var& q );				// this := copy of q
	void		MoveData		( Var& q );				// this := data of q; q := 0.0
	void		SwapData		( Var& q );				// this := data of q; q := data of this

	void		SetType			( vtype typ )			{ kill_data(); init_data(typ); }
	void		SetNumber		( )						{ kill_data(); init_data(0.0); }
	void		SetVoid			( )						{ kill_data(); init_data(); }
	void		SetString		( )						{ SetType(isText); }
	void		SetList			( )						{ SetType(isList); }
	void		SetProc			( )						{ SetType(isProc); }

	vtype		GetType			( )	const				{ return type; }
	bool		IsNumber		( )	const				{ return type==isNumber; }
	bool		IsText			( )	const				{ return type==isText;   }
	bool		IsList			( )	const				{ return type==isList;   }
	bool		IsProc			( )	const				{ return type==isProc;   }
	bool		IsNoNumber		( )	const				{ return type!=isNumber; }
	bool		IsNoText		( )	const				{ return type!=isText;   }
	bool		IsNoList		( )	const				{ return type!=isList;   }
	bool		IsNoProc		( )	const				{ return type!=isProc;   }

	String&		Name			( )						{ return name; }
	bool		IsNamed			( )						{ return name.Len(); }
	void		ClearName		( )						{ name.Clear(); }
	void		SetName			( cString& nam )		{ name = nam; }

	double&		Value			( )						{ XXTRAP(type!=isNumber); return value(); }
	long		LongValue		( )						{ return (long)Value(); }

	String&		Text			( )						{ XXTRAP(type!=isText);   return text(); }
	cString&	Text			( ) const				{ XXTRAP(type!=isText);   return text(); }
	ptr			TextAddr		( )						{ XXTRAP(type!=isText);   return text().Text(); }
	UCS1Char*	Ucs1Addr		( )						{ XXTRAP(type!=isText);   return text().Ucs1(); }
	UCS2Char*	Ucs2Addr		( )						{ XXTRAP(type!=isText);   return text().Ucs2(); }
	UCS4Char*	Ucs4Addr		( )						{ XXTRAP(type!=isText);   return text().Ucs4(); }
	uint		TextLen			( )						{ XXTRAP(type!=isText);   return text().Len(); }

	String&		Proc			( )						{ XXTRAP(type!=isProc);   return proc(); }
	cString&	Proc			( ) const				{ XXTRAP(type!=isProc);   return proc(); }
	uptr		ProcAddr		( )						{ XXTRAP(type!=isProc);   return (uptr)proc().Text(); }
	uint		ProcSize		( )						{ XXTRAP(type!=isProc);   return proc().Len(); }

	Var*		Parent			( )						{ return parent; }
	uint		Index			( )						{ return index; }
	Vek&		List			( )						{ XXTRAP(type!=isList);   return list(); }
	uint		ListSize		( )						{ XXTRAP(type!=isList);   return list().used; }
	Var&		operator[]		( uint i );
	bool		Contains		( cVar* q )	const		{ while (q&&q!=this) q=q->parent; return q!=NULL; }	// does this contain q ?
	bool		Contains		( cVar& q )	const		{ return Contains(&q); }
	bool		IsSubslicer		( )						{ return list().size==0 && list().used!=0; }

	Var*		FindItem		( cString& name ) const;

	void 		ResizeList		( uint n );
	void		InsertItems		( uint idx, uint n );	// füge leere Variablen in List ein
	void		InsertItem		( uint idx )			{ InsertItems(idx,1); }
	void		InsertItem		( uint idx, Var* q );
	void		InsertItem		( uint idx, Var& q )	{ InsertItem(idx,&q); }
	void		AppendItem		( Var* q );
	void		AppendItem		( Var& q )				{ AppendItem(&q); }
	void		DeleteItems		( uint idx, uint n );	// lösche Variablen aus List
	void		DeleteItem		( uint idx )			{ DeleteItems(idx,1); }
	void		DeleteLastItem	( );
	void		AppendList		( Var& q );				// append contents of list q to this list; q becomes empty list
	void		AppendList		( Var* q )				{ AppendList(*q); }
	void		Sort			( );					// sortiere List
	void		RSort			( );					// sortiere List rückwärts

	Var&		MaxVar			( Var& q );
	Var&		MinVar			( Var& q );
	Var&		MaxVar			( );					// of list
	Var&		MinVar			( );					// of list

	void		ConvertFrom		( CharEncoding );
	void		ConvertTo		( CharEncoding );
	void		LogVar			( );
	String		ListVar			( bool quote_strings, bool include_names );
	double		ToNumber		( ) const;
	String		ToString		( bool quotestring, String(*disass_proc)(cString&)=NULL ) const;
	void		ConvertToList	( );
	void		SplitLines		( cString& sep );
	void		SplitLines		( );

	Var&		operator+=		( double d );
	Var&		operator-=		( double d );
	Var&		operator*=		( double d );
	Var&		operator/=		( double d );
	Var&		operator%=		( double d );
	Var&		operator>>=		( double d );
	Var&		operator<<=		( double d );
	Var&		operator&=		( double d );
	Var&		operator|=		( double d );
	Var&		operator^=		( double d );

	Var&		operator+=		( cVar& q );
	Var&		operator-=		( cVar& q );
	Var&		operator*=		( cVar& q );
	Var&		operator/=		( cVar& q );
	Var&		operator%=		( cVar& q );
	Var&		operator>>=		( cVar& d );
	Var&		operator<<=		( cVar& d );
	Var&		operator&=		( cVar& d );
	Var&		operator|=		( cVar& d );
	Var&		operator^=		( cVar& d );

	Var			operator+		( double d ) const;
	Var			operator-		( double d ) const;
	Var			operator*		( double d ) const;
	Var			operator/		( double d ) const;
	Var			operator%		( double d ) const;
	Var			operator>>		( double d ) const;
	Var			operator<<		( double d ) const;
	Var			operator&		( double d ) const;
	Var			operator|		( double d ) const;
	Var			operator^		( double d ) const;

	Var			operator+		( cVar& q ) const;
	Var			operator-		( cVar& q ) const;
	Var			operator*		( cVar& q ) const;
	Var			operator/		( cVar& q ) const;
	Var			operator%		( cVar& q ) const;
	Var			operator>>		( cVar& q ) const;
	Var			operator<<		( cVar& q ) const;
	Var			operator&		( cVar& q ) const;
	Var			operator|		( cVar& q ) const;
	Var			operator^		( cVar& q ) const;

	Var&		operator+=		( cString& s );				// concat
	Var			operator+		( cString& s ) const;		// concat
	Var&		AppendString	( cString& q, String(*disass_proc)(cString&)=NULL );
	Var&		AppendString	( cVar&    q, String(*disass_proc)(cString&)=NULL );
	Var 		ConcatString	( cString& q, String(*disass_proc)(cString&)=NULL ) const;
	Var			ConcatString	( cVar&    q, String(*disass_proc)(cString&)=NULL ) const;

	bool		operator&&		( double q ) const;
	bool		operator||		( double q ) const;
	bool		operator&&		( cVar& q ) const;
	bool		operator||		( cVar& q ) const;

	bool		operator==		( cVar& q ) const;
	bool		operator>		( cVar& q ) const;
	bool		operator<		( cVar& q ) const;
	bool		operator!=		( cVar& q ) const			{ return !operator==(q); }
	bool		operator>=		( cVar& q ) const			{ return !operator<(q);  }
	bool		operator<=		( cVar& q ) const			{ return !operator>(q);  }

	bool		operator==		( cUTF8Str q ) const		{ return operator==(Var(q)); }
	bool		operator>		( cUTF8Str q ) const		{ return operator> (Var(q)); }
	bool		operator<		( cUTF8Str q ) const		{ return operator< (Var(q)); }
	bool		operator!=		( cUTF8Str q ) const		{ return operator!=(Var(q)); }
	bool		operator>=		( cUTF8Str q ) const		{ return operator>=(Var(q)); }
	bool		operator<=		( cUTF8Str q ) const		{ return operator<=(Var(q)); }

	// die folgenden hauptsächlich wg. operatorXY(0), was sonst als NULL interpretiert wird. GRRR!
	bool		operator==		( int q ) const				{ return operator==(Var(q)); }
	bool		operator>		( int q ) const				{ return operator> (Var(q)); }
	bool		operator<		( int q ) const				{ return operator< (Var(q)); }
	bool		operator!=		( int q ) const				{ return operator!=(Var(q)); }
	bool		operator>=		( int q ) const				{ return operator>=(Var(q)); }
	bool		operator<=		( int q ) const				{ return operator<=(Var(q)); }

	// die folgenden hauptsächlich damit operatorXY(double) nicht zu operatorXY(int) autocasted
	bool		operator==		( double q ) const			{ return operator==(Var(q)); }
	bool		operator>		( double q ) const			{ return operator> (Var(q)); }
	bool		operator<		( double q ) const			{ return operator< (Var(q)); }
	bool		operator!=		( double q ) const			{ return operator!=(Var(q)); }
	bool		operator>=		( double q ) const			{ return operator>=(Var(q)); }
	bool		operator<=		( double q ) const			{ return operator<=(Var(q)); }

friend void		TestVarClass	( );
};


extern void		TestVarClass	( );


#endif



