using System;
using System.Data;
using IndianHealthService.BMXNet;
using IndianHealthService.BMXNet.Ado;



namespace IndianHealthService.BMXNet.Tests
{
    //f:\Program Files\Microsoft\ilmerge\ilmerge.exe /out:$(OutDir)BMXCIANet10.dll $(OutDir)IndianHealthService.BMXNet.EHR.dll $(OutDir)BMXNet20.dll
    /// <summary>
    /// Extends BMX functionality for easier development and debugging.
    /// Copied from Component Framework project IndianHealthService.Xo.Framework.Rpms
    /// </summary>
    public class RpcSession
	{
      
		private BMXNetBroker m_brokerLibrary;
		private BMXNetDataAdapter m_cachedDataAdapter;

        private String debug_lastRpcSignature;

        public String Debug_lastRpcSignature
        {
            get { return debug_lastRpcSignature; }
            set { debug_lastRpcSignature = value; }
        }
        private String debug_lastResult;

        public String Debug_lastResult
        {
            get { return debug_lastResult; }
            set { debug_lastResult = value; }
        }
		private String _rpcResult;
                		

		public RpcSession()
		{
			this.m_cachedDataAdapter= new BMXNetDataAdapter();
		}

        public void AuthenticatedBroker(BMXNetBroker aConnectedLibrary) 
		{
			this.m_brokerLibrary=aConnectedLibrary;			
		}

        public void AuthenticatedConnectionInfo(BMXNetBroker aBroker) 
		{
            this.m_brokerLibrary = aBroker;			
		}

		public virtual String TransmitRPC(String rpcCommand,String rpcParameter,String context){

            if (rpcParameter.Length > 32600)
            {
                throw new Exception("RPC parameter length exceeds maximum allowable size.");
            }

			this.debug_lastRpcSignature=rpcCommand+"^"+rpcParameter+"^"+context;
            
            this.m_brokerLibrary.AppContext=context;

			this.RpcResult=this.m_brokerLibrary.TransmitRPC(rpcCommand,rpcParameter);

			this.debug_lastResult=this.RpcResult;


			return this.RpcResult;
		}

		public String SafelyTransmitRPC(String rpcCommand,String rpcParameter,String context)
		{
			try 
			{
				return this.TransmitRPC(rpcCommand,rpcParameter,context);
			} 
			catch (Exception exception) 
			{
      			return "Exception: "+exception.Message;
			}
		}

		//TODO: Fix Broker - remove this stuff
		private void FixUpBrokerBMXIENissue(DataTable aDataTable) 
		{
			if (aDataTable.Columns.IndexOf("NEW ROW")==-1)
				return;

			foreach (DataRow each in aDataTable.Rows) 
			{
				each["NEW ROW"]=each["BMXIEN"];
			}
	}


		public bool SaveChanges(DataTable aDataTable) 
		{
			BMXNetConnection bmxConnection;
			BMXNetCommand bmxSelectCommand;
			BMXNetCommand bmxUpdateCommand;
			BMXNetDataAdapter bmxDataAdaptor;		

			DataTable changes=aDataTable.GetChanges();
			if (changes==null)
				return false;

			this.FixUpBrokerBMXIENissue(changes);

			this.m_brokerLibrary.AppContext="BMXRPC";
			bmxConnection= new BMXNetConnection(this.m_brokerLibrary);
	
			bmxConnection.Open();
			if (bmxConnection.State != ConnectionState.Open)
				throw new BMXNetException("Unable to connect to RPMS.");

			try 
			{		
				bmxDataAdaptor=this.m_cachedDataAdapter;

				bmxSelectCommand=bmxConnection.CreateCommand() as BMXNetCommand;
				bmxSelectCommand.CommandText=aDataTable.ExtendedProperties["BMXNetSelectStatementForUpdate"] as String;
				bmxDataAdaptor.SelectCommand=bmxSelectCommand;

				DataTable schema=bmxDataAdaptor.FillSchema(aDataTable,SchemaType.Source);
				bmxUpdateCommand = bmxConnection.CreateCommand() as BMXNetCommand;
				bmxUpdateCommand.BMXBuildUpdateCommand(schema);
				bmxDataAdaptor.UpdateCommand=bmxUpdateCommand;
	
				bmxDataAdaptor.Update(changes);
				aDataTable.AcceptChanges();

				return true;
			}
			catch (Exception exception) 
			{
                throw new BMXNetException("Unable to save data to RPMS.",exception);
			} 
			finally 
			{
				if (bmxConnection != null)
					bmxConnection.ToString();
			}

		}


		public virtual DataTable TransmitTableGenerationRPC(String generationString) 
		{
            return this.TransmitTableGenerationRPC(generationString,new DataSet());
		}


