/***********************************************************************
 * 
 *  Copyright (C) 2005-2006 Novell, Inc. All Rights Reserved.
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License as published by the Free Software Foundation; version 2.1
 *  of the License.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Library Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, Novell, Inc.
 * 
 *  To contact Novell about this file by physical or electronic mail, 
 *  you may find current contact information at www.novell.com.
 * 
 ***********************************************************************/

using System;
using System.Net;
using System.IO;
using System.Net.Sockets;
using Mono.Unix;
using System.Text;

namespace Novell.CASA.MiCasa.Communication
{
    /// <summary>
    /// Summary description for UnixIPCClientChannel.
    /// </summary>
    public class UnixIPCClientChannel : ClientChannel
    {

        private Socket mSocket = null;
        private string socketFileName = "/tmp/.novellCASA";
        private EndPoint sockEndPoint;

        public UnixIPCClientChannel()
        {
        }

        public void Open()
        {
            mSocket = new Socket( AddressFamily.Unix,
                            SocketType.Stream,
                            ProtocolType.IP );

			if (mSocket == null)
			{
				throw new Exception("could not get socket");
			}
			
			sockEndPoint = new UnixEndPoint(socketFileName);            
			UnixFileSystemInfo sockFileInfo = new UnixFileInfo(socketFileName);
            UnixUserInfo sockFileOwner = sockFileInfo.OwnerUser;

            // root is the owner of the file "/tmp/.novellCASA"
			if (sockFileOwner.UserId == 0)
			{
				mSocket.Connect(sockEndPoint);
			}
			else
			{
				throw new Exception("not a valid miCASA service");
			}

        }

        public int Read(byte[] buf)
        {
            buf = Read();

            if (buf != null)
            {
                //Console.WriteLine("Bytes read = " + buf.Length);
                return buf.Length;
            }
            else
                return 0;
        }

        public byte[] Read()
        {
            byte[] returnBuffer = null;
            int bytesRecvd = 0;

            try
            {
                /* We need to read 'msgLen' to know how many bytes to
                 * allocate. 
                 */

                byte[] msgIdBytes = new byte[2];
                bytesRecvd = mSocket.Receive(msgIdBytes);
		if( 0 == bytesRecvd )
                {
                    return null;
                }
                byte[] msgLenBytes = new byte[4];
                bytesRecvd = mSocket.Receive(msgLenBytes);
		if( 0 == bytesRecvd )
                {
                    return null;
                }

                uint msgLen = BitConverter.ToUInt32(msgLenBytes,0);
		if( msgLen > 6 )
                {
		    System.Text.Encoding encoding = System.Text.Encoding.ASCII;
                    byte[] buf = null;
		    int bytesAvailable;
		    int totalBytes = 0;
		    int msgLencount = 0;
		    string bufstring = null;
	            byte[] temp = null;
		    while(totalBytes<(msgLen-6))
		    {
			    bytesAvailable = mSocket.Available;
			    if( 0 == bytesAvailable)
        	            {
        	                break;
        	            }
			    buf = new byte[bytesAvailable];
		            bytesRecvd = mSocket.Receive (buf);
			    bufstring = bufstring + encoding.GetString(buf); //keep buffering in a string
			    totalBytes = totalBytes + bytesAvailable;
		    }
		    if(totalBytes==0)
			return null;
		    
		    byte[] finalbuf = encoding.GetBytes(bufstring);//finally, convert the string to a byte array of size 'totalBytes'
		    int returnBufferLen = msgIdBytes.Length+msgLenBytes.Length+totalBytes;
		    returnBuffer = new byte[returnBufferLen];
                    Array.Copy(msgIdBytes,returnBuffer,2);
                    Array.Copy(msgLenBytes,0,returnBuffer,2,4);
                    Array.Copy(finalbuf,0,returnBuffer,6,finalbuf.Length);
		    return returnBuffer;
                }
	        else
                {
                    returnBuffer = new byte[6];
                    Array.Copy(msgIdBytes,returnBuffer,2);
                    Array.Copy(msgLenBytes,0,returnBuffer,2,4);
                    return returnBuffer;
                }
            }
            catch (Exception e)
            {
                Console.WriteLine(e.ToString());
                return null;
            }            
        }
        
        public int Write(byte[] buf)
        {
            try
            {
                mSocket.Send(buf);
		//Console.WriteLine("Bytes written = " + buf.Length);
                return buf.Length;
            }
            catch (Exception e)
            {
                Console.WriteLine(e.ToString());
                return 0;
            }
        }

        public void Close()
        {
            mSocket.Close();        
        }
    }
}