using System;
using System.Collections.Generic;
using Gtk;

namespace DMX2
{
	[System.ComponentModel.ToolboxItem(true)]
	public partial class SeqLinUI : SequenceurUI
	{

		bool fullUpdFlag = true;
		SequenceurLineaire sequenceur;
		ListStore lsEffets=null;
		TreeViewColumn nomCol;

		bool effetChange = false;
		public void EffetChange ()
		{
			effetChange = true;
		}

		void RenamePopup (object sender, ContextMenuEventArgs e)
		{
				Menu m = new Menu();
				MenuItem renameItem = new MenuItem("Renommer le Sequenceur");
				renameItem.ButtonPressEvent +=	new ButtonPressEventHandler(OnRenameItemButtonPressed);
				m.Add(renameItem);
				m.ShowAll();
				m.Popup();
		}

		void OnRenameItemButtonPressed (object o, ButtonPressEventArgs args)
		{
			var dlg = new Dialog ("Nouveau Nom ?", GetAncestor(Gtk.Window.GType) as Gtk.Window , DialogFlags.Modal); var entry = new Entry (sequenceur.Name);
			dlg.AddButton (Stock.Ok, ResponseType.Ok).GrabDefault(); dlg.AddButton (Stock.Cancel, ResponseType.Cancel);
			dlg.VBox.Add (entry); dlg.VBox.ShowAll (); 
			entry.ActivatesDefault=true;

			 

			if ((ResponseType)dlg.Run () == ResponseType.Ok) {
				sequenceur.Name = entry.Text;
				titreLabel.Text = sequenceur.Name;
			}
			dlg.Destroy();
		}

		public SeqLinUI (SequenceurLineaire s ) : base (s)
		{
			this.Build ();
			titreLabel.Text = s.Name;
			sequenceur = s;

			tirettesContextHelper.ContextMenu += TirettePopup;

			new ContextMenuHelper(seqMasterScale,MasterPopup);

			new ContextMenuHelper(evBBox,CompteurPopup);
			new ContextMenuHelper(frame1,RenamePopup);

#region Construction listeEffets

			// Construction de la liste d'effets
			var numCol = new TreeViewColumn();
			nomCol = new TreeViewColumn();
			var dureeCol = new TreeViewColumn();
			var transCol = new TreeViewColumn();

			var numCell = new CellRendererText();
			var nomCell = new CellRendererText();
			var dureeCell = new CellRendererText();
			var transCell = new CellRendererText();

			numCol.Title = "N°";
			nomCol.Title = "Effet";
			dureeCol.Title = "Duree";
			transCol.Title = "Transition";

			numCol.PackEnd(numCell,true);
			nomCol.PackStart(nomCell,true);
			dureeCol.PackEnd(dureeCell,true);
			transCol.PackEnd(transCell,true);

			numCol.SetCellDataFunc(numCell,	new TreeCellDataFunc(RenderNum));
			nomCol.SetCellDataFunc(nomCell,	new TreeCellDataFunc(RenderNom));
			dureeCol.SetCellDataFunc(dureeCell,	new TreeCellDataFunc(RenderDuree));
			transCol.SetCellDataFunc(transCell,	new TreeCellDataFunc(RenderTrans));

			nomCol.MinWidth = 150;
			nomCol.Expand=true;
			dureeCol.MaxWidth=50;
			transCol.MaxWidth=50;
		
			effetsListe.AppendColumn(numCol);
			effetsListe.AppendColumn(nomCol);
			effetsListe.AppendColumn(transCol);
			effetsListe.AppendColumn(dureeCol);

			lsEffets = new ListStore(typeof(SequenceurLineaire.Effet));
			effetsListe.Model = lsEffets;

			nomCell.Editable = true;
			dureeCell.Editable = true;
			transCell.Editable = true;

			nomCell.Edited += EditNom;
			dureeCell.Edited += EditDuree;
			transCell.Edited += EditTrans;

			//Update(true);
			UpdListeEffets();

#endregion
		}



		void EditNom (object o, EditedArgs args)
		{
			Gtk.TreeIter iter;
			lsEffets.GetIter (out iter, new Gtk.TreePath (args.Path));
			SequenceurLineaire.Effet e = lsEffets.GetValue(iter,0) as SequenceurLineaire.Effet;
			e.Nom = args.NewText;
		}

