/VFSEncoder.cs
namespace VFSEncoder {
	using Gtk;
	using System;
	using System.Threading;
	using System.IO;
	using System.Reflection;
	using System.Collections;
	using System.Diagnostics;
	using System.Text.RegularExpressions;

	public class VFSEncoder {
		static ArrayList EncoderProfiles;

		static Window window;
		static Table options;
		static Label[] label = new Label[2];
		static Label status;
		static ComboBox profiles;
		static FileChooserDialog filechooser;
		static FileChooserButton browse;
		static Button go, stop;
		static Process p;

		static bool cancel_encode = false;

		static void fatal_error(string msg) {
			MessageDialog d = new MessageDialog(null, DialogFlags.Modal, MessageType.Error, ButtonsType.Close, msg);
			d.Title = "Error";
			d.Run();
			d.Destroy();
			Environment.Exit(1);
		}

		static void LoadEncoderProfiles() {
			EncoderProfiles = new ArrayList();
			EncoderProfile current = null;

			StreamReader r = null;
			try {
				r = new StreamReader("profiles.txt");
			} catch (FileNotFoundException) {
				fatal_error("Could not open profiles.txt");
			}
			Regex section_re = new Regex(@"^\[(.+)\]\s*(.*)$");
			Regex option_re = new Regex(@"(?:(\w+)\s*:\s*(\w+)\s*)");

			string line;
			try {
				while(null != (line = r.ReadLine())) {
					if (line.Length == 0) continue;

					Match m = section_re.Match(line);
					if (m.Success) {
						string title = m.Groups[1].ToString();
						string args = m.Groups[2].ToString();
						current = new EncoderProfile(title);
						//Console.WriteLine("\n[" + title + "]");
						if (args != "") {
							m = option_re.Match(args);
							while (m.Success) {
								//Console.WriteLine(m.Groups[1].Value + " => " + m.Groups[2].Value);
								current.SetOption(m.Groups[1].Value, m.Groups[2].Value);
								m = m.NextMatch();
							}
						}
						EncoderProfiles.Add(current);
					} else {
						if (current != null) {
							//Console.WriteLine(line);
							current.AddStep(line);
						} else {
							Console.WriteLine("args before profile! : {0}", line);
						}
					}
				}
			} catch(IOException e) {
				Console.WriteLine(e.Message);
			}
			r.Close();
		}

		static void delete_event(object obj, DeleteEventArgs args) {
			Application.Quit();
		}

		static void stop_click(object obj, EventArgs args) {
			p.StandardInput.Write("q");
			p.StandardInput.Flush();
			Thread.Sleep(50);	// Wait for ffmpeg to listen
			p.Kill();
			p.WaitForExit();
			cancel_encode = true;
		}

		static void go_click(object obj, EventArgs args) {
			if (browse.Filename == null) {
				status.Text = "No file selected!";
				return;
			}

			browse.Sensitive = false;
			profiles.Sensitive = false;
			go.Visible = false;
			stop.Visible = true;

			EncoderProfile ep = (EncoderProfile) EncoderProfiles[profiles.Active];

			string outfile = Path.Combine("output", Path.ChangeExtension(Path.GetFileName(browse.Filename), ep.Extension));

			foreach (string ffargs in ep.Steps) {
				p = new Process();
				p.StartInfo.FileName = "ffmpeg";
				p.StartInfo.Arguments = String.Format("-y -i \"{0}\" {2} \"{1}\"", browse.Filename, outfile, ffargs);
				p.StartInfo.UseShellExecute = false;
				p.StartInfo.RedirectStandardInput = true;

				status.Text = "Encoding...";
				p.Start();
				
				while (!p.HasExited) {
					Application.RunIteration(false);
					Thread.Sleep(50);
				}
				p.WaitForExit();
				if (cancel_encode || p.ExitCode != 0)
					break;
			}

			status.Text = String.Format("Finished encoding {0}.", outfile);

			browse.Sensitive = true;
			profiles.Sensitive = true;
			stop.Visible = false;
			go.Visible = true;
			cancel_encode = false;
		}

		public static int Main(string[] args) {
			FileFilter filter;
			string appdir;

			appdir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
			Directory.SetCurrentDirectory(appdir);

			Application.Init();

			LoadEncoderProfiles();
			if (EncoderProfiles.Count == 0) {
				fatal_error("Couldn't find any encoder commands. Do you have profiles.txt?");
			}

			window = new Window("VFS Encoder");
			window.DeleteEvent += delete_event;
			window.DefaultWidth = 300;

			filechooser = new FileChooserDialog("Choose the file to encode", window, FileChooserAction.Open, "Cancel", ResponseType.Cancel, "Open", ResponseType.Accept);
			filter = new FileFilter();
			filter.Name = "Video files";
			filter.AddMimeType("video/mp4");
			filter.AddPattern("*.mp4");
			filter.AddMimeType("video/x-msvideo");
			filter.AddPattern("*.avi");
			filter.AddMimeType("video/quicktime");
			filter.AddPattern("*.mov");
			filter.AddMimeType("video/x-ms-wmv");
			filter.AddPattern("*.wmv");
			filter.AddPattern("*.asf");
			filter.AddMimeType("video/mpeg");
			filter.AddPattern("*.mpg");
			filter.AddPattern("*.vob");
			filter.AddPattern("*.mpeg");
			filter.AddPattern("*.mp2v");
			filter.AddMimeType("video/x-flv");
			filter.AddPattern("*.flv");
			filechooser.AddFilter(filter);

			filter = new FileFilter();
			filter.Name = "All Files";
			filter.AddPattern("*");
			filechooser.AddFilter(filter);

			options = new Table(2, 4, false);
			label[0] = new Label("File");
			options.Attach(label[0], 0, 1, 0, 1, AttachOptions.Shrink, 0, 4, 2);
			label[1] = new Label("Encoder Profile");
			options.Attach(label[1], 0, 1, 1, 2, AttachOptions.Shrink, 0, 4, 2);
			browse = new FileChooserButton(filechooser);
			options.Attach(browse, 1, 2, 0, 1);
			profiles = ComboBox.NewText();
			foreach (EncoderProfile ep in EncoderProfiles)
				profiles.AppendText(ep.Title);
			profiles.Active = 0;
			options.Attach(profiles, 1, 2, 1, 2);
			go = new Button("Go!");
			go.Clicked += new EventHandler(go_click);
			options.Attach(go, 0, 2, 2, 3);
			stop = new Button("Stop");
			stop.Clicked += new EventHandler(stop_click);
			options.Attach(stop, 0, 2, 2, 3);
			status = new Label();
			options.Attach(status, 0, 2, 3, 4, AttachOptions.Fill, AttachOptions.Shrink, 0, 2);
			status.Justify = Justification.Left;
			status.Text = "VFSEncoder Ready";

			if (args.Length == 1) {
				browse.SetFilename(args[0]);
				Console.WriteLine("Set filename to " + args[0]);
			}

			window.Add(options);
			options.Show();
			window.ShowAll();

			Application.Run();
			return 0;
		}
	}
}

// vim:set ts=4 sw=4 sts=4: