#define ENABLE_LOG
/*
 * Copyright (c) 2014 - 2022 t_saki@serenegiant.com 
 */

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

namespace Serenegiant.UVC
{

    public class UVCDrawer : MonoBehaviour, IUVCDrawer
    {
        /**
        *未设置IUVCSElector时
        *或IUVCSElector在选择分辨率时为空
        *返回时的默认分辨率（宽度）
		 */
        public int DefaultWidth = 1280;
        /**
		*未设置IUVCSElector时
        *或IUVCSElector在选择分辨率时为空
        *返回时的默认分辨率（高度）
		 */
        public int DefaultHeight = 720;


        /**
		 * 连接时及描绘时过滤器用
		 */
        public UVCFilter[] UVCFilters;

        /**
		 * GameObject保留UVC设备的视频目标材质
         * 如果未设置，则使用与分配此脚本相同的GameObjec。
		 */
        public List<GameObject> RenderTargets;

        [HideInInspector]
        public Action<Texture> StartPreviewAction;
        [HideInInspector]
        public Action StopPreviewAction;
        //--------------------------------------------------------------------------------
        private const string TAG = "UVCDrawer#";

        /**
		 * 从UVC设备绘制视频到Material
		 * 从目标游戏对象获取
		 * 优先顺位：
		 *	 TargetGameObjectのSkybox
		 *	 > TargetGameObjectのRenderer
		 *	 > TargetGameObjectのRawImage
		 *	 > TargetGameObjectのMaterial
		 * 如果任何方法都无法获得，则在Start中投掷Unity Exception
		 */
        private UnityEngine.Object[] TargetMaterials;
        /**
		 * 原始纹理
		 * 在设置UVC相机视频接收纹理之前
		 * GetComponent<Renderer>().material.mainTexture中描述的相应参数的值
		 */
        private Texture[] SavedTextures;

        private Quaternion[] quaternions;


        //================================================================================

        // Start is called before the first frame update
        void Start()
        {
#if (!NDEBUG && DEBUG && ENABLE_LOG)
            Console.WriteLine($"{TAG}Start:");
#endif
            UpdateTarget();

        }

        //		// Update is called once per frame
        //		void Update()
        //		{
        //
        //		}

        //================================================================================

        /**
		 * UVC设备已连接
		 * IOn UVCAttach Handler实施
		 * @param manager 调用方UVCmanager
		 * @param device 目标UVC设备信息
		 * @return true: 使用UVC设备， false: 不使用UVC设备
		 */
        public bool OnUVCAttachEvent(UVCManager manager, UVCDevice device)
        {
#if (!NDEBUG && DEBUG && ENABLE_LOG)
            Console.WriteLine($"{TAG}OnUVCAttachEvent:{device}");
#endif
            //XXX现在的安装基本上接受所有的UVC机器
            //但是因为THETA S、THETA V和THETA Z1有不能取得影像的接口，所以要提交
            //与Can Draw相同，可通过检查器设定UVC设备过滤器
            var result = !device.IsRicoh || device.IsTHETA;

            result &= UVCFilter.Match(device, UVCFilters);

            return result;
        }

        /**
		 * UVC设备已拆除
		 * IOn UVC细节事件处理程序
		 * @param manager 调用方UVCmanager
		 * @param device 目标UVC设备信息
		 */
        public void OnUVCDetachEvent(UVCManager manager, UVCDevice device)
        {
#if (!NDEBUG && DEBUG && ENABLE_LOG)
            Console.WriteLine($"{TAG}OnUVCDetachEvent:{device}");
#endif
        }

