/**********************************************************************************
* Blueprint Reality Inc. CONFIDENTIAL
* 2021 Blueprint Reality Inc.
* All Rights Reserved.
*
* NOTICE:  All information contained herein is, and remains, the property of
* Blueprint Reality Inc. and its suppliers, if any.  The intellectual and
* technical concepts contained herein are proprietary to Blueprint Reality Inc.
* and its suppliers and may be covered by Patents, pending patents, and are
* protected by trade secret or copyright law.
*
* Dissemination of this information or reproduction of this material is strictly
* forbidden unless prior written permission is obtained from Blueprint Reality Inc.
***********************************************************************************/

#if UNITY_STANDALONE_WIN
using BlueprintReality.Interprocess.Textures;
using BlueprintReality.MixCast;
using BlueprintReality.MixCast.Thrift;
using BlueprintReality.Thrift.SharedTextures;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using UnityEngine;

namespace BlueprintReality.SharedTextures
{
    public class SharedTextureSending : MonoBehaviour
    {
        public delegate bool ShareFunc(string texId, SharedTex texInfo);

        static bool exists = false;
        private static void EnsureExists()
        {
            if (!exists)
            {
                new GameObject().AddComponent<SharedTextureSending>();
                exists = true;
            }
        }

        public static ShareFunc ShareFuncOverride { get; protected set; }
        public static void SetShareFunc(ShareFunc newShareFunc)
        {
            ShareFuncOverride = newShareFunc;
        }

        private static Dictionary<string, Texture> registeredLocalTextures = new Dictionary<string, Texture>();
        public static event Action<string, SharedTex> OnTextureSent;

        private void Awake()
        {
            name = GetType().Name;
            gameObject.hideFlags = HideFlags.HideAndDontSave;
            DontDestroyOnLoad(gameObject);
        }

        public static bool RegisterLocal(string texId, OwnedUnitySharedTexture sharedTex)
        {
            EnsureExists();
            SharedTexturePlugin.EnsureExists();

            SharedTex texInfo = new SharedTex()
            {
                Handle = sharedTex.Handle.ToInt64(),
                Width = sharedTex.SourceTex.width,
                Height = sharedTex.SourceTex.height,
                Format = (int)sharedTex.Format,
                ProcId = UnityInfo.GetProcessId(),
            };

            bool shareResult = false;
            if (ShareFuncOverride == null)
            {
                SharedTextureCommunication.Client client = string.IsNullOrEmpty(SharedTexturePlugin.manualThriftAddress) ?
                    UnityThriftMixCastClient.Get<SharedTextureCommunication.Client>() :
                    UnityThriftMixCastClient.Get<SharedTextureCommunication.Client>(SharedTexturePlugin.manualThriftAddress);

                shareResult = client.TrySharedTextureNotify(texId, texInfo);
            }
            else
            {
                shareResult = ShareFuncOverride(texId, texInfo);
            }

            if (shareResult)
            {
                registeredLocalTextures.Add(texId, sharedTex.SourceTex);
                if (OnTextureSent != null)
                    OnTextureSent(texId, texInfo);

                return true;
            }
            else
            {
                Debug.Log("Couldn't register texture due to Thrift error");
                return false;
            }
        }

        public static bool UnregisterLocal(string texId)
        {
            if (string.IsNullOrEmpty(texId))
                return false;

            EnsureExists();
            SharedTexturePlugin.EnsureExists();

            if (registeredLocalTextures.ContainsKey(texId))
            {
                Debug.Log("Unregistering shared tex: " + texId);
                registeredLocalTextures.Remove(texId);
                SharedTex emptyTex = new SharedTex(0, 0, 0, 0);

                if (ShareFuncOverride == null)
                {
                    SharedTextureCommunication.Client client = string.IsNullOrEmpty(SharedTexturePlugin.manualThriftAddress) ?
                        UnityThriftMixCastClient.Get<SharedTextureCommunication.Client>() :
                        UnityThriftMixCastClient.Get<SharedTextureCommunication.Client>(SharedTexturePlugin.manualThriftAddress);

                    if (client != null)
                    {
                        bool res = client.TrySharedTextureNotify(texId, emptyTex);
                        if (OnTextureSent != null)
                            OnTextureSent(texId, emptyTex);
                        return res;
                    }
                    else
                        return false;
                }
                else
                {
                    bool result = ShareFuncOverride.Invoke(texId, emptyTex);
                    if (OnTextureSent != null)
                        OnTextureSent(texId, emptyTex);
                    return result;
                }
            }
            else
            {
                Debug.LogError("No Local Texture found for ID: " + texId);
                return false;
            }
        }

        public static bool HasLocalTexture(string texId)
        {
            return registeredLocalTextures.ContainsKey(texId);
        }
        public static bool TryGetLocalTexture(string texId, out Texture texture)
        {
            return registeredLocalTextures.TryGetValue(texId, out texture);
        }
    }
}
#endif
