using System;
using System.Collections;

using Gtk;

using MonoDevelop.Core;
using MonoDevelop.Ide.Gui;

namespace MonoDevelop.Ide.Gui.Dialogs
{
	internal class DirtyFilesDialog : Gtk.Dialog
	{

		Button btnSaveAndQuit;
		Button btnQuit;
		Button btnCancel;
		TreeView tvFiles;
		TreeStore tsFiles;
		CellRendererToggle togRender;
		CellRendererText textRender;
		
		public DirtyFilesDialog() : base (GettextCatalog.GetString ("Save Files"), IdeApp.Workbench.RootWindow, DialogFlags.Modal)
		{
			tsFiles = new TreeStore (typeof (string), typeof (bool), typeof (SdiWorkspaceWindow), typeof (bool));
			tvFiles = new TreeView (tsFiles);
			TreeIter topCombineIter = TreeIter.Zero;
			Hashtable projectIters = new Hashtable ();
			
			foreach (Document doc in IdeApp.Workbench.Documents) {
				if (!doc.IsDirty)
					continue;
				
				IViewContent viewcontent = doc.Window.ViewContent;
				 
				if (viewcontent.Project != null) {
					TreeIter projIter = TreeIter.Zero;
					if (projectIters.ContainsKey (viewcontent.Project))
						projIter = (TreeIter) projectIters[viewcontent.Project];
					else {
						if (topCombineIter.Equals (TreeIter.Zero))
							projIter = tsFiles.AppendValues (GettextCatalog.GetString ("Project: {0}", viewcontent.Project.Name), true, null, false);
						else
							projIter = tsFiles.AppendValues (topCombineIter, GettextCatalog.GetString ("Project: {0}", viewcontent.Project.Name), true, null, false);
						projectIters[viewcontent.Project] = projIter;
					}
					tsFiles.AppendValues (projIter, viewcontent.PathRelativeToProject, true, viewcontent.WorkbenchWindow);
				} else {
					if (viewcontent.ContentName == null) {
						viewcontent.ContentName = System.IO.Path.Combine (Environment.GetFolderPath (Environment.SpecialFolder.Personal), viewcontent.UntitledName);
					}
					tsFiles.AppendValues (viewcontent.ContentName, true, viewcontent.WorkbenchWindow);
				}
			}
			if (!topCombineIter.Equals (TreeIter.Zero)) {
				if (!tsFiles.IterHasChild (topCombineIter))
					tsFiles.Remove (ref topCombineIter); 
			}

			TreeViewColumn mainColumn = new TreeViewColumn ();
			mainColumn.Title = "header";
			
			togRender = new CellRendererToggle ();
			togRender.Toggled += toggled;
			mainColumn.PackStart (togRender, false);
			mainColumn.AddAttribute (togRender, "active", 1);
			mainColumn.AddAttribute (togRender, "inconsistent", 3);
			
			textRender = new CellRendererText ();
			mainColumn.PackStart (textRender, true);
			mainColumn.AddAttribute (textRender, "text", 0);

			tvFiles.AppendColumn (mainColumn);
			tvFiles.HeadersVisible = false;
			tvFiles.ExpandAll ();

			ScrolledWindow sc = new ScrolledWindow ();
			sc.Add (tvFiles);
			sc.ShadowType = ShadowType.In;

			sc.BorderWidth = 6;
			this.VBox.PackStart (sc, true, true, 6);
			
			btnSaveAndQuit = new Button (GettextCatalog.GetString ("_Save and Quit"));
			btnQuit = new Button (Gtk.Stock.Quit);
			btnCancel = new Button (Gtk.Stock.Cancel);

			btnSaveAndQuit.Clicked += SaveAndQuit;
			btnQuit.Clicked += Quit;
			btnCancel.Clicked += Cancel;

			this.ActionArea.PackStart (btnCancel);
			this.ActionArea.PackStart (btnQuit);
			this.ActionArea.PackStart (btnSaveAndQuit);
			this.SetDefaultSize (300, 200);
			this.ShowAll ();
		}
		