        //		/**
        //		 * 分辨率选択
        //		 * IOn UVCSElect Size Handler的实现
        //		 * @param manager 调用方UVCmanager
        //		 * @param device 目标UVC设备信息
        //		 * @param formats 有关相应分辨率的信息
        //		 */
        //		public SupportedFormats.Size OnUVCSelectSize(UVCManager manager, UVCDevice device, SupportedFormats formats)
        //		{
        //#if (!NDEBUG && DEBUG && ENABLE_LOG)
        //			Console.WriteLine($"{TAG}OnUVCSelectSize:{device}");
        //#endif
        //			if (device.IsTHETA_V || device.IsTHETA_Z1)
        //			{
        //#if (!NDEBUG && DEBUG && ENABLE_LOG)
        //				Console.WriteLine($"{TAG}OnUVCSelectSize:THETA V/Z1");
        //#endif
        //				return FindSize(formats, 3840, 1920);
        //			}
        //			else if (device.IsTHETA_S)
        //			{
        //#if (!NDEBUG && DEBUG && ENABLE_LOG)
        //				Console.WriteLine($"{TAG}OnUVCSelectSize:THETA S");
        //#endif
        //				return FindSize(formats, 1920, 1080);
        //			}
        //			else
        //			{
        //#if (!NDEBUG && DEBUG && ENABLE_LOG)
        //				Console.WriteLine($"{TAG}OnUVCSelectSize:other UVC device,{device}");
        //#endif
        //				return formats.Find(DefaultWidth, DefaultHeight);
        //			}
        //		}

        /**
		 * 获取IUVCdrawer是否可以绘制指定的UVC设备的视频
		 * 实现IUVCdrawer
		 * @param manager 调用方UVCmanager
		 * @param device 目标UVC设备信息
		 */
        public bool CanDraw(UVCManager manager, UVCDevice device)
        {
            return UVCFilter.Match(device, UVCFilters);
        }

        /**
	     * 已开始获取视频
         * 实现IUVCdrawer
         * @param manager 调用方UVCManager
         * @param device 对象的UVC设备的信息
         * @param tex 从UVC设备接收视频的纹理实例
		 */
        public void OnUVCStartEvent(UVCManager manager, UVCDevice device, Texture tex)
        {
#if (!NDEBUG && DEBUG && ENABLE_LOG)
            Console.WriteLine($"{TAG}OnUVCStartEvent:{device}");
#endif
            HandleOnStartPreview(tex);
            StartPreviewAction?.Invoke(tex);
        }

        /**
		 * 视频获取已完成
         * 实现IUVCdrawer
         * @param manager 调用方UVCManager
         * @param device 对象的UVC设备的信息
		 */
        public void OnUVCStopEvent(UVCManager manager, UVCDevice device)
        {
#if (!NDEBUG && DEBUG && ENABLE_LOG)
            Console.WriteLine($"{TAG}OnUVCStopEvent:{device}");
#endif
            HandleOnStopPreview();
            StopPreviewAction?.Invoke();
        }

        //================================================================================
        /**
		 * 更新目标
		 */
        private void UpdateTarget()
        {
            bool found = false;
            if ((RenderTargets != null) && (RenderTargets.Count > 0))
            {
                TargetMaterials = new UnityEngine.Object[RenderTargets.Count];
                SavedTextures = new Texture[RenderTargets.Count];
                quaternions = new Quaternion[RenderTargets.Count];
                int i = 0;
                foreach (var target in RenderTargets)
                {
                    if (target != null)
                    {
                        var material = TargetMaterials[i] = GetTargetMaterial(target);
                        if (material != null)
                        {
                            found = true;
                        }
#if (!NDEBUG && DEBUG && ENABLE_LOG)
                        Console.WriteLine($"{TAG}UpdateTarget:material={material}");
#endif
                    }
                    i++;
                }
            }
            if (!found)
            {   //找不到一个目标时，该脚本
                //尝试从AddComponent GameObject获取
                //在XXX RenderTargets中设置gameObject？
                TargetMaterials = new UnityEngine.Object[1];
                SavedTextures = new Texture[1];
                quaternions = new Quaternion[1];
                TargetMaterials[0] = GetTargetMaterial(gameObject);
                found = TargetMaterials[0] != null;
            }

            if (!found)
            {
                throw new UnityException("no target material found.");
            }
        }

