/**
 * 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;
using UnityEngine;
namespace Live2D.Cubism.Framework.HarmonicMotion
{
    /// 
    /// Controller for s.
    /// 
    public sealed class CubismHarmonicMotionController : MonoBehaviour, ICubismUpdatable
    {
        /// 
        /// Default number of channels.
        /// 
        private const int DefaultChannelCount = 1;
        /// 
        /// Blend mode.
        /// 
        [SerializeField]
        public CubismParameterBlendMode BlendMode = CubismParameterBlendMode.Additive;
        /// 
        /// The timescales for each channel.
        /// 
        [SerializeField]
        public float[] ChannelTimescales;
        /// 
        /// Sources.
        /// 
        private CubismHarmonicMotionParameter[] Sources { get; set; }
        /// 
        /// Destinations.
        /// 
        private CubismParameter[] Destinations { get; set; }
        /// 
        /// Model has update controller component.
        /// 
        [HideInInspector]
        public bool HasUpdateController { get; set; }
        /// 
        /// Refreshes the controller. Call this method after adding and/or removing .
        /// 
        public void Refresh()
        {
            var model = this.FindCubismModel();
            // Catch sources and destinations.
            Sources = model
                .Parameters
                .GetComponentsMany();
            Destinations = new CubismParameter[Sources.Length];
            for (var i = 0; i < Sources.Length; ++i)
            {
                Destinations[i] = Sources[i].GetComponent();
            }
            // Get cubism update controller.
            HasUpdateController = (GetComponent() != null);
        }
        /// 
        /// Called by cubism update controller. Order to invoke OnLateUpdate.
        /// 
        public int ExecutionOrder
        {
            get { return CubismUpdateExecutionOrder.CubismHarmonicMotionController; }
        }
        /// 
        /// Called by cubism update controller. Needs to invoke OnLateUpdate on Editing.
        /// 
        public bool NeedsUpdateOnEditing
        {
            get { return false; }
        }
        /// 
        /// Called by cubism update controller. Updates controller.
        /// 
        public void OnLateUpdate()
        {
            // Return if it is not valid or there's nothing to update.
            if (!enabled || Sources == null)
            {
                return;
            }
            // Update sources and destinations.
            for (var i = 0; i < Sources.Length; ++i)
            {
                Sources[i].Play(ChannelTimescales);
                Destinations[i].BlendToValue(BlendMode, Sources[i].Evaluate());
            }
        }
        #region Unity Events Handling
        /// 
        /// Called by Unity. Makes sure cache is initialized.
        /// 
        private void Start()
        {
            // Initialize cache.
            Refresh();
        }
        /// 
        /// Called by Unity. Updates controller.
        /// 
        private void LateUpdate()
        {
            if (!HasUpdateController)
            {
                OnLateUpdate();
            }
        }
        /// 
        /// Called by Unity. Resets channels.
        /// 
        private void Reset()
        {
            // Reset/Initialize channel timescales.
            ChannelTimescales = new float[DefaultChannelCount];
            for (var s = 0; s < DefaultChannelCount; ++s)
            {
                ChannelTimescales[s] = 1f;
            }
        }
        #endregion
    }
}