/**
 * 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 System;
using UnityEngine;
namespace Live2D.Cubism.Core
{
    /// 
    /// Extension for Cubism related arrays.
    /// 
    public static class ArrayExtensionMethods
    {
        #region Parameters
        /// 
        /// Finds a  by its ID.
        /// 
        /// Container.
        /// ID to match.
        /// Parameter on success;  otherwise.
        public static CubismParameter FindById(this CubismParameter[] self, string id)
        {
            if (self == null)
            {
                return null;
            }
            for (var i = 0; i < self.Length; ++i)
            {
                if (self[i].name != id)
                {
                    continue;
                }
                return self[i];
            }
            return null;
        }
        /// 
        /// Revives (and sorts) s.
        /// 
        /// Container.
        /// TaskableModel to unmanaged model.
        internal static void Revive(this CubismParameter[] self, CubismUnmanagedModel model)
        {
            Array.Sort(self, (a, b) => a.UnmanagedIndex - b.UnmanagedIndex);
            for (var i = 0; i < self.Length; ++i)
            {
                self[i].Revive(model);
            }
        }
        /// 
        /// Writes opacities to unmanaged model.
        /// 
        /// Source buffer.
        /// 
        internal static void WriteTo(this CubismParameter[] self, CubismUnmanagedModel unmanagedModel)
        {
            // Get address.
            var unmanagedParameters = unmanagedModel.Parameters;
            var values = unmanagedParameters.Values;
            // Push.
            for (var i = 0; i < self.Length; ++i)
            {
                values[self[i].UnmanagedIndex] = self[i].Value;
            }
        }
        /// 
        /// Writes opacities to unmanaged model.
        /// 
        /// Source buffer.
        /// 
        internal static void ReadFrom(this CubismParameter[] self, CubismUnmanagedModel unmanagedModel)
        {
            // Get address.
            var unmanagedParameters = unmanagedModel.Parameters;
            var values = unmanagedParameters.Values;
            // Pull.
            for (var i = 0; i < self.Length; ++i)
            {
                self[i].Value = values[self[i].UnmanagedIndex];
            }
        }
        #endregion
        #region Parts
        /// 
        /// Finds a  by its ID.
        /// 
        /// .
        /// ID to match.
        /// Part if found;  otherwise.
        public static CubismPart FindById(this CubismPart[] self, string id)
        {
            if (self == null)
            {
                return null;
            }
            for (var i = 0; i < self.Length; ++i)
            {
                if (self[i].name != id)
                {
                    continue;
                }
                return self[i];
            }
            return null;
        }
        /// 
        /// Revives (and sorts) s.
        /// 
        /// Container.
        /// TaskableModel to unmanaged model.
        internal static void Revive(this CubismPart[] self, CubismUnmanagedModel model)
        {
            Array.Sort(self, (a, b) => a.UnmanagedIndex - b.UnmanagedIndex);
            for (var i = 0; i < self.Length; ++i)
            {
                self[i].Revive(model);
            }
        }
        /// 
        /// Writes opacities to unmanaged model.
        /// 
        /// Source buffer.
        /// 
        internal static void WriteTo(this CubismPart[] self, CubismUnmanagedModel unmanagedModel)
        {
            // Get address.
            var unmanagedParts = unmanagedModel.Parts;
            var opacities = unmanagedParts.Opacities;
            // Push.
            for (var i = 0; i < self.Length; ++i)
            {
                opacities[self[i].UnmanagedIndex] = self[i].Opacity;
            }
        }
        #endregion
        #region Drawables
        /// 
        /// Finds a  by its ID.
        /// 
        /// .
        /// ID to match.
        /// Part if found;  otherwise.
        public static CubismDrawable FindById(this CubismDrawable[] self, string id)
        {
            if (self == null)
            {
                return null;
            }
            for (var i = 0; i < self.Length; ++i)
            {
                if (self[i].name != id)
                {
                    continue;
                }
                return self[i];
            }
            return null;
        }
        /// 
        /// Revives (and sorts) s.
        /// 
        /// Container.
        /// TaskableModel to unmanaged model.
        internal static void Revive(this CubismDrawable[] self, CubismUnmanagedModel model)
        {
            Array.Sort(self, (a, b) => a.UnmanagedIndex - b.UnmanagedIndex);
            for (var i = 0; i < self.Length; ++i)
            {
                self[i].Revive(model);
            }
        }
        /// 
        /// Reads new data from a model.
        /// 
        /// Buffer to write to.
        /// Unmanaged model to read from.
        internal static unsafe void ReadFrom(this CubismDynamicDrawableData[] self, CubismUnmanagedModel unmanagedModel)
        {
            // Get addresses.
            var drawables = unmanagedModel.Drawables;
            var flags = drawables.DynamicFlags;
            var opacities = drawables.Opacities;
            var drawOrders = drawables.DrawOrders;
            var renderOrders = drawables.RenderOrders;
            var vertexPositions = drawables.VertexPositions;
            // Pull data.
            for (var i = 0; i < self.Length; ++i)
            {
                var data = self[i];
                data.Flags = flags[i];
                data.Opacity = opacities[i];
                data.DrawOrder = drawOrders[i];
                data.RenderOrder = renderOrders[i];
                // Read vertex positions only if necessary.
                if (!data.AreVertexPositionsDirty)
                {
                    continue;
                }
                // Copy vertex positions.
                fixed (Vector3* dataVertexPositions = data.VertexPositions)
                {
                    for (var v = 0; v < data.VertexPositions.Length; ++v)
                    {
                        dataVertexPositions[v].x = vertexPositions[i][(v * 2) + 0];
                        dataVertexPositions[v].y = vertexPositions[i][(v * 2) + 1];
                    }
                }
            }
            // Clear dynamic flags.
            drawables.ResetDynamicFlags();
        }
        #endregion
    }
}