/*
 * This file is part of SubLib.
 * Copyright (C) 2005-2007 Pedro Castro
 *
 * SubLib is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * SubLib is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

using System;
using System.Collections;
using System.Text;
using SubLib;

public enum CommandType { Unknown, Open, Save, Display, DisplayIncomplete, Stats, ChangeFrameRate, ChangeInputFrameRate, FindWithTime };

public class Command {
	public CommandType type = CommandType.Unknown;
	public string obj1 = null;
	public string obj2 = null;
	public SubtitleType subType;
	
	public Command(CommandType newType, string arg1, string arg2){
		type = newType;
		obj1 = arg1;
		obj2 = arg2;
	}
	
	public void SetSubType(string type) {
		switch (type) {
			case "microdvd":
				subType = SubtitleType.MicroDVD;
				break;
			case "subrip":
				subType = SubtitleType.SubRip;
				break;
			case "advancedsubstationalpha":
				subType = SubtitleType.AdvancedSubStationAlpha;
				break;
			case "mplayer":
				subType = SubtitleType.MPlayer;
				break;
			case "mplayer2":
				subType = SubtitleType.MPlayer2;
				break;
			case "mpsub":
				subType = SubtitleType.MPSub;
				break;
            case "substationalpha":
                subType = SubtitleType.SubStationAlpha;
                break;
			case "subviewer1":
            	subType = SubtitleType.SubViewer1;
                break;
            case "subviewer2":
            	subType = SubtitleType.SubViewer2;
                break;
			case "aqtitle":
            	subType = SubtitleType.AQTitle;
                break;
			case "macsub":
            	subType = SubtitleType.MacSUB;
                break;
			case "phoenix":
				subType = SubtitleType.PhoenixJapanimationSociety;
				break;
			case "panimator":
				subType = SubtitleType.Panimator;
				break;
			case "sofni":
            	subType = SubtitleType.Sofni;
            	break;
			case "subcreator1x":
            	subType = SubtitleType.SubCreator1x;
            	break;
			case "viplay":
            	subType = SubtitleType.ViPlaySubtitleFile;
            	break;
			case "dkssubtitleformat":
				subType = SubtitleType.DKSSubtitleFormat;
				break;
            case "karaokelyricslrc":
            	subType = SubtitleType.KaraokeLyricsLRC;
                break;
            case "karaokelyricsvkt":
            	subType = SubtitleType.KaraokeLyricsVKT;
                break;
            case "adobeencoredvd":
            	subType = SubtitleType.AdobeEncoreDVD;
            	break; 
			default:
				subType = SubtitleType.Unknown;
				break;
		}
	}
}


public class Executable {

	public ArrayList GetCommands(string[] args){
		ArrayList commands = new ArrayList();
		for(int count = 0 ; count < args.Length ; count++){
			switch (args[count]){
				case "-open":
					Command openCommand = new Command (CommandType.Open, args[++count], null);
					if ((count+1 < args.Length) && !args[count+1].StartsWith("-"))
						openCommand.obj2 = args[count+1];
					commands.Add(openCommand);
                                    
					break;
				case "-save":
					Command saveCommand = new Command(CommandType.Save, args[++count], null);
					saveCommand.SetSubType(args[++count]); 
					commands.Add(saveCommand);
					break;
				case "-display":
					commands.Add(new Command(CommandType.Display, null, null));
					break;
				case "-displayincomplete":
					commands.Add(new Command(CommandType.DisplayIncomplete, null, null));
					break;
				case "-stats":
					commands.Add(new Command(CommandType.Stats, null, null));
					break;
				case "-changefps":
					commands.Add(new Command(CommandType.ChangeFrameRate, args[++count], null));
					break;
				case "-changeinputfps":
					commands.Add(new Command(CommandType.ChangeInputFrameRate, args[++count], null));
					break;
				case "-findwithtime":
					commands.Add(new Command(CommandType.FindWithTime, args[++count], null));
					break;
            }		
		}
		return commands;
	}
	
	public void ShowCommands(ArrayList commands){
		Console.WriteLine("Showing " + commands.Count + " commands:");
		int count = 1;
		foreach(Command command in commands){
			Console.WriteLine("\t" + count + " - " + command.ToString());
			count++;
		}
	}
	
	public void ExecuteCommands(ArrayList commands){
		SubtitleFactory subtitleFactory = new SubtitleFactory();
		subtitleFactory.Verbose = true;
		subtitleFactory.IncludeIncompleteSubtitles = true;
		Subtitles subtitles = null;
		IncompleteSubtitleCollection incompleteSubtitles = null;
		foreach(Command command in commands){
			switch(command.type){
				case CommandType.Open:
					Console.WriteLine("[*] Opening subtitles from " + command.obj1);
					subtitles = subtitleFactory.Open(command.obj1); 
					incompleteSubtitles = subtitleFactory.IncompleteSubtitles;
					Console.WriteLine();
					break;
				case CommandType.Save:
					Console.WriteLine("[*] Saving subtitles to " + command.obj1 + " using format " + command.subType);
					FileProperties fileProperties = new FileProperties(command.obj1, Encoding.UTF8, command.subType, TimingMode.Times);
					SubtitleSaver saver = new SubtitleSaver();
					saver.Save(subtitles, fileProperties, SubtitleTextType.Text);
					break;
				case CommandType.Display:
					Console.WriteLine("[*] Showing subtitles");
					Console.WriteLine("-------------------------- SUBTITLES ------------------------");
					Console.WriteLine(subtitles.Collection.ToString());
					Console.WriteLine("-------------------------- PROPERTIES -----------------------");
					Console.WriteLine(subtitles.Properties.ToString());
					break;
				case CommandType.DisplayIncomplete:
					Console.WriteLine("[*] Showing incomplete subtitles");
					Console.WriteLine(incompleteSubtitles.ToString());
					break;
				case CommandType.Stats:
					Console.WriteLine("[*] Showing statistics");
					TimeSpan maxDuration = new TimeSpan(0);
					TimeSpan minDuration = TimeSpan.FromDays(300);
					TimeSpan totalDuration = new TimeSpan(0);
					long maxDurationFrames = 0;
					long minDurationFrames = Int64.MaxValue;
					long totalDurationFrames = 0;
					foreach (Subtitle subtitle in subtitles.Collection) {
						TimeSpan duration = subtitle.Times.End - subtitle.Times.Start;
						long durationFrames = (long)(subtitle.Frames.End - subtitle.Frames.Start);
						if (duration > maxDuration)
							maxDuration = duration;
						if (durationFrames > maxDurationFrames)
							maxDurationFrames = durationFrames;
						if (duration < minDuration)
							minDuration = duration;
						if (durationFrames < minDurationFrames)
							minDurationFrames = durationFrames;
						totalDuration += duration;
						totalDurationFrames += durationFrames;
					}
					int numberOfSubtitles = subtitles.Collection.Count;
					long ticks = totalDuration.Ticks;
					long averageTicks = ticks / numberOfSubtitles;
					TimeSpan averageDuration = TimeSpan.FromTicks(averageTicks);
					long averageDurationFrames = totalDurationFrames / numberOfSubtitles;
					Console.WriteLine("Number of subtitles: " + numberOfSubtitles);
					Console.WriteLine("Total duration: " + totalDuration + " (" + totalDurationFrames + ")");
					Console.WriteLine("Maximum duration: " + maxDuration + " (" + maxDurationFrames + ")");
					Console.WriteLine("Minimum duration: " + minDuration + " (" + minDurationFrames + ")");
					Console.WriteLine("Average Duration: " + averageDuration + " (" + averageDurationFrames + ")");
					break;
				case CommandType.ChangeFrameRate:
					Console.WriteLine("[*] Changing FPS from " + subtitles.Properties.CurrentFrameRate + " to " + command.obj1);
					float newFrameRate = (float)Convert.ToDouble(command.obj1);
					subtitles.ChangeFrameRate(newFrameRate);
					break;
				case CommandType.ChangeInputFrameRate:
					Console.WriteLine("[*] Changing input FPS from " + subtitles.Properties.OriginalFrameRate + " to " + command.obj1);
					float newOriginalFrameRate = (float)Convert.ToDouble(command.obj1);
					subtitles.ChangeOriginalFrameRate(newOriginalFrameRate);
					break;
				case CommandType.FindWithTime:
					Console.WriteLine("[*] Finding time " + command.obj1 + " in " + subtitles.Collection.Count + " subtitles.");
					float time = (float)Convert.ToDouble(command.obj1);
					int foundSubtitle = subtitles.FindWithTime(time);
					if (foundSubtitle == -1)
						System.Console.WriteLine("Subtitle not found");
					else
						System.Console.WriteLine("Found subtitle " + foundSubtitle);
					break;
                default:
					Console.WriteLine("[!] Unknown Command. Terminating.");
					return;
			}
		}
	}
	
	private bool UsingWindows() {
		OperatingSystem os = Environment.OSVersion;
		string osName = os.ToString();
		osName = osName.ToLower();
		return (osName.IndexOf("micros") != -1) || (osName.IndexOf("win") != -1);
	}

	public void ShowUsage() {
		string osBit = "";
		if (!UsingWindows())
			osBit = "mono";
		Console.WriteLine("Usage: " + osBit + " SubLib.exe <commands>");
		Console.WriteLine();
		Console.WriteLine("Commands:");
		Console.WriteLine("\t -open <file>");
		Console.WriteLine("\t -save <file> <format>");
		Console.WriteLine("\t\t (supported formats: microdvd, subrip, advancedsubstationalpha, mplayer, mplayer2, mpsub, substationalpha, subviewer1, subviewer2, karaokelyricslrc, karaokelyricsvkt, adobeencoredvd)");
		Console.WriteLine("\t -display");
		Console.WriteLine("\t -displayincomplete");
		Console.WriteLine("\t -stats");
		Console.WriteLine("\t -changefps <new fps>");
		Console.WriteLine("\t -findwithtime <seconds>");
		Console.WriteLine();
		Console.WriteLine("Examples:");
		Console.WriteLine("\t " + osBit + " SubLib.exe -open subtitle.sub -display");
		Console.WriteLine("\t " + osBit + " SubLib.exe -open subtitle.sub -save subtitle.srt subrip");
		Console.WriteLine("\t " + osBit + " SubLib.exe -open subtitle.srt -stats");
		Console.WriteLine("\t " + osBit + " SubLib.exe -open subtitle.sub 25 -changefps 30 -display");
	}
	
	public static int Main(string[] args) {
		Executable executable = new Executable();
		if (args.Length == 0) {
			executable.ShowUsage();
			return 0;
		}
		ArrayList commands = executable.GetCommands(args);
		executable.ExecuteCommands(commands);
		return 0;
	}
		
}

