using System.Net.Sockets;
using System.Net;
using System.Runtime.InteropServices;
using System.Text;
using System;
using System.Web.Hosting;
using System.Threading.Tasks;
using System.Threading;
using System.Collections.Generic;
using System.Collections.Concurrent;
using System.IO;
using System.Text.RegularExpressions;
using static ILRewriteProfilerHelper.ProfilerHelper;
using System.Diagnostics;

namespace ILRewriteProfilerHelper
{
	    public class GlobalIP1
    {
       
        public  Socket socketUDP= new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);

        public  IPEndPoint GlobalEndPoint; // Global IPEndPoint variable
        public  void InitializeEndPoint(string ipAddress, int port)
        {
            GlobalEndPoint = new IPEndPoint(IPAddress.Parse(ipAddress), port);
        }

    
    }

      [StructLayout(LayoutKind.Sequential, Pack = 1)]
        struct MsgHdr
        {
            public int header_len;
            public int total_len;
            public int msg_type;
        }

    //----------------
    [Serializable]
    public struct AppId
        {
            public int id { get; set; }

    }

    [Serializable]
    public struct TierInfo
        {
            public int tierID { get; set; }
            public int AppServerID{ get; set; }
            public int appID { get; set; }
         }


    [Serializable]
    public struct TestInfo
        {
            public int TestNumber { get; set; }
        public int bciInstrSessionPct { get; set; }

        public int captureMethodForAllFP { get; set; }
        }

    [Serializable]
    public struct NDCookie
        {
            public int enableNDSession { get; set; }
            public string CookieName { get; set; }
            public int headerInResponse { get; set; }
            public int mpos { get; set; }
            public int maxFPCountInSession { get; set; }
            public int ndSessionIdleTimeOutSecs { get; set; }

        }


  
    [Serializable]
    public struct NVCookie
        {
            public string NVCookieName { get; set; }
    }


    [Serializable]
    public struct CorelationHeader
        {
            public string corelationheader { get; set; }
    }


    [Serializable]
    public struct BackendNameRule
    {
        public string BackendNameRuleValue { get; set; }

    }

    [Serializable]
    public struct otel
    {
        public string otelkeyword { get; set; }

    }

    [Serializable]
    public struct DBBackendName
    {
        public int enableDBBackendName { get; set; }

    }

    [Serializable]
    public struct recvstructure
    {
        public CorelationHeader corelationHeader { get; set; }
        public NVCookie nVCookie { get; set; }
        public NDCookie nDCookie { get; set; }
        public TestInfo testInfo { get; set; }
        public TierInfo tierInfo { get; set; }
        public AppId appId { get; set; }
        public BackendNameRule backendNameRule { get; set; }
        public otel otel { get; set; }
        public DBBackendName DBBackendName { get; set; }
    }

    //-------------------------------------

    [StructLayout(LayoutKind.Sequential, Pack = 1)]
        struct WrapHeaderVar
        {
            public int WhLen;
            public int ApiReqLen;
            public int AwsReqLen;
            public int FuncNameLen;
            public int TagsLength;
            public short AgentType;
            public short MessageType;
            public long fpid;
            public int appid;
            public int protocol;
        }

        [StructLayout(LayoutKind.Sequential, Pack = 1)]
        struct WrapHeader
        {
            public WrapHeaderVar WrapHeaderVar;
            public string apiReqId;
            public string awsReqId;
            public string funcName;
            public string tags;//; separated key=value pairs
        }

        [StructLayout(LayoutKind.Sequential, Pack = 1)]
        struct MethodEntryVar_t
        {
            public int mid;
            public long flowpathinstance;
            public long threadId;
            public long startTime;
            public int methodName;
            public int query_string;
            public int urlParameter;
            public int query_parameter;
        }

        [StructLayout(LayoutKind.Sequential, Pack = 1)]
        struct methodEntry_t   
        {
            public MethodEntryVar_t methodEntryVar;

            public string methodName;
            public string query_string;
            public string urlParameter;
            public string query_parameter;
        }

        [StructLayout(LayoutKind.Sequential, Pack = 1)]
        struct MethodExitVar_t
        {
            public int statusCode;
            public int mid;
            public int eventType;
            public int isCallout;
            public long threadId;
            public long duration;
            public long flowpathinstance;
            public long cpuTime;

            public int methodName;
            public int backend_header;
            public int requestNotificationPhase;
            public long tierCallOutSeqNum;
            public long endTime;
        }

        [StructLayout(LayoutKind.Sequential, Pack = 1)]
        struct transactionStartVar_t
        {
            public int fp_header;
            public int url;
            public int btHeaderValue;
            public int ndCookieSet;
            public int nvCookieSet;
            public int correlationHeader;
            public long flowpathinstance;
            public long qTimeMS;
            public long startTimeFP;
        }

        [StructLayout(LayoutKind.Sequential, Pack = 1)]
        struct transactionEnd_t
        {
            public int statuscode;
            public long flowpathinstance;
            public long endTime;
            public long cpuTime;
            public int tracerequest;
        }

        [StructLayout(LayoutKind.Sequential, Pack = 1)]
        struct Reqrespheadervar_t
        {
            public int statuscode;
            public int buffer_len;
            public int type_len;
            public int OTL_version;
            public int OTL_traceflag;
            public int OTL_traceID;
            public int OTL_parentID;
            public int OTL_tracestate;
            public long flowpathinstance;

        }

        [StructLayout(LayoutKind.Sequential, Pack = 1)]
        struct Reqrespheader_t
        {
            public Reqrespheadervar_t reqrespheadervar;
            public string buffer;
            public string type;
            public string OTL_traceID;
            public string OTL_parentID;
            public string OTL_tracestate;
        }

        [StructLayout(LayoutKind.Sequential, Pack = 1)]
        struct MethodExit_t
        {
            public MethodExitVar_t MethodExitVar;

            public string methodName;
            public string backend_header;
            public string requestNotificationPhase;
        }

    [StructLayout(LayoutKind.Sequential, Pack = 1)]
         struct transactionStart_t
        {
            public transactionStartVar_t transactionStartVar;

            public string header;
            public string url;
            public string btHeaderValue;
            public string ndCookieSet;
            public string nvCookieSet;
            public string correlationHeader;
        }

    public class DataItem
    {
        public int IntValue { get; }
        public byte[] ByteArray { get; }

        public DataItem(int intValue, ref byte[] byteArray)
        {
            IntValue = intValue;
            ByteArray = byteArray;
        }
    }

    


    public class UDPclass
    {

		public string applicationName;

        public UDPclass(string processname)
		{
            applicationName = processname;
		}
        public string Getvariable(string key)
        {
            try
            {
                string ndhome = null;
                if (Environment.GetEnvironmentVariable("NDHOME")!=null)
                {
                    ndhome = Environment.GetEnvironmentVariable("NDHOME");
                }
                else
                {
                    ndhome = "C:\\opt\\cavisson\\netdiagnostics";

				}
                string filePath = ndhome+"\\dotnet\\config\\ndsettings.conf";
                string keywordToSearch = "CAV_APP_AGENT_" + key;

                string keywordValue = Environment.GetEnvironmentVariable(keywordToSearch);


                if (keywordValue == null)
                {
                    keywordValue = GetValueForKeyword(filePath, key);

                }
                return keywordValue;
            }
            catch(Exception ex)
            {
                logger.LogError("An error occurred in Getvariable: " + ex.Message);
                ProfilerHelper.Log((int)LogLevel.ERROR, "An error occurred in Getvariable: " + ex.Message);
                return null;
            }
        }



        public string GetValueForKeyword(string filePath, string keyword)
        {
            try
            {

                string[] lines = File.ReadAllLines(filePath);

                foreach (string line in lines)
                {
                    if (line.StartsWith(keyword + "=", StringComparison.OrdinalIgnoreCase))
                    {

                        string[] parts = line.Split(new[] { '=' }, 2);
                        if (parts.Length == 2)
                        {
                            return parts[1].Trim();
                        }
                    }
                }

                return null;
            }
            catch (IOException ex)
            {
                logger.LogError("Error: " + ex.Message);
                ProfilerHelper.Log((int)LogLevel.ERROR, "Error: " + ex.Message);
                return null;

            }
        }


        public bool ReturnenableNDsession()
        {
            if(recvstructure1.nDCookie.enableNDSession != 0)
            {
                return true;
            }
            return false;
        }
  
  
        public bool CheckAndPrintByteArrayList(int rsock)
        {
            int count1 = 0;

            while (true)
            {
                try
                {
                    lock (global_lockObject)
                    {
                        Monitor.Wait(global_lockObject);

                       

                    foreach (var items in PrintList)
                    {
                         //   logger.LogError( $" items.IntValue {items.IntValue} count : {++count1 }");
                            //StringBuilder sb = new StringBuilder(); // Use StringBuilder for efficient string concatenation
                            //for (int i1 = 0; i1 < items.IntValue; i1++)
                            //{
                            //    sb.Append(items.ByteArray[i1]);
                            //    sb.Append(" ");
                            //}

                            //string packetContent = sb.ToString();
                            //logger.LogError("packetBytes content: " + packetContent);
                            rudp.rudp_sendto(rsock, items.ByteArray, items.IntValue, globalIP.GlobalEndPoint);
                          

                            bytearray55kb.Release(items.ByteArray);

          }

                    PrintList.Clear();
                

            }
        }
                catch(Exception ex)
                {
                    logger.LogError("EXCEPTION: "+ex.Message);
                    ProfilerHelper.Log((int)LogLevel.ERROR, "EXCEPTION: " + ex.Message);

                }
            }
        }

        //static void DecodeUdpMessageWrapper(byte[] buf, int readBytes)
        //{
        //    int numBytes = 0;
        //    byte[] str = buf;
        //    int curIndex = 0;
        //    int whlen = 0;
        //    int totalLen = 0;

        //    while (curIndex < readBytes)
        //    {
        //        if (buf[curIndex] != 94)
        //        {
        //            break;
        //        }

        //        whlen = BitConverter.ToInt32(new byte[] { buf[curIndex + 1], buf[curIndex + 2], buf[curIndex + 3], buf[curIndex + 4] }, 0);
        //        if (whlen < 40)
        //            break;
        //        curIndex += whlen;
        //        if (curIndex >= readBytes)
        //            break;
        //        if (buf[curIndex] == 10)
        //        {
        //            byte[] ptr = new byte[readBytes - curIndex];
        //            Array.Copy(buf, curIndex, ptr, 0, readBytes - curIndex);
        //            curIndex++;
        //            numBytes = ptr.Length;
        //            ptr = RemoveFirstElement(ptr);
        //            DecodeUdpMessage(str, numBytes);
        //            str = ptr;
        //            continue;
        //        }

        //        if (curIndex > readBytes - 6)
        //            break;
        //        totalLen = BitConverter.ToInt32(new byte[] { buf[curIndex + 1 + 4], buf[curIndex + 1 + 5], buf[curIndex + 1 + 6], buf[curIndex + 1 + 7] }, 0);
        //        if (totalLen < 12)
        //            break;
        //        curIndex += totalLen - 1;
        //        if (curIndex >= readBytes)
        //            break;
        //        if (buf[curIndex] == 10)
        //        {
        //            byte[] ptr = new byte[readBytes - curIndex];
        //            Array.Copy(buf, curIndex, ptr, 0, readBytes - curIndex);
        //            curIndex++;
        //            numBytes = ptr.Length;
        //            ptr = RemoveFirstElement(ptr);
        //            DecodeUdpMessage(str, numBytes);
        //            str = ptr;
        //        }
        //        else
        //            break;
        //    }

        //    // Process missing data
        //    if (readBytes - curIndex > 1)
        //        DecodeUdpMessage(str, readBytes - curIndex);
        //}

        //static void DecodeUdpMessage(byte[] buf, int readBytes)
        //{
        //    StringBuilder sb = new StringBuilder();

        //    for (int i=0;i< readBytes; i++)
        //    {
        //        sb.Append(buf[i]);
        //        sb.Append(" ");
        //    }
        //    string packetContent = sb.ToString();
        //    ProfilerHelper.Log((int)LogLevel.ERROR, "packetContent: " + packetContent);

        //}

        //static byte[] RemoveFirstElement(byte[] array)
        //{
        //    byte[] newArray = new byte[array.Length - 1];
        //    Array.Copy(array, 1, newArray, 0, newArray.Length);
        //    return newArray;
        //}


        private void SendChunk(Socket s, EndPoint ep, byte[] data, int offset, int chunkSize)
        {
            s.BeginSendTo(data, offset, chunkSize, SocketFlags.None, ep, ar =>
            {
                try
                {
                    s.EndSendTo(ar);
                }
                catch (Exception ex)
                {
                    logger.LogError("Error: " + ex.Message);
                    ProfilerHelper.Log((int)LogLevel.ERROR, "Error: " + ex.Message);

                }
            }, null);
        }

        public class ByteArrayPool
        {
            private ConcurrentQueue<byte[]> pool;
            private int arraySize;

            public ByteArrayPool(int poolSize, int arraySize)
            {
                this.arraySize = arraySize;
                this.pool = new ConcurrentQueue<byte[]>();

                for (int i = 0; i < poolSize; i++)
                {
                    this.pool.Enqueue(new byte[arraySize]);
                }
            }

            public byte[] Acquire()
            {
                if (pool.TryDequeue(out var array))
                {
                    return array;
                }
                else
                {
                    return new byte[arraySize];
                }
            }

            public void Release(byte[] array)
            {
                if (array.Length == arraySize)
                {
                    Array.Clear(array, 0, array.Length);
                    pool.Enqueue(array);
                }
                else
                {
                    throw new ArgumentException("Invalid array size for this pool.");
                }
            }
        }


        private List<DataItem> PrintList = new List<DataItem>();

        public void StoreByteArrays()
        {

            if (len >= 45 * 1024)
            {
                lock (global_lockObject)
                {
                    DataItem data1 = new DataItem(len, ref globalbyte1);
                    PrintList.Add(data1);
                    Monitor.Pulse(global_lockObject);
                }
                globalbyte1 = bytearray55kb.Acquire();
                len = 0;               
            }

        }


        public unsafe void GetByteslong(long value, int offset)
        {
            for (int i = 0; i < sizeof(long); i++) //remove loop
            {
                globalbyte1[offset + i] = (byte)(value >> (i * 8));
            }
        }

        public unsafe void GetBytesint(int value, int offset)
        {
            globalbyte1[offset] = (byte)(value & 0xFF);
            globalbyte1[offset + 1] = (byte)((value >> 8) & 0xFF);
            globalbyte1[offset + 2] = (byte)((value >> 16) & 0xFF);
            globalbyte1[offset + 3] = (byte)((value >> 24) & 0xFF);
        }

        public unsafe void GetBytesshort(short value, int offset)
        {
            globalbyte1[offset] = (byte)(value & 0xFF);
            globalbyte1[offset + 1] = (byte)((value >> 8) & 0xFF);
        }

        public int WrapHeaderVarlen;

        public string serverName;
        public string tagsString;
        public string tiername;



        static string GetMachineName()
        {
            string machineName = string.Empty;

            try
            {
                machineName = System.Net.Dns.GetHostName();
            }
            catch (Exception ex)
            {
                logger.LogError("Error retrieving machine name: " + ex.Message);
            }

            return machineName;
        }


        public int preparewrapheader()
        {

            if (serverName == null)
            {
                serverName = Getvariable("SERVER");
                if (serverName == null)
                {
                serverName = GetMachineName();
            }  
            }  

            if (tiername == null)
            {
                tiername = Getvariable("TIER");
            }


            if (tagsString == null)
            {
                tagsString = string.Format("tierName={0};ndAppServerHost={1};appName={2};agentName={3}", tiername, serverName, applicationName, applicationName);
            }

            if (WrapHeaderVarlen == 0)
            {
                WrapHeaderVarlen = Marshal.SizeOf(typeof(WrapHeaderVar));
            }

            int TagsLength = tagsString != null ? tagsString.Length : 0;
            
            int WhLen1 = WrapHeaderVarlen + TagsLength + 1;

            return WhLen1;


        }
            public void populatewrapheader( IntPtr tlsData, int WhLen ,short msgType)
        {
     

            string apiReqId = null;
            string awsReqId = null;
            string funcName = null;
            if (serverName == null)
            {
				serverName = Getvariable("SERVER");
				if (serverName == null)
				{
                serverName = GetMachineName();
            }
			}


            if (tiername == null)
            {
                tiername = Getvariable("TIER");
            }


            if (tagsString == null)
            {
                tagsString = string.Format("tierName={0};ndAppServerHost={1};appName={2};agentName={3}", tiername, serverName, applicationName, applicationName);
            }

            if (WrapHeaderVarlen == 0)
            {
                WrapHeaderVarlen = Marshal.SizeOf(typeof(WrapHeaderVar));
            }

            int ApiReqLen = 0;
            int AwsReqLen = 0;
            int TagsLength = tagsString != null ? tagsString.Length : 0;
            int FuncNameLen = 0;

            globalbyte1[len] = (byte)'^';

                len += 1;

                short agentType = 2;

                //public int WhLen;
                GetBytesint(WhLen, len);
                len += sizeof(int);

                //public int ApiReqLen;
                GetBytesint(ApiReqLen,  len);
                len += sizeof(int);

                //public int AwsReqLen;
                GetBytesint(AwsReqLen,  len);
                len += sizeof(int);

                //public int FuncNameLen;
                GetBytesint(FuncNameLen,  len);
                len += sizeof(int);
                //public int TagsLength;

                GetBytesint(TagsLength,  len);
                len += sizeof(int);

                //public short AgentType;
                GetBytesshort(agentType,  len);
                len += sizeof(short);

                //public short MessageType;
                GetBytesshort(msgType,  len);
                len += sizeof(short);

                //public long fpid
                GetByteslong((long)tlsData,  len);
                len += sizeof(long);

                //public int appid
                if (recvstructure1.tierInfo.appID == 0)
                {
                    GetBytesint((int)-1, len);
                }
                else {
                    GetBytesint((int)recvstructure1.appId.id, len);
                }

                len += sizeof(int);

                //public int protocol
                GetBytesint((int)1, len);
                len += sizeof(int);


                if (ApiReqLen > 0)
                {
                    GetBytes2(apiReqId,  ApiReqLen, len);

                    len += ApiReqLen;
                }

                if (AwsReqLen > 0)
                {
                    GetBytes2(awsReqId,  AwsReqLen, len);

                    len += AwsReqLen;
                }

                if (FuncNameLen > 0)
                {
                    GetBytes2(funcName,  FuncNameLen, len);

                    len += FuncNameLen;
                }

                if (TagsLength > 0)
                {
                    GetBytes2(tagsString,  TagsLength, len);

                    len += TagsLength;
                }
       }

        public int MsgHdrlen;
        public int MethodEntryVarlen;
        public int MethodExitVarlen;

        public byte[] globalbyte1 = new byte[54 * 1024];
        private readonly object bytearray_lockObject = new object();
        private readonly object global_lockObject = new object();

        public int len = 0;



        public void methodentryexitfunction([In] IntPtr tlsData, [In] UInt64 finfo, int eventType, String urlStr, int statuscode, long methodWallTime, ulong threadId, int isCallOutDone, string RequestNotificationPhase, string DBQueryParam, string methodName, int mid, int StatusCode, long dur)
        {

            int localbytelen = 0;
            byte[] localbyte1 = null;

            if (eventType == 0)
            {
                try
                {
                    logger.LogInfo("methodentryfunction tlsdata " + tlsData + " for methodname " + methodName + " methodWallTime " + methodWallTime);
                    ProfilerHelper.Log((int)LogLevel.ERROR, "methodentryfunction tlsdata " + tlsData + " for methodname " + methodName+ " methodWallTime " +methodWallTime);

                    lock (bytearray_lockObject)
                    {
                        string urlParameter = null;
                        int methodNamelen = methodName != null ? methodName.Length : 0;
                        int query_stringlen = urlStr != null ? urlStr.Length : 0;     //-----url--
                        int urlParameterlen = 0;    //no


                        int query_parameter = DBQueryParam != null ? DBQueryParam.Length : 0;

                        if (MsgHdrlen == 0)
                        {
                            MsgHdrlen = Marshal.SizeOf(typeof(MsgHdr));
                        }

                        int header_len = MsgHdrlen;

                        if (MethodEntryVarlen == 0)
                        {
                            MethodEntryVarlen = Marshal.SizeOf(typeof(MethodEntryVar_t));
                        }

                        int total_len = MethodEntryVarlen + header_len + methodNamelen +
                                      query_stringlen + urlParameterlen + query_parameter + 3;
                        int whlen = preparewrapheader();

                        populatewrapheader(tlsData, whlen, 0);

                        int msg_type = 0;

                        globalbyte1[len] = (byte)'^';

                        len += 1;

                        //public int header_len;
                        GetBytesint(header_len, len);
                        len += sizeof(int);

                        //public int total_len;
                        GetBytesint(total_len, len);
                        len += sizeof(int);

                        //public int msg_type;
                        GetBytesint(msg_type, len);
                        len += sizeof(int);



                        globalbyte1[len] = (byte)'|';

                        len += 1;



                        //public int mid;
                        GetBytesint(mid, len);
                        len += sizeof(int);

                        //public long flowpathinstance;
                        GetByteslong((long)tlsData, len);
                        len += sizeof(long);

                        //public long threadId;
                        GetByteslong((long)Thread.CurrentThread.ManagedThreadId, len);
                        len += sizeof(long);

                        //public long startTime;
                        GetByteslong((long)methodWallTime, len);
                        len += sizeof(long);

                        //public int methodName;
                        GetBytesint(methodNamelen, len);
                        len += sizeof(int);

                        //public int query_string;
                        GetBytesint(query_stringlen, len);
                        len += sizeof(int);

                        //public int urlParameter;
                        GetBytesint(urlParameterlen, len);
                        len += sizeof(int);

                        //public int query_parameter;
                        GetBytesint(query_parameter, len);
                        len += sizeof(int);

                        if (methodNamelen > 0)
                        {
                            GetBytes2(methodName, methodNamelen, len);

                            len += methodNamelen;
                        }

                        if (query_stringlen > 0)
                        {
                            GetBytes2(urlStr, query_stringlen, len);

                            len += query_stringlen;
                        }

                        if (urlParameterlen > 0)
                        {
                            GetBytes2(urlParameter, urlParameterlen, len);

                            len += urlParameterlen;
                        }
                        if (query_parameter > 0)
                        {
                            GetBytes2(DBQueryParam, query_parameter, len);

                            len += query_parameter;
                        }
                        globalbyte1[len] = (byte)'\n';

                        len += 1;

                        if (len >= 45 * 1024)
                        {
                            localbyte1 = globalbyte1;
                            localbytelen = len;
                            globalbyte1 = bytearray55kb.Acquire();
                            len = 0;
                        }

                    }
                    if (localbytelen > 0)
                    {
                        lock (global_lockObject)
                        {
                            DataItem data1 = new DataItem(localbytelen, ref localbyte1);
                            PrintList.Add(data1);
                            Monitor.Pulse(global_lockObject);
                        }
                    }
                }
                catch (Exception ex)
                {
					if (ex.HResult == 2146233080) //Index was outside the bounds of the array
					{
						lock (bytearray_lockObject)
						{
							bytearray55kb.Release(globalbyte1);
							globalbyte1 = bytearray55kb.Acquire();
							len = 0;
						}
					}
					logger.LogError("An error occurred in methodexitfunction: " + ex.Message);
                    logger.LogError("An error occurred in methodexitfunction: " + ex.Message);
                    var LineNumber = new StackTrace(ex, true).GetFrame(0).GetFileLineNumber();
                    logger.LogError("Exception Occurred: For method: [" + methodName + "] for thread id: [" + Thread.CurrentThread.ManagedThreadId + "] Exception: [" + ex.Message + "---line no=" + LineNumber);
                    String st = System.Environment.StackTrace;
                    logger.LogError("StackTrace:\n" + st);
                }

            }
            else if (eventType == 1)
            {
                try
                {
                    logger.LogInfo("methodexitfunction tlsdata " + tlsData + " for methodname " + methodName + "%%%%%%%%%%methodWallTime: " + methodWallTime);
                    ProfilerHelper.Log((int)LogLevel.ERROR, "methodexitfunction tlsdata " + tlsData + " for methodname " + methodName + "%%%%%%%%%%methodWallTime: " + methodWallTime);


                    lock (bytearray_lockObject)
                    {
                        int isCallout = 1;
                        long duration = methodWallTime;
                        long cpuTime = 0;

                        int methodNamelen = methodName != null ? methodName.Length : 0;
                        int backend_headerlen = urlStr != null ? urlStr.Length : 0;
                        int requestNotificationPhaselen = RequestNotificationPhase != null ? RequestNotificationPhase.Length : 0;

                        if (MsgHdrlen == 0)
                        {
                            MsgHdrlen = Marshal.SizeOf(typeof(MsgHdr));
                        }
                        int header_len = MsgHdrlen;

                        if (MethodExitVarlen == 0)
                        {
                            MethodExitVarlen = Marshal.SizeOf<MethodExitVar_t>();
                        }

                        int whlen = preparewrapheader();

                        // int len = 0;

                        int total_len = MethodExitVarlen + header_len + methodNamelen + backend_headerlen +
                       requestNotificationPhaselen + 3;

                        populatewrapheader(tlsData, whlen, 0);

                        int msg_type = 1;

                        globalbyte1[len] = (byte)'^';

                        len += 1;

                        //public int header_len;
                        GetBytesint(header_len, len);
                        len += sizeof(int);

                        //public int total_len;
                        GetBytesint(total_len, len);
                        len += sizeof(int);

                        //public int msg_type;
                        GetBytesint(msg_type, len);
                        len += sizeof(int);

                        globalbyte1[len] = (byte)'|';

                        len += 1;

                        //public int statusCode;
                        GetBytesint(StatusCode, len);
                        len += sizeof(int);

                        //public int mid;
                        GetBytesint(mid, len);
                        len += sizeof(int);

                        //public int eventType;
                        GetBytesint(eventType, len);
                        len += sizeof(int);

                        //public int isCallout;
                        GetBytesint(isCallout, len);
                        len += sizeof(int);

                        //public long threadId;
                        GetByteslong((long)Thread.CurrentThread.ManagedThreadId, len);
                        len += sizeof(long);

                        //public long duration;
                        GetByteslong(duration, len);
                        len += sizeof(long);

                        //public long flowpathinstance;
                        GetByteslong((long)tlsData, len);
                        len += sizeof(long);

                        //public long cpuTime;
                        GetByteslong(cpuTime, len);
                        len += sizeof(long);

                        GetBytesint(methodNamelen, len);
                        len += sizeof(int);

                        GetBytesint(backend_headerlen, len);
                        len += sizeof(int);

                        GetBytesint(requestNotificationPhaselen, len);
                        len += sizeof(int);

                        GetByteslong(0, len); //tierCallOutSeqNum
                        len += sizeof(long);

                        GetByteslong(dur, len); //endTime
                        len += sizeof(long);

                        if (methodNamelen > 0)
                        {
                            GetBytes2(methodName, methodNamelen, len);

                            len += methodNamelen;
                        }

                        if (backend_headerlen > 0)
                        {
                            GetBytes2(urlStr, backend_headerlen, len);

                            len += backend_headerlen;
                        }

                        if (requestNotificationPhaselen > 0)
                        {
                            GetBytes2(RequestNotificationPhase, requestNotificationPhaselen, len);

                            len += requestNotificationPhaselen;
                        }

                        globalbyte1[len] = (byte)'\n';

                        len += 1;

                        if (len >= 45 * 1024)
                        {
                            localbyte1 = globalbyte1;
                            localbytelen = len;
                            globalbyte1 = bytearray55kb.Acquire();
                            len = 0;
                        }

                    }
                    if (localbytelen > 0)
                    {
                        lock (global_lockObject)
                        {
                            DataItem data1 = new DataItem(localbytelen, ref localbyte1);
                            PrintList.Add(data1);
                            Monitor.Pulse(global_lockObject);
                        }
                    }

                }
                catch(Exception ex)
                {
					if (ex.HResult == 2146233080) //Index was outside the bounds of the array
					{
						lock (bytearray_lockObject)
						{
							bytearray55kb.Release(globalbyte1);
							globalbyte1 = bytearray55kb.Acquire();
							len = 0;
						}
					}
                    logger.LogError("An error occurred in methodexitfunction: " + ex.Message);
                    ProfilerHelper.Log((int)LogLevel.ERROR, "An error occurred in methodexitfunction: " + ex.Message);
                    var LineNumber = new StackTrace(ex, true).GetFrame(0).GetFileLineNumber();
                    logger.LogError("Exception Occurred: For method: [" + methodName + "] for thread id: [" + Thread.CurrentThread.ManagedThreadId + "] Exception: [" + ex.Message + "---line no=" + LineNumber);
                    String st = System.Environment.StackTrace;
                    logger.LogError("StackTrace:\n" + st);
                }
            }
            else
            {
                logger.LogError("Wrong eventType for method: " + methodName);
                ProfilerHelper.Log((int)LogLevel.ERROR, "Wrong eventType for method: " + methodName);

                return;
            }
        }

        public int transactionStartVarlen;
        public void transactionstartfunction(String fpStr, String urlStr, String btStr, String NDCookie, String NVCookie, String corrId, long qtime, long startTime, string methodName, IntPtr tlsData)
        {
            try
            {
                logger.LogInfo("transactionstartfunction tlsdata " + tlsData + " for methodname " + methodName + " ARYANNNNN " + corrId+ "fpStr: "+ fpStr);
                ProfilerHelper.Log((int)LogLevel.ERROR, "transactionstartfunction tlsdata " + tlsData + " for methodname " + methodName +" ARYANNNNN "+ corrId);

                int localbytelen = 0;
                byte[] localbyte1 = null;
                lock (bytearray_lockObject)
                {


                    {
                        long qTimeMS = 0;

                        int fp_headerlen = fpStr != null ? fpStr.Length : 0;
                        int urllen = urlStr != null ? urlStr.Length : 0;
                        int btHeaderValuelen = btStr != null ? btStr.Length : 0;
                        int ndCookieSetlen = NDCookie != null ? NDCookie.Length : 0;
                        int nvCookieSetlen = NVCookie != null ? NVCookie.Length : 0;
                        int correlationHeaderlen = corrId != null ? corrId.Length : 0;

                        if (MsgHdrlen == 0)
                        {
                            MsgHdrlen = Marshal.SizeOf(typeof(MsgHdr));
                        }

                        int header_len = MsgHdrlen;

                        if (transactionStartVarlen == 0)
                        {
                            transactionStartVarlen = Marshal.SizeOf<transactionStartVar_t>();
                        }
                        int whlen = preparewrapheader();

                        //int len = 0;

                        int total_len = transactionStartVarlen + header_len + fp_headerlen + ndCookieSetlen + nvCookieSetlen + correlationHeaderlen + btHeaderValuelen + urllen + 3;


                        populatewrapheader(tlsData, whlen, 0);

                        int msg_type = 2;

                        globalbyte1[len] = (byte)'^';

                        len += 1;

                        //public int header_len;
                        GetBytesint(header_len, len);
                        len += sizeof(int);

                        //public int total_len;
                        GetBytesint(total_len, len);
                        len += sizeof(int);

                        //public int msg_type;
                        GetBytesint(msg_type, len);
                        len += sizeof(int);

                        globalbyte1[len] = (byte)'|';

                        len += 1;

                        //public int fp_header;
                        GetBytesint(fp_headerlen, len);
                        len += sizeof(int);

                        //public int url;
                        GetBytesint(urllen, len);
                        len += sizeof(int);

                        //public int btHeaderValue;
                        GetBytesint(btHeaderValuelen, len);
                        len += sizeof(int);

                        //public int ndCookieSet;
                        GetBytesint(ndCookieSetlen, len);
                        len += sizeof(int);

                        //public int nvCookieSet;
                        GetBytesint(nvCookieSetlen, len);
                        len += sizeof(int);

                        //public int correlationHeader;
                        GetBytesint(correlationHeaderlen, len);
                        len += sizeof(int);

                        //public long flowpathinstance;
                        GetByteslong((long)tlsData, len);
                        len += sizeof(long);

                        //public long qTimeMS;
                        GetByteslong(qTimeMS, len);
                        len += sizeof(long);

                        //public long startTimeFP;
                        GetByteslong(startTime, len);
                        len += sizeof(long);

                        if (fp_headerlen > 0)
                        {
                            GetBytes2(fpStr, fp_headerlen, len);

                            len += fp_headerlen;
                        }

                        if (urllen > 0)
                        {
                            GetBytes2(urlStr, urllen, len);

                            len += urllen;
                        }

                        if (btHeaderValuelen > 0)
                        {
                            GetBytes2(btStr, btHeaderValuelen, len);

                            len += btHeaderValuelen;
                        }

                        if (ndCookieSetlen > 0)
                        {
                            GetBytes2(NDCookie, ndCookieSetlen, len);

                            len += ndCookieSetlen;
                        }

                        if (nvCookieSetlen > 0)
                        {
                            GetBytes2(NVCookie, nvCookieSetlen, len);

                            len += nvCookieSetlen;
                        }

                        if (correlationHeaderlen > 0)
                        {
                            GetBytes2(corrId, correlationHeaderlen, len);

                            len += correlationHeaderlen;
                        }

                        globalbyte1[len] = (byte)'\n';

                        len += 1;

                        if (len >= 45 * 1024)
                        {
                            localbyte1 = globalbyte1;
                            localbytelen = len;
                            globalbyte1 = bytearray55kb.Acquire();
                            len = 0;
                        }

                    }
                    if (localbytelen > 0)
                    {
                        lock (global_lockObject)
                        {
                            DataItem data1 = new DataItem(localbytelen, ref localbyte1);
                            PrintList.Add(data1);
                            Monitor.Pulse(global_lockObject);
                        }
                    }
                }
            }
            catch(Exception ex)
            {
				if (ex.HResult == 2146233080) //Index was outside the bounds of the array
				{
					lock (bytearray_lockObject)
					{
						bytearray55kb.Release(globalbyte1);
						globalbyte1 = bytearray55kb.Acquire();
						len = 0;
					}
				}
                logger.LogError("An error occurred in transactionstartfunction: " + ex.Message);
                ProfilerHelper.Log((int)LogLevel.ERROR, "An error occurred in transactionstartfunction: " + ex.Message);
                var LineNumber = new StackTrace(ex, true).GetFrame(0).GetFileLineNumber();
                logger.LogError("Exception Occurred: For method: [" + methodName + "] for thread id: [" + Thread.CurrentThread.ManagedThreadId + "] Exception: [" + ex.Message + "---line no=" + LineNumber);
                String st = System.Environment.StackTrace;
                logger.LogError("StackTrace:\n" + st);


            }
        }

        public int transactionEndlen;
        public void transactionendfunction([In] IntPtr tlsData, [In] UInt64 finfo, int statusCode, long fpEndTime, string methodName)
        {
            try
            {
                logger.LogInfo("transactionendfunction tlsdata " + tlsData + " for methodname " + methodName);
                ProfilerHelper.Log((int)LogLevel.ERROR, "transactionendfunction tlsdata " + tlsData + " for methodname " + methodName);


                int localbytelen = 0;
                byte[] localbyte1 = null;

                lock (bytearray_lockObject)
                {
                    if (transactionEndlen == 0)
                    {
                        transactionEndlen = Marshal.SizeOf<transactionEnd_t>();
                    }

                    if (MsgHdrlen == 0)
                    {
                        MsgHdrlen = Marshal.SizeOf(typeof(MsgHdr));
                    }

                    int header_len = MsgHdrlen;

                    int whlen = preparewrapheader();

                    // int len = 0;

                    int total_len = transactionEndlen + header_len + 3;


                    populatewrapheader(tlsData, whlen, 0);

                    int msg_type = 3;

                    globalbyte1[len] = (byte)'^';

                    len += 1;

                    //public int header_len;
                    GetBytesint(header_len, len);
                    len += sizeof(int);

                    //public int total_len;
                    GetBytesint(total_len, len);
                    len += sizeof(int);

                    //public int msg_type;
                    GetBytesint(msg_type, len);
                    len += sizeof(int);

                    globalbyte1[len] = (byte)'|';

                    len += 1;

                    GetBytesint(statusCode, len);
                    len += sizeof(int);

                    //public long flowpathinstance;
                    GetByteslong((long)tlsData, len);
                    len += sizeof(long);

                    //public long endTime;
                    GetByteslong(fpEndTime, len);
                    len += sizeof(long);

                    //public long cpuTime;
                    GetByteslong((long)0, len);
                    len += sizeof(long);

                    //public int tracerequest;
                    GetBytesint((int)0, len);
                    len += sizeof(int);

                    globalbyte1[len] = (byte)'\n';
                    len += 1;
                    if (len >= 45 * 1024)
                    {
                        localbyte1 = globalbyte1;
                        localbytelen = len;
                        globalbyte1 = bytearray55kb.Acquire();
                        len = 0;
                    }

                }
                if (localbytelen > 0)
                {
                    lock (global_lockObject)
                    {
                        DataItem data1 = new DataItem(localbytelen, ref localbyte1);
                        PrintList.Add(data1);
                        Monitor.Pulse(global_lockObject);
                    }
                }
            }
            catch(Exception ex)
            {
				if (ex.HResult == 2146233080) //Index was outside the bounds of the array
				{
					lock (bytearray_lockObject)
					{
						bytearray55kb.Release(globalbyte1);
						globalbyte1 = bytearray55kb.Acquire();
						len = 0;
					}
				}
                logger.LogError("An error occurred in transactionendfunction: " + ex.Message);
                ProfilerHelper.Log((int)LogLevel.ERROR, "An error occurred in transactionendfunction: " + ex.Message);
                var LineNumber = new StackTrace(ex, true).GetFrame(0).GetFileLineNumber();
                logger.LogError("Exception Occurred: For method: [" + methodName + "] for thread id: [" + Thread.CurrentThread.ManagedThreadId + "] Exception: [" + ex.Message + "---line no=" + LineNumber);
                String st = System.Environment.StackTrace;
                logger.LogError("StackTrace:\n" + st);

            }
        }

        public int Reqrespheadervarlen;

        public void capturereqrespfunction([In] IntPtr tlsData, string buffer, string type, int statusCode, string methodName, string otl_traceid, string otl_parentid,string otl_tracestate,int otl_version,int otl_traceflag)
        {
            try
            {
                logger.LogInfo("capturehttpreqresp tlsdata " + tlsData + " for methodname " + methodName + " otl_traceid " + otl_traceid + ":" + otl_traceid.Length + "otl_parentid " + otl_parentid + ":" + otl_parentid.Length + " otl_tracestate " + otl_tracestate + ":" + otl_tracestate.Length + " otl_version " + otl_version + " otl_traceflag " + otl_traceflag);
                ProfilerHelper.Log((int)LogLevel.ERROR, "capturehttpreqresp tlsdata " + tlsData + " for methodname " + methodName + " otl_traceid " + otl_traceid + ":" + otl_traceid.Length + "otl_parentid " + otl_parentid + ":" + otl_parentid.Length + " otl_tracestate " + otl_tracestate + ":" + otl_tracestate.Length + " otl_version " + otl_version + " otl_traceflag " + otl_traceflag);

                //otl_traceid = null;



                int localbytelen = 0;
                byte[] localbyte1 = null;

                lock (bytearray_lockObject)
                {

                    if (Reqrespheadervarlen == 0)
                    {
                        Reqrespheadervarlen = Marshal.SizeOf<Reqrespheadervar_t>();
                        logger.LogInfo("Reqrespheadervarlen " + Reqrespheadervarlen);
                        ProfilerHelper.Log((int)LogLevel.ERROR, "Reqrespheadervarlen " + Reqrespheadervarlen);

                    }

                    int N = Reqrespheadervarlen;

                    int type_len = type != null ? type.Length : 0;
                    int buffer_len = buffer != null ? buffer.Length : 0;
                    int OTL_traceIDlen = otl_traceid != null ? otl_traceid.Length : 0;
                    int OTL_parentIDlen = otl_parentid != null ? otl_parentid.Length : 0;
                    int OTL_tracestatelen = otl_tracestate != null ? otl_tracestate.Length : 0;
                    logger.LogInfo("OTL_traceIDlen " + OTL_traceIDlen + " OTL_parentIDlen " + OTL_parentIDlen + " OTL_tracestatelen " + OTL_tracestatelen);
                    ProfilerHelper.Log((int)LogLevel.ERROR, "OTL_traceIDlen " + OTL_traceIDlen + " OTL_parentIDlen " + OTL_parentIDlen + " OTL_tracestatelen " + OTL_tracestatelen);

                    if (MsgHdrlen == 0)
                    {
                        MsgHdrlen = Marshal.SizeOf(typeof(MsgHdr));
                    }

                    int header_len = MsgHdrlen;


                    int whlen = preparewrapheader();

                    // int len = 0;

                    int total_len = Reqrespheadervarlen + header_len + type_len + buffer_len + OTL_traceIDlen + OTL_parentIDlen + OTL_tracestatelen + 3;


                    populatewrapheader(tlsData, whlen, 0);

                    int msg_type = 6;

                    globalbyte1[len] = (byte)'^';

                    len += 1;

                    //public int header_len;
                    GetBytesint(header_len, len);
                    len += sizeof(int);

                    //public int total_len;
                    GetBytesint(total_len, len);
                    len += sizeof(int);

                    //public int msg_type;
                    GetBytesint(msg_type, len);
                    len += sizeof(int);

                    globalbyte1[len] = (byte)'|';

                    len += 1;

                    //public int statuscode;
                    GetBytesint(statusCode, len);
                    len += sizeof(int);

                    //public int buffer_len;
                    GetBytesint(buffer_len, len);
                    len += sizeof(int);

                    //public int type_len;
                    GetBytesint(type_len, len);
                    len += sizeof(int);

                    //public int OTL_version;
                    GetBytesint(otl_version, len);
                    len += sizeof(int);

                    //public int OTL_traceflag;
                    GetBytesint(otl_traceflag, len);
                    len += sizeof(int);

                    //public int otl_traceid;
                    GetBytesint(OTL_traceIDlen, len);
                    len += sizeof(int);

                    //public int OTL_parentID;
                    GetBytesint(OTL_parentIDlen, len);
                    len += sizeof(int);

                    //////public int OTL_tracestate;
                    GetBytesint(OTL_tracestatelen, len);
                    len += sizeof(int);

                    //public long flowpathinstance;
                    GetByteslong((long)tlsData, len);
                    len += sizeof(long);

                    if (buffer_len > 0)
                    {
                        GetBytes2(buffer, buffer_len, len);

                        len += buffer_len;
                    }

                    if (type_len > 0)
                    {
                        GetBytes2(type, type_len, len);

                        len += type_len;
                    }

                    if (OTL_traceIDlen > 0)
                    {
                        GetBytes2(otl_traceid, OTL_traceIDlen, len);

                        len += OTL_traceIDlen;
                    }

                    if (OTL_parentIDlen > 0)
                    {
                        GetBytes2(otl_parentid, OTL_parentIDlen, len);

                        len += OTL_parentIDlen;
                    }

                    if (OTL_tracestatelen > 0)
                    {
                        GetBytes2(otl_tracestate, OTL_tracestatelen, len);

                        len += OTL_tracestatelen;
                    }

                    globalbyte1[len] = (byte)'\n';

                    len += 1;
                    logger.LogInfo("capturehttpreqresp finished");
                    ProfilerHelper.Log((int)LogLevel.ERROR, "capturehttpreqresp finished");
                    if (len >= 45 * 1024)
                    {
                        localbyte1 = globalbyte1;
                        localbytelen = len;
                        globalbyte1 = bytearray55kb.Acquire();
                        len = 0;
                    }

                }
                if (localbytelen > 0)
                {
                    lock (global_lockObject)
                    {
                        DataItem data1 = new DataItem(localbytelen, ref localbyte1);
                        PrintList.Add(data1);
                        Monitor.Pulse(global_lockObject);
                    }
                }
            }
            catch(Exception ex)
            {
				if (ex.HResult == 2146233080) //Index was outside the bounds of the array
				{
					lock (bytearray_lockObject)
					{
						bytearray55kb.Release(globalbyte1);
						globalbyte1 = bytearray55kb.Acquire();
						len = 0;
					}
				}
                logger.LogError("An error occurred in capturereqrespfunction: " + ex.Message);
                ProfilerHelper.Log((int)LogLevel.ERROR, "An error occurred in capturereqrespfunction: " + ex.Message);
                var LineNumber = new StackTrace(ex, true).GetFrame(0).GetFileLineNumber();
                logger.LogError("Exception Occurred: For method: [" + methodName + "] for thread id: [" + Thread.CurrentThread.ManagedThreadId + "] Exception: [" + ex.Message + "---line no=" + LineNumber);
                String st = System.Environment.StackTrace;
                logger.LogError("StackTrace:\n" + st);
            }

        }

        public void GetBytes2(string inputString, int len, int offset)
        {
            // Check if the input string length is sufficient
            if (inputString.Length < len)
            {
                // Handle the case when inputString length is shorter than len
                logger.LogInfo("Input string is shorter than the specified length.");
                ProfilerHelper.Log((int)LogLevel.ERROR, "Input string is shorter than the specified length.");
                // ... handle the situation or return
                return;
            }

            // Ensure the offset is within the range of globalbyte1
            if (offset + len > globalbyte1.Length)
            {
                // Handle the case when offset + len exceeds globalbyte1.Length
                logger.LogInfo("Specified offset + length exceeds the buffer size.");
                ProfilerHelper.Log((int)LogLevel.ERROR, "Specified offset + length exceeds the buffer size.");
                // ... handle the situation or return
                return;
            }

            try
            {
                // Perform Buffer.BlockCopy if input is valid
                Buffer.BlockCopy(Encoding.ASCII.GetBytes(inputString), 0, globalbyte1, offset, len);
            }
            catch (Exception ex)
            {
                // Handle any exceptions thrown during Buffer.BlockCopy
                logger.LogError($"An exception occurred: {ex.Message}");
                ProfilerHelper.Log((int)LogLevel.ERROR, $"An exception occurred: {ex.Message}");
                // ... handle the situation, throw an exception, or log the error
            }
        }



        public void parseJSON(ref string receiveBytes)
        {
            try
            {
                string pattern = @"""([^""]+)""[^{]*\{[^}]+\}";

                MatchCollection matches = Regex.Matches(receiveBytes, pattern);

                if(matches.Count == 0)
                {
                    return; 
                }

                var keyValuePairs = new Dictionary<string, string>();

                for (int i = 0; i < matches.Count; i++)
                {
                    string key = matches[i].Groups[1].Value;
                    string value = matches[i].Value;
                    keyValuePairs[key] = value;
                    if (key == "AppId")
                    {
                        logger.LogInfo("key: " + key);
                        ProfilerHelper.Log((int)LogLevel.ERROR, "key: " + key);

                        Match match = Regex.Match(value, "\"id\":\\s*(\\d+)");

                        if (match.Success)
                        {
                            int id;
                            if (int.TryParse(match.Groups[1].Value, out id))
                            {
                                // AppId appId = new AppId { id = id };
                                recvstructure1.appId = new AppId { id = id };
                                logger.LogInfo("id: " + recvstructure1.appId);
                                ProfilerHelper.Log((int)LogLevel.ERROR, "id: " + recvstructure1.appId);
                            }
                            else
                            {
                                logger.LogError("Unable to parse 'id' value as an integer.");
                                ProfilerHelper.Log((int)LogLevel.ERROR, "Unable to parse 'id' value as an integer.");
                            }
                        }
                        else
                        {
                            logger.LogError("Unable to find 'id' in the input string.");
                            ProfilerHelper.Log((int)LogLevel.ERROR, "Unable to find 'id' in the input string.");
                        }
                    }
                    else if (key == "TierInfo")
                    {
                        logger.LogInfo("\nkey: " + key);
                        ProfilerHelper.Log((int)LogLevel.ERROR, "\nkey: " + key);
                        // Use regular expressions to extract the values
                        Match tierIDMatch = Regex.Match(value, "\"tierID\":\\s*(\\d+)");
                        Match appServerIDMatch = Regex.Match(value, "\"AppServerID\":\\s*(\\d+)");
                        Match appIDMatch = Regex.Match(value, "\"appID\":\\s*(\\d+)");

                        if (tierIDMatch.Success && appServerIDMatch.Success && appIDMatch.Success)
                        {
                            int tierID, appServerID, appID;

                            if (int.TryParse(tierIDMatch.Groups[1].Value, out tierID) &&
                                int.TryParse(appServerIDMatch.Groups[1].Value, out appServerID) &&
                                int.TryParse(appIDMatch.Groups[1].Value, out appID))
                            {
                                recvstructure1.tierInfo = new TierInfo
                                {
                                    tierID = tierID,
                                    AppServerID = appServerID,
                                    appID = appID
                                };
                                logger.LogInfo("tierID: " + recvstructure1.tierInfo.tierID);
                                logger.LogInfo("AppServerID: " + recvstructure1.tierInfo.AppServerID);
                                logger.LogInfo("appID: " + recvstructure1.tierInfo.appID);
                                ProfilerHelper.Log((int)LogLevel.ERROR, "tierID: " + recvstructure1.tierInfo.tierID);
                                ProfilerHelper.Log((int)LogLevel.ERROR, "AppServerID: " + recvstructure1.tierInfo.AppServerID);
                                ProfilerHelper.Log((int)LogLevel.ERROR, "appID: " + recvstructure1.tierInfo.appID);
                            }
                            else
                            {
                                logger.LogError("Unable to parse one or more values as integers.");
                                ProfilerHelper.Log((int)LogLevel.ERROR, "Unable to parse one or more values as integers.");
                            }
                        }
                        else
                        {
                            logger.LogError("Unable to find one or more expected values in the input string.");
                            ProfilerHelper.Log((int)LogLevel.ERROR, "Unable to find one or more expected values in the input string.");
                        }
                    }
                    else if (key == "TestInfo")
                    {
                        logger.LogInfo("\nkey: " + key);
                        ProfilerHelper.Log((int)LogLevel.ERROR, "\nkey: " + key);
                        // Use regular expressions to extract the values
                        Match testNumberMatch = Regex.Match(value, "\"TestNumber\":\\s*(\\d+)");
                        Match bciInstrSessionPctMatch = Regex.Match(value, "\"bciInstrSessionPct\":\\s*(\\d+)");
                        Match captureMethodForAllFPMatch = Regex.Match(value, "\"captureMethodForAllFP\":\\s*(\\d+)");

                        if (testNumberMatch.Success && bciInstrSessionPctMatch.Success && captureMethodForAllFPMatch.Success)
                        {
                            int testNumber, bciInstrSessionPct, captureMethodForAllFP;

                            if (int.TryParse(testNumberMatch.Groups[1].Value, out testNumber) &&
                                int.TryParse(bciInstrSessionPctMatch.Groups[1].Value, out bciInstrSessionPct) &&
                                int.TryParse(captureMethodForAllFPMatch.Groups[1].Value, out captureMethodForAllFP))
                            {
                                recvstructure1.testInfo = new TestInfo
                                {
                                    TestNumber = testNumber,
                                    bciInstrSessionPct = bciInstrSessionPct,
                                    captureMethodForAllFP = captureMethodForAllFP
                                };
                                logger.LogInfo("TestNumber: " + recvstructure1.testInfo.TestNumber);
                                testrunno = $"TR{recvstructure1.testInfo.TestNumber}";
                                logger.LogInfo("bciInstrSessionPct: " + recvstructure1.testInfo.bciInstrSessionPct);
                                logger.LogInfo("captureMethodForAllFP: " + recvstructure1.testInfo.captureMethodForAllFP);

                                ProfilerHelper.Log((int)LogLevel.ERROR, "TestNumber: " + recvstructure1.testInfo.TestNumber);
                                ProfilerHelper.Log((int)LogLevel.ERROR, "bciInstrSessionPct: " + recvstructure1.testInfo.bciInstrSessionPct);
                                ProfilerHelper.Log((int)LogLevel.ERROR, "captureMethodForAllFP: " + recvstructure1.testInfo.captureMethodForAllFP);
                            }
                            else
                            {
                                logger.LogError("Unable to parse one or more values as integers.");
                                ProfilerHelper.Log((int)LogLevel.ERROR, "Unable to parse one or more values as integers.");
                            }
                        }
                        else
                        {
                            logger.LogError("Unable to find one or more expected values in the input string.");

                            ProfilerHelper.Log((int)LogLevel.ERROR, "Unable to find one or more expected values in the input string.");
                        }
                    }
                    else if (key == "NDCookie")
                    {
                        logger.LogInfo("\nkey: " + key);
                        ProfilerHelper.Log((int)LogLevel.ERROR, "\nkey: " + key);
                        // Use regular expressions to extract the values
                        Match enableNDSessionMatch = Regex.Match(value, "\"enableNDSession\":\\s*(\\d+)");
                        Match cookieNameMatch = Regex.Match(value, "\"CookieName\":\\s*\"(.*?)\"");
                        Match headerInResponseMatch = Regex.Match(value, "\"headerInResponse\":\\s*(\\d+)");
                        Match mposMatch = Regex.Match(value, "\"mpos\":\\s*(\\d+)");
                        Match maxFPCountInSessionMatch = Regex.Match(value, "\"maxFPCountInSession\":\\s*(\\d+)");
                        Match ndSessionIdleTimeOutSecsMatch = Regex.Match(value, "\"ndSessionIdleTimeOutSecs\":\\s*(\\d+)");

                        if (enableNDSessionMatch.Success && cookieNameMatch.Success && headerInResponseMatch.Success &&
                            mposMatch.Success && maxFPCountInSessionMatch.Success && ndSessionIdleTimeOutSecsMatch.Success)
                        {
                            int enableNDSession, headerInResponse, mpos, maxFPCountInSession, ndSessionIdleTimeOutSecs;

                            if (int.TryParse(enableNDSessionMatch.Groups[1].Value, out enableNDSession) &&
                                int.TryParse(headerInResponseMatch.Groups[1].Value, out headerInResponse) &&
                                int.TryParse(mposMatch.Groups[1].Value, out mpos) &&
                                int.TryParse(maxFPCountInSessionMatch.Groups[1].Value, out maxFPCountInSession) &&
                                int.TryParse(ndSessionIdleTimeOutSecsMatch.Groups[1].Value, out ndSessionIdleTimeOutSecs))
                            {
                                string cookieName = cookieNameMatch.Groups[1].Value;
                                recvstructure1.nDCookie = new NDCookie
                                {
                                    enableNDSession = enableNDSession,
                                    CookieName = cookieName,
                                    headerInResponse = headerInResponse,
                                    mpos = mpos,
                                    maxFPCountInSession = maxFPCountInSession,
                                    ndSessionIdleTimeOutSecs = ndSessionIdleTimeOutSecs
                                };
                                logger.LogInfo("enableNDSession: " + recvstructure1.nDCookie.enableNDSession);
                                logger.LogInfo("CookieName: " + recvstructure1.nDCookie.CookieName);
                                logger.LogInfo("headerInResponse: " + recvstructure1.nDCookie.headerInResponse);
                                logger.LogInfo("mpos: " + recvstructure1.nDCookie.mpos);
                                logger.LogInfo("maxFPCountInSession: " + recvstructure1.nDCookie.maxFPCountInSession);
                                logger.LogInfo("ndSessionIdleTimeOutSecs: " + recvstructure1.nDCookie.ndSessionIdleTimeOutSecs);

                                ProfilerHelper.Log((int)LogLevel.ERROR, "enableNDSession: " + recvstructure1.nDCookie.enableNDSession);
                                ProfilerHelper.Log((int)LogLevel.ERROR, "CookieName: " + recvstructure1.nDCookie.CookieName);
                                ProfilerHelper.Log((int)LogLevel.ERROR, "headerInResponse: " + recvstructure1.nDCookie.headerInResponse);
                                ProfilerHelper.Log((int)LogLevel.ERROR, "mpos: " + recvstructure1.nDCookie.mpos);
                                ProfilerHelper.Log((int)LogLevel.ERROR, "maxFPCountInSession: " + recvstructure1.nDCookie.maxFPCountInSession);
                                ProfilerHelper.Log((int)LogLevel.ERROR, "ndSessionIdleTimeOutSecs: " + recvstructure1.nDCookie.ndSessionIdleTimeOutSecs);
                            }
                            else
                            {
                                logger.LogError("Unable to parse one or more values as integers.");
                                ProfilerHelper.Log((int)LogLevel.ERROR, "Unable to parse one or more values as integers.");
                            }
                        }
                        else
                        {
                            logger.LogError("Unable to find one or more expected values in the input string.");
                            ProfilerHelper.Log((int)LogLevel.ERROR, "Unable to find one or more expected values in the input string.");
                        }
                    }
                    else if (key == "NVCookie")
                    {
                        logger.LogInfo("\nkey: " + key);
                        ProfilerHelper.Log((int)LogLevel.ERROR, "\nkey: " + key);
                        // Use regular expressions to extract the value
                        Match nvCookieNameMatch = Regex.Match(value, "\"NVCookieName\":\\s*\"(.*?)\"");

                        if (nvCookieNameMatch.Success)
                        {
                            string nvCookieName = nvCookieNameMatch.Groups[1].Value;
                            recvstructure1.nVCookie = new NVCookie
                            {
                                NVCookieName = nvCookieName
                            };
                            logger.LogInfo("NVCookieName: " + recvstructure1.nVCookie.NVCookieName);
                            ProfilerHelper.Log((int)LogLevel.ERROR, "NVCookieName: " + recvstructure1.nVCookie.NVCookieName);
                        }
                        else
                        {
                            logger.LogError("Unable to find the expected value in the input string.");
                            ProfilerHelper.Log((int)LogLevel.ERROR, "Unable to find the expected value in the input string.");
                        }
                    }
                    else if (key == "CorelationHeader")
                    {
                        logger.LogInfo("\nkey: " + key);
                        ProfilerHelper.Log((int)LogLevel.ERROR, "\nkey: " + key);
                        // Use regular expressions to extract the value
                        Match corelationheaderMatch = Regex.Match(value, "\"corelationheader\":\\s*\"(.*?)\"");

                        if (corelationheaderMatch.Success)
                        {
                            string corelationheader = corelationheaderMatch.Groups[1].Value;
                            recvstructure1.corelationHeader = new CorelationHeader
                            {
                                corelationheader = corelationheader
                            };
                            logger.LogInfo("corelationheader: " + recvstructure1.corelationHeader.corelationheader);
                            ProfilerHelper.Log((int)LogLevel.ERROR, "corelationheader: " + recvstructure1.corelationHeader.corelationheader);
                        }
                        else
                        {
                            logger.LogError("Unable to find the expected value in the input string.");
                            ProfilerHelper.Log((int)LogLevel.ERROR, "Unable to find the expected value in the input string.");
                        }
                    }
                    else if (key == "BackendNameRule")
                    {
                        logger.LogInfo("\nkey: " + key);
                        ProfilerHelper.Log((int)LogLevel.ERROR, "\nkey: " + key);

                        // Use regular expressions to extract the value
                        Match bakendnamingruleMatch = Regex.Match(value, "\"BackendNameRuleValue\":\\s*\"(.*?)\"");

                        if (bakendnamingruleMatch.Success)
                        {
                            string backendNameRuleValue = bakendnamingruleMatch.Groups[1].Value;

                            // Create a BackendNameRule structure
                            recvstructure1.backendNameRule = new BackendNameRule
                            {
                                BackendNameRuleValue = backendNameRuleValue
                            };

                            logger.LogInfo("BackendNameRuleValue: " + recvstructure1.backendNameRule.BackendNameRuleValue);
                            ProfilerHelper.Log((int)LogLevel.ERROR, "BackendNameRuleValue: " + recvstructure1.backendNameRule.BackendNameRuleValue);

                        }
                    }
                    else if (key == "otel")
                    {
                        logger.LogInfo("\nkey: " + key);
                        ProfilerHelper.Log((int)LogLevel.ERROR, "\nkey: " + key);

                        // Use regular expression to extract the value for the specific key
                        Match otelmatch = Regex.Match(value, "\"otelkeyword\":\\s*\"(.*?)\"");

                        if (otelmatch.Success)
                        {
                            string otelkeywordvalue = otelmatch.Groups[1].Value;

                            // Create a BackendNameRule structure
                            recvstructure1.otel = new otel
                            {
                                otelkeyword = otelkeywordvalue
                            };

                            logger.LogInfo("otelkeyword: " + recvstructure1.otel.otelkeyword);
                            ProfilerHelper.Log((int)LogLevel.ERROR, "otelkeyword: " + recvstructure1.otel.otelkeyword);
                            profilerHelper.SetPropHeadCheck();
                        }
                    }
                    else if (key == "enableDBBackendName")
                    {
                        logger.LogInfo("\nkey: " + key);
                        ProfilerHelper.Log((int)LogLevel.ERROR, "\nkey: " + key);

                        // Use regular expression to extract the value for the specific key
                        Match DBBackendNamematch = Regex.Match(value, "\"enableDBBackendName\":\\s*(\\d+)");

                        if (DBBackendNamematch.Success)
                        {
                            string DBBackendNamekeywordvalue = DBBackendNamematch.Groups[1].Value;
                            int DBBackendNamekeywordvalueint;
                            int.TryParse(DBBackendNamekeywordvalue,out DBBackendNamekeywordvalueint);

                            // Create a BackendNameRule structure
                            recvstructure1.DBBackendName = new DBBackendName
                            {
                                enableDBBackendName = DBBackendNamekeywordvalueint
                            };

                            logger.LogInfo("enableDBBackendName: " + recvstructure1.DBBackendName.enableDBBackendName);
                            ProfilerHelper.Log((int)LogLevel.ERROR, "enableDBBackendName: " + recvstructure1.DBBackendName.enableDBBackendName);
                        }
                    }
                    else
                    {
                        logger.LogError("ERROR: No matching key " + key + " defined");
                        ProfilerHelper.Log((int)LogLevel.ERROR, "ERROR: No matching key "+key+" defined");
                    }

                }
            }
            catch(Exception ex)
            {
                logger.LogError("EXCEPTION: " + ex.Message); 
                ProfilerHelper.Log((int)LogLevel.ERROR, "EXCEPTION: " + ex.Message);

            }
        }

        
     

        

       

        public async Task SendHeartbeatMessage()
        {

            while (true)
            {
                try
                {
                    // Wait for the specified interval before sending the next heartbeat
                    Thread.Sleep(120 * 1000);
                    int localbytelen = 0;
                    byte[] localbyte1 = null;
                    lock (bytearray_lockObject)
                    {
                        int whlen = preparewrapheader();

                        populatewrapheader((IntPtr)0, whlen, 3);
                     //   logger.LogInfo($"Sending Heartbeat Message on {ep.Address} : {ep.Port}");
                    //    ProfilerHelper.Log((int)LogLevel.ERROR, $"Sending Heartbeat Message on {ep.Address} : {ep.Port}");
                        globalbyte1[len] = (byte)'\n';
                        len += 1;


                        localbyte1 = globalbyte1;
                        localbytelen = len;
                        globalbyte1 = bytearray55kb.Acquire();
                        len = 0;


                    }
                    if (localbytelen > 0)
                    {
                        lock (global_lockObject)
                        {
                            DataItem data1 = new DataItem(localbytelen, ref localbyte1);
                            PrintList.Add(data1);
                            Monitor.Pulse(global_lockObject);
                        }
                    }

                }

                catch (Exception ex)
                    {
					if (ex.HResult == 2146233080) //Index was outside the bounds of the array
					{
						lock (bytearray_lockObject)
						{
							bytearray55kb.Release(globalbyte1);

							globalbyte1 = bytearray55kb.Acquire();
							len = 0;
						}
					}
                     logger.LogError("Exception: " + ex.Message);
                     ProfilerHelper.Log((int)LogLevel.ERROR, "Exception: " + ex.Message);
                }

            }


        }

        void send_Agent_Initialize_Msg()
        {
            Thread.Sleep(50);

            try
            {
                int localbytelen = 0;
                byte[] localbyte1 = null;
                lock (bytearray_lockObject)
                {
                    int whlen = preparewrapheader();
                    populatewrapheader((IntPtr)0, whlen, 8);
                 //   logger.LogInfo($"Sending agent Initialize Message on {ep.Address} : {ep.Port}");
                  //  ProfilerHelper.Log((int)LogLevel.ERROR, $"Sending agent Initialize Message on {ep.Address} : {ep.Port}");
                    globalbyte1[len] = (byte)'\n';
                    len += 1;
                     
                   
                        localbyte1 = globalbyte1;
                        localbytelen = len;
                        globalbyte1 = bytearray55kb.Acquire();
                        len = 0;
                    

                }
                if (localbytelen > 0)
                {
                    lock (global_lockObject)
                    {
                        DataItem data1 = new DataItem(localbytelen, ref localbyte1);
                        PrintList.Add(data1);
                        Monitor.Pulse(global_lockObject);
                    }
                }


            }
            catch (Exception ex)
            {
                logger.LogError("Error: " + ex.Message);
                ProfilerHelper.Log((int)LogLevel.ERROR, "Error: " + ex.Message);
            }
        }

        public UdpClient UdpClient;
        public recvstructure recvstructure1 = new recvstructure ();
        public Socket s;
        public IPEndPoint ep;
        public ByteArrayPool bytearray55kb;
        public EndPoint remoteEndpoint;
        public string udpip;
        public string udpport;
	    public ProfilerHelper profilerHelper;
 

        public EndPoint epserver;

        public static RUDP rudp;
      //  private static int rsock;

   
        public string serverIP;
        public int serverPort;
        public Thread eventloopThread;
        public bool isReceiving;

        public void Starteventloop()
        {
          
            isReceiving = true;
            eventloopThread = new Thread(() =>
            {
                int retryCount = 5; // Set the number of retries
                while (isReceiving && retryCount > 0)
                {
                   
                    
                    if (RUDP.EventLoop())
                    {
                        // Successful receive, reset retry count
                        retryCount = 3;
                    }
                    else
                    {

                        // Retry after a delay
                        Thread.Sleep(2000); // Adjust the delay as needed
                        retryCount--;
                    }
                }

            });
            eventloopThread.Start();
        }


        public Thread sendingThread;
        public bool issending;

        public void startsendingdata(int rsock)
        {
           
            issending = true;
            sendingThread = new Thread(() =>
            {
                int retryCount = 5; // Set the number of retries
                while (issending && retryCount > 0)
                {
                  

                    if (CheckAndPrintByteArrayList(rsock))
                    {
                        // Successful receive, reset retry count
                         retryCount = 3;
                    }
                    else
                    {

                        // Retry after a delay
                        Thread.Sleep(2000); // Adjust the delay as needed
                        retryCount--;
                    }
                }

            });
            sendingThread.Start();
        }

      

        public static GlobalIP1 globalIP = null;
        public void  startudpclient()
        {
          //  ProfilerHelper.Log((int)LogLevel.ERROR, "calling startudpclient");

            try
            {
                if (serverIP == null && serverPort == 0)
                {
                    profilerHelper = new ProfilerHelper();

                    if (udpip == null)
                    {
                        udpip = Getvariable("PROXYIP");
                        if(udpip == null)
                        {
                            udpip = "127.0.0.1";
                            logger.LogError("Unable to find PROXYIP");
                            ProfilerHelper.Log((int)LogLevel.ERROR, "Unable to find PROXYIP");
                        }    
                    }

                    if (udpport == null)
                    {
                        udpport = Getvariable("PROXYPORT");
                        if (udpport == null)
                        {
                            udpport = "443";
                            logger.LogError("Unable to find PROXYPORT");
                            ProfilerHelper.Log((int)LogLevel.ERROR, "Unable to find udpport");
                        }
                    }

                    bytearray55kb = new ByteArrayPool(15, 54 * 1024);
                    serverIP = udpip;
                    serverPort = int.Parse(udpport);
                    rudp = new RUDP();
                   // RUDP rudpInstance = new RUDP();
                    if (globalIP == null)
                        globalIP = new GlobalIP1();
                    globalIP.InitializeEndPoint(serverIP, serverPort);
                    //   globalIP.socketUDP.Blocking=false;
                    int rsock;
                    rsock = rudp.rudp_socket(0);
                    logger.LogError("i am here");
                  //  rudpInstance.rudp_event_handler(rsock, EventHandler);

                    //IPEndPoint serverEndpoint = globalIP.GlobalEndPoint;
                    logger.LogInfo("i am here"+ serverIP +"  "+ serverPort);
                    logger.LogError("i am here");

                    startsendingdata(rsock);

                    logger.LogError("i am here");

                    //Task.Run(() => CheckAndPrintByteArrayList());




                    Task.Run(() => SendHeartbeatMessage());


                    send_Agent_Initialize_Msg();



                  Starteventloop();

                  
                }
            }
            catch (Exception ex)
            {
                logger.LogInfo("Error: " + ex.Message);
                ProfilerHelper.Log((int)LogLevel.ERROR, "Error: " + ex.Message);

            }
        }
    }
}
