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

namespace FairyGUI
{
    /// <summary>
    /// Helper for drag and drop.
    /// 这是一个提供特殊拖放功能的功能类。与GObject.draggable不同,拖动开始后,他使用一个替代的图标作为拖动对象。
    /// 当玩家释放鼠标/手指,目标组件会发出一个onDrop事件。
    /// </summary>
    public class DragDropManager
    {
        private GLoader _agent;
        private object _sourceData;
        private GObject _source;

        private static DragDropManager _inst;
        public static DragDropManager inst
        {
            get
            {
                if (_inst == null)
                    _inst = new DragDropManager();
                return _inst;
            }
        }

        public DragDropManager()
        {
            _agent = (GLoader)UIObjectFactory.NewObject(ObjectType.Loader);
            _agent.gameObjectName = "DragDropAgent";
            _agent.SetHome(GRoot.inst);
            _agent.touchable = false;//important
            _agent.draggable = true;
            _agent.SetSize(100, 100);
            _agent.SetPivot(0.5f, 0.5f, true);
            _agent.align = AlignType.Center;
            _agent.verticalAlign = VertAlignType.Middle;
            _agent.sortingOrder = int.MaxValue;
            _agent.onDragEnd.Add(__dragEnd);
        }

        /// <summary>
        /// Loader object for real dragging.
        /// 用于实际拖动的Loader对象。你可以根据实际情况设置loader的大小,对齐等。
        /// </summary>
        public GLoader dragAgent
        {
            get { return _agent; }
        }

        /// <summary>
        /// Is dragging?
        /// 返回当前是否正在拖动。
        /// </summary>
        public bool dragging
        {
            get { return _agent.parent != null; }
        }

        /// <summary>
        /// Start dragging.
        /// 开始拖动。
        /// </summary>
        /// <param name="source">Source object. This is the object which initiated the dragging.</param>
        /// <param name="icon">Icon to be used as the dragging sign.</param>
        /// <param name="sourceData">Custom data. You can get it in the onDrop event data.</param>
        /// <param name="touchPointID">Copy the touchId from InputEvent to here, if has one.</param>
        public void StartDrag(GObject source, string icon, object sourceData, int touchPointID = -1)
        {
            if (_agent.parent != null)
                return;

            _sourceData = sourceData;
            _source = source;
            _agent.url = icon;
            GRoot.inst.AddChild(_agent);
            _agent.xy = GRoot.inst.GlobalToLocal(Stage.inst.GetTouchPosition(touchPointID));
            _agent.StartDrag(touchPointID);
        }

        /// <summary>
        /// Cancel dragging.
        /// 取消拖动。
        /// </summary>
        public void Cancel()
        {
            if (_agent.parent != null)
            {
                _agent.StopDrag();
                GRoot.inst.RemoveChild(_agent);
                _sourceData = null;
            }
        }

        private void __dragEnd(EventContext evt)
        {
            if (_agent.parent == null) //cancelled
                return;

            GRoot.inst.RemoveChild(_agent);

            object sourceData = _sourceData;
            GObject source = _source;
            _sourceData = null;
            _source = null;

            GObject obj = GRoot.inst.touchTarget;
            while (obj != null)
            {
                if (obj.hasEventListeners("onDrop"))
                {
                    obj.RequestFocus();
                    obj.DispatchEvent("onDrop", sourceData, source);
                    return;
                }
                obj = obj.parent;
            }
        }
    }
}