using System;
using System.Collections.Generic;
using System.Linq;
using ComponentFramework.Modules;
using MTV3D65;
using ComponentFramework;

namespace OctreeRendering
{
    class KeyboardState : Service, IKeyboardState
    {
        const int SimultaneousKeys = 256;

        readonly TV_KEYDATA[] keyBuffer = new TV_KEYDATA[SimultaneousKeys];
        readonly Dictionary<CONST_TV_KEY, KeyState> keys = new Dictionary<CONST_TV_KEY, KeyState>();

        public KeyboardState(ICore core) : base(core) { }

        public KeyState GetKeyState(CONST_TV_KEY key)
        {
            KeyState idle;
            if (!keys.TryGetValue(key, out idle))
                idle = KeyState.Up;

            return idle;
        }

        public override void Update(TimeSpan elapsedTime)
        {
            if (keys.Keys.Count > 0)
                // I know, I just blogged about this being bad practice, but whatever. ^_^
                foreach (CONST_TV_KEY key in keys.Keys.ToArray())
                    switch (keys[key])
                    {
                        case KeyState.Pressed:
                            keys.Remove(key);
                            keys.Add(key, KeyState.Down);
                            break;
                        case KeyState.Released:
                            keys.Remove(key);
                            break;
                    }

            int keyCount = 0;
            InputEngine.GetKeyBuffer(keyBuffer, ref keyCount);
            foreach (var keyData in keyBuffer.Take(keyCount))
            {
                var key = (CONST_TV_KEY) keyData.Key;
                KeyState state = keyData.Pressed == 1 ? KeyState.Pressed : 
                    keyData.Released == 1 ? KeyState.Released : KeyState.Up;

                keys.Remove(key);
                if (state != KeyState.Up)
                    keys.Add(key, state);
            }
        }
    }

    interface IKeyboardState : IService 
    {
        KeyState GetKeyState(CONST_TV_KEY key);
    }

    public enum KeyState
    {
        Up,
        Pressed,
        Released,
        Down
    }

    public static class KeyStateExtensions
    {
        public static bool IsDown(this KeyState state)
        {
            return state == KeyState.Down || state == KeyState.Pressed;
        }
    }
}
