using System;
using System.Collections.Generic;
using System.Threading;
using System.Net;
using System.Configuration;
using Microsoft.Win32;
using System.IO;

namespace BRServer
{
    /*
     * 航天二院最新服务器协议
     */
    public class CasicSender 
    {
        private TelecomServer server;

        public CasicSender(TelecomServer server)
        {
            this.server = server;
        }

        public bool doSendTimeConfig(String devCode, String ver, String typeName, CasicSession session, String flag, String deviceId_Telecom)
        {
            //TODO: construct the receving casic data
            String preamble = "A3";
            byte btpreamble = byte.Parse(preamble, System.Globalization.NumberStyles.HexNumber);

            String version = ver;
            byte btVersion = byte.Parse(version, System.Globalization.NumberStyles.HexNumber);

            String deviceId = devCode;//6个字节
            byte[] btDevId = new byte[6];
            btDevId[0] = byte.Parse(deviceId.Substring(0, 2), System.Globalization.NumberStyles.HexNumber);
            btDevId[1] = byte.Parse(deviceId.Substring(2, 2), System.Globalization.NumberStyles.HexNumber);
            btDevId[2] = byte.Parse(deviceId.Substring(4, 2), System.Globalization.NumberStyles.HexNumber);
            btDevId[3] = byte.Parse(deviceId.Substring(6, 2), System.Globalization.NumberStyles.HexNumber);
            btDevId[4] = byte.Parse(deviceId.Substring(8, 2), System.Globalization.NumberStyles.HexNumber);
            btDevId[5] = byte.Parse(deviceId.Substring(10, 2), System.Globalization.NumberStyles.HexNumber);

            String routeFlag = flag;
            byte btRouteFlag = byte.Parse(routeFlag, System.Globalization.NumberStyles.HexNumber);

            String dstNodeAddr = devCode.Substring(8);//2个字节 ** ****** ****
            byte[] btDstNode = new byte[2];
            btDstNode[0] = byte.Parse(dstNodeAddr.Substring(0, 2), System.Globalization.NumberStyles.HexNumber);
            btDstNode[1] = byte.Parse(dstNodeAddr.Substring(2, 2), System.Globalization.NumberStyles.HexNumber);

            String seq = "01";
            byte btSeq = byte.Parse(seq, System.Globalization.NumberStyles.HexNumber);

            byte[] btPdu = new byte[2]; //2个字节
            byte[] tag = null;

            switch (typeName)
            {
                case "北燃沉降监测仪":
                    btPdu[0] = 0x05;
                    btPdu[1] = 0x95;
                    tag = this.getTimeTag();
                    break;
                default:
                    break;
            }

            int totalLen = 6 + 1 + 2 + 2 + 1 + tag.Length;
            byte[] btLens = new byte[2];
            byte[] btlens0 = BitConverter.GetBytes(totalLen);
            btLens[0] = btlens0[1];
            btLens[1] = btlens0[0];

            byte[] enTag = null;
            int a = tag.Length % 8;
            if (a != 0)
            {
                enTag = new byte[tag.Length + 8 - a];
                tag.CopyTo(enTag, 0);
                for (int i = 0; i < 8 - a; i++)
                {
                    enTag[tag.Length + i] = 0;
                }
            }
            else
            {
                enTag = new byte[tag.Length];
                tag.CopyTo(enTag, 0);
            }

            TEA.encrypt(ref enTag, enTag.Length);

            //wrap the whole data
            byte[] result = new byte[1 + 1 + 2 + 6 + 1 + 2 + 2 + 1 + enTag.Length];
            result[0] = btpreamble;
            result[1] = btVersion;
            btLens.CopyTo(result, 2);
            btDevId.CopyTo(result, 4);
            result[10] = btRouteFlag;
            btDstNode.CopyTo(result, 11);
            btPdu.CopyTo(result, 13);
            result[15] = btSeq;
            enTag.CopyTo(result, 16);

            
            //增加CRC校验
            String strCrc = StringUtil.To16HexString(String.Format("{0:X}", (int)CodeUtils.CRC16_AD(result)));
            byte[] btcrc = { CodeUtils.String2Byte(strCrc.Substring(0, 2)), CodeUtils.String2Byte(strCrc.Substring(2, 2)) };
            byte[] afcrc = new byte[result.Length + 2];
            result.CopyTo(afcrc, 0);
            btcrc.CopyTo(afcrc, result.Length);

            String strBase64Value = Convert.ToBase64String(afcrc);
            //TODO:发送数据
            int ret = SendNACommand(deviceId_Telecom, strBase64Value, session);
            if (ret != 201)
            {
                session.Logger.Info("回复校时信息失败，返回的Http状态码：" + ret);
                return false;
            }

            session.Logger.Info("回复校时信息成功  设备类型：" + typeName + " 设备编号:" + devCode + " 回复校时信息：" + strBase64Value);   
            return true;
        }


        //获取校时tag信息
        private byte[] getTimeTag()
        {
            byte[] result = new byte[12];

            SystemTimeConfig sysTimeConfig = new SystemTimeConfig(null);
            byte[] btConfig = sysTimeConfig.getConfig(new byte[0]);
            btConfig.CopyTo(result, 0);

            return result;
        }

        private int SendNACommand(String deviceId_Telecom, String strValue, CasicSession session)
        {
            NASDK currsdk = new NASDK(ConfigurationManager.AppSettings["TelecomIP"],
                Convert.ToInt32(ConfigurationManager.AppSettings["TelecomPORT"]),
                ConfigurationManager.AppSettings["AppID"],
                ConfigurationManager.AppSettings["AppKey"],
                GetWindowsServiceInstallPath(ConfigurationManager.AppSettings["ServiceName"]) + "\\outgoing.CertwithKey.pkcs12",
                "IoM@1234");
            TokenResult token = currsdk.getToken();
            if (token == null)
            {
                session.Logger.Error("获取Token失败！");
                return 0;
            }
            string strToken = token.accessToken;

            CommandPara cp = new CommandPara();
            cp.paraName = "Value";
            cp.paraValue = strValue;

            int result = currsdk.sendCommand(strToken, deviceId_Telecom, null, "Config", "Config", cp,session);
            return result;
        }

        /// <summary>
        /// 获取服务安装路径
        /// </summary>
        /// <param name="ServiceName"></param>
        /// <returns></returns>
        public static string GetWindowsServiceInstallPath(string ServiceName)
        {
            string key = @"SYSTEM\CurrentControlSet\Services\" + ServiceName;
            string path = Registry.LocalMachine.OpenSubKey(key).GetValue("ImagePath").ToString();
            //替换掉双引号   
            path = path.Replace("\"", string.Empty);

            FileInfo fi = new FileInfo(path);
            return fi.Directory.ToString();
        }

    }
}