//-----------------------------------------------------------------------
// Copyright 2016 Tobii AB (publ). All rights reserved.
//-----------------------------------------------------------------------

using System;
using System.IO;
using SimpleJSON;
using UnityEngine;

namespace Tobii.EyeTracking
{
    [Serializable]
    public struct GazeFocusSettings
    {
#if UNITY_EDITOR
        private static readonly string DirectoryPath = @"Assets\Tobii\Resources";
        private static readonly string FilePath = @"Assets\Tobii\Resources\GazeFocusSettings.json";
#else
        private static readonly string ResourcePath = "GazeFocusSettings";
#endif
        private static readonly int MaximumLayersInUnity = 32;

        /// <summary>
        /// Layers to detect gaze focus on.
        /// </summary>
        public int LayerMask;

        /// <summary>
        /// Maximum distance to detect gaze focus within.
        /// </summary>
        public float MaximumDistance;

        /// <summary>
        /// Gets the stored gaze focus settings.
        /// </summary>
        /// <returns></returns>
        public static GazeFocusSettings Get()
        {
#if UNITY_EDITOR
            if (!IsInitialized())
            {
                Initialize();
            }

            string settingsAsJson = File.ReadAllText(FilePath);
	        return GetSettingsFromObject(JSON.Parse(settingsAsJson));

#else
            TextAsset settings = Resources.Load<TextAsset>(ResourcePath);

            if (null == settings)
            {
                return CreateDefault();
            }

	        return GetSettingsFromObject(JSON.Parse(settings.text));
#endif
		}

	    private static GazeFocusSettings GetSettingsFromObject(JSONNode json)
	    {
		    var gfs = new GazeFocusSettings();
		    gfs.LayerMask = json["LayerMask"].AsInt;
		    gfs.MaximumDistance = json["MaximumDistance"].AsFloat;
		    return gfs;
	    }

        /// <summary>
        /// Overwrites the currently stored settings with the supplied
        /// gazeFocusSettings. This call will only affect the stored settings,
        /// it will not update the settings loaded by the gaze focus system.
        /// </summary>
        /// <remarks>Will only store settings if called in Unity Editor.</remarks>
        /// <param name="gazeFocusSettings"></param>
        public static void Set(GazeFocusSettings gazeFocusSettings)
        {
#if UNITY_EDITOR
	        var json = new JSONClass();
	        json["LayerMask"].AsInt = gazeFocusSettings.LayerMask;
	        json["MaximumDistance"].AsFloat = gazeFocusSettings.MaximumDistance;
	        string settingsAsJson = json.ToString();
			File.WriteAllText(FilePath, settingsAsJson);
#endif
        }

        public static GazeFocusSettings CreateDefault()
        {
            return new GazeFocusSettings
            {
                LayerMask = CreateDefaultLayerMask(),
                MaximumDistance = Mathf.Infinity
            };
        }

        public bool Equals(GazeFocusSettings otherSettings)
        {
            return this.LayerMask == otherSettings.LayerMask &&
                (float.IsInfinity(this.MaximumDistance) && float.IsInfinity(otherSettings.MaximumDistance) ||
                 Math.Abs(this.MaximumDistance - otherSettings.MaximumDistance) < float.Epsilon);
        }

#if UNITY_EDITOR
        private static bool IsInitialized()
        {
            return File.Exists(FilePath);
        }

        private static void Initialize()
        {
            Directory.CreateDirectory(DirectoryPath);
            Set(CreateDefault());
        }
#endif

        /// <summary>
        /// Creates a default layer mask with all non-empty layers selected.
        /// </summary>
        private static int CreateDefaultLayerMask()
        {
            int layerMask = 0;
            for (int i = 0; i < MaximumLayersInUnity; ++i)
            {
                if (!string.Empty.Equals(UnityEngine.LayerMask.LayerToName(i)))
                {
                    layerMask |= (1 << i);
                }
            }

            return layerMask;
        }
    }
}