		void EditDuree (object o, EditedArgs args)
		{
			Gtk.TreeIter iter;int d;
			lsEffets.GetIter (out iter, new Gtk.TreePath (args.Path));
			SequenceurLineaire.Effet e = lsEffets.GetValue(iter,0) as SequenceurLineaire.Effet;
			if(int.TryParse(args.NewText , out d))
				e.Duree = TimeSpan.FromMilliseconds(d * 100);
		}

		void EditTrans (object o, EditedArgs args)
		{
			Gtk.TreeIter iter; int t;
			lsEffets.GetIter (out iter, new Gtk.TreePath (args.Path));
			SequenceurLineaire.Effet e = lsEffets.GetValue(iter,0) as SequenceurLineaire.Effet;
			if(int.TryParse(args.NewText , out t))
				e.Transition = TimeSpan.FromMilliseconds(t * 100);
			
		}

#region Affichage Liste d'Effets
		void RenderNum (TreeViewColumn tree_column, CellRenderer cell, TreeModel tree_model, TreeIter iter)
		{
			SequenceurLineaire.Effet e =  tree_model.GetValue (iter, 0) as SequenceurLineaire.Effet;
			(cell as Gtk.CellRendererText).Text = (sequenceur.Effets.IndexOf(e)+1).ToString() ;
		}

		void RenderNom (TreeViewColumn tree_column, CellRenderer cell, TreeModel tree_model, TreeIter iter)
		{
			SequenceurLineaire.Effet e =  tree_model.GetValue (iter, 0) as SequenceurLineaire.Effet;
			(cell as Gtk.CellRendererText).Text = e.Nom;
		}

		void RenderDuree (TreeViewColumn tree_column, CellRenderer cell, TreeModel tree_model, TreeIter iter)
		{
			SequenceurLineaire.Effet e =  tree_model.GetValue (iter, 0) as SequenceurLineaire.Effet;
			(cell as Gtk.CellRendererText).Text = (e.Duree.TotalMilliseconds/100).ToString();
		}

		void RenderTrans (TreeViewColumn tree_column, CellRenderer cell, TreeModel tree_model, TreeIter iter)
		{
			SequenceurLineaire.Effet e =  tree_model.GetValue (iter, 0) as SequenceurLineaire.Effet;
			(cell as Gtk.CellRendererText).Text = (e.Transition.TotalMilliseconds/100).ToString();
		}

		void UpdListeEffets ()
		{
			lsEffets.Clear();
			foreach (var effet in sequenceur.Effets) {
				lsEffets.AppendValues(effet);
			}
		}
#endregion

		public override void Update (bool full)
		{
			if (fullUpdFlag || full)
				FullUpdate ();
			UpdateValues ();
			timeLabel.LabelProp = string.Format (@"{0:0\.0}", sequenceur.TimeStamp.TotalMilliseconds / 100);

			if (sequenceur.EffetCourrant.Duree != TimeSpan.Zero)
				pbDuree.Fraction = Math.Min (1.0d, sequenceur.TimeStamp.TotalMilliseconds / sequenceur.EffetCourrant.Duree.TotalMilliseconds);
			else
				pbDuree.Fraction = 0.0d;

			if (sequenceur.EffetCourrant.Transition != TimeSpan.Zero)
				pbTrans.Fraction = Math.Min (1.0d, sequenceur.TimeStamp.TotalMilliseconds / sequenceur.EffetCourrant.Transition.TotalMilliseconds);
			else
				pbTrans.Fraction = 0.0d;

			if (effetChange) {
				SelectionneEffet (sequenceur.IndexEffetCourrant);
				posLabel.Text = string.Format("n°{0}",sequenceur.IndexEffetCourrant +1 );
			}
		}

		void SelectionneEffet (int index)
		{
			if(index <0 ) return;
			effetsListe.SetCursor( new TreePath( new int[1] {index })   ,null,false);
			effetChange = false;
		}

		protected void OnCircuitsActionActivated (object sender, EventArgs e)
		{
			// récupère la fenètre principale
			Window win = this.GetAncestor(Gtk.Window.GType) as Window;
			var dlg = new SelSeqCircuits (sequenceur.Circuits,win);
			if ((ResponseType)dlg.Run () == ResponseType.Ok) {
					sequenceur.ChangeCircuits(dlg.GetResultList());
			}
			dlg.Destroy();
			fullUpdFlag = true;
		}

