using System;
using System.Collections.Generic;

namespace DataEditorX.Core
{
    public delegate void StatusBool(bool val);
    public interface ICommand : ICloneable
    {
        bool Excute(params object[] args);
    }
    public interface IBackableCommand : ICommand
    {
        void Undo();
    }
    public interface ICommandManager
    {
        void ExcuteCommand(ICommand command, params object[] args);
        void Undo();
        void ReverseUndo();//反撤销

        event StatusBool UndoStateChanged;
    }
    public class CommandManager : ICommandManager
    {
        private readonly Stack<ICommand> undoStack = new Stack<ICommand>();
        private readonly Stack<ICommand> reverseStack = new Stack<ICommand>();

        public event StatusBool UndoStateChanged;

        public CommandManager()
        {
            UndoStateChanged += new StatusBool(this.CommandManager_UndoStateChanged);
            UndoStateChanged += new StatusBool(this.CommandManager_ReverseUndoStateChanged);
        }

        private void CommandManager_UndoStateChanged(bool val)
        {

        }

        private void CommandManager_ReverseUndoStateChanged(bool val)
        {

        }

        #region ICommandManager 成员
        public void ExcuteCommand(ICommand command, params object[] args)
        {
            if (!command.Excute(args))
            {
                return;
            }

            this.reverseStack.Clear();

            if (command is IBackableCommand)
            {
                this.undoStack.Push((ICommand)command.Clone());
            }
            else
            {
                this.undoStack.Clear();
            }

            UndoStateChanged(this.undoStack.Count > 0);
        }

        public void Undo()
        {
            IBackableCommand command = (IBackableCommand)this.undoStack.Pop();
            if (command == null)
            {
                return;
            }

            command.Undo();
            this.reverseStack.Push((ICommand)command.Clone());

            UndoStateChanged(this.undoStack.Count > 0);
            //UndoStateChanged(reverseStack.Count > 0);
        }

        public void ReverseUndo()
        {
            IBackableCommand command = (IBackableCommand)this.reverseStack.Pop();
            if (command == null)
            {
                return;
            }

            command.Excute();
            this.undoStack.Push((ICommand)command.Clone());

            UndoStateChanged(this.undoStack.Count > 0);
        }
        #endregion
    }
}
