﻿//----------------------------------------------------------------------------------
// GVRNavi | Garpix Virtual Reality Navigation
// Copyright (c) 2017 Garpix Ltd.
//
// Plugin Homepage: https://gvrnavi.garpix.com
// Author Homepage: https://garpix.com
// Support: support@garpix.com
// License: Asset Store Terms of Service and EULA
// License URI: See LICENSE file in the project root for full license information.
//----------------------------------------------------------------------------------

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

namespace GVRNavi
{
    [RequireComponent(typeof(BoxCollider))]
    public class VRScrollBarGaze : VRObjectGaze, IVRColored, IVRContainer
    {
        #region variables

        public VRObjectFloatEvent OnValueChanged;

        public Image imageBackground, imageForeground;
        public SpriteRenderer spriteRendererBackground, spriteRendererForeground;
        public Color colorNormal = Color.white, colorHovered = Color.white, colorActive = Color.white;
        public float minPosition = -1f, maxPosition = 1f;

        public float value
        {
            get { return _value; }
            set
            {
                float f = Mathf.Clamp(value, 0f, 1f);
                if (f != _value)
                {
                    _value = Mathf.Clamp(value, 0f, 1f);
                    UpdateForegroundPosition();
                    if (OnValueChanged != null)
                        OnValueChanged.Invoke(this, _value);
                }
            }
        }
        public VRTweenColor tweenColor
        {
            get
            {
                if (_tweenColor == null)
                {
                    _tweenColor = gameObject.GetComponent<VRTweenColor>();
                    if (_tweenColor == null)
                        _tweenColor = gameObject.AddComponent<VRTweenColor>();
                }
                return _tweenColor;
            }
        }

        [SerializeField]
        protected VRSpriteType _spriteType;
        protected Color _currentColor;
        protected VRTweenColor _tweenColor;
        protected List<VRObjectGaze> _listChilds;
        protected List<IVRColored> _listChildsColored;
        protected float _globalAlpha = 1f;
        private float _value = 0.5f;
        private bool _check = false;

        #endregion


        protected override void Start()
        {
            base.Start();
            SetColor(colorNormal);
            UpdateGlobalAlphaForChilds();
        }

        protected virtual void FixedUpdate()
        {
            if (_check)
                CheckForegroundPosition();
        }

        #region IGvrGazeResponder

        public override void OnGazeEnter()
        {
            base.OnGazeEnter();
            SetColor(colorHovered);
        }

        public override void OnGazeExit()
        {
            base.OnGazeExit();
            _check = false;
            SetColor(colorNormal);
        }

        public override void OnGazeTrigger()
        {
            base.OnGazeTrigger();
            _check = true;
            SetColor(colorActive);
        }

        #endregion IGvrGazeResponder

        #region IVRContainer

        public virtual void SubscribeChild(VRObjectGaze child)
        {
            if (child == null)
                return;
            if (_listChilds == null)
                _listChilds = new List<VRObjectGaze>();
            if (_listChildsColored == null)
                _listChildsColored = new List<IVRColored>();
            if (!_listChilds.Contains(child))
                _listChilds.Add(child);
            if (child is IVRColored)
                _listChildsColored.Add(child as IVRColored);
        }

        public virtual void UnsubscribeChild(VRObjectGaze child)
        {
            if (child == null)
                return;
            if (_listChilds != null)
                _listChilds.Remove(child);
            if (child is IVRColored && _listChildsColored != null)
                _listChildsColored.Remove(child as IVRColored);
        }

        public virtual void UpdateGlobalAlphaForChilds()
        {
            float alpha = (_parentContainer != null) ? _parentContainer.GetGlobalAlpha() * _globalAlpha : _globalAlpha;
            if (_listChildsColored != null)
                foreach (var child in _listChildsColored)
                    child.SetGlobalAlpha(alpha);
        }

        public virtual float GetGlobalAlpha()
        {
            return (_parentContainer != null) ? _parentContainer.GetGlobalAlpha() * _globalAlpha : _globalAlpha;
        }

        public bool IsChild(VRObjectGaze gaze)
        {
            if (_listChilds != null)
            {
                if (_listChilds.Contains(gaze))
                    return true;
                foreach (var child in _listChilds)
                    if (child is IVRContainer)
                        if ((child as IVRContainer).IsChild(gaze))
                            return true;
            }
            return false;
        }

        #endregion IVRContainer

        #region IVRColored

        public void SetGlobalAlpha(float alpha)
        {
            _globalAlpha = alpha;
            SetColor(_currentColor);
            UpdateGlobalAlphaForChilds();
        }

        #endregion IVRColored

        public void ValueIncrease(float v)
        {
            value += v;
        }

        public void ValueDecrease(float v)
        {
            value -= v;
        }

        public virtual void UpdateColors()
        {
            SetColor(Application.isPlaying ? _currentColor : colorNormal);
        }

        protected virtual void SetColor(Color color)
        {
            _currentColor = color;
            color.a *= GetGlobalAlpha();
            SetColliderEnable(color.a > 0f);
            SetColor(imageForeground, color);
            SetColor(spriteRendererForeground, color);
            SetColor(imageBackground, color);
            SetColor(spriteRendererBackground, color);
        }

        protected virtual void SetColor(SpriteRenderer spriteRenderer, Color color)
        {
            if (spriteRenderer == null)
                return;
            if (Application.isPlaying)
                tweenColor.StartColoring(spriteRenderer.color, color, 0.2f, spriteRenderer);
            else
                spriteRenderer.color = color;
        }

        protected virtual void SetColor(Image image, Color color)
        {
            if (image == null)
                return;
            if (Application.isPlaying)
                tweenColor.StartColoring(image.color, color, 0.2f, image);
            else
                image.color = color;
        }

        protected virtual void UpdateForegroundPosition()
        {
            float x = Mathf.Lerp(minPosition, maxPosition, value);
            if (imageForeground != null)
            {
                Vector3 pos = imageForeground.transform.localPosition;
                if (x != pos.x)
                {
                    pos.x = x;
                    imageForeground.transform.localPosition = pos;
                }
            }
            if (spriteRendererForeground != null)
            {
                Vector3 pos = spriteRendererForeground.transform.localPosition;
                if (x != pos.x)
                {
                    pos.x = x;
                    spriteRendererForeground.transform.localPosition = pos;
                }
            }
        }

        protected virtual void CheckForegroundPosition()
        {
            if (_spriteType == VRSpriteType.Image && imageForeground == null)
                return;
            if (_spriteType == VRSpriteType.SpriteRenderer && spriteRendererForeground == null)
                return;

            Camera c = VR3DRoot.Instance != null ?
                               VR3DRoot.Instance.mainCamera != null ?
                                   VR3DRoot.Instance.mainCamera :
                                   Camera.current :
                               Camera.current;
            Ray ray = new Ray(c.transform.position, c.transform.forward);
            RaycastHit[] hits = Physics.RaycastAll(ray, Mathf.Infinity, Physics.DefaultRaycastLayers, QueryTriggerInteraction.Collide);
            if (hits != null && hits.Length > 0)
            {
                foreach (var hit in hits)
                {
                    if (hit.transform == transform)
                    {
                        Transform tr = _spriteType == VRSpriteType.Image ?
                            imageForeground.transform : spriteRendererForeground.transform;
                        Vector3 local = tr.localPosition;
                        tr.position += hit.point - tr.position;
                        local.x = Mathf.Clamp(tr.localPosition.x, minPosition, maxPosition);
                        tr.localPosition = local;
                        value = (local.x - minPosition) / Mathf.Abs(maxPosition - minPosition);
                        break;
                    }
                }
            }
        }
    }
}