		protected void OnCloseActionActivated (object sender, EventArgs e)
		{
			this.Destroy();
		}


		Dictionary<Circuit,VScale> tirettes = new Dictionary<Circuit, VScale>();

		static VScale NouvelleTirette ()
		{
			VScale tirette = new VScale (null);
			tirette.WidthRequest = 25;
			tirette.HeightRequest = 150;
			tirette.CanFocus = true;
			tirette.Inverted = true;
			tirette.Adjustment.Upper = 255;
			tirette.Adjustment.PageIncrement = 10;
			tirette.Adjustment.StepIncrement = 1;
			tirette.DrawValue = true;
			tirette.Digits = 0;
			tirette.Name = "sclTirette";
			return tirette;
		}

		void TirettePopup (object sender, ContextMenuEventArgs e)
		{
			Circuit c  = e.Widget.Data[circuitKey] as Circuit;
			Menu m = Conduite.Courante.EventManager.GetMenu(c,TirettePopupEnd);
			m.ShowAll();
			m.Popup();
		}

		void TirettePopupEnd (object state, string eventId)
		{
			Circuit c = state as Circuit;
			sequenceur.BindCircuitEvent(c,eventId);
			Console.WriteLine("{0} bound to {1}", c, eventId );
		}

		void MasterPopup (object sender, ContextMenuEventArgs e)
		{
			Menu m = Conduite.Courante.EventManager.GetMenu(null,
			    delegate(object o,string eventId){
					sequenceur.BindMasterEvent(eventId);
				}
			);
			m.ShowAll();
			m.Popup();
		}

		void CompteurPopup (object sender, ContextMenuEventArgs e)
		{
			Menu m = new Menu();

			MenuItem item = new MenuItem("Effet Suivant");
			m.Add(item);
			item.Submenu = Conduite.Courante.EventManager.GetMenu(null,
			    delegate(object o,string eventId){
					sequenceur.BindEffetSuivantEvent(eventId);
				}
			);

			item = new MenuItem("Effet Precedent");
			m.Add(item);
			item.Submenu = Conduite.Courante.EventManager.GetMenu(null,
			    delegate(object o,string eventId){
					sequenceur.BindEffetPrecedentEvent(eventId);
				}
			);

			m.ShowAll();
			m.Popup();

		}


		static Label NouveauLabel ()
		{
			Label l = new Label();
			l.WidthRequest = 50;
			l.HeightRequest = 66;
			l.Xalign = 1F;
			l.Yalign = 0F;
			l.UseMarkup = true;
			l.Angle = 65;
			l.Name = "lblTirette";
			return l;
		}


		int lastKnownWidth =0;
		object circuitKey = new object();

		ContextMenuHelper tirettesContextHelper = new ContextMenuHelper();

		protected void FullUpdate ()
		{
			fullUpdFlag = true;
		
			lastKnownWidth = zoneWid.Allocation.Width;

			if (lastKnownWidth < 50) {
				fullUpdFlag=false;
				return;
			}

			foreach (Widget wid in new List<Widget>(zoneWid.Children))
				zoneWid.Remove (wid);

			tirettes.Clear();

			int xpos=10, ypos=0;
			VScale tirette; Fixed.FixedChild fx;
			Label label;

			foreach (Circuit c in sequenceur.Circuits) {
				tirettes[c] = tirette = NouvelleTirette();
				zoneWid.Add(tirette);
				fx = ( zoneWid[tirette] as Fixed.FixedChild);
				fx.X = xpos; fx.Y = ypos;
				tirette.Show();
				tirette.ValueChanged += TiretteActionee;
				tirette.Data.Add(circuitKey,c);
				tirettesContextHelper.AttachToWidget(tirette);
				tirette.TooltipText = c.Name;


				label = NouveauLabel();
				zoneWid.Add(label);
				fx = ( zoneWid[label] as Fixed.FixedChild);
				fx.X = xpos-30;
				fx.Y = ypos+150;
				label.LabelProp = string.Format( "{0}-{1}", c.ID, c.ShortName);
				label.Show();

				xpos+=30;
				if(lastKnownWidth < xpos +30)
				{
					xpos = 10; 
					ypos += 215;
				}
			}

			posLabel.Text = string.Format("n°{0}",sequenceur.IndexEffetCourrant +1);

			fullUpdFlag=false;
		}

