using System;
using System.IO;
using System.Data;


namespace DarkStrideToolbox
{
	public enum enumTableType
	{
		Graphic,
		DataTable,
		Border,
		Other,
		Sound
	};
	public enum enumBorderFillType
	{
		None,
		Graphic,
		Color
	};


	public class DSGobFile
	{
		#region Properties
		private DSSortedList m_oTables = new DSSortedList();
		private string m_sFileName = "";

		private const string m_cVERSION_11 = "DarkStride Gob File v1.1";
		private const string m_cVERSION_20 = "DarkStride Gob File v2.0";
		#endregion


		public DSGobFile()
		{
		}


		public DSGobTable GetTable( string sTableName )
		{
			return( (DSGobTable)m_oTables.GetByKey( sTableName ) );
		}
		public void AddTable( DSGobTable oTable )
		{
			m_oTables.Add( oTable.TableName,oTable );
		}

		public void RemoveTable( DSGobTable oTable )
		{
			m_oTables.Remove( oTable.TableName );
		}

		public void LoadGobFile( string sFileName )
		{
			StreamReader oStream = null;
			string sLine = "";
			DSGobTable oTable = null;


			//Initialize our variables
			m_sFileName = sFileName;
			m_oTables = new DSSortedList();

			//Open the file and parse it!
			oStream = new StreamReader( sFileName );

			//Read in the header information
			sLine = oStream.ReadLine();
			if( sLine.Equals( m_cVERSION_11 ) == false &&
				sLine.Equals( m_cVERSION_20 ) == false )
			{
				throw new System.Exception( "File is not a proper Gob file or is not a recognized version." );
			}

			//Now read in our values!
			sLine = oStream.ReadLine();
			while( sLine != null )
			{
				oTable = new DSGobTable();				
				oTable.DeSerialize( sLine );
				m_oTables.Add( oTable.TableName,oTable );

				sLine = oStream.ReadLine();
			}

			oStream.Close();


			//Add this to our resource collection if their is one
			DSResourceManager.GetGlobalInstance().LoadGob( this );
		}
		public void SaveGobFile()
		{
			if( m_sFileName.Length == 0 )
			{
				throw new System.Exception( "This is a new Gob file that was not loaded, so the file name must be specified." );
			}

			SaveGobFile( m_sFileName );
		}
		public void SaveGobFile( string sFileName )
		{
			string sTable = "";
			DSGobTable oTable = null;
			StreamWriter oStream = null;

			m_sFileName = sFileName;
			oStream = new StreamWriter( m_sFileName,false );
			oStream.WriteLine( m_cVERSION_20 );

			for( int i=0 ; i<m_oTables.Count ; i++ )
			{
				oTable = (DSGobTable)m_oTables.GetByIndex( i );
				sTable = oTable.Serialize();
				oTable = null;

				oStream.WriteLine( sTable );
			}				

			oStream.Close();
		}


		public DSSortedList GetTables( enumTableType oFilterToType )
		{
			DSGobTable oLoopTable = null;
			DSSortedList oRetVal = new DSSortedList();


			for( int i=0 ; i<m_oTables.Count ; i++ )
			{
				oLoopTable = (DSGobTable)m_oTables.GetByIndex( i );

				if( oLoopTable.TableType == oFilterToType )
				{
					oRetVal.Add( oLoopTable.TableName,oLoopTable );
				}
			}		
			
			
			return( oRetVal );
		}


		public object FindValue( string sTableName,string sColNameToSearch,object oValueToFind,string sColNameToReturn )
		{
			return( FindValue( sTableName,sColNameToSearch,oValueToFind,sColNameToReturn,true ) );
		}
		public object FindValue( string sTableName,string sColNameToSearch,object oValueToFind,string sColNameToReturn,bool bThrowErrorIfNotFound )
		{
			DSGobTable oTable = null;
			object oRetVal = null;


