using System;
using System.Text;
using System.Threading;

using Cosmos.UserFrame;
using System.IO.Pipes;

//using Microsoft.Win32.SafeHandles;
//using System;
//using System.Diagnostics;
//using System.IO;
//using System.Runtime.InteropServices;
//using System.Security.AccessControl;
//using System.Security.Principal;
//using System.Text;
//using System.Threading;

//using Cosmos.BaseFrame;
//using Cosmos.UserFrame;
//using Cosmos.ServiceProvider;
//using Cosmos.Common;
//using Cosmos.CommonManager;
//using Cosmos.UI;


namespace Cosmos.Service
{
    // Delegate for passing received message back to caller
    public delegate void DelegateMessage(string Reply);

    class PipeServer
    {
        public event DelegateMessage PipeMessage;
        string _pipeName;

        private readonly int RECV_BUFFER_SIZE = 1024;


        private bool m_bConnected;
        public bool PipeConnected { get { return this.m_bConnected; } set { this.m_bConnected = value; } }         // POS 기능키
        
        /// <summary>
        /// 서버 대기
        /// </summary>
        /// <param name="PipeName"></param>
        public void Listen(string PipeName)
        {
            try
            {
                m_bConnected = false;

                // Set to class level var so we can re-use in the async callback method
                _pipeName = PipeName;
                // Create the new async pipe 
                NamedPipeServerStream pipeServer = new NamedPipeServerStream(PipeName, System.IO.Pipes.PipeDirection.InOut, 1, PipeTransmissionMode.Message, PipeOptions.Asynchronous);

                // Wait for a connection
                pipeServer.BeginWaitForConnection(new AsyncCallback(WaitForConnectionCallBack), pipeServer);
                
                m_bConnected = true;
            }
            catch (Exception ex)
            {
                UserLog.WriteLogFile(UserCom.LOG_ERROR, System.Reflection.Assembly.GetExecutingAssembly().ManifestModule.Name,
                    System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name + "." + System.Reflection.MethodBase.GetCurrentMethod().Name + "()"
                    , ex.Message);
            }
        }

        /// <summary>
        /// 메세지 콜백
        /// </summary>
        /// <param name="iar"></param>
        private void WaitForConnectionCallBack(IAsyncResult iar)
        {
            try
            {
                // Get the pipe
                NamedPipeServerStream pipeServer = (NamedPipeServerStream)iar.AsyncState;

                // End waiting for the connection
                pipeServer.EndWaitForConnection(iar);

                byte[] buffer = new byte[RECV_BUFFER_SIZE];

                // Read the incoming message
                int rByteSize = pipeServer.Read(buffer, 0, RECV_BUFFER_SIZE);

                // Convert byte buffer to string
                UnicodeEncoding encoder = new UnicodeEncoding();
                string stringData = encoder.GetString(buffer, 0, rByteSize);  //encoder.GetString(buffer, 0, buffer.Length);
                //Debug.WriteLine(stringData + Environment.NewLine);

                //UserLog.WriteLogFile(UserCom.LOG_ERROR, System.Reflection.Assembly.GetExecutingAssembly().ManifestModule.Name,
                //    System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name + "." + System.Reflection.MethodBase.GetCurrentMethod().Name + "()"
                //    , stringData);

                // Pass message back to calling form
                PipeMessage.Invoke(stringData);

                // Kill original sever and create new wait server
                pipeServer.Close();
                pipeServer.Dispose();
                pipeServer = null;

                Thread.Sleep(100);

                pipeServer = new NamedPipeServerStream(_pipeName, System.IO.Pipes.PipeDirection.InOut, 1, PipeTransmissionMode.Message, PipeOptions.Asynchronous);

                // Recursively wait for the connection again and again....
                pipeServer.BeginWaitForConnection(new AsyncCallback(WaitForConnectionCallBack), pipeServer);

                m_bConnected = true;
            }
            catch (Exception ex)
            {

                m_bConnected = false;
                UserLog.WriteLogFile(UserCom.LOG_ERROR, System.Reflection.Assembly.GetExecutingAssembly().ManifestModule.Name,
                    System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name + "." + System.Reflection.MethodBase.GetCurrentMethod().Name + "()"
                    , ex.Message);
                return;
            }
        }
    }

    class PipeClient
    {
        /// <summary>
        /// 파이프 전송
        /// </summary>
        /// <param name="SendStr"></param>
        /// <param name="PipeName"></param>
        /// <param name="TimeOut"></param>
        public bool Send(string SendStr, string PipeName, int TimeOut = 1000)
        {
            try
            {
                NamedPipeClientStream pipeStream = new NamedPipeClientStream(".", PipeName, System.IO.Pipes.PipeDirection.InOut, PipeOptions.Asynchronous);

                // The connect function will indefinitely wait for the pipe to become available
                // If that is not acceptable specify a maximum waiting time (in ms)
                pipeStream.Connect(TimeOut);
                //Debug.WriteLine("[Client] Pipe connection established");


                UnicodeEncoding encoder = new UnicodeEncoding();
                byte[] _buffer = encoder.GetBytes(SendStr);


                //byte[] _buffer = Encoding.UTF8.GetBytes(SendStr);
                pipeStream.BeginWrite(_buffer, 0, _buffer.Length, AsyncSend, pipeStream);

                return true;

            }
            catch (TimeoutException ex)
            {
                UserLog.WriteLogFile(UserCom.LOG_ERROR, System.Reflection.Assembly.GetExecutingAssembly().ManifestModule.Name,
                    System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name + "." + System.Reflection.MethodBase.GetCurrentMethod().Name + "()"
                    , ex.Message);
            }

            return false;
        }

        /// <summary>
        /// Async전송
        /// </summary>
        /// <param name="iar"></param>
        private void AsyncSend(IAsyncResult iar)
        {
            try
            {
                // Get the pipe
                NamedPipeClientStream pipeStream = (NamedPipeClientStream)iar.AsyncState;

                // End the write
                pipeStream.EndWrite(iar);
                pipeStream.Flush();

                Thread.Sleep(100);

                pipeStream.Close();
                pipeStream.Dispose();
            }
            catch (Exception ex)
            {
                UserLog.WriteLogFile(UserCom.LOG_ERROR, System.Reflection.Assembly.GetExecutingAssembly().ManifestModule.Name,
                    System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name + "." + System.Reflection.MethodBase.GetCurrentMethod().Name + "()"
                    , ex.Message);
            }
        }

    }
}