		public virtual DataTable TransmitTableGenerationRPC(String generationString, DataSet aDataSet) 
		{
			BMXNetConnection bmxConnection;
			BMXNetCommand bmxCommand;
			BMXNetDataAdapter bmxDataAdaptor;

			this.m_brokerLibrary.AppContext="BMXRPC";
			bmxConnection= new BMXNetConnection(this.m_brokerLibrary);
			
			bmxConnection.Open();
			if (bmxConnection.State != ConnectionState.Open)
				throw new BMXNetException("Unable to connect to RPMS.");

			try 
			{
				bmxCommand = bmxConnection.CreateCommand() as BMXNetCommand;
				bmxCommand.CommandText = generationString;
				bmxDataAdaptor = new BMXNetDataAdapter();
				bmxDataAdaptor=this.m_cachedDataAdapter;
				bmxDataAdaptor.SelectCommand=bmxCommand;
				
				DataSet dataSet = aDataSet;
				bmxDataAdaptor.Fill(dataSet);
				DataTable answer=dataSet.Tables[0];

				answer.ExtendedProperties["BMXNetSelectStatementForUpdate"]=bmxCommand.CommandText;
				answer.ExtendedProperties["RpmsQuery"]=generationString;
				answer.ExtendedProperties["RpmsSchema"]=this.RpmsSchema(generationString);
				
				return answer;
			}
			catch (Exception exception) 
			{
                 throw new Exception("Unable to retrive data from RPMS.",exception);
			} 
			finally 
			{
				if (bmxConnection != null)
					bmxConnection.ToString();
			}

		}



		public virtual DataTable TransmitTableGenerationRPC(String generationString, DataSet aDataSet, String aTableName) 
		{
			BMXNetConnection bmxConnection;
			BMXNetCommand bmxCommand;
			BMXNetDataAdapter bmxDataAdaptor;

			this.m_brokerLibrary.AppContext="BMXRPC";
			bmxConnection= new BMXNetConnection(this.m_brokerLibrary);
			
			bmxConnection.Open();
            if (bmxConnection.State != ConnectionState.Open)
            {
                 throw new BMXNetException("Unable to connect to RPMS.");
            }

			try 
			{
				bmxCommand = bmxConnection.CreateCommand() as BMXNetCommand;
				bmxCommand.CommandText = generationString;
				bmxDataAdaptor = new BMXNetDataAdapter();
				bmxDataAdaptor=this.m_cachedDataAdapter;
				bmxDataAdaptor.SelectCommand=bmxCommand;
				
				DataSet dataSet = aDataSet;
				DataTable answer=aDataSet.Tables.Add(aTableName);
				bmxDataAdaptor.Fill(answer);

				answer.ExtendedProperties["BMXNetSelectStatementForUpdate"]=bmxCommand.CommandText;
				answer.ExtendedProperties["RpmsQuery"]=generationString;
				answer.ExtendedProperties["RpmsSchema"]=this.RpmsSchema(generationString);
				
				return answer;
			}
			catch (Exception exception) 
			{
                 throw new Exception("Unable to retrive data from RPMS.", exception);
			} 
			finally 
			{
				if (bmxConnection != null)
					bmxConnection.ToString();
			}
		}




		private String RpmsSchema(String aString) 
		{
			char[] carrotDelimiter="^".ToCharArray();
			String[] parts=aString.Split(carrotDelimiter);
			return parts[1];
		}

		public DataTable TableFromRPC(String rpcCommand,String rpcParameter,String context) 
		{
			return this.TableFromRPC(rpcCommand,rpcParameter,context,new DataSet());		
		}


		
		public DataTable TableFromRPC(String rpcCommand,String rpcParameter,String context,DataSet aDataSet)
		{
			return this.TableFromRPC(rpcCommand,rpcParameter,context,aDataSet,"Table");		
		}

	

		public DataTable TableFromRPC(String rpcCommand,String rpcParameter,String context,DataSet aDataSet, String aTableName)
		{
			String tableGenerationRpc=this.TransmitRPC(rpcCommand,rpcParameter,context);

            if (IsTableGenerationRpc(tableGenerationRpc))
                return this.TransmitTableGenerationRPC(tableGenerationRpc, aDataSet, aTableName);
            else
            {
                 return null;
            }
		}

		public String RpcResult 
		{
			get { return this._rpcResult; }
			set { this._rpcResult=value; }
		}



		public virtual DataTable TableFromSQL(String sql) 
		{
			BMXNetConnection bmxConnection;
			BMXNetCommand bmxCommand;
			BMXNetDataAdapter bmxDataAdaptor;

			this.m_brokerLibrary.AppContext="BSDXRPC";
			bmxConnection= new BMXNetConnection(this.m_brokerLibrary);
			
			bmxConnection.Open();
            if (bmxConnection.State != ConnectionState.Open)
            {
                 throw new BMXNetException("Unable to connect to RPMS.");
            }

			try 
			{
				bmxCommand = bmxConnection.CreateCommand() as BMXNetCommand;
				bmxCommand.CommandText = sql;
				bmxDataAdaptor = new BMXNetDataAdapter();
				bmxDataAdaptor=this.m_cachedDataAdapter;
				bmxDataAdaptor.SelectCommand=bmxCommand;
				
				DataSet dataSet = new DataSet();
				bmxDataAdaptor.Fill(dataSet);

				DataTable answer=dataSet.Tables[0];

				answer.ExtendedProperties["BMXNetSelectStatementForUpdate"]=bmxCommand.CommandText;
				answer.ExtendedProperties["SqlQuery"]=sql;
				
				return answer;
			}
			catch (Exception exception) 
			{
                 throw new Exception("Unable to retrive sql data from RPMS.", exception);
			} 
			finally 
			{
				if (bmxConnection != null)
					bmxConnection.ToString();
				//TODO: bmxConnection.Close();
                //BMX framework lifecylce needs to be better defined.
			}

		}


		public bool IsTableGenerationRpc(String aString) 
		{		
			String validFetchTransactionPrefix="BMX ADO SS";

			return aString.StartsWith(validFetchTransactionPrefix);
		}
		

		public virtual void Close() 
		{
			this.m_brokerLibrary.CloseConnection();
		}
		
	}
}