using System;
using System.Net;
using System.Net.Sockets;
using Mono.Unix;
using System.IO;
using System.Text;
using System.Threading;
using sscs.common;
using sscs.constants;

namespace sscs.communication
{

/* Platform specific class which implements 
 * the 'Communication' interface.
 */

    class UnixCommunication : Communication
    {
        private Socket listeningSocket;
        private Socket connectedSocket;
        private string socketFileName = "/tmp/.novellCASA";
        private EndPoint sockEndPoint;
        private ManualResetEvent eventVar = null;


        //Methods
        internal UnixCommunication()
        {
            CSSSLogger.ExecutionTrace(this);
            Syscall.umask(0);
            if(File.Exists(socketFileName))
                File.Delete(socketFileName);
            listeningSocket = new Socket( AddressFamily.Unix,
                                          SocketType.Stream,
                                          ProtocolType.IP );
            sockEndPoint = new UnixEndPoint(socketFileName);
            eventVar = new ManualResetEvent(true);

        }

        ~UnixCommunication()
        {
            CSSSLogger.ExecutionTrace(this);
            eventVar.Close();
            CloseCommunicationEndPoint();
            
        }  

        // This code executes in the listening thread.
        public void StartCommunicationEndPoint()
        {
            CSSSLogger.ExecutionTrace(this);
            try
            {
                listeningSocket.Bind(sockEndPoint);
                listeningSocket.Listen(50);
            }
            catch(Exception e)
            {
                CSSSLogger.ExpLog(e.ToString());
            }
            while(true)
            {
                try
                {
                    eventVar.Reset();
                    listeningSocket.BeginAccept(new AsyncCallback(ListenCb),
                                               listeningSocket);
                    eventVar.WaitOne();
                }
                catch(Exception e)
                {
                    CSSSLogger.ExpLog(e.ToString());
                    throw e;
                }
            }
        }

        public void CloseCommunicationEndPoint()
        {
            CSSSLogger.ExecutionTrace(this);
            listeningSocket.Close();
            if(File.Exists( socketFileName ))
                File.Delete(socketFileName);    
        }

        // On receipt of a new client, this method is called.
        private void ListenCb (IAsyncResult state)
        {
            try
            {
                CSSSLogger.ExecutionTrace(this);
                connectedSocket = ((Socket)state.AsyncState).EndAccept (state);
                eventVar.Set();
                ServiceClient();
            }
            catch(Exception e)
            {
                /* All resources would have been cleaned up before reaching
                 * here. 
                 */ 
                CSSSLogger.ExpLog(e.ToString());
            }
            /* End of thread function */
        }

        private void ServiceClient()
        {
            CSSSLogger.ExecutionTrace(this);
            IPCChannel ipcChannel = IPCChannel.Create(connectedSocket);
            AppHandler appHandler = new AppHandler(ipcChannel);

            try
            {
               int retVal = appHandler.ServiceApp();
               if( retVal != RetCodes.SUCCESS )
                   CSSSLogger.DbgLog("Servicing client failed.");
            } 
            catch( Exception e )
            {
                CSSSLogger.ExpLog(e.ToString());
            }
            finally
            {
                ipcChannel.Close();
            }
        }
    }
}