			//First find our table
			oTable = GetTable( sTableName );
			if( oTable == null )
			{
				throw new System.Exception( "Unable to find table <" + sTableName + "> in Gob file." );
			}
			
			//Now find our column
			oRetVal = oTable.FindValue( sColNameToSearch,oValueToFind,sColNameToReturn,bThrowErrorIfNotFound );

			//Do a null replacement, DBNull is harder to check.
			if( oRetVal != null )
			{
				if( oRetVal.GetType().ToString() == "System.DBNull" )
				{
					oRetVal = null;
				}
			}

			return( oRetVal );
		}

		public object FindValue( string sTableName,int nRowIndex,string sColNameToReturn )
		{
			return( FindValue( sTableName,nRowIndex,sColNameToReturn,true ) );
		}
		public object FindValue( string sTableName,int nRowIndex,string sColNameToReturn,bool bThrowErrorIfNotFound )
		{
			DSGobTable oTable = null;
			object oRetVal = null;


			//First find our table
			oTable = GetTable( sTableName );
			if( oTable == null )
			{
				throw new System.Exception( "Unable to find table <" + sTableName + "> in Gob file." );
			}

			//Now find our column
			oRetVal = oTable.FindValue( nRowIndex,sColNameToReturn,bThrowErrorIfNotFound );

			//Do a null replacement, DBNull is harder to check.
			if( oRetVal != null )
			{
				if( oRetVal.GetType().ToString() == "System.DBNull" )
				{
					oRetVal = null;
				}
			}

			return( oRetVal );
		}

        

		#region Properties
		public DSSortedList Tables
		{
			get
			{
				return( m_oTables );
			}
		}
		public string FileName
		{
			get
			{
				return( m_sFileName );
			}
			set
			{
				m_sFileName = value;
			}
		}
		#endregion
	}
	

	public class DSGobTable
	{
public long nCount = 0;
public double nTotalFindTime = 0;

		#region Properties
		private const string m_cVERSION_1 = "DSGobTable v1.0";
		private const string m_cVERSION_2 = "DSGobTable v2.0";

		private object[,] m_oData = null;
		private System.Data.DataTable m_oDataTable = new DataTable();
		private System.IO.MemoryStream m_oFile = null;
		private string m_sOriginalFileName = "";
		private string m_sFolderName = "";
		private enumTableType m_nTableType = enumTableType.Graphic;
		private long m_nRealPic_Left = 0;
		private long m_nRealPic_Top = 0;
		private long m_nRealPic_Right = 0;
		private long m_nRealPic_Bottom = 0;

		//Border information
		private string[] m_saBorderGraphicKey = new string[ 8 ];
		private string m_sBorderFill_GraphicKey = "";
		private enumBorderFillType m_nBorderFill_Type = enumBorderFillType.None;
		private int m_nBorderFill_Color = System.Drawing.Color.White.ToArgb();
		private bool m_bBorderFill_Stretch = false;
		private long m_nBorderFillDiffPoint_Left = 0;
		private long m_nBorderFillDiffPoint_Top = 0;
		private long m_nBorderFillDiffPoint_Right = 0;
		private long m_nBorderFillDiffPoint_Bottom = 0;

		private int m_nAlphaColor = System.Drawing.Color.Blue.ToArgb();

		private long m_nMaxSoundInstances = -1;

		private const string m_cSEP = "[*GTSep*]";
		private const string m_cLF_REPLACEMENT = "[*BkslN*]";
		private const string m_cCR_REPLACEMENT = "[*BkslR*]";
		private const string m_cNULL_REPLACEMENT = "[*Bksl0*]";
		#endregion


		public DSGobTable(){}


		public void AddFile( System.IO.MemoryStream oFile )
		{
			m_oFile = oFile;
		}
		public void AddColumn( string sColName )
		{
			string sTemp = "";

			AddColumn( sColName,sTemp.GetType() );
		}
		public void AddColumn( string sColName,System.Type oColType )
		{
			DataColumn oColumn = null;

			oColumn = new DataColumn();
			oColumn.DataType = oColType;
			oColumn.ColumnName = sColName;

			m_oDataTable.Columns.Add(oColumn);

			CreateObjAryFromDataTable();
		}

