using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Text.RegularExpressions;
using Common;
using Dao;
using Domain;
using RCUHost.Protocols;

namespace RCUHost.Implement
{
	public class AirConditionStatusReceiver : GenericReceiverBase, IAirConditionStatusReceiver
	{
		public IHostRepository HostRepository { get; set; }

		public IHostAirRepository HostAirRepository { get; set; }

		/// <summary>
		/// 应用空调设置
		/// </summary>
		/// <param name="hostAir"></param>
		public void SendAirConditionSetting(HostAir hostAir, Host host)
		{
			byte[] data = CreateAirConditionSettingDataPacket(hostAir);

            SendAndPushCommandQueue(data, host.HostNumber, host.MAC);// host.IP, host.Port);
		}

		/// <summary>
		/// 空调单个属性下发
		/// </summary>
		/// <param name="host"></param>
		/// <param name="airNo"></param>
		/// <param name="property"></param>
		/// <param name="status"></param>
        /// <param name="seasonData">季节数据</param>
        public void SetAirProperty(Host host, int airNo, AirProperty property, int status, byte[] seasonData = null)
        {
            if (property == AirProperty.CompensatoryTemp ||
                property == AirProperty.LockTemp ||
                property == AirProperty.SleepMode ||
                property == AirProperty.Time)
            {
                throw new ApplicationException("无效的属性值，请使用对应方法设置。");
            }
            byte[] statusData = new byte[1];
            if (property == AirProperty.Season)
            {
                statusData = new byte[12];
                statusData = seasonData;
            }
            else
            {
                statusData[0] = (byte)status;
            }
            var data = CreateAirPropertyDataPacket(airNo, property, statusData);
            SendAndPushCommandQueue(data, host.HostNumber, host.MAC);// host.IP, host.Port);
        }

		/// <summary>
		/// 设置空调补偿温度
		/// </summary>
		/// <param name="host"></param>
		/// <param name="airNo"></param>
		/// <param name="compensatoryTemp"></param>
		public void SetCompensatoryTemp(Host host, int airNo, float compensatoryTemp)
		{
			byte[] statusData = new byte[1];

			statusData[0] = ConvertCompensatoryTempToHost(compensatoryTemp);

			var data = CreateAirPropertyDataPacket(airNo, AirProperty.CompensatoryTemp, statusData);

            SendAndPushCommandQueue(data, host.HostNumber, host.MAC);// host.IP, host.Port);
		}

		/// <summary>
		/// 设置空调锁定温度
		/// </summary>
		/// <param name="host"></param>
		/// <param name="airNo"></param>
		/// <param name="isLock"></param>
		/// <param name="lockTemp"></param>
		public void SetLockTemp(Host host, int airNo, bool isLock, int lockTemp)
		{
			byte[] statusData = new byte[2];
			statusData[0] = (byte)(isLock ? 1 : 0);
			statusData[1] = (byte)lockTemp;

			var data = CreateAirPropertyDataPacket(airNo, AirProperty.LockTemp, statusData);

            SendAndPushCommandQueue(data, host.HostNumber, host.MAC);// host.IP, host.Port);
		}

		/// <summary>
		/// 设置空调睡眠模式
		/// </summary>
		/// <param name="host"></param>
		/// <param name="airNo"></param>
		/// <param name="sleepFlag"></param>
		/// <param name="SleepDevition"></param>
		/// <param name="sleepStartTime"></param>
		/// <param name="sleepEndTime"></param>
		public void SetSleepMode(Host host, int airNo, bool sleepFlag, int sleepDevition, string sleepStartTime, string sleepEndTime)
		{
            using (MemoryStream stream = new MemoryStream())
            {
                using (BinaryWriter writer = new BinaryWriter(stream))
                {
                    writer.Write(sleepFlag);
                    writer.Write((byte)sleepDevition);
                    writer.Write(ConvertTimeToBytes(sleepStartTime));
                    writer.Write(ConvertTimeToBytes(sleepEndTime));

                    var data = CreateAirPropertyDataPacket(airNo, AirProperty.SleepMode, stream.ToArray());

                    SendAndPushCommandQueue(data, host.HostNumber, host.MAC);// host.IP, host.Port);
                }
            }
		}

