using System.Net.Sockets;
using System.Collections.Generic;
using System.Threading;
using System;

namespace WorldOfPeacecraft
{
	public class Backend : IBackend
	{
		private Sender Send;
		private Receiver Rec;
		private Parser Parse;
		private TcpClient Client;
		private Dictionary<int, Dragon> Dragons;
		private Dictionary<int, Player> Players;
		private LinkedList<Message> ChatMessages;
		private Map Map;
        private Buffer SenderBuffer;
		private IGui Gui;
		private int SelfId;
		private AutoResetEvent InitializedEvent = new AutoResetEvent(false);
		private bool initialized = false;
		private Pathwalker Pathwalker = new Pathwalker();
		private AI ai;

        public delegate void ChallengeEventHandler(Challenge c);
        public event ChallengeEventHandler Challenge;

		public Backend (IGui gui)
		{
			Gui = gui;
			Dragons = new Dictionary<int, Dragon> ();
			Players = new Dictionary<int, Player> ();
			ChatMessages = new LinkedList<Message> ();
			Client = new TcpClient ();
			Buffer receiverBuffer = new Buffer(10000);
			SenderBuffer = new Buffer(100);
			Parse = new Parser (this, receiverBuffer);
			Rec = new Receiver (Client, receiverBuffer);
			Send = new Sender (Client, SenderBuffer);
			SenderBuffer.AddLine ("get:ents");
			SenderBuffer.AddLine ("get:me");
			SenderBuffer.AddLine ("get:map");

			ai = new AI(this);
		}

		public void SetSelfId (int id)
		{
			this.SelfId = id;
			Players[SelfId].LocationChanged += OnPlayerMoved;
		}

		public IEnumerable<IEntity> GetDragons ()
		{
			return Dragons.Values;
		}

		public IEnumerable<IPlayer> GetPlayers ()
		{
			return Players.Values;
		}

		public void removeDragon (Dragon dragon)
		{
			Dragons.Remove (dragon.GetId ());
		}

		public void removePlayer (Player player)
		{
			Players.Remove (player.GetId ());
		}
		
		public void clearPlayers ()
		{
			Players.Clear ();
		}
		
		public void clearDragons ()
		{
			Dragons.Clear ();
		}

		public Player getPlayer (int playerId)
		{
			try {
				return Players [playerId];
			} catch (KeyNotFoundException e) {
				return null;
			}
		}

        public Dictionary<int, Player> getPlayerList()
        {
            return Players;
        }

		public Dragon getDragon (int dragonId)
		{
			return Dragons[dragonId];
		}

        public Dictionary<int, Dragon> getDragonList()
        {
            return Dragons;
        }

		public Map getMapObject ()
		{
			return Map;
		}

		public void SetDragon (Dragon dragon)
		{
			Dragons [dragon.GetId ()] = dragon;
		}

		public void SetPlayer (Player player)
		{
			Players [player.GetId ()] = player;
		}

		public void SetMap (Map map)
		{
			this.Map = map;
			InitializedEvent.Set();
		}

		public ITile[,] GetMap ()
		{
			if (Map == null) {
				return null;
			}
			return Map.GetTiles ();
		}

		public void AddChatMessage (Message message)
		{
			ChatMessages.AddLast (message);
		}

		public IEnumerable<IChatMessage> GetChatMessages ()
		{
			return ChatMessages;
		}

		public void SendCommand (string command)
		{
			SenderBuffer.AddLine (command);
		}

		public void SendChatMessage (string message)
		{
			SenderBuffer.AddLine ("ask:say:" + message);
		}

        public void moveUp()
        {
            SenderBuffer.AddLine("ask:mv:up");
        }

        public void moveDown()
        {
            SenderBuffer.AddLine("ask:mv:dwn");
        }
        public void moveLeft()
        {
            SenderBuffer.AddLine("ask:mv:lft");
        }
        public void moveRight()
        {
            SenderBuffer.AddLine("ask:mv:rgt");
        }

		public void MoveTo (int x, int y)
		{
			// Hier müsste man locken
			Pathwalker.Stop();
			LinkedList<Coordinate> path = Pathfinder.FindPath (Players [SelfId].Coord, new Coordinate (x, y), Map);
			Pathwalker.SetCoords (path);
			MoveStep();
		}

		public void MoveStep ()
		{
			if (Pathwalker.HasMoreSteps ()) {
				SenderBuffer.AddLine ("ask:" + Pathwalker.NextStep ());
			}
		}

		public void OnPlayerMoved (int x, int y)
		{
			MoveStep();
		}

		public void RefreshGui ()
		{
			Gui.PerformRefresh ();
		}

		private void StartThreads() {
			Parse.Start ();
			Rec.Start ();
			Send.Start ();
		}

		public void Stop() {
			Parse.Stop ();
			Send.Stop ();
			Client.Close ();
		}

		public void Initialize(){
			Client.Connect ("85.214.103.114", 110);
			StartThreads ();
			InitializedEvent.WaitOne();
			initialized = true;
		}

        public void ChallengeIncome(Challenge c)
        {
            Challenge(c);
        }
	}
}