		public int GetColumnIndex( string sColName )
		{
			return( m_oDataTable.Columns[ sColName ].Ordinal );
		}


		public void SetData( string sColName,long nRowIndex,object oData )
		{
			long nColIndex = -1;

			nColIndex = GetColumnIndex( sColName );
			if( nColIndex == -1 )
			{
				throw new System.Exception( "Column <" + sColName + "> does not exist in this table." );
			}

			SetData( nColIndex,nRowIndex,oData );
		}
		public void SetData( long nColIndex,long nRowIndex,object oData )
		{
			DataRow oRow = null;

			if( nColIndex > m_oDataTable.Columns.Count || nColIndex < 0 )
			{
				throw new System.Exception( "Column <" + nColIndex.ToString() + "> does not exist." );
			}

			if( nRowIndex > m_oDataTable.Rows.Count )
			{
				while( nRowIndex > m_oDataTable.Rows.Count )
				{
					oRow = m_oDataTable.NewRow();
					m_oDataTable.Rows.Add( oRow );
				}
			}
			else
			{
				oRow = m_oDataTable.Rows[ (int)nRowIndex ];
			}

			oRow[ (int)nColIndex ] = oData;
		
			CreateObjAryFromDataTable();
		}

		public object GetData( string sColName,long nRowIndex )
		{
			long nColIndex = -1;

			nColIndex = GetColumnIndex( sColName );
			if( nColIndex == -1 )
			{
				throw new System.Exception( "Column <" + sColName + "> does not exist in this table." );
			}

			return( GetData( nColIndex,nRowIndex ) );
		}
		public object GetData( long nColIndex,long nRowIndex )
		{
			object oRetVal = null;


			if( nColIndex < 0 || nColIndex > m_oDataTable.Columns.Count )
			{
				throw new System.Exception( "Column <" + nColIndex.ToString() + "> does not exist." );
			}
			if( nRowIndex < 0 || nRowIndex > m_oDataTable.Rows.Count )
			{
				throw new System.Exception( "Row <" + nRowIndex.ToString() + "> does not exist." );
			}

			oRetVal = m_oData[ (int)nRowIndex,(int)nColIndex ];

			return( oRetVal );
		}


		public object FindValue( string sColNameToSearch,object oValueToFind,string sColNameToReturn )
		{
			return( FindValue( sColNameToSearch,oValueToFind,sColNameToReturn,true ) );
		}
		public object FindValue( string sColNameToSearch,object oValueToFind,string sColNameToReturn,bool bThrowErrorIfNotFound )
		{
nCount++;
DateTime dtStart = DateTime.Now;
			System.Data.DataRow oRow = null;
			object oScanVal = null;
			object oRetVal = null;
			int nColIndexToReturn = -1;
			int nColIndexToSearch = -1;


			//Now find our column
			nColIndexToSearch = GetColumnIndex( sColNameToSearch );
			if( nColIndexToSearch == -1 )
			{
				throw new System.Exception( "Unable to find column <" + sColNameToSearch + "> in table <" + this.TableName + "> in Gob file." );
			}

			//Now search for our row
			if( m_oDataTable.Columns[ sColNameToSearch ].Unique == true )
			{
				m_oDataTable.PrimaryKey = new System.Data.DataColumn[]{ m_oDataTable.Columns[ sColNameToSearch ] };
				oRow = m_oDataTable.Rows.Find( oValueToFind );
			}
			else
			{
				//Now search for our row
				oRow = null;
				for( int i=0 ; i<m_oDataTable.Rows.Count ; i++ )
				{
					oScanVal = GetData( nColIndexToSearch,i );
					if( oScanVal.ToString() == oValueToFind.ToString() )
					{
						oRow = m_oDataTable.Rows[ i ];
						break;
					}
				}
			}

