// 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.SGS.Common;
using Hiperscan.SGS.SerialInterface;
using Hiperscan.Unix;


namespace Hiperscan.QuickStep.Dialog
{

    public class SharedDevicesManagerDialog : Gtk.Dialog
    {
        
        private enum Store : int
        {
            Shared,
            Serial,
            Name,
            Port,
            Status,
            Device            
        }
        
        private TreeView tv;
        private readonly ScrolledWindow sw;
        private readonly Label label;
        private readonly DeviceList device_list;


        public SharedDevicesManagerDialog(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 += (sender, args) =>
            {
                try
                {
                    if (this.tv.Model.GetIterFromString(out TreeIter iter, args.Path))
                    {
                        bool val = (bool)this.tv.Model.GetValue(iter, (int)Store.Shared);
                        IDevice dev = (IDevice)this.tv.Model.GetValue(iter, (int)Store.Device);

                        this.tv.Model.SetValue(iter, (int)Store.Shared, !val);
                        UserInterface.Instance.ProcessEvents();

                        Spectrometer.State state = dev.GetState();
                        if (state != Spectrometer.State.Unprogrammed &&
                            state != Spectrometer.State.Disconnected &&
                            state != Spectrometer.State.Unknown &&
                            state != Spectrometer.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)
                {
                    InfoMessageDialog.Show(this,
                                           Catalog.GetString("Cannot (dis)connect device: {0}"),
                                           ex.Message);
                }
            };

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

            this.tv = new TreeView
            {
                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
            {
                HscrollbarPolicy = PolicyType.Automatic,
                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;
            RemoteSerialInterface.StateChanged += this.OnRemoteSerialInterfaceStateChanged;
            this.Update(device_list);
            
            this.Run();
            this.Destroy();
        }
        
        ~SharedDevicesManagerDialog()
        {
            RemoteSerialInterface.StateChanged -= this.OnRemoteSerialInterfaceStateChanged;
        }
        
        private void OnRemoteSerialInterfaceStateChanged()
        {
            Application.Invoke((sender, e) => 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(IDevice));
 
            List<string> serials = new List<string>(device_list.Keys);
            serials.Sort();
            bool device_found = false;
            foreach (string serial in serials)
            {
                IDevice dev = device_list[serial];
                
                if (dev.Info.IsRemote || dev.IsConnected == false)
                    continue;

                device_found = true;
                
                if (dev.IsShared)
                {
                    string status;
                    if (RemoteSerialInterface.IsConnected(dev))
                    {
                        status = string.Format(Catalog.GetString("Shared, connected to client on {0}"),
                                               RemoteSerialInterface.GetClientName(dev));
                    }
                    else
                    {
                        status = Catalog.GetString("Shared, not connected to a client");
                    }

                    store.AppendValues(true,
                                       dev.Info.SerialNumber,
                                       dev.CurrentConfig.Name,
                                       RemoteSerialInterface.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;
        }
    }
}