using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Etsi.Ttcn3.Tri;
using TestCast.Ttcn3.TriTci;
using System.IO;

namespace TestCastTortureAdapter
{
    /**
     * NOTE To build the .dat file, please follow these step:
     *  1. In Wireshark, select the diameter packet
     *  2. Select Diameter Protocol subtree
     *  3. Right click/Copy/Bytes (Hex Stream)
     *  4. Paste the clipboard into the .dat file
     *  5. The .dat file name shall match a testcase name in TortureTest_DIAMETER\TortureTestSolution\DiameterTortureTestCases.ttcn
     */
    class TortureAdapter : ITriCommunicationSA,ITriPlatformPA, IChannelEventHandler
    {
        #region ITriCommunicationSA Members
        private string m_sTestCaseName = null;

        public TriStatus TriCall(ITriComponentId componentId, ITriPortId tsiPortId, ITriAddress sutAddress, ITriSignatureId signatureId, ITriParameterList parameterList)
        {
            return TriStatus.TriOk;
        }

        public TriStatus TriCallBC(ITriComponentId componentId, ITriPortId tsiPortId, ITriSignatureId signatureId, ITriParameterList parameterList)
        {
            return TriStatus.TriOk;
        }

        public TriStatus TriCallMC(ITriComponentId componentId, ITriPortId tsiPortId, ITriAddressList sutAddresses, ITriSignatureId signatureId, ITriParameterList parameterList)
        {
            return TriStatus.TriOk;
        }

        public TriStatus TriEndTestCase()
        {
            m_sTestCaseName = null;
            return TriStatus.TriOk;
        }

        public TriStatus TriExecuteTestCase(ITriTestCaseId testCaseId, ITriPortIdList portIdList)
        {
            m_sTestCaseName = testCaseId.BaseName;
            if (portIdList == null || portIdList.Size == 0)
            {
                Console.WriteLine("Should have at least 1 port.");
                return TriStatus.TriError;
            }
            m_port = portIdList[0];
            return TriStatus.TriOk;
        }

        private ITriPortId m_port;
        private ITriComponentId m_comp;

        public TriStatus TriMap(ITriPortId compPortId, ITriPortId tsiPortId)
        {
            m_comp = compPortId.Component;
            new System.Threading.Thread(new System.Threading.ThreadStart(SendMessageFor)).Start();
            return TriStatus.TriOk;
        }

        private static string Hexa = "0123456789abcdef";
        private void SendMessageFor()
        {
            System.Threading.Thread.Sleep(500);
            try
            {
                string sFilePath = "data\\" + m_sTestCaseName + ".dat";//..\\..\\..\\..\\
                if (!File.Exists(sFilePath))
                {
                    Console.WriteLine("Could not find the file: " + sFilePath);
                    return;
                }

                FileStream fs = new FileStream(sFilePath, FileMode.Open);
                int nLen = (int)fs.Length;
                byte[] data = new byte[nLen];
                int nRead = 0;
                while ((nRead = fs.Read(data, (int)fs.Position, nLen)) > 0)
                    nLen -= nRead;
                fs.Close();
                // Convert into hexadecimal array
                byte[] conv = new byte[data.Length / 2];
                byte idx1 = 0x00;
                byte idx2 = 0x00;
                for (int i = 0, j = 0; i < data.Length; i += 2)
                {
                    idx1 = (byte)Hexa.IndexOf((char)data[i]);
                    idx2 = (byte)Hexa.IndexOf((char)data[i + 1]);
                    conv[j++] = (byte)((byte)(idx1 & 0x0f) << 4 | (byte)(idx2 & 0x0f));
                }
                TriMessage msg = new TriMessage(conv, conv.Length * 8);
                if (!m_evExit.WaitOne(0))
                {
                    TriTciChannel.Instance.EnqueueMessage(m_port, new TriAddress(), m_comp, msg);
                    Console.WriteLine(string.Format("{0} bytes sent.", data.Length));
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.ToString());
            }
        }

        public TriStatus TriRaise(ITriComponentId componentId, ITriPortId tsiPortId, ITriAddress sutAddress, ITriSignatureId signatureId, ITriException exc)
        {
            return TriStatus.TriOk;
        }

