using GeoCoordinatePortable;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using skyscraper5.Skyscraper.Scraper.Storage.InMemory.Model;
using AprsSharp.Parsers.Aprs;
using skyscraper5.Skyscraper;
using skyscraper5.Aprs.AprsSharp;
using System.IO;

namespace skyscraper5.Aprs.AprsStorage
{
	internal class AprsFilesystemStorage : LX9SESStorage
	{
		public AprsFilesystemStorage(DirectoryInfo root)
		{
			this.rootDirectory = root;
			this.jsonSerializerSettings = new JsonSerializerSettings()
			{
				NullValueHandling = NullValueHandling.Ignore,
				Formatting = Formatting.Indented
			};
		}

		private readonly DirectoryInfo rootDirectory;
		private readonly JsonSerializerSettings jsonSerializerSettings;

		private void EnsureDirectoryExists(DirectoryInfo di)
		{
			if (di.Exists)
				return;

			EnsureDirectoryExists(di.Parent);
			di.Create();
		}

		public bool AprsPosition(DateTime currentTime, string packetSender, GeoCoordinate positionCoordinates, string piComment)
		{
			string path = Path.Combine(rootDirectory.FullName, "APRS", String.Format("{0}.json", packetSender));
			FileInfo fi = new FileInfo(path);

			InMemoryAprsData aprsEntry;
			if (fi.Exists)
				aprsEntry = JsonConvert.DeserializeObject<InMemoryAprsData>(File.ReadAllText(fi.FullName));
			else
			{
				aprsEntry = new InMemoryAprsData(packetSender);
				EnsureDirectoryExists(fi.Directory);
			}

			bool result = aprsEntry.LastSeen < currentTime;
			if (!result)
				return false;
			aprsEntry.LastSeen = currentTime;
			result = aprsEntry.Longitude != positionCoordinates.Longitude || aprsEntry.Latitude != positionCoordinates.Latitude;
			if (result)
			{
				aprsEntry.Longitude = positionCoordinates.Longitude;
				aprsEntry.Latitude = positionCoordinates.Latitude;
				aprsEntry.Comment = piComment;
				aprsEntry.TimesMoved++;
				if (aprsEntry.TimesMoved > 2)
					Console.WriteLine("{0} is actually moving", packetSender);
				File.WriteAllText(fi.FullName, JsonConvert.SerializeObject(aprsEntry, Formatting.Indented, jsonSerializerSettings));
				return true;
			}
			return false;
		}

		public bool AprsWeatherReport(DateTime currentTime, string packetSender, WeatherInfo wi)
		{
			string path = Path.Combine(rootDirectory.FullName, "APRS", "Weather", packetSender, String.Format("{0}.json", currentTime.ToUnixTime()));
			FileInfo fi = new FileInfo(path);

			if (fi.Exists)
				return false;

			EnsureDirectoryExists(fi.Directory);
			File.WriteAllText(fi.FullName, JsonConvert.SerializeObject(wi, Formatting.Indented, jsonSerializerSettings));
			return true;
		}

		public bool AprsStationCapabilities(string packetSender, StationCapabilities stationCapabilities)
		{
			string path = Path.Combine(rootDirectory.FullName, "APRS", "Capabilities", String.Format("{0}.json", packetSender));
			FileInfo fi = new FileInfo(path);
			if (fi.Exists)
				return false;

			EnsureDirectoryExists(fi.Directory);
			File.WriteAllText(fi.FullName, JsonConvert.SerializeObject(stationCapabilities, Formatting.Indented, jsonSerializerSettings));
			return true;
		}

		public bool AprsGpsSentence(DateTime currentTime, string packetSender, double? course, double? magneticVariation, double? speed)
		{
			string path = Path.Combine(rootDirectory.FullName, "APRS", String.Format("{0}.json", packetSender));
			FileInfo fi = new FileInfo(path);

			InMemoryAprsData aprsEntry;
			if (fi.Exists)
				aprsEntry = JsonConvert.DeserializeObject<InMemoryAprsData>(File.ReadAllText(fi.FullName));
			else
			{
				return false;
			}

			bool result = aprsEntry.LastSeen == currentTime;
			if (!result)
				return false;
			result = aprsEntry.Course != course || aprsEntry.MagneticVariation != magneticVariation || aprsEntry.Speed != speed;
			if (result)
			{
				aprsEntry.Course = course;
				aprsEntry.MagneticVariation = magneticVariation;
				aprsEntry.Speed = speed;
				File.WriteAllText(fi.FullName, JsonConvert.SerializeObject(aprsEntry, Formatting.Indented, jsonSerializerSettings));
				return true;
			}
			return false;
		}

		public void AprsMessage(string sender, DateTime currentTime, string receiver, string message)
		{
			int msgCrc32 = Hasher.HashObjects(sender, receiver, message);
			string path = Path.Combine(rootDirectory.FullName, "APRS", "Messages", String.Format("{1}_{0}.json", currentTime.ToUnixTime(), msgCrc32));
			FileInfo fi = new FileInfo(path);
			if (fi.Exists)
				return;

			var foo = new { sender, currentTime, receiver, message };

			EnsureDirectoryExists(fi.Directory);
			File.WriteAllText(fi.FullName, JsonConvert.SerializeObject(foo, Formatting.Indented, jsonSerializerSettings));
		}
	}
}