			if( oRow == null )
			{
				if( bThrowErrorIfNotFound == true )
				{
					throw new System.Exception( "Unable to find a row in in table <" + this.TableName + "> with the primary key of value <" + oValueToFind.ToString() + "> specified in the Gob file." );
				}
				else
				{
					return( null );
				}
			}

			//Find our column to return
			nColIndexToReturn = GetColumnIndex( sColNameToReturn );
			if( nColIndexToReturn == -1 )
			{
				throw new System.Exception( "Unable to find column <" + sColNameToReturn + "> in table <" + this.TableName + "> in Gob file." );
			}

 			//Return our data
			oRetVal = oRow[ nColIndexToReturn ];

DateTime dtStop = DateTime.Now;
TimeSpan oSpan = dtStop - dtStart;
nTotalFindTime = oSpan.TotalSeconds;

			return( oRetVal );
		}

		public object FindValue( int nRowIndex,string sColNameToReturn )
		{
			return( FindValue( nRowIndex,sColNameToReturn,true ) );
		}
		public object FindValue( int nRowIndex,string sColNameToReturn,bool bThrowErrorIfNotFound )
		{
nCount++;
DateTime dtStart = DateTime.Now;
			object oRetVal = null;
			int nColIndexToReturn = -1;


			//Find our column to return
			nColIndexToReturn = GetColumnIndex( sColNameToReturn );
			if( nColIndexToReturn == -1 )
			{
				throw new System.Exception( "Unable to find column <" + sColNameToReturn + "> in table <" + this.TableName + "> in Gob file." );
			}

			//Return our row
			oRetVal = m_oData[ nRowIndex,nColIndexToReturn ];

DateTime dtStop = DateTime.Now;
TimeSpan oSpan = dtStop - dtStart;
nTotalFindTime = oSpan.TotalSeconds;

			return( oRetVal );
		}


		public string EscapeString( string sRecord )
		{
			string sRetVal = sRecord;

			sRetVal = sRetVal.Replace( "\r",m_cCR_REPLACEMENT );
			sRetVal = sRetVal.Replace( "\n",m_cLF_REPLACEMENT );
			sRetVal = sRetVal.Replace( "\0",m_cNULL_REPLACEMENT );

			return( sRetVal );
		}
		public string UnEscapeString( string sRecord )
		{
			string sRetVal = sRecord;

			sRetVal = sRetVal.Replace( m_cCR_REPLACEMENT,"\r" );
			sRetVal = sRetVal.Replace( m_cLF_REPLACEMENT,"\n" );
			sRetVal = sRetVal.Replace( m_cNULL_REPLACEMENT,"\0" );

			return( sRetVal );
		}


