using System.Diagnostics;
using PlaylistsNET.Content;
using PlaylistsNET.Models;

bool RunProgram(string progname, string args, string directory = null)
{
	Process process = new Process();
	process.StartInfo.FileName = progname;
	process.StartInfo.Arguments = args;
	process.StartInfo.UseShellExecute = false;
	if (!string.IsNullOrEmpty(directory))
		process.StartInfo.WorkingDirectory = directory;
	Console.WriteLine("Starting {0} at {1}", progname, DateTime.Now);
	process.Start();
	process.WaitForExit();
return process.ExitCode == 0;
}

void EnsureFolderExists(DirectoryInfo directory)
{
	if (directory.Exists)
		return;

	EnsureFolderExists(directory.Parent);
	directory.Create();
	directory.Refresh();
}

string GetChannelName(M3uPlaylistEntry entry)
{
	if (entry.CustomProperties.ContainsKey("EXTINF"))
	{
		string extinf = entry.CustomProperties["EXTINF"];
		string[] extInfArgs = extinf.Split(',');
		string channelName = extInfArgs[extInfArgs.Length - 1];
		channelName = CleanString(channelName);
		return channelName;
	}
	foreach (KeyValuePair<string,string> can in entry.CustomProperties)
	{
		if (can.Key.StartsWith("EXTINF:-1"))
		{
			string fullname = can.ToString();
			int offset = fullname.IndexOf("\",");
			fullname = fullname.Substring(offset + 2);
			fullname = fullname.Substring(0, fullname.Length - 1);
			fullname = CleanString(fullname);
			return fullname;
		}
	}
	throw new NotImplementedException();
}

string CleanString(string channelName)
{
	char[] invalidChars = Path.GetInvalidFileNameChars();
	char[] buffer = channelName.ToCharArray();
	for (int i = 0; i < buffer.Length; i++)
	{
		if (invalidChars.Contains(buffer[i]))
		{
			buffer[i] = '_';
		}
		if (buffer[i] > 126)
		{
			buffer[i] = '-';
		}
		if (buffer[i] == ';')
		{
			buffer[i] = '+';
		}
	}
	return new string(buffer);
}

// See https://aka.ms/new-console-template for more information
Console.WriteLine("Hello, World!");

DirectoryInfo streamDir = new DirectoryInfo(Path.Combine("iptv\\streams"));
if (!streamDir.Exists)
{
	if (!RunProgram("git", "clone https://github.com/iptv-org/iptv"))
	{
		Console.WriteLine("Failed to clone the git repository.");
		return;
	}
}
else
{
	RunProgram("git", "pull", "iptv");
}

streamDir.Refresh();
FileInfo csvName = new FileInfo(String.Format("{0}.csv", DateTime.Now.Ticks));
StringWriter csvBuilder = new StringWriter();

foreach (FileInfo m3uinfo in streamDir.GetFiles("*.m3u"))
{
	M3uContent m3u = new M3uContent();
	PlaylistsNET.Models.M3uPlaylist m3uPlaylist = m3u.GetFromString(File.ReadAllText(m3uinfo.FullName));
	List<PlaylistsNET.Models.M3uPlaylistEntry> playlistEntries = m3uPlaylist.PlaylistEntries;
	string countryName = Path.GetFileNameWithoutExtension(m3uinfo.Name);
	foreach (M3uPlaylistEntry entry in playlistEntries)
	{
		string channelName = GetChannelName(entry);
		string outputFileName = Path.Combine("output", countryName, String.Format("{0}.ts", channelName));
		string outputFlagName = Path.Combine("output", countryName, String.Format("{0}.fail", channelName));
		FileInfo outputFileInfo = new FileInfo(outputFileName);
		if (!outputFileInfo.Exists)
		{
			if (File.Exists(outputFlagName))
				continue;
			EnsureFolderExists(outputFileInfo.Directory);
			string tspArgs = String.Format("-v -I hls \"{0}\" -P until -s 60 -O file \"{1}\"", entry.Path, outputFileInfo.FullName);
			if (!RunProgram("tsp", tspArgs))
			{
				File.WriteAllText(outputFlagName, "");
			}
		}
		outputFileInfo.Refresh();
		if (outputFileInfo.Exists)
		{
			uint[] pidStats = AnalyzeStream(outputFileInfo);
			int activePids = pidStats.Count(x => x > 0);
			string outputLine = String.Format("{0};{1};{2};", outputFileInfo.Directory.Name, channelName, activePids);
			for (int i = 0; i < pidStats.Length; i++)
			{
				if (pidStats[i] > 0)
				{
					outputLine += String.Format("0x{0:X4};", i);
				}
			}
			csvBuilder.WriteLine(outputLine);
			Console.WriteLine(outputLine);
		}
	}
}
File.WriteAllText(csvName.FullName, csvBuilder.ToString());

uint[] AnalyzeStream(FileInfo outputFileInfo)
{
	FileStream fileStream = outputFileInfo.OpenRead();
	BufferedStream bufferedStream = new BufferedStream(fileStream, 192512);
	byte[] packetBuffer = new byte[188];
	uint[] result = new uint[0x2000];
	while (true)
	{
		if (bufferedStream.Read(packetBuffer, 0, packetBuffer.Length) != packetBuffer.Length)
			break;
		if (packetBuffer[0] != 'G')
			break;
		int pid = packetBuffer[1] & 0x1f;
		pid <<= 8;
		pid += packetBuffer[2];
		result[pid]++;
	}
	bufferedStream.Close();
	fileStream.Close();
	return result;
}