		protected override void OnDestroyed ()
		{
			btnSaveAndQuit.Clicked -= SaveAndQuit;
			btnQuit.Clicked -= Quit;
			btnCancel.Clicked -= Cancel;
			if (togRender != null) {
				togRender.Toggled -= toggled;
				togRender.Destroy ();
				togRender = null;
			}
			if (textRender != null) {
				textRender.Destroy ();
				textRender = null;
			}
			if (tsFiles != null) {
				tsFiles.Dispose ();
				tsFiles = null;
			}
			base.OnDestroyed ();
		}
		
		ArrayList arrSaveWorkbenches = new ArrayList ();
		void SaveAndQuit (object o, EventArgs e)
		{
			tsFiles.Foreach (new TreeModelForeachFunc (CollectWorkbenches));
			foreach (SdiWorkspaceWindow window in arrSaveWorkbenches) {
				window.ViewContent.Save (window.ViewContent.ContentName);
			}

			Respond (Gtk.ResponseType.Ok);
			Hide ();
		}

		bool CollectWorkbenches (TreeModel model, TreePath path, TreeIter iter)
		{
			if ((bool)tsFiles.GetValue (iter, 1)) {
				if (tsFiles.GetValue (iter, 2) != null)
					arrSaveWorkbenches.Add (tsFiles.GetValue (iter, 2));
			}
			
			return false;
		}

		void Quit (object o, EventArgs e)
		{
			Respond (Gtk.ResponseType.Ok);
			Hide ();
		}

		void Cancel (object o, EventArgs e)
		{
			Respond (Gtk.ResponseType.Cancel);
			Hide ();
		}

		void toggled (object o, ToggledArgs e)
		{
			TreeIter iter;
			tsFiles.GetIterFromString (out iter, e.Path);
			bool newsetting = !(bool)tsFiles.GetValue (iter, 1);
			tsFiles.SetValue (iter, 1, newsetting);
			if (tsFiles.IterHasChild (iter))
				ToggleChildren (iter, newsetting);
			
			TreeIter iterFirst;
			tsFiles.GetIterFirst (out iterFirst);
			if (tsFiles.IterHasChild (iterFirst))
				NewCheckStatus (iterFirst);
		}

		void NewCheckStatus (TreeIter iter)
		{
			if (tsFiles.IterHasChild (iter)) {
				TreeIter childIter;
				tsFiles.IterNthChild (out childIter, iter, 0);
				if (tsFiles.IterHasChild (childIter))
					NewCheckStatus (childIter);
				bool lastsetting = (bool)tsFiles.GetValue (childIter, 1);
				bool inconsistant = (bool)tsFiles.GetValue (childIter, 3);
				bool anytrue;
				anytrue = lastsetting;
				while (tsFiles.IterNext (ref childIter)) {
					if (tsFiles.IterHasChild (childIter))
						NewCheckStatus (childIter);
					bool newsetting = (bool)tsFiles.GetValue (childIter, 1);
					if (newsetting != lastsetting || (bool)tsFiles.GetValue (childIter, 3) == true)
						inconsistant = true;
					if (newsetting)
						anytrue = true;
					lastsetting = newsetting;
				}
				
				tsFiles.SetValue (iter, 3, inconsistant);
				tsFiles.SetValue (iter, 1, anytrue);
			}
		}

		void ToggleChildren (TreeIter iter, bool setting)
		{
			TreeIter newIter;
			tsFiles.IterNthChild (out newIter, iter, 0);
			do {
				tsFiles.SetValue (newIter, 1, setting);
				if (tsFiles.IterHasChild (newIter))
					ToggleChildren (newIter, setting);
			}
			while (tsFiles.IterNext (ref newIter));
		}
	}
}