		/// <summary>
		/// 设置空调定时设置
		/// </summary>
		/// <param name="host"></param>
		/// <param name="airNo"></param>
		/// <param name="timeFlag"></param>
		/// <param name="startTime1"></param>
		/// <param name="endTime1"></param>
		/// <param name="startTime2"></param>
		/// <param name="endTime2"></param>
		/// <param name="startTime3"></param>
		/// <param name="endTime3"></param>
		public void SetTimeSetting(Host host, int airNo, bool timeFlag, string startTime1, string endTime1, string startTime2, string endTime2, string startTime3, string endTime3)
		{
            using (MemoryStream stream = new MemoryStream())
            {
                using (BinaryWriter writer = new BinaryWriter(stream))
                {
                    writer.Write(timeFlag);
                    writer.Write(ConvertTimeToBytes(startTime1));
                    writer.Write(ConvertTimeToBytes(endTime1));
                    writer.Write(ConvertTimeToBytes(startTime2));
                    writer.Write(ConvertTimeToBytes(endTime2));
                    writer.Write(ConvertTimeToBytes(startTime3));
                    writer.Write(ConvertTimeToBytes(endTime3));

                    var data = CreateAirPropertyDataPacket(airNo, AirProperty.Time, stream.ToArray());

                    SendAndPushCommandQueue(data, host.HostNumber, host.MAC);// host.IP, host.Port);
                }
            }
		}

		public override CommandType CommandType
		{
			get { return CommandType.AirConditionStatus; }
		}

		#region Private Methods

		private byte[] CreateAirConditionSettingDataPacket(HostAir hostAir)
		{
			SystemHeader systemHeader = CreateSystemHeader();

			AirConditionSettingPacket airConditionSettingPacket = CreateAirConditionSettingPacket(hostAir);

			int size = StructConverter.SizeOf(systemHeader) + StructConverter.SizeOf(airConditionSettingPacket);

			systemHeader.FrameLength = (ushort)size;

			byte[] buffer = new byte[size];

			byte[] src1 = StructConverter.StructToBytes(systemHeader);
			Array.Copy(src1, 0, buffer, 0, src1.Length);

			byte[] src3 = StructConverter.StructToBytes(airConditionSettingPacket);
			Array.Copy(src3, 0, buffer, src1.Length, src3.Length);

			return buffer;
		}

