using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System.Xml.Serialization;
using System.IO;
using System.Xml;
using System;

[Serializable]
public class Player
{
	const string playerSaveFile = "/player.xml";
	[XmlIgnore]
	public static Player info = null;
	
	[XmlAttribute("starId")]
	public int starId = 0;

	[XmlAttribute("objId")]
	public int currentObjectId = 0;
	
	[XmlAttribute("jump")]
	public float jumpDistance = 5f;
	
	[XmlAttribute("scanner")]
	public int scannerPower = 0;
	
	[XmlArray("visited")]
	public List<VisitedStarSystem> visitedSystems = new List<VisitedStarSystem>();

	[XmlArray("triggers")]
	[XmlArrayItem("t")]
	public Logic.Trigger[] triggers = null;

	[XmlIgnore]
	public int StarId
	{
		get {return starId;}
		set {starId = value; Save ();}
	}

	[Serializable]
	public class VisitedPlanet
	{
		[XmlAttribute("id")]
		public int id = -1; // id on StarMap
		[XmlArray("used")]
		[XmlArrayItem("u")]
		public List<int> usedPoints = null;
		[XmlArray("disc")]
		[XmlArrayItem("d")]
		public List<int> discoveredPoints = null;
		[XmlAttribute("all")]
		public bool all = false;
	}

	[Serializable]
	public class VisitedStarSystem
	{
		[XmlAttribute("id")]
		public int id = -1; // id on StarMap
		[XmlArray("planet")]
		[XmlArrayItem("p")]
		public List<VisitedPlanet> visitetPlanet = null;
		// some status here?
	}

	[XmlIgnore]
	public Logic.Trigger[] ResourceList
	{
		get {
			List<Logic.Trigger> resources = new List<Logic.Trigger>();
			foreach(var trigger in Logic.triggers.triggerList.Values)
			{
				if (trigger.type == Logic.Trigger.Type.resource && trigger.value > 0)
				{
					resources.Add(trigger);
				}
			}
			return resources.ToArray();
		}
	}

	// TODO make it different :(
	VisitedStarSystem GetVisitedSystem(int systemId)
	{
		foreach (var star in visitedSystems)
		{
			if (systemId == star.id)
			{
				return star;
			}
		}
		VisitedStarSystem system = new VisitedStarSystem () {
			id = systemId
		};
		visitedSystems.Add(system);
		return system;
	}

	public static bool IsPlanetVisited(int planetId)
	{
		VisitedStarSystem system = info.GetVisitedSystem (info.StarId);
		if (system.visitetPlanet != null) {
			foreach (var visitedPlanet in system.visitetPlanet) {
				if (planetId == visitedPlanet.id) {
					return true;
				}
			}
		}
		return false;
	}

	VisitedPlanet GetVisitedPlanet(int planetId)
	{
		VisitedStarSystem system = info.GetVisitedSystem (info.StarId);
		if (system.visitetPlanet != null) {
			foreach (var visitedPlanet in system.visitetPlanet) {
				if (planetId == visitedPlanet.id) {
					return visitedPlanet;
				}
			}
		} else {
			system.visitetPlanet = new List<VisitedPlanet>();
		}
		VisitedPlanet planet = new VisitedPlanet () {
			id = planetId
		};
		system.visitetPlanet.Add(planet);
		return planet;
	}

	public static void VisitPoint(int pointId)
	{
		VisitedPlanet planet = info.GetVisitedPlanet (info.currentObjectId);
		if (planet.usedPoints == null)
		{
			planet.usedPoints = new List<int>();
		}
		if (!planet.usedPoints.Contains(pointId))
		{
			planet.usedPoints.Add(pointId);
		}
	}

	public static bool IsPointVisited(int pointId)
	{
		VisitedPlanet planet = info.GetVisitedPlanet (info.currentObjectId);
		if (planet.usedPoints == null)
		{
			return false;
		}
		return (planet.usedPoints.Contains (pointId));
	}
	
	public static void DiscoverPoint(int pointId)
	{
		VisitedPlanet planet = info.GetVisitedPlanet (info.currentObjectId);
		if (planet.discoveredPoints == null)
		{
			planet.discoveredPoints = new List<int>();
		}
		if (!planet.discoveredPoints.Contains(pointId))
		{
			planet.discoveredPoints.Add(pointId);
		}
	}
	
	public static bool IsPointDiscovered(int pointId)
	{
		VisitedPlanet planet = info.GetVisitedPlanet (info.currentObjectId);
		if (planet.discoveredPoints == null)
		{
			return false;
		}
		return (planet.discoveredPoints.Contains (pointId));
	}

	static Player()
	{
		string[] list = {
			Res.antimatter,
			Res.rareMaterials,
			Res.transuranicMaterials,
			Res.biologicalMaterials,
			Res.artificalMaterials,
			Res.infoSourceMaterials
		};
		foreach (var resName in list)
		{
			Logic.triggers.triggerList.Add(resName, new Logic.Trigger(resName, 0, Logic.Trigger.Type.resource));
		}
		info = new Player ();
	}
	
	public Player ()
	{
	}
	
	public static void Load(string fileName = playerSaveFile)
	{
		info = LoadFromFile (fileName);
		Logic.triggers.triggerList.Clear();
		if (info != null)
		{
			if (info.triggers != null)
			{
				foreach (var trigger in info.triggers)
				{
					Logic.triggers.triggerList.Add (trigger.name, trigger);
				}
			}
		}
		else
		{
			info = new Player();
		}
	}

	public static void Save(string fileName = playerSaveFile)
	{
		if (info != null)
		{
			info.triggers = new Logic.Trigger[Logic.triggers.triggerList.Values.Count];
			Logic.triggers.triggerList.Values.CopyTo(info.triggers, 0);
			SaveToFile(info, fileName);
		}
	}

	public static bool IsHaveSaveFile(string fileName = playerSaveFile)
	{
		return File.Exists (Application.persistentDataPath + fileName);
	}

	static Player LoadFromFile(string fileName = playerSaveFile)
	{
		if (File.Exists (Application.persistentDataPath + fileName))
		{
			XmlSerializer serialReader = new XmlSerializer (typeof(Player));
			Stream writer = new FileStream (Application.persistentDataPath + fileName, FileMode.Open);
			var playerInfo = (Player)serialReader.Deserialize (writer);
			writer.Close ();
			return playerInfo;
		}
		else
		{
			return null;
		}
	}

	static void SaveToFile (Player structure, string fileName = playerSaveFile)
	{
		XmlSerializer serialWrite = new XmlSerializer(typeof(Player));
		XmlTextWriter writer = new XmlTextWriter (Application.persistentDataPath + fileName, System.Text.UTF8Encoding.UTF8);
		writer.Formatting = Formatting.Indented;
		writer.IndentChar = ' ';
		serialWrite.Serialize (writer, structure);
		writer.Close();
	}
}