		public string Serialize()
		{
			string sRetVal = "";

		
			if( this.TableType == enumTableType.Border ||
				this.TableType == enumTableType.DataTable )
			{
				m_oFile = null;
			}
			if( this.TableType != enumTableType.DataTable )
			{
				m_oDataTable.Clear();
			}

			sRetVal = EscapeString( DSMisc.Serialize( m_oDataTable ) ) + m_cSEP + 
					  EscapeString( m_sOriginalFileName ) + m_cSEP + 
					  EscapeString( DSMisc.Serialize( m_oFile ) ) + m_cSEP +
					  EscapeString( m_sFolderName ) + m_cSEP + 
					  Convert.ToInt64( m_nTableType ).ToString() + m_cSEP +
					  m_nRealPic_Left.ToString() + m_cSEP + 
					  m_nRealPic_Top.ToString() + m_cSEP + 
					  m_nRealPic_Right.ToString() + m_cSEP + 
					  m_nRealPic_Bottom.ToString() + m_cSEP;

			for( int i=0 ; i<8 ; i++ )
			{
				sRetVal += m_saBorderGraphicKey[i] + m_cSEP;
			}

			sRetVal +=m_sBorderFill_GraphicKey + m_cSEP +
					  m_nBorderFill_Color.ToString() + m_cSEP +
					  m_nBorderFillDiffPoint_Left.ToString() + m_cSEP +
					  m_nBorderFillDiffPoint_Top.ToString() + m_cSEP +
					  m_nBorderFillDiffPoint_Right.ToString() + m_cSEP +
					  m_nBorderFillDiffPoint_Bottom.ToString() + m_cSEP + 
					  Convert.ToInt32( m_nBorderFill_Type ).ToString() + m_cSEP + 
					  m_nAlphaColor.ToString() + m_cSEP + 
					  m_nMaxSoundInstances.ToString() + m_cSEP;

			return( sRetVal );
		}
		public string DeSerialize( string sRecord )
		{
			string[] saParsed = null;


			saParsed = DSMisc.Split( sRecord,m_cSEP );

			m_oDataTable = (System.Data.DataTable)DSMisc.DeSerialize( UnEscapeString( saParsed[ 0 ] ) );
			m_sOriginalFileName = UnEscapeString( saParsed[ 1 ] );
			m_oFile = (System.IO.MemoryStream)DSMisc.DeSerialize( UnEscapeString( saParsed[ 2 ] ) );

			//Convert our data object into an object array
			CreateObjAryFromDataTable();

			if( m_oFile != null )
			{
				m_oFile.Seek( 0,System.IO.SeekOrigin.Begin );
			}


			if( saParsed.Length > 5 )
			{
				m_sFolderName		= UnEscapeString( saParsed[ 3 ] );
				m_nTableType		= (enumTableType)Convert.ToInt64( UnEscapeString( saParsed[ 4 ] ) );
				m_nRealPic_Left		= Convert.ToInt64( saParsed[ 5 ] );
				m_nRealPic_Top		= Convert.ToInt64( saParsed[ 6 ] );
				m_nRealPic_Right	= Convert.ToInt64( saParsed[ 7 ] );
				m_nRealPic_Bottom	= Convert.ToInt64( saParsed[ 8 ] );

				for( int i=0 ; i<8 ; i++ )
				{
					m_saBorderGraphicKey[ i ] = saParsed[ 9+i ];
				}

				m_sBorderFill_GraphicKey		= saParsed[ 17 ];
				m_nBorderFill_Color				= Convert.ToInt32( saParsed[ 18 ] );
				m_nBorderFillDiffPoint_Left		= Convert.ToInt64( saParsed[ 19 ] );
				m_nBorderFillDiffPoint_Top		= Convert.ToInt64( saParsed[ 20 ] );
				m_nBorderFillDiffPoint_Right	= Convert.ToInt64( saParsed[ 21 ] );
				m_nBorderFillDiffPoint_Bottom	= Convert.ToInt64( saParsed[ 22 ] );
				m_nBorderFill_Type				= (enumBorderFillType)Convert.ToInt64( saParsed[ 23 ] );
				m_nAlphaColor					= Convert.ToInt32( saParsed[ 24 ] );
			}
			else if( this.IsFile == false )
			{
				m_nTableType = enumTableType.DataTable;
			}
			else
			{
				m_nTableType = enumTableType.Other;
			}

			if( saParsed.Length > 26 )
			{
				m_nMaxSoundInstances = Convert.ToInt64( saParsed[ 25 ] );
			}
			else
			{
				m_nMaxSoundInstances = -1;
			}


			return( "" );
		}
		private void CreateObjAryFromDataTable()
		{
			m_oData = new object[ m_oDataTable.Rows.Count,m_oDataTable.Columns.Count ];
			for( int nRows=0 ; nRows<m_oDataTable.Rows.Count ; nRows++ )
			{
				for( int nCols=0 ; nCols<m_oDataTable.Columns.Count ; nCols++ )
				{
					m_oData[ nRows,nCols ] = m_oDataTable.Rows[ nRows ][ nCols ];
				}
			}
		}