        public TriStatus TriRaiseBC(ITriComponentId componentId, ITriPortId tsiPortId, ITriSignatureId signatureId, ITriException exc)
        {
            return TriStatus.TriOk;
        }

        public TriStatus TriRaiseMC(ITriComponentId componentId, ITriPortId tsiPortId, ITriAddressList sutAddresses, ITriSignatureId signatureId, ITriException exc)
        {
            return TriStatus.TriOk;
        }

        public TriStatus TriReply(ITriComponentId componentId, ITriPortId tsiPortId, ITriAddress sutAddress, ITriSignatureId signatureId, ITriParameterList parameterList, ITriParameter returnValue)
        {
            return TriStatus.TriOk;
        }

        public TriStatus TriReplyBC(ITriComponentId componentId, ITriPortId tsiPortId, ITriSignatureId signatureId, ITriParameterList parameterList, ITriParameter returnValue)
        {
            return TriStatus.TriOk;
        }

        public TriStatus TriReplyMC(ITriComponentId componentId, ITriPortId tsiPortId, ITriAddressList sutAddresses, ITriSignatureId signatureId, ITriParameterList parameterList, ITriParameter returnValue)
        {
            return TriStatus.TriOk;
        }

        public TriStatus TriSAReset()
        {
            return TriStatus.TriOk;
        }

        public TriStatus TriSend(ITriComponentId componentId, ITriPortId tsiPortId, ITriAddress address, ITriMessage sentMessage)
        {
            return TriStatus.TriOk;
        }

        public TriStatus TriSendBC(ITriComponentId componentId, ITriPortId tsiPortId, ITriMessage sentMessage)
        {
            return TriStatus.TriOk;
        }

        public TriStatus TriSendMC(ITriComponentId componentId, ITriPortId tsiPortId, ITriAddressList addresses, ITriMessage sentMessage)
        {
            return TriStatus.TriOk;
        }

        public TriStatus TriSutActionInformal(string description)
        {
            return TriStatus.TriOk;
        }

        public TriStatus TriUnmap(ITriPortId compPortId, ITriPortId tsiPortId)
        {
            return TriStatus.TriOk;
        }

        #endregion

        #region IChannelEventHandler Members
        System.Threading.ManualResetEvent m_evExit = new System.Threading.ManualResetEvent(false);
        public void OnConnectionClosed()
        {
            Console.WriteLine("Connection closed...");
            m_evExit.Set();
        }

        public void OnConnectionEstablished()
        {
            Console.WriteLine("Connection established...");
        }

        public void OnError(string sErrorDescription)
        {
            Console.WriteLine("TRI error: ");
            Console.WriteLine(sErrorDescription);
        }

        #endregion


        public void run()
        {
            SendMessageFor();

            TriProvider.Instance.TriPlatformPA = this;
            TriProvider.Instance.TriCommunicationSA = this;
            TriTciChannel.Instance.ApplicationName = "TortureTestAdapter";
            TriTciChannel.Instance.EventHandler = this;

            if (TriTciChannel.Instance.Open())
            {
                m_evExit.WaitOne();
            }

            System.Threading.Thread.Sleep(1000);
        }

        #region ITriPlatformPA Members

        public TriStatus TriExternalFunction(ITriFunctionId functionId, ITriParameterList parameterList, ITriParameter returnValue)
        {
            throw new NotImplementedException();
        }

        public TriStatus TriPAReset()
        {
            return TriStatus.TriOk;
        }

        public TriStatus TriReadTimer(ITriTimerId timerId, ITriTimerDuration elapsedTime)
        {
            throw new NotImplementedException();
        }

        public TriStatus TriStartTimer(ITriTimerId timerId, ITriTimerDuration duration)
        {
            throw new NotImplementedException();
        }

        public TriStatus TriStopTimer(ITriTimerId timerId)
        {
            throw new NotImplementedException();
        }

        public TriStatus TriTimerRunning(ITriTimerId timerId, ITriBoolean running)
        {
            throw new NotImplementedException();
        }

        #endregion
    }
}
