/////////////////////////////////////////////////////////////////////////////
// Name:        the engine
// Purpose:     wxBugTracker
// Author:      Aleksandras Gluchovas (mailto:alex@soften.ktu.lt)
// Modified by:
// Created:     20/10/1999
// RCS-ID:      $Id: txtrecset.h,v 1.4 2001/02/22 13:01:02 georgetasker Exp $
// Copyright:   (c) Aleksandras Gluchovas
// Licence:   	GPL (version 2.0 or later)
/////////////////////////////////////////////////////////////////////////////

#ifndef __TXTRECSET_G__
#define __TXTRECSET_G__

#include "wx/dynarray.h"

#include "myutils.h"
#include "strlist.h"
#include "scripttempl.h"

////////////////////////////////////////
// general purpose classes (reusable) //
////////////////////////////////////////

enum FIELD_TYPES
{
	FT_RECORD,
	FT_VALUE,
};

class FieldBase
{
public:
	FieldBase();
	virtual ~FieldBase();

	virtual wxString& GetName();
	virtual void SetName( const wxString& name );

	// overridables

	virtual int GetType() = 0;
	virtual FieldBase* Clone() = 0;
	virtual const wxString& GetValue() = 0;

	virtual void Dump() = 0;

protected:
	wxString     mName;

	friend class Record; // accesses mName without GetName() for performance
};

class StringValue : public FieldBase
{
public:
	StringValue();
	StringValue( const wxString& name, const wxString& value );
	StringValue( const wxString& value );

	// overriden methods of FieldBase

	virtual int GetType(); // returns FT_VALUE
	virtual const wxString& GetValue();

	virtual void SetValue( const wxString& value );
	virtual FieldBase* Clone();

	virtual void Dump();

public: /* protected really (for direct access while sorting/filgering)*/

	wxString mValue;

	long   mUserLong; // used to optimize sorting and filtering, e.g. stringified
					  // date is converted to milliseconds and stoared in mUserLong
};

class StringListValue : public StringValue
{
public:
	virtual void SetValue( const wxString& value );
	StrListT& GetValues();

protected:
	StrListT mValues;
};

WX_DEFINE_ARRAY( FieldBase*, FieldListT );

enum ESCAPEMENT_TYPES
{
	ESCAPE_NONE,
	ESCAPE_ENCODE,
	ESCAPE_DECODE
};

////////////////////////////////////

class Record : public FieldBase
{
public:
	Record();
	Record( const wxString& name );
	Record( const wxString& name, const wxString& strValue );
	~Record();

	virtual int GetType(); // returns FT_RECORD

	virtual wxString& GetStringValue();
	virtual const wxString& GetValue();
	virtual void SetStringValue( const wxString& value );

	bool LoadFromText( char*& cur, char* end );

	wxString GetTextContent();
	bool LoadFromString( const wxString& text );

	wxString GetXMLTextContent( const wxString& lmargin = "" );
	bool LoadFromXML( char*& cur, char* end );
	bool LoadFromXMLString( const wxString& XMLtext );

	bool EnsureExists( const wxString& name, int fieldType = FT_VALUE );

	inline FieldListT& GetFields() { return mFields; }

	bool SetValueByIndex( size_t idx, const wxString& value );
	bool SetValueByName( const wxString& name, const wxString& value );
	bool SetFieldByName( const wxString& name, FieldBase* pField );

	const wxString& GetValueByName( const wxString& name );
	const wxString& GetValueByIndex( size_t idx );

	bool HasValue( const wxString& name );
	void AssignValuesFrom( Record& other, int escapeType = ESCAPE_NONE );
	void CopyFieldsFrom( Record& other );
	void AddFieldsByPrefix( const wxString& prefix, Record& other );
	void AssignFieldsToTemplate( ScriptTemplate& templ, 
								 int escapeType = ESCAPE_NONE );

	void CopyStringValues( StrListT& toLst );
	void AddStringValues( StrListT& fromLst );

	void AddStringField( const wxString& name, const wxString& value );
	void AddIntField( const wxString& name, int value );

	void AddRecord( const wxString& name, const wxString& stringValue );

	int  GetIntValueByName( const wxString& name );
	void SetIntValueByName( const wxString& name, int value );

	FieldBase& GetFieldByName( const wxString& name );
	FieldBase& GetFieldByIndex( size_t idx );
	FieldBase& FieldAt( size_t idx ); 
	bool ReplaceFieldByName( const wxString& name, FieldBase* pNewField );

