// Created with MonoDevelop
//
//    Copyright (C) 2009 Hiperscan GmbH Dresden, Germany
//
//    This program is free software: you can redistribute it and/or modify
//    it under the terms of the GNU General Public License as published by
//    the Free Software Foundation, either version 3 of the License, or
//    (at your option) any later version.
//
//    This program 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 General Public License for more details.
//
//    You should have received a copy of the GNU General Public License
//    along with this program.  If not, see <http://www.gnu.org/licenses/>.



using System;
using System.Text;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Tcp;
using System.Runtime.Serialization.Formatters;
using System.Collections.Generic;
using System.Net;

using Hiperscan.Unix;
using System.Runtime.Serialization;


namespace Hiperscan.Spectroscopy.IdentModule
{

    [Serializable]
    [DataContract(Name = "ClassificationType", Namespace = "http://www.hiperscan.com/spectroscopy/identmodule")]
    public enum ClassificationType
    {
        [EnumMember] None,
        [EnumMember] Single,
        [EnumMember] Multiple,
        [EnumMember] NonMultiple,
    }

    public interface IIdentServer
    {
        byte[] GetChallenge();
        List<AccessDatabaseInfo> Initialize(string serial, byte[] master_response);

        List<string> GetModelClassNames(AuthentificationSet authentification);
        ModelClassInfo GetModelClassInfo(AuthentificationSet authentification);
        ModelClassExtensionInfo GetModelClassExtensionInfo(AuthentificationSet authentification);

        ResultSet Classify(AuthentificationSet authentification, Spectrum spectrum);

        IdentModuleInfo GetIdentModuleInfo();
        UpdateCertificateInfo GetUpdateCertificateData();

        byte[] GetValidationDocument(string model_class_name);
        Dictionary<string,byte[]> GetAdditionalTestPdfs();

        byte[] GetLicense();
        byte[] GetLogfile();
        byte[] GetUpdateChangesFile();
    }

    public static class IdentServer
    {
        public const string SERVICE_NAME = "hiperscan.identserver";
        public const int TCP_PORT = 8293;

        public static IIdentServer GetRemoteObject(string server, int tcp_port)
        {
            string service_name = IdentServer.SERVICE_NAME + (tcp_port == IdentServer.TCP_PORT ? String.Empty : tcp_port.ToString());
            if (server == "localhost")
                server = IdentServer.LocalHostAddress;

            IChannel channel = ChannelServices.GetChannel(service_name);
            if (channel == null)
            {
                System.Collections.IDictionary settings = new System.Collections.Hashtable();
                settings["name"]   = service_name;
                settings["port"]   = 0;
                settings["secure"] = false;

                if (server == IdentServer.LocalHostAddress)
                    settings["bindTo"] = server;

                BinaryServerFormatterSinkProvider provider = new BinaryServerFormatterSinkProvider();
                provider.TypeFilterLevel = TypeFilterLevel.Full;
                channel = new TcpChannel(settings, null, provider);
                ChannelServices.RegisterChannel(channel, false);
            }

            StringBuilder sb = new StringBuilder(@"tcp://");
            sb.Append(server);
            sb.Append(':');
            sb.Append(tcp_port);
            sb.Append('/');
            sb.Append(service_name);

            return (IIdentServer)Activator.GetObject(typeof(IIdentServer), sb.ToString());
        }

        public static void CloseChannel(int tcp_port)
        {

            try
            {
                string service_name = IdentServer.SERVICE_NAME + (tcp_port == IdentServer.TCP_PORT ? String.Empty : tcp_port.ToString());
                IChannel channel = ChannelServices.GetChannel(service_name);
                if (channel == null)
                    return;

                ChannelServices.UnregisterChannel(channel);
                Console.WriteLine("Tcp channel closed successfully.");
            }
            catch (Exception ex)
            {
                Console.WriteLine("Tcp channel closing failed: {0}.", ex);
            }
        }

        public static string LocalHostAddress
        {
            get
            {
                string address = String.Empty;
                try
                {
                    address = IPAddress.Loopback.ToString();
                    if (String.IsNullOrEmpty(address) == true)
                        throw new Exception(Catalog.GetString("No IPv4 local address found."));
                }
                catch (Exception)
                {
                    address = IPAddress.IPv6Loopback.ToString();
                    if (String.IsNullOrEmpty(address) == true)
                        throw new Exception(Catalog.GetString("No IPv6 local address found."));
                }

                return address;
            }
        }
    }
}
