using System;
using System.Collections.Generic;
using System.Linq;
using Monkey.UI.Windows;

namespace Monkey.UI
{

    public static class UIManager
    {

        private static readonly UnityEngine.Color _headingForegroundColor = UnityEngine.Color.black;

        private static int _nextWindowIdentifier;
        private static Dictionary<Type, Window> _windows;
        private static Dictionary<Type, bool> _windowVisibilityStates;

        static UIManager()
        {
            _nextWindowIdentifier = 0;
            _windows = new Dictionary<Type, Window>();
            _windowVisibilityStates = new Dictionary<Type, bool>();
        }

        public static void Draw()
        {
            foreach (KeyValuePair<Type, Window> windowEntry in _windows)
            {
                if (!_windowVisibilityStates[windowEntry.Key])
                    continue;

                windowEntry.Value.Draw();
            }
        }

        public static void RegisterWindow<T>(string title, UnityEngine.Rect dimensions) where T : Window
        {
            if (String.IsNullOrEmpty(title))
                throw new ArgumentNullException(nameof(title));

            if (_windows.ContainsKey(typeof(T)))
                throw new InvalidOperationException();

            if (_windowVisibilityStates.ContainsKey(typeof(T)))
                throw new InvalidOperationException();

            _windows.Add(typeof(T), (Activator.CreateInstance(typeof(T), _nextWindowIdentifier++, title, dimensions) as T));
            _windowVisibilityStates.Add(typeof(T), false);
        }

        public static T GetWindow<T>() where T : Window
        {
            if (!_windows.ContainsKey(typeof(T)))
                throw new InvalidOperationException();

            return (_windows[typeof(T)] as T);
        }

        public static bool IsWindowVisible<T>() where T : Window
        {
            if (!_windowVisibilityStates.ContainsKey(typeof(T)))
                throw new InvalidOperationException();

            return _windowVisibilityStates[typeof(T)];
        }

        public static void SetWindowVisibility<T>(bool isVisible) where T : Window
        {
            if (!_windowVisibilityStates.ContainsKey(typeof(T)))
                throw new InvalidOperationException();

            _windowVisibilityStates[typeof(T)] = isVisible;

            if (IsAnyWindowVisible())
                UnityEngine.Cursor.visible = true;
        }

        public static bool IsAnyWindowVisible()
        {
            return _windowVisibilityStates.Any(q => (q.Value));
        }

        public static void DrawHeading(string text)
        {
            if (String.IsNullOrEmpty(text))
                throw new ArgumentNullException(nameof(text));

            UnityEngine.Color oldForegroundColor = UnityEngine.GUI.color;

            UnityEngine.GUI.color = _headingForegroundColor;

            UnityEngine.GUILayout.Label(text);

            UnityEngine.GUI.color = oldForegroundColor;
        }

        public static void DrawHorizontalSlider(Action<float> onValueChangedAction, float value, float minimumValue, float maximumValue)
        {
            if (onValueChangedAction == null)
                throw new ArgumentNullException(nameof(onValueChangedAction));

            float temporaryValue = UnityEngine.GUILayout.HorizontalSlider(value, minimumValue, maximumValue);

            if (temporaryValue != value)
                onValueChangedAction(temporaryValue);
        }

        public static void DrawToggle(Action<bool> onValueChangedAction, bool value, string text)
        {
            if (onValueChangedAction == null)
                throw new ArgumentNullException(nameof(onValueChangedAction));

            if (String.IsNullOrEmpty(text))
                throw new ArgumentNullException(nameof(text));

            bool temporaryValue = UnityEngine.GUILayout.Toggle(value, text);

            if (temporaryValue != value)
                onValueChangedAction(temporaryValue);
        }

    }

}