	Record& GetRecordByName( const wxString& name );
	Record& GetRecordByIndex( size_t idx );
	size_t GetFieldCount();

	void AddField( FieldBase* pField );
	void RemoveFieldByIndex( size_t idx );
	void RemoveField( FieldBase* pField );
	void RemoveAllFields();

	// inlined for performance, because it's called from innter-loops mostly!

	inline FieldBase* FindField( const wxString& name )
	{
		size_t sz = mFields.Count();
		FieldListT& lst = mFields;

		for( size_t i = 0; i != sz; ++i )
		{
			FieldBase* pField = lst[i];

			if ( pField->mName == name ) return pField; // don't use GetName() for performance
		}

		return NULL;
	}

	const wxString& operator[]( size_t idx );
	const wxString& operator[]( const wxString& name );

	virtual FieldBase* Clone();

	virtual void Dump();


protected:
	FieldListT mFields;
	wxString   mStrValue; // usually an empty string

	static wxString m_sEmptyValue;
};

WX_DEFINE_ARRAY( Record*, RecordListT );

// base clase which generalizes access and operations with records
// in a relational-db or similar data-store

class RecordSetBase : public wxObject
{
public:
	RecordSetBase();
	virtual ~RecordSetBase();

	virtual void Open( const wxString& source ) = 0;
	virtual void MoveFirst() = 0;
	virtual void MoveLast() = 0;
	virtual void MoveNext() = 0;
	virtual void MovePrev() = 0;
	virtual bool IsEof() = 0;
	virtual int  GetRecordCount() = 0;

	virtual void ModifyRecord() = 0; // invoke this, if any fields of currently traversed
									 // record where modified

	virtual void AppendRecord( Record* pRecord ) = 0;
	virtual void AppendRecordsFrom( RecordSetBase& other ) = 0;
	virtual void RemoveAll() = 0;
	virtual void RemoveRecord() = 0;

	virtual void UseIndex( const wxString& idxName ) = 0;
	virtual bool FindFirst( const wxString& name, const wxString& value ) = 0;
	virtual bool FindFirst( const wxString& name1, const wxString& value1,
						    const wxString& name2, const wxString& value2 ) = 0;

	// returns -1 if not supported
	virtual int GetRecordPos() = 0;
	virtual bool SetRecordPos( unsigned int pos ) = 0;

	virtual wxString GetTextContent() = 0;

	virtual void Flush() = 0;
	virtual void CloseSet();

	virtual Record& GetRecord() = 0; // returns currently traversed record
};

class InMemoryRecordSet : public RecordSetBase
{
public:
	InMemoryRecordSet();
	InMemoryRecordSet( const wxString& source );
	~InMemoryRecordSet();

	virtual void Open( const wxString& source );
	virtual void MoveFirst();
	virtual void MoveLast();
	virtual void MoveNext();
	virtual void MovePrev();
	virtual bool IsEof();
	virtual int  GetRecordCount();

	virtual void ModifyRecord();
	virtual void AppendRecord( Record* pRecord );
	virtual void AppendRecordsFrom( RecordSetBase& other );
	virtual void RemoveAll();
	virtual void RemoveRecord();

	virtual void UseIndex ( const wxString& idxName );
	virtual bool FindFirst( const wxString& name,  const wxString& value );
	virtual bool FindFirst( const wxString& name1, const wxString& value1,
						    const wxString& name2, const wxString& value2 );

	virtual int GetRecordPos();
	virtual bool SetRecordPos( unsigned int pos );

	virtual wxString GetTextContent();

	virtual void Flush();
	virtual void CloseSet();

	virtual Record& GetRecord();

protected:
	int  mAppended;
	bool mModified;
	bool mRemoved;

	FieldListT mRecList;
	size_t	   mCurRecNo; // currently traversed record in the set
	bool       mIsEof;
};

class InMemoryXMLRecordSet : public InMemoryRecordSet
{
public:
	InMemoryXMLRecordSet();
	InMemoryXMLRecordSet( const wxString& source );

	virtual void Open( const wxString& source );
};

class TextFileRecordSet : public InMemoryRecordSet
{
public:
	TextFileRecordSet();
	~TextFileRecordSet();
	TextFileRecordSet( const wxString& fname );

	// overriden methods of InMemoryRecordSet class

	virtual void Open( const wxString& source );
	virtual void Flush();
	virtual void CloseSet();

protected:
	void DoOpen( const wxString& fname );

protected:
	wxString mFName;
};

#endif // __BT_ENGINE_G__