        /**
		* 获取将图像绘制为纹理的材质
		* 如果指定的GameObject具有Skybox/Render/RawImage/Material，则从中获取Material
		* 如果每个都分配了多个，则返回第一个找到的可用项
		* 优先级：Skybox>Render>RawImage>Material
		* @param target
		* @return如果找不到，则返回null
		*/
        UnityEngine.Object GetTargetMaterial(GameObject target/*NonNull*/)
        {
            // 尝试获取Skybox
            var skyboxs = target.GetComponents<Skybox>();
            if (skyboxs != null)
            {
                foreach (var skybox in skyboxs)
                {
                    if (skybox.isActiveAndEnabled && (skybox.material != null))
                    {
                        RenderSettings.skybox = skybox.material;
                        return skybox.material;
                    }
                }
            }
            // 如果无法获取Skybox，则尝试获取渲染器
            var renderers = target.GetComponents<Renderer>();
            if (renderers != null)
            {
                foreach (var renderer in renderers)
                {
                    if (renderer.enabled && (renderer.material != null))
                    {
                        return renderer.material;
                    }

                }
            }
            // 如果Skybox和Render都无法获取，则尝试获取原始图像
            var rawImages = target.GetComponents<RawImage>();
            if (rawImages != null)
            {
                foreach (var rawImage in rawImages)
                {
                    if (rawImage.enabled && (rawImage.material != null))
                    {
                        return rawImage;
                    }

                }
            }
            // 如果Skybox、Render、Raw Image都无法获取，则尝试获取材质
            var material = target.GetComponent<Material>();
            if (material != null)
            {
                return material;
            }
            return null;
        }

        private void RestoreTexture()
        {
            for (int i = 0; i < TargetMaterials.Length; i++)
            {
                var target = TargetMaterials[i];
                try
                {
                    if (target is Material)
                    {
                        (target as Material).mainTexture = SavedTextures[i];
                    }
                    else if (target is RawImage)
                    {
                        (target as RawImage).texture = SavedTextures[i];
                    }
                }
                catch
                {
                    Console.WriteLine($"{TAG}RestoreTexture:Exception cought");
                }
                SavedTextures[i] = null;
                quaternions[i] = Quaternion.identity;
            }
        }

        private void ClearTextures()
        {
            for (int i = 0; i < SavedTextures.Length; i++)
            {
                SavedTextures[i] = null;
            }
        }

        /**
		 * 镜像取得开始时の处理
		 * @param tex 接收视频的纹理
		 */
        private void HandleOnStartPreview(Texture tex)
        {
#if (!NDEBUG && DEBUG && ENABLE_LOG)
            Console.WriteLine($"{TAG}HandleOnStartPreview:({tex})");
#endif
            int i = 0;
            foreach (var target in TargetMaterials)
            {
                if (target is Material)
                {
#if (!NDEBUG && DEBUG && ENABLE_LOG)
                    Console.WriteLine($"{TAG}HandleOnStartPreview:assign Texture to Material({target})");
#endif
                    SavedTextures[i++] = (target as Material).mainTexture;
                    (target as Material).mainTexture = tex;
                }
                else if (target is RawImage)
                {
#if (!NDEBUG && DEBUG && ENABLE_LOG)
                    Console.WriteLine($"{TAG}HandleOnStartPreview:assign Texture to RawImage({target})");
#endif
                    SavedTextures[i++] = (target as RawImage).texture;
                    (target as RawImage).texture = tex;
                }
            }
        }

        /**
		 * 影像取得结束时的Unity侧的处理
		 */
        private void HandleOnStopPreview()
        {
#if (!NDEBUG && DEBUG && ENABLE_LOG)
            Console.WriteLine($"{TAG}HandleOnStopPreview:");
#endif
            // 撤消目标纹理
            RestoreTexture();
#if (!NDEBUG && DEBUG && ENABLE_LOG)
            Console.WriteLine($"{TAG}HandleOnStopPreview:finished");
#endif
        }

    } // class UVCDrawer

} // namespace Serenegiant.UVC
