/**
 * Copyright(c) Live2D Inc. All rights reserved.
 *
 * Use of this source code is governed by the Live2D Open Software license
 * that can be found at https://www.live2d.com/eula/live2d-open-software-license-agreement_en.html.
 */
using Live2D.Cubism.Core.Unmanaged;
using Live2D.Cubism.Framework;
using UnityEngine;
namespace Live2D.Cubism.Core
{
    /// 
    /// Single  drawable.
    /// 
    [CubismDontMoveOnReimport]
    public sealed class CubismDrawable : MonoBehaviour
    {
        #region Factory Methods
        /// 
        /// Creates drawables for a .
        /// 
        /// Handle to unmanaged model.
        /// Drawables root.
        internal static GameObject CreateDrawables(CubismUnmanagedModel unmanagedModel)
        {
            var root = new GameObject("Drawables");
            // Create drawables.
            var unmanagedDrawables = unmanagedModel.Drawables;
            var buffer = new CubismDrawable[unmanagedDrawables.Count];
            for (var i = 0; i < buffer.Length; ++i)
            {
                var proxy = new GameObject();
                buffer[i] = proxy.AddComponent();
                buffer[i].transform.SetParent(root.transform);
                buffer[i].Reset(unmanagedModel, i);
            }
            return root;
        }
        #endregion
        /// 
        /// Unmanaged drawables from unmanaged model.
        /// 
        private CubismUnmanagedDrawables UnmanagedDrawables { get; set; }
        /// 
        ///  backing field.
        /// 
        [SerializeField, HideInInspector]
        private int _unmanagedIndex = -1;
        /// 
        /// Position in unmanaged arrays.
        /// 
        internal int UnmanagedIndex
        {
            get { return _unmanagedIndex; }
            private set { _unmanagedIndex = value; }
        }
        /// 
        /// Copy of Id.
        /// 
        public string Id
        {
            get
            {
                // Pull data.
                return UnmanagedDrawables.Ids[UnmanagedIndex];
            }
        }
        /// 
        /// Texture UnmanagedIndex.
        /// 
        public int TextureIndex
        {
            get
            {
                // Pull data.
                return UnmanagedDrawables.TextureIndices[UnmanagedIndex];
            }
        }
        /// 
        /// Copy of the masks.
        /// 
        public CubismDrawable[] Masks
        {
            get
            {
                var drawables = this
                    .FindCubismModel(true)
                    .Drawables;
                // Get addresses.
                var counts = UnmanagedDrawables.MaskCounts;
                var indices = UnmanagedDrawables.Masks;
                // Pull data.
                var buffer = new CubismDrawable[counts[UnmanagedIndex]];
                for (var i = 0; i < buffer.Length; ++i)
                {
                    for (var j = 0; j < drawables.Length; ++j)
                    {
                        if (drawables[j].UnmanagedIndex != indices[UnmanagedIndex][i])
                        {
                            continue;
                        }
                        buffer[i] = drawables[j];
                        break;
                    }
                }
                return buffer;
            }
        }
        /// 
        /// Copy of vertex positions.
        /// 
        public Vector3[] VertexPositions
        {
            get
            {
                // Get addresses.
                var counts = UnmanagedDrawables.VertexCounts;
                var positions = UnmanagedDrawables.VertexPositions;
                // Pull data.
                var buffer = new Vector3[counts[UnmanagedIndex]];
                for (var i = 0; i < buffer.Length; ++i)
                {
                    buffer[i] = new Vector3(
                        positions[UnmanagedIndex][(i * 2) + 0],
                        positions[UnmanagedIndex][(i * 2) + 1]
                    );
                }
                return buffer;
            }
        }
        /// 
        /// Copy of vertex texture coordinates.
        /// 
        public Vector2[] VertexUvs
        {
            get
            {
                // Get addresses.
                var counts = UnmanagedDrawables.VertexCounts;
                var uvs = UnmanagedDrawables.VertexUvs;
                // Pull data.
                var buffer = new Vector2[counts[UnmanagedIndex]];
                for (var i = 0; i < buffer.Length; ++i)
                {
                    buffer[i] = new Vector2(
                        uvs[UnmanagedIndex][(i * 2) + 0],
                        uvs[UnmanagedIndex][(i * 2) + 1]
                    );
                }
                return buffer;
            }
        }
        /// 
        /// Copy of triangle indices.
        /// 
        public int[] Indices
        {
            get
            {
                // Get addresses.
                var counts = UnmanagedDrawables.IndexCounts;
                var indices = UnmanagedDrawables.Indices;
                // Pull data.
                var buffer = new int[counts[UnmanagedIndex]];
                for (var i = 0; i < buffer.Length; ++i)
                {
                    buffer[i] = indices[UnmanagedIndex][i];
                }
                return buffer;
            }
        }
        /// 
        /// True if double-sided.
        /// 
        public bool IsDoubleSided
        {
            get
            {
                // Get address.
                var flags = UnmanagedDrawables.ConstantFlags;
                // Pull data.
                return flags[UnmanagedIndex].HasIsDoubleSidedFlag();
            }
        }
        /// 
        /// True if masking is requested.
        /// 
        public bool IsMasked
        {
            get
            {
                // Get address.
                var counts = UnmanagedDrawables.MaskCounts;
                // Pull data.
                return counts[UnmanagedIndex] > 0;
            }
        }
        /// 
        /// True if inverted mask.
        /// 
        public bool IsInverted
        {
            get
            {
                // Get address.
                var flags = UnmanagedDrawables.ConstantFlags;
                // Pull data.
                return flags[UnmanagedIndex].HasIsInvertedMaskFlag();
            }
        }
        /// 
        /// True if additive blending is requested.
        /// 
        public bool BlendAdditive
        {
            get
            {
                // Get address.
                var flags = UnmanagedDrawables.ConstantFlags;
                // Pull data.
                return flags[UnmanagedIndex].HasBlendAdditiveFlag();
            }
        }
        /// 
        /// True if multiply blending is setd.
        /// 
        public bool MultiplyBlend
        {
            get
            {
                // Get address.
                var flags = UnmanagedDrawables.ConstantFlags;
                // Pull data.
                return flags[UnmanagedIndex].HasBlendMultiplicativeFlag();
            }
        }
        /// 
        /// Revives instance.
        /// 
        /// Handle to unmanaged model.
        internal void Revive(CubismUnmanagedModel unmanagedModel)
        {
            UnmanagedDrawables = unmanagedModel.Drawables;
        }
        /// 
        /// Restores instance to initial state.
        /// 
        /// Handle to unmanaged model.
        /// Position in unmanaged arrays.
        private void Reset(CubismUnmanagedModel unmanagedModel, int unmanagedIndex)
        {
            Revive(unmanagedModel);
            UnmanagedIndex = unmanagedIndex;
            name = Id;
        }
    }
}