		/// <summary>
		/// 创建 AirConditionSettingPacket
		/// </summary>
		/// <param name="hostAir"></param>
		/// <returns></returns>
		private AirConditionSettingPacket CreateAirConditionSettingPacket(HostAir hostAir)
		{
			AirConditionSettingPacket packet = new AirConditionSettingPacket();

			packet.AirNo = Convert.ToByte(hostAir.Modal.ModalType.ID);

			packet.OnOff = Convert.ToByte(hostAir.OnOff);
			packet.SettingTemp = Convert.ToByte(hostAir.SettingTemp);
			packet.CompensatoryTemp = ConvertCompensatoryTempToHost(hostAir.CompensatoryTemp);
			packet.Speed = Convert.ToByte(hostAir.Speed);
			packet.Mode = Convert.ToByte(hostAir.Mode);
			packet.IsLockTemp = Convert.ToByte(hostAir.IsLockTemp);
			packet.LockTemp = Convert.ToByte(hostAir.LockTemp);

			packet.KeepTemp = Convert.ToByte(hostAir.KeepTemp);
			packet.InitTemp = Convert.ToByte(hostAir.InitTemp);
			packet.HighTemp = Convert.ToByte(hostAir.HightTemp);
			packet.LowerTemp = Convert.ToByte(hostAir.LowerTemp);
			packet.ColdHotSwitchDelayTime = Convert.ToByte(hostAir.ColdHotSwitchDelayTime);
			packet.ColdHotMode = Convert.ToByte(hostAir.ColdHotMode);
			packet.DeadTemp = Convert.ToByte(hostAir.DeadTemp);
			packet.HotDevition = Convert.ToByte(hostAir.HotDevition);
			packet.ColdDevition = Convert.ToByte(hostAir.ColdDevition);
			packet.WelcomeTime = Convert.ToByte(hostAir.WelcomeTime);
			packet.RelateRoomStatus = Convert.ToByte(hostAir.RelateRoomStatus);
			packet.RelateDoorContact = Convert.ToByte(hostAir.RelateDoorContact);
			packet.FanStop = Convert.ToByte(hostAir.FanStop);
			packet.DisableFanHighSpeed = Convert.ToByte(hostAir.DisableFanHighSpeed);

			packet.SleepFlag = Convert.ToByte(hostAir.SleepFlag);
			packet.SleepStartTime = ConvertTimeToBytes(hostAir.SleepStartTime);
			packet.SleepEndTime = ConvertTimeToBytes(hostAir.SleepEndTime);
			packet.SleepDevition = Convert.ToByte(hostAir.SleepDevition);

			packet.TimeFlag = Convert.ToByte(hostAir.TimeFlag);
			packet.TimeStartTime1 = ConvertTimeToBytes(hostAir.TimeStartTime1);
			packet.TimeEndTime1 = ConvertTimeToBytes(hostAir.TimeEndTime1);
			packet.TimeStartTime2 = ConvertTimeToBytes(hostAir.TimeStartTime2);
			packet.TimeEndTime2 = ConvertTimeToBytes(hostAir.TimeEndTime2);
			packet.TimeStartTime3 = ConvertTimeToBytes(hostAir.TimeStartTime3);
			packet.TimeEndTime3 = ConvertTimeToBytes(hostAir.TimeEndTime3);
			
			return packet;
		}

		private byte[] CreateAirPropertyDataPacket(int airNo, AirProperty perperty, byte[] data)
		{
			if(data == null || data.Length == 0)
			{
				throw new ArgumentNullException("data");
			}

            using (MemoryStream stream = new MemoryStream())
            {
                using (BinaryWriter writer = new BinaryWriter(stream))
                {
                    int headerSize = StructConverter.SizeOf(typeof(SystemHeader));

                    stream.Seek(headerSize, SeekOrigin.Begin);
                    writer.Write((byte)airNo);					//空调号
                    writer.Write((byte)perperty);				//空调属性
                    writer.Write(data);							//属性值
                    writer.Write(new byte[] { 0, 0 });			//CRC16校验

                    var systemHeader = CreateSystemHeader(CommandType.AirProperty, (int)stream.Length - headerSize);
                    var headerData = StructConverter.StructToBytes(systemHeader);

                    stream.Seek(0, SeekOrigin.Begin);

                    writer.Write(headerData);

                    return stream.ToArray();
                }
            }
		}

		/// <summary>
		/// 转换时间到字节数组
		/// 例如：
		///		12:05 => byte0=12, byte1=05
		/// </summary>
		/// <returns></returns>
		private byte[] ConvertTimeToBytes(string time)
		{
			byte[] bytes = new byte[] { 0, 0 };

			if (!String.IsNullOrEmpty(time))
			{
				string[] temp = time.Split(':');

				bytes[0] = Convert.ToByte(temp[0]);
				bytes[1] = Convert.ToByte(temp[1]);
			}

			return bytes;
		}

		/// <summary>
		/// 将补偿温度转换为主机存储格式
		///		具体格式参见协议
		/// </summary>
		/// <param name="temp"></param>
		/// <returns></returns>
		private byte ConvertCompensatoryTempToHost(float temp)
		{
			byte val = Convert.ToByte(Math.Floor(Math.Abs(temp * 10)));

			if (temp < 0)
			{
				return (val |= 0x80);
			}

			return val;
		}

		#endregion
	}
}
