/*
	$Id: Hiyoko.cs 26 2010-01-17 20:09:14Z catwalk $
*/
using System;
using System.Linq;
using System.IO;
using System.Windows;
using System.Windows.Input;
using System.Windows.Threading;
using System.Configuration;
using System.ComponentModel;
using System.Threading;
using System.Diagnostics;
using System.Net;
using IronPython.Hosting;
using IronPython.Modules;
using Hiyoko.Forms;
using Hiyoko.Utilities;
using Hiyoko.Net;
using Hiyoko.Net.Twitter;

namespace Hiyoko{
	public partial class Program : Application{
		private PythonEngine pythonEngine = null;
		private ApplicationSettings settings;
		private CommandLine commandLine;
		private NetworkJobServer networkJobServer;
		private string executablePath;
		
		protected override void OnStartup(StartupEventArgs e){
			if(!ApplicationProcess.IsFirst){
				ApplicationProcess.InvokeRemote("Show");
				this.Shutdown();
			}else{
				ApplicationProcess.Actions.Add("Show", new Action(delegate{
					this.Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(delegate{
						if(this.MainWindow != null){
							this.MainWindow.Show();
							this.MainWindow.Activate();
						}
					}));
				}));
				//System.Windows.Forms.Application.EnableVisualStyles();
				this.DispatcherUnhandledException += this.HandleUnhandleExceptions;
				
				// 初期化
				this.commandLine = new CommandLine();
				this.networkJobServer = new NetworkJobServer();
				this.executablePath = System.Windows.Forms.Application.ExecutablePath;
				
				// 設定読み込み
				this.settings = new ApplicationSettings("Application");
				this.settings.UpgradeOnce();
				this.settings.PropertyChanged += this.ApplicationSettings_Changed;
				if(this.settings.StartupScriptPath == null){
					this.settings.StartupScriptPath = Environment.GetFolderPath(Environment.SpecialFolder.Personal) + @"\HiyokoStartup.py";
				}
				if(this.settings.IsUseWebProxy){
					Hiyoko.Net.Twitter.TwitterAPI.Proxy = new System.Net.WebProxy(this.settings.WebProxyUri);
				}
				this.ApplyShutdownMode();
				this.networkJobServer.Timeout = Program.Settings.ConnectionTimeout;
				
				// MainForm初期化
				MainForm mainForm = this.LoadMainForm();
				if(!(this.settings.IsResident && (this.commandLine.Options.ContainsKey("hide")))){
					mainForm.Show();
				}
				
				// 初期アカウント設定
				if(this.settings.AccessToken == null){
					SettingsForm settings = new SettingsForm();
					settings.Owner = mainForm;
					settings.ShowDialog();
				}
				
				ThreadPool.QueueUserWorkItem(new WaitCallback(delegate{
					// IronPython初期化
					EngineOptions options = new EngineOptions();
					options.ShowClrExceptions = true;
					options.ClrDebuggingEnabled = true;
					options.ExceptionDetail = false;
					this.pythonEngine = new PythonEngine(options);
					this.pythonEngine.LoadAssembly(System.Reflection.Assembly.GetExecutingAssembly());
					ClrModule clr = (ClrModule)this.pythonEngine.Import("clr");
					clr.AddReferenceByPartialName("System");
					clr.AddReferenceByPartialName("System.Core");
					clr.AddReferenceByPartialName("System.Drawing");
					clr.AddReferenceByPartialName("System.Xml");
					clr.AddReferenceByPartialName("System.Xml.Linq");
					clr.AddReferenceByPartialName("System.Web");
					clr.AddReferenceByPartialName("System.Windows.Forms");
					clr.AddReferenceByPartialName("System.Runtime.Remoting");
					clr.AddReferenceByPartialName("WindowsBase");
					clr.AddReferenceByPartialName("PresentationCore");
					clr.AddReferenceByPartialName("PresentationFramework");
					
					// Startupスクリプト実行
					string[] scripts = new string[]{
						this.settings.StartupScriptPath,
						Path.GetDirectoryName(this.executablePath) + @"\DefaultStartup.py"
					}.Where(file => File.Exists(file)).Take(1).ToArray();
					this.Dispatcher.BeginInvoke(DispatcherPriority.Render, new Action(delegate{
						MainForm.Outputs.Add(new MessageOutputItem(String.Format("スタートアップスクリプト実行中 - {0}", scripts[0])));
					}));
					if(scripts.Length > 0){
						try{
							string result = null;
							using(MemoryStream standardOutput = new MemoryStream()){
								this.pythonEngine.SetStandardOutput(standardOutput);
								this.pythonEngine.ExecuteFile(scripts[0]);
								result = System.Text.ASCIIEncoding.ASCII.GetString(standardOutput.ToArray());
							}
							this.Dispatcher.BeginInvoke(DispatcherPriority.Render, new Action(delegate{
								if(!String.IsNullOrEmpty(result)){
									MainForm.Outputs.Add(new MessageOutputItem(result));
								}
								MainForm.Outputs.Add(new SuccessOutputItem("スタートアップスクリプト実行完了"));
							}));
						}catch(Exception ex){
							this.Dispatcher.BeginInvoke(DispatcherPriority.Render, new Action(delegate{
								mainForm.Outputs.Add(new ErrorOutputItem(this.pythonEngine.FormatException(ex)));
							}));
						}
					}
				}));
			}
			base.OnStartup(e);
		}
		
