using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;

namespace Smackbio
{
	public delegate Boolean TimeLogCallback(
		String TerminalType,
		Int32 TerminalID,
		String SerialNumber,
		Int32 TransactionID,
		DateTime LogTime,
		Decimal UserID,
		Int32 DoorID,
		String AttendanceStatus,
		String VerifyMode,
		Int32 JobCode,
		String Antipass,
		Byte[] Photo);

	public delegate Boolean AdminLogCallback(
		String TerminalType,
		Int32 TerminalID,
		String SerialNumber,
		Int32 TransactionID,
		DateTime LogTime,
		Decimal AdminID,
        Decimal UserID,
		String Action,
		Int32 Result);

	public delegate Boolean AlarmLogCallback(
		String TerminalType,
		Int32 TerminalID,
		String SerialNumber,
		Int32 TransactionID,
		DateTime LogTime,
		Int64 UserID,
		Int32 DoorID,
		String AlarmType);

	public delegate void PingCallback(
		String TerminalType,
		Int32 TerminalID,
		String SerialNumber,
		Int32 TransactionID);

	public class LogServer : IDisposable
	{
		public Boolean m_Disposed;
		public UInt16 m_PortNo;
		public TcpListener m_Listner;
		static LinkedList<Terminal> m_TerminalList = new LinkedList<Terminal>();

		public TimeLogCallback m_TimeLogCallBack = null;
		public AdminLogCallback m_AdminLogCallBack = null;
		public AlarmLogCallback m_AlarmLogCallBack = null;
		public PingCallback m_PingCallBack = null;

		public LogServer(UInt16 portNo,
			TimeLogCallback timeLogCallback,
			AdminLogCallback adminLogCallback,
			AlarmLogCallback alarmLogCallback,
			PingCallback pingCallback)
		{
			// Initialize objects.
			m_Disposed = false;
			m_PortNo = portNo;
			m_TimeLogCallBack = timeLogCallback;
			m_AdminLogCallBack = adminLogCallback;
			m_AlarmLogCallBack = alarmLogCallback;
			m_PingCallBack = pingCallback;

			// Start TCP Listner.
			m_Listner = new TcpListener(IPAddress.Any, m_PortNo);
			m_Listner.Server.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
			m_Listner.Start();

			// Begin Accept.
			m_Listner.BeginAcceptTcpClient(new AsyncCallback(LogServer.OnAccept), this);
		}

		~LogServer()
		{
			CleanUp(false);
		}

		private void CleanUp(bool dispose)
		{
			if (m_Disposed)
				return;

			m_Disposed = true;

			if (dispose)
			{
				// Dispose the listener and terminals.
				try
				{
					m_Listner.Stop();
					foreach (Terminal e in m_TerminalList)
					{
						if (e != null)
							e.Dispose();
					}
				}
				catch
				{

				}
			}
		}

		public void Dispose()
		{
			CleanUp(true);
		}

		public static void OnAccept(IAsyncResult iar)
		{
			LogServer server = (LogServer)iar.AsyncState;
			Terminal term = new Terminal(server.m_TimeLogCallBack,
				server.m_AdminLogCallBack,
				server.m_AlarmLogCallBack,
				server.m_PingCallBack);

			try
			{
				// Establish connection and add a terminal into the list.
				term.EstablishConnect(server.m_Listner.EndAcceptTcpClient(iar));
				m_TerminalList.AddLast(term);
			}
			catch
			{
				term.Dispose();
			}

			try
			{
				// For disposed listener.
				server.m_Listner.BeginAcceptTcpClient(new AsyncCallback(LogServer.OnAccept), server);
			}
			catch
			{

			}
		}
	}

	public static class Extension
	{
		static string alphabet = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
		public static string ToRadixString(this Decimal val, int radix = 36)
		{
			string s = "";

			while(val != 0)
			{
				int rem = (int)(val % radix);
				val = Math.Truncate(val / radix);

				s = alphabet[rem] + s;
			}

			return s;
		}
	}
}
