using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;

namespace XELF.Sphynx {

	/// <summary>
	/// 履歴
	/// </summary>
	interface Record : IDisposable {
		void Do(Stage stage);
		void Undo(Stage stage);
	}

	/// <summary>
	/// ステージ全体を記憶する履歴
	/// </summary>
	class EntireRecord : Record {
		readonly List<Gimmick> gimmicks;
		public EntireRecord(Stage stage) {
			gimmicks = new List<Gimmick>(stage.Gimmicks.Count);
			foreach (Gimmick gimmick in stage.Gimmicks) {
				var clone = gimmick.Clone(true);
				gimmicks.Add(clone);
			}
		}
		public void Do(Stage stage) {
			stage.Clear();
			foreach (Gimmick gimmick in gimmicks) {
				var clone = gimmick.Clone(true);
				clone.Registered = true;
			}
			stage.ResolveAll();
		}
		public void Undo(Stage stage) {
			stage.Clear();
			foreach (Gimmick gimmick in gimmicks) {
				var clone = gimmick.Clone(true);
				clone.Registered = true;
			}
			stage.ResolveAll();
		}
		public void Dispose() {
			if (gimmicks != null) {
				foreach (Gimmick gimmick in gimmicks) {
					gimmick.Dispose();
				}
				gimmicks.Clear();
			}
		}
	}

	/// <summary>
	/// ギミックを追加する履歴
	/// </summary>
	class CreateGimmickRecord : Record {
		readonly Gimmick gimmick;

		public CreateGimmickRecord(Gimmick gimmick) {
			this.gimmick = gimmick;
		}
		public void Do(Stage stage) {
			//stage.Gimmicks.Add(gimmick);
		}
		public void Undo(Stage stage) {
			gimmick.Registered = false;
		}
		public void Dispose() {
			gimmick.Dispose();
		}
	}

	/// <summary>
	/// ギミックを削除する履歴
	/// </summary>
	class RemoveGimmickRecord : Record {
		readonly Gimmick gimmick;

		public RemoveGimmickRecord(Gimmick gimmick) {
			this.gimmick = gimmick;
		}
		public void Do(Stage stage) {
			gimmick.Registered = false;
		}
		public void Undo(Stage stage) {
			gimmick.Registered = true;
		}
		public void Dispose() {
		}
	}

	/// <summary>
	/// ギミックを置き換える履歴
	/// </summary>
	class ReplaceGimmickRecord : Record {
		readonly Gimmick oldGimmick;
		readonly Gimmick newGimmick;

		public ReplaceGimmickRecord(Gimmick oldGimmick, Gimmick newGimmick) {
			this.oldGimmick = oldGimmick;
			this.newGimmick = newGimmick;
		}
		public void Do(Stage stage) {
			oldGimmick.Registered = false;
			newGimmick.Registered = true;
		}
		public void Undo(Stage stage) {
			oldGimmick.Registered = true;
			newGimmick.Registered = false;
		}
		public void Dispose() {
			newGimmick.Dispose();
		}
	}

	/// <summary>
	/// 履歴一覧
	/// </summary>
	class History : IDisposable {
		readonly Stack<Record> UndoRecords = new Stack<Record>();
		readonly Stack<Record> RedoRecords = new Stack<Record>();

		public int UndoCount {
			get { return UndoRecords.Count; }
		}
		public int RedoCount {
			get { return RedoRecords.Count; }
		}
		public void Restore(Stage stage) {
			if (UndoRecords.Count > 0) {
				var record = UndoRecords.Peek();
				record.Do(stage);
			}
		}
		public void Redo(Stage stage) {
			if (RedoRecords.Count > 0) {
				var record = RedoRecords.Pop();
				record.Do(stage);
				UndoRecords.Push(record);
			}
		}

		public void Dispose() {
			ClearUndoRecords();
			ClearRedoRecords();
		}
		void ClearUndoRecords() {
			foreach (var record in UndoRecords) {
				record.Dispose();
			}
			UndoRecords.Clear();
		}
		void ClearRedoRecords() {
			foreach (var record in RedoRecords) {
				record.Dispose();
			}
			RedoRecords.Clear();
		}

		public void Do(Stage stage, Record record) {
			record.Do(stage);
			UndoRecords.Push(record);
			ClearRedoRecords();
		}

		public void Undo(Stage stage) {
			if (UndoRecords.Count > 0) {
				var record = UndoRecords.Pop();
				record.Undo(stage);
				RedoRecords.Push(record);
				//record.Dispose();
			}
		}

		public void InsertEntire(Stage stage) {
			UndoRecords.Push(new EntireRecord(stage));
		}
	}

}
