// SharedDevicesManager.cs created with MonoDevelop
// User: klose at 16:08 20.12.2010
// CVS release: $Id: SharedDevicesManager.cs,v 1.1 2011-01-06 16:36:28 klose Exp $
//
//    QuickStep: Acquire, view and identify spectra 
//    Copyright (C) 2010  Thomas Klose, Hiperscan GmbH Dresden, Germany
//
//    This program 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 3 of the License, or
//    (at your option) any later version.
//
//    This program 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, see <http://www.gnu.org/licenses/>.
//

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

using Hiperscan.SGS;
using Hiperscan.Unix;


namespace Hiperscan.GUI
{
	
	public class SharedDevicesManager : Gtk.Dialog
	{
		
		private enum Store : int
		{
			Shared,
			Serial,
			Name,
			Port,
			Status,
			Device			
		}
		
		private TreeView tv;
		private ScrolledWindow sw;
		private Label label;
		private DeviceList device_list;
		
		public SharedDevicesManager(DeviceList device_list) 
			: base(Catalog.GetString("Specify shared devices"), MainClass.MainWindow, DialogFlags.Modal)
		{
			this.device_list = device_list;
			
			this.AddButton(Stock.Close, ResponseType.Close);

			this.HasSeparator  = true;
			this.WidthRequest  = 700;
			this.HeightRequest = 350;
			
			CellRendererToggle toggle = new CellRendererToggle();
			toggle.Toggled += delegate(object sender, ToggledArgs args) {
				try
				{
					TreeIter iter;
					if (this.tv.Model.GetIterFromString(out iter, args.Path))
					{
						bool val = (bool)this.tv.Model.GetValue(iter, (int)Store.Shared);
						Device dev = (Device)this.tv.Model.GetValue(iter, (int)Store.Device);

						this.tv.Model.SetValue(iter, (int)Store.Shared, !val);
						UserInterface.ProcessEvents_();
						
						Device.State state = dev.GetState();
						if (state != Device.State.Unprogrammed &&
						    state != Device.State.Disconnected &&
						    state != Device.State.Unknown      &&
						    state != Device.State.Shared)
						{
							MainWindow.UI.StopStream(dev);
							dev.WaitForIdle(10000);
						}

						bool success;
						if (val)
							success = MainWindow.UI.UnshareDevice(this, dev);
						else
							success = MainWindow.UI.ShareDevice(this, dev);
						
						if (!success)
							this.tv.Model.SetValue(iter, (int)Store.Shared, val);
						
						GLib.Timeout.Add(100, delegate { 
							this.Update(device_list); 
							return false;
						});
					}
				}
				catch (Exception ex)
				{
					new InfoMessage(this, Catalog.GetString("Cannot (dis)connect device: {0}"), ex.Message);
				}
			};

			TreeViewColumn column = new TreeViewColumn(string.Empty, toggle, "active", Store.Shared);
			column.Widget = new Image(Stock.Network, IconSize.Menu);
			column.Widget.Show();

			this.tv = new TreeView();
 
			this.tv.RulesHint = true;
			this.tv.AppendColumn(column);
			this.tv.AppendColumn(Catalog.GetString("Serial number"), new CellRendererText(), "text",   Store.Serial);
			this.tv.AppendColumn(Catalog.GetString("Device name"),   new CellRendererText(), "text",   Store.Name);
			this.tv.AppendColumn(Catalog.GetString("TCP port"),      new CellRendererText(), "text",   Store.Port);
			this.tv.AppendColumn(Catalog.GetString("Status"),        new CellRendererText(), "text",   Store.Status);

			this.sw = new ScrolledWindow();
			this.sw.HscrollbarPolicy = PolicyType.Automatic;
			this.sw.VscrollbarPolicy = PolicyType.Automatic;
			this.sw.Add(this.tv);
			
			this.label = new Label(Catalog.GetString("No connected local devices available."));
				
			this.VBox.PackStart(sw);
			this.VBox.PackStart(label);
			this.VBox.Homogeneous = false;
			this.ShowAll();

			device_list.Changed += this.Update;
			SharedUSB.StateChanged += this.OnSharedUSBStateChanged;
			this.Update(device_list);
			
			this.Run();
			this.Destroy();
		}
		
		~SharedDevicesManager()
		{
			SharedUSB.StateChanged -= this.OnSharedUSBStateChanged;
		}
		
		private void OnSharedUSBStateChanged()
		{
			Application.Invoke(delegate {
				this.Update(this.device_list);
			});
		}
		
		private void Update(DeviceList device_list)
		{
			ListStore store = new ListStore(typeof(bool), typeof(string), typeof(string), typeof(string), typeof(string), typeof(Device));
 
			List<string> serials = new List<string>(device_list.Keys);
			serials.Sort();
			bool device_found = false;
			foreach (string serial in serials)
			{
				Device dev = device_list[serial];
				
				if (dev.Info.IsRemote || !dev.IsConnected)
					continue;

				device_found = true;
				
				if (dev.IsShared)
				{
					string status;
					if (SharedUSB.IsConnected(dev))
						status = string.Format(Catalog.GetString("Shared, connected to client on {0}"), SharedUSB.GetClientName(dev));
					else
						status = Catalog.GetString("Shared, not connected to a client");
						
					store.AppendValues(true,
					                   dev.Info.SerialNumber,
					                   dev.CurrentConfig.Name,
					                   SharedUSB.GetTcpPort(dev).ToString(),
					                   status,
					                   dev);
				}
				else
				{
					store.AppendValues(false,
					                   dev.Info.SerialNumber,
					                   dev.CurrentConfig.Name,
					                   Catalog.GetString("n/a"),
					                   Catalog.GetString("Not shared"),
					                   dev);
				}
			}

			this.tv.Model = store;

			this.label.Visible = !device_found;
			this.sw.Visible    =  device_found;
		}
	}
}
