using System;
using UnityEngine;
namespace FairyGUI
{
    /// 
    /// 
    /// 
    [ExecuteInEditMode]
    [AddComponentMenu("FairyGUI/UI Painter")]
    [RequireComponent(typeof(MeshCollider), typeof(MeshRenderer))]
    public class UIPainter : MonoBehaviour, EMRenderTarget
    {
        /// 
        /// 
        /// 
        public Container container { get; private set; }
        /// 
        /// 
        /// 
        public string packageName;
        /// 
        /// 
        /// 
        public string componentName;
        /// 
        /// 
        /// 
        public int sortingOrder;
        [SerializeField]
        string packagePath;
        [SerializeField]
        Camera renderCamera = null;
        [SerializeField]
        bool fairyBatching = false;
        [SerializeField]
        bool touchDisabled = false;
        GComponent _ui;
        [NonSerialized]
        bool _created;
        [NonSerialized]
        bool _captured;
        [NonSerialized]
        Renderer _renderer;
        [NonSerialized]
        RenderTexture _texture;
        Action _captureDelegate;
        void OnEnable()
        {
            if (Application.isPlaying)
            {
                if (this.container == null)
                {
                    CreateContainer();
                    if (!string.IsNullOrEmpty(packagePath) && UIPackage.GetByName(packageName) == null)
                        UIPackage.AddPackage(packagePath);
                }
            }
            else
            {
                EMRenderSupport.Add(this);
            }
        }
        void OnDisable()
        {
            if (!Application.isPlaying)
                EMRenderSupport.Remove(this);
        }
        void OnGUI()
        {
            if (!Application.isPlaying)
                EM_BeforeUpdate();
        }
        void Start()
        {
            useGUILayout = false;
            if (!_created && Application.isPlaying)
                CreateUI();
        }
        void OnDestroy()
        {
            if (Application.isPlaying)
            {
                if (_ui != null)
                {
                    _ui.Dispose();
                    _ui = null;
                }
                container.Dispose();
                container = null;
            }
            else
            {
                EMRenderSupport.Remove(this);
            }
            DestroyTexture();
        }
        void CreateContainer()
        {
            this.container = new Container("UIPainter");
            this.container.renderMode = RenderMode.WorldSpace;
            this.container.renderCamera = renderCamera;
            this.container.touchable = !touchDisabled;
            this.container.fairyBatching = fairyBatching;
            this.container._panelOrder = sortingOrder;
            this.container.hitArea = new MeshColliderHitTest(this.gameObject.GetComponent());
            SetSortingOrder(this.sortingOrder, true);
            this.container.layer = CaptureCamera.hiddenLayer;
        }
        /// 
        /// Change the sorting order of the panel in runtime.
        /// 
        /// sorting order value
        /// false if you dont want the default sorting behavior.
        public void SetSortingOrder(int value, bool apply)
        {
            this.sortingOrder = value;
            container._panelOrder = value;
            if (apply)
                Stage.inst.ApplyPanelOrder(container);
        }
        /// 
        /// 
        /// 
        public GComponent ui
        {
            get
            {
                if (!_created && Application.isPlaying)
                    CreateUI();
                return _ui;
            }
        }
        /// 
        /// 
        /// 
        public void CreateUI()
        {
            if (_ui != null)
            {
                _ui.Dispose();
                _ui = null;
                DestroyTexture();
            }
            _created = true;
            if (string.IsNullOrEmpty(packageName) || string.IsNullOrEmpty(componentName))
                return;
            _ui = (GComponent)UIPackage.CreateObject(packageName, componentName);
            if (_ui != null)
            {
                this.container.AddChild(_ui.displayObject);
                this.container.size = _ui.size;
                _texture = CaptureCamera.CreateRenderTexture(Mathf.RoundToInt(_ui.width), Mathf.RoundToInt(_ui.height), UIConfig.depthSupportForPaintingMode);
                _renderer = this.GetComponent();
                if (_renderer != null)
                {
                    _renderer.sharedMaterial.mainTexture = _texture;
                    _captureDelegate = Capture;
                    if (_renderer.sharedMaterial.renderQueue == 3000) //Set in transpare queue only
                    {
                        this.container.onUpdate += () =>
                        {
                            UpdateContext.OnEnd += _captureDelegate;
                        };
                    }
                }
            }
            else
                Debug.LogError("Create " + componentName + "@" + packageName + " failed!");
        }
        void Capture()
        {
            CaptureCamera.Capture(this.container, _texture, this.container.size.y, Vector2.zero);
            if (_renderer != null)
                _renderer.sortingOrder = container.renderingOrder;
        }
        void DestroyTexture()
        {
            if (_texture != null)
            {
                if (Application.isPlaying)
                    RenderTexture.Destroy(_texture);
                else
                    RenderTexture.DestroyImmediate(_texture);
                _texture = null;
                if (_renderer != null)
                    _renderer.sharedMaterial.mainTexture = null;
            }
        }
        #region edit mode functions
        void CaptureInEditMode()
        {
            if (!EMRenderSupport.packageListReady || UIPackage.GetByName(packageName) == null)
                return;
            _captured = true;
            DisplayObject.hideFlags = HideFlags.DontSaveInEditor;
            GComponent view = (GComponent)UIPackage.CreateObject(packageName, componentName);
            if (view != null)
            {
                DestroyTexture();
                _texture = CaptureCamera.CreateRenderTexture(Mathf.RoundToInt(view.width), Mathf.RoundToInt(view.height), false);
                Container root = (Container)view.displayObject;
                root.layer = CaptureCamera.layer;
                root.gameObject.hideFlags = HideFlags.None;
                root.gameObject.SetActive(true);
                GameObject cameraObject = new GameObject("Temp Capture Camera");
                Camera camera = cameraObject.AddComponent();
                camera.depth = 0;
                camera.cullingMask = 1 << CaptureCamera.layer;
                camera.clearFlags = CameraClearFlags.Depth;
                camera.orthographic = true;
                camera.nearClipPlane = -30;
                camera.farClipPlane = 30;
                camera.enabled = false;
                camera.targetTexture = _texture;
                float halfHeight = (float)_texture.height / 2;
                camera.orthographicSize = halfHeight;
                cameraObject.transform.localPosition = root.cachedTransform.TransformPoint(halfHeight * camera.aspect, -halfHeight, 0);
                UpdateContext context = new UpdateContext();
                //run two times
                context.Begin();
                view.displayObject.Update(context);
                context.End();
                context.Begin();
                view.displayObject.Update(context);
                context.End();
                RenderTexture old = RenderTexture.active;
                RenderTexture.active = _texture;
                GL.Clear(true, true, Color.clear);
                camera.Render();
                RenderTexture.active = old;
                camera.targetTexture = null;
                view.Dispose();
                GameObject.DestroyImmediate(cameraObject);
                if (_renderer != null)
                    _renderer.sharedMaterial.mainTexture = _texture;
            }
        }
        public void ApplyModifiedProperties(bool sortingOrderChanged)
        {
            if (sortingOrderChanged)
            {
                if (Application.isPlaying)
                    SetSortingOrder(sortingOrder, true);
                else
                    EMRenderSupport.orderChanged = true;
            }
        }
        public void OnUpdateSource(object[] data)
        {
            if (Application.isPlaying)
                return;
            this.packageName = (string)data[0];
            this.packagePath = (string)data[1];
            this.componentName = (string)data[2];
            if ((bool)data[3])
                _captured = false;
        }
        public int EM_sortingOrder
        {
            get { return sortingOrder; }
        }
        public void EM_BeforeUpdate()
        {
            if (_renderer == null)
                _renderer = this.GetComponent();
            if (_renderer != null && _renderer.sharedMaterial.mainTexture != _texture)
                _renderer.sharedMaterial.mainTexture = _texture;
            if (packageName != null && componentName != null && !_captured)
                CaptureInEditMode();
        }
        public void EM_Update(UpdateContext context)
        {
            if (_renderer != null)
                _renderer.sortingOrder = context.renderingOrder++;
        }
        public void EM_Reload()
        {
            _captured = false;
        }
        #endregion
    }
}