		bool updating=false;
		void TiretteActionee (object sender, EventArgs e)
		{
			if (updating)return;
			VScale t = sender as VScale;
			Circuit c = t.Data[circuitKey] as Circuit;
			sequenceur.ChangeValeur(c,(int)(t.Value));
		}

		protected void UpdateValues()
		{
			updating = true;
			foreach (Circuit c in tirettes.Keys) {
				tirettes[c].Value = sequenceur.ValeurBruteCircuit(c);
				string tname;
				if(sequenceur.EstChange(c)){ 
					if (sequenceur.EstCapture(c))
						tname="sclTiretteM";
					else 
						tname="sclTiretteC";
				}
				else if (sequenceur.EnTransition(c))
					tname="sclTiretteT";
				else
					tname="sclTirette";
				if (tirettes[c].Name != tname) tirettes[c].Name = tname;
			}
			seqMasterScale.Value = sequenceur.Master;
			updating=false;
		}	

		protected void OnZoneWidSizeAllocated (object o, SizeAllocatedArgs args)
		{
			if (!fullUpdFlag) {
				if(lastKnownWidth != args.Allocation.Width)
					FullUpdate ();
			}
		}		

		int IndexEffetSelectionne()
		{
			var sel = effetsListe.Selection.GetSelectedRows();
			if(sel.Length ==0) return -1;
			return effetsListe.Selection.GetSelectedRows()[0].Indices[0];
		}

		protected void OnSaveActionActivated (object sender, EventArgs e)
		{
			int pos = sequenceur.SauveEffet("Nouvel Effet", TimeSpan.Zero,TimeSpan.FromSeconds(5));
			UpdListeEffets();
			effetChange = true; Update(false);
			effetsListe.SetCursor(new TreePath( new int[1] {pos})  ,nomCol,true);
		}


		protected void OnGoForwardActionActivated (object sender, EventArgs e)
		{
			// Si l'effet courant est selectioné, on passe au suivant, sinon, on passe a celui selectionné.
			if(sequenceur.IndexEffetCourrant == IndexEffetSelectionne())
				sequenceur.IndexEffetCourrant++;
			else
				sequenceur.IndexEffetCourrant = IndexEffetSelectionne();
		}

		protected void OnGoBackActionActivated (object sender, EventArgs e)
		{
			sequenceur.IndexEffetCourrant--;
		}

		protected void OnMediaPauseActionActivated (object sender, EventArgs e)
		{
			sequenceur.Paused = ! sequenceur.Paused;
		}		

		protected void OnMediaNextActionActivated (object sender, EventArgs e)
		{
			sequenceur.FinDeTransition();
		}

		protected void OnApplyActionActivated (object sender, EventArgs e)
		{
			int pos = IndexEffetSelectionne();
			if(pos==-1) return;
			sequenceur.RemplaceEffet(pos);
			UpdListeEffets();
			effetChange = true; Update(false);
		}		

		protected void OnSaveAfterActionActivated (object sender, EventArgs e)
		{
			int pos = sequenceur.InsereEffetApres(IndexEffetSelectionne(),"Nouvel Effet",TimeSpan.Zero,TimeSpan.FromSeconds(5));
			UpdListeEffets();
			effetChange = true; Update(false);
			effetsListe.SetCursor(new TreePath( new int[1] {pos})  ,nomCol,true);
		}	

		protected void OnDeleteActionActivated (object sender, EventArgs e)
		{
			int pos = IndexEffetSelectionne();
			if(pos==-1) return;
			sequenceur.SupprimeEffet(pos);
			UpdListeEffets();
			effetChange = true; Update(false);
		}

		protected void OnMoveUpActionActivated (object sender, EventArgs e)
		{
			int pos = IndexEffetSelectionne();
			if(pos==-1) return;
			pos = sequenceur.MonteEffet(pos);
			UpdListeEffets();
			effetChange = true; Update(false);
		}
	
		protected void OnMoveDownActionActivated (object sender, EventArgs e)
		{
			int pos = IndexEffetSelectionne();
			if(pos==-1) return;
			pos = sequenceur.BaisseEffet(pos);
			UpdListeEffets();
			effetChange = true; Update(false);
		}

		protected void OnSeqMasterScaleValueChanged (object sender, EventArgs e)
		{
			if (updating)return;
			sequenceur.Master = (int)(seqMasterScale.Value);
		}		


	}
}