		#region Properties
		public string TableName
		{
			get
			{
				return( m_oDataTable.TableName );
			}
			set
			{
				m_oDataTable.TableName = value;
			}
		}
		public System.Data.DataTable DataTable
		{
			get
			{
				return( m_oDataTable );
			}
			set
			{
				m_oDataTable = value;
			}
		}
		public System.IO.MemoryStream File
		{
			get
			{
				return( m_oFile );
			}
		}
		public bool IsFile
		{
			get
			{
				return( m_oFile != null );
			}
		}
		public string OriginalFileName
		{
			get
			{
				return( m_sOriginalFileName );
			}
			set
			{
				m_sOriginalFileName = value;
			}
		}
		public int RowCount
		{
			get
			{
				return( m_oDataTable.Rows.Count );
			}
		}
		public string FolderName
		{
			get
			{
				return( m_sFolderName );
			}
			set
			{
				m_sFolderName = value;
			}
		}
		public enumTableType TableType
		{
			get
			{
				return( m_nTableType );
			}
			set
			{
				m_nTableType = value;
			}
		}
		public long RealPic_Left
		{
			get
			{
				return( m_nRealPic_Left );
			}
			set
			{
				m_nRealPic_Left = value;
			}
		}
		public long RealPic_Top
		{
			get
			{
				return( m_nRealPic_Top );
			}
			set
			{
				m_nRealPic_Top = value;
			}
		}
		public long RealPic_Right
		{
			get
			{
				return( m_nRealPic_Right );
			}
			set
			{
				m_nRealPic_Right = value;
			}
		}
		public long RealPic_Bottom
		{
			get
			{
				return( m_nRealPic_Bottom );
			}
			set
			{
				m_nRealPic_Bottom = value;
			}
		}

		public int AlphaColor
		{
			get
			{
				return( m_nAlphaColor );
			}
			set
			{
				m_nAlphaColor = value;
			}
		}


		public string[] BorderGraphicKey
		{
			get
			{
				return( m_saBorderGraphicKey );
			}
			set
			{
				m_saBorderGraphicKey = value;
			}
		}
	
		public enumBorderFillType BorderFillType
		{
			get
			{
				return( m_nBorderFill_Type );
			}
			set
			{
				m_nBorderFill_Type = value;
			}
		}
		public string BorderFillGraphicKey
		{
			get
			{
				return( m_sBorderFill_GraphicKey );
			}
			set
			{
				m_sBorderFill_GraphicKey = value;
			}
		}
		public int BorderFillColor
		{
			get
			{
				return( m_nBorderFill_Color );
			}
			set
			{
				m_nBorderFill_Color = value;
			}
		}
		public bool BorderFillStretch
		{
			get
			{
				return( m_bBorderFill_Stretch );
			}
			set
			{
				m_bBorderFill_Stretch = value;
			}
		}
		public long BorderFillDiffPoint_Left
		{
			get
			{
				return( m_nBorderFillDiffPoint_Left );
			}
			set
			{
				m_nBorderFillDiffPoint_Left = value;
			}
		}
		public long BorderFillDiffPoint_Top
		{
			get
			{
				return( m_nBorderFillDiffPoint_Top );
			}
			set
			{
				m_nBorderFillDiffPoint_Top = value;
			}
		}
		public long BorderFillDiffPoint_Right
		{
			get
			{
				return( m_nBorderFillDiffPoint_Right );
			}
			set
			{
				m_nBorderFillDiffPoint_Right = value;
			}
		}
		public long BorderFillDiffPoint_Bottom
		{
			get
			{
				return( m_nBorderFillDiffPoint_Bottom );
			}
			set
			{
				m_nBorderFillDiffPoint_Bottom = value;
			}
		}

		public long MaxSoundInstances
		{
			get
			{
				return( m_nMaxSoundInstances );
			}
			set
			{
				m_nMaxSoundInstances = value;
			}
		}
		#endregion
	}
}