		private MainForm LoadMainForm(){
			MainForm mainForm = new MainForm();
			this.MainWindow = mainForm;
			return mainForm;
		}
		
		private void UnloadMainForm(){
			var mode = this.ShutdownMode;
			this.ShutdownMode = ShutdownMode.OnExplicitShutdown;
			MainForm mainForm = MainForm;
			mainForm.IsResident = false;
			mainForm.Close();
			this.ShutdownMode = mode;
		}
		
		protected override void OnExit(ExitEventArgs e){
			if(ApplicationProcess.IsFirst){
				this.pythonEngine.Dispose();
				this.settings.Save();
			}
			base.OnExit(e);
		}
		
		private void HandleUnhandleExceptions(object sender, DispatcherUnhandledExceptionEventArgs e){
			if(e.Exception.GetType().Namespace == "IronPython.Runtime.Exceptions"){
				e.Handled = true;
				if(MessageBox.Show(
					String.Format("IronPythonスクリプトでエラーが発生しました。続行しますか？\n\n{0}", this.pythonEngine.FormatException(e.Exception)),
					"エラー",
					MessageBoxButton.YesNo) == MessageBoxResult.Yes){
				}else{
					this.Shutdown();
				}
			}
		}
		
		private void ApplicationSettings_Changed(object sender, PropertyChangedEventArgs e){
			ApplicationSettings settings = (ApplicationSettings)sender;
			switch(e.PropertyName){
				case "ConnectionTimeout":{
					this.networkJobServer.Timeout = settings.ConnectionTimeout;
					break;
				}
				case "IsResident":{
					this.ApplyShutdownMode();
					break;
				}
				case "WebProxyUri":
				case "IsUseWebProxy":{
					this.InitalizeWebProxy();
					break;
				}
			}
		}
		
		private void ApplyShutdownMode(){
			this.ShutdownMode = (this.settings.IsResident) ? ShutdownMode.OnExplicitShutdown : ShutdownMode.OnLastWindowClose;
		}
		
		private void InitalizeWebProxy(){
			if(this.settings.IsUseWebProxy){
				var uri = this.settings.WebProxyUri;
				var proxy = new WebProxy(uri);
				if(!String.IsNullOrEmpty(uri.UserInfo)){
					string[] strs = uri.UserInfo.Split(new char[]{':'});
					if(strs.Length >= 2){
						proxy.Credentials = new NetworkCredential(strs[0], strs[1]);
					}
				}
				this.networkJobServer.Proxy = TwitterAPI.Proxy = proxy;
			}else{
				this.networkJobServer.Proxy = TwitterAPI.Proxy = WebRequest.DefaultWebProxy;
			}
		}
		
		public static PythonEngine PythonEngine{
			get{
				Program prog = Application.Current as Program;
				return (prog != null) ? prog.pythonEngine : null;
			}
		}
		
		public static MainForm MainForm{
			get{
				return Application.Current.MainWindow as MainForm;
			}
		}
		
		public static ApplicationSettings Settings{
			get{
				Program prog = Application.Current as Program;
				return (prog != null) ? prog.settings : null;
			}
		}
		
		public static NetworkJobServer NetworkJobServer{
			get{
				Program prog = Application.Current as Program;
				return (prog != null) ? prog.networkJobServer : null;
			}
		}
		
		public static string ExecutablePath{
			get{
				Program prog = Application.Current as Program;
				return (prog != null) ? prog.executablePath : null;
			}
		}
		/*
		public static void ReloadMainForm(){
			Program prog = Application.Current as Program;
			if((prog == null) && (MainForm == null)){
				throw new InvalidOperationException();
			}
			
			prog.UnloadMainForm();
			prog.LoadMainForm().Show();
		}
		*/
	}
}