using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using skyscraper5.Skyscraper.Plugins;

namespace skyscraper5.DsmCc
{
    class DsmCcMessageUnpacker
    {
        private static DsmCcMessageUnpacker _instance;

        public static DsmCcMessageUnpacker GetInstance()
        {
            if (_instance == null)
                _instance = new DsmCcMessageUnpacker();
            return _instance;
        }

        private ConstructorInfo[] constructors;

        private DsmCcMessageUnpacker()
        {
	        constructors = PluginManager.GetInstance().GetDsmCcMessages();
        }
        
        public DsmCcMessage UnpackMessage(DsmCcMessageHeader childHeader, byte[] messageContent)
        {
            /**
             * DSM-CC Types:
             * 0x01 => User to Network Configuration Message
             * 0x02 => User to Network Session Message
             * 0x03 => Download Message
             * 0x04 => SDB Channel Change Protocol
             * 0x05 => User to Network Pass-Thru Message
             */
            if (messageContent.Length == 0)
                return null;
            if (childHeader.DsmccType == 0x00)
                return null;
            if (childHeader.DsmccType >= 0x06 && childHeader.DsmccType <= 0x7f)
                return null;    //According to https://github.com/wireshark/wireshark/blob/master/epan/dissectors/packet-mpeg-dsmcc.c, this is reserved.
            if (childHeader.DsmccType >= 0x80 && childHeader.DsmccType <= 0xff)
                return null;    //At this time, we have no way of knowing who the "user" is which specifies "user defined" message types.
            if (childHeader.MessageId == 0x472e)
                return null;
            ConstructorInfo constructorInfo = constructors[childHeader.MessageId];
            if (constructorInfo == null)
                throw new NotImplementedException(String.Format("DSM-CC Message {0:X4}", childHeader.MessageId));

            object invoke = constructorInfo.Invoke(new object[] { messageContent });
            DsmCcMessage result = (DsmCcMessage)invoke;
            result.Header = childHeader;
            return result;
        }
    }
}
