// Created with MonoDevelop
//
//    Copyright (C) 2023 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 System.Linq;
using Hiperscan.SGS.Common;

namespace Hiperscan.SGS
{
    public partial class DeviceList
    {
        public IEnumerable<IDevice> Values
        {
            get
            {
                lock (this)
                    return new List<IDevice>(this.Devices.Values);
            }
        }

        public IEnumerable<string> Serials
        {
            get
            {
                lock (this)
                    return new List<string>(this.Devices.Keys);
            }
        }

        public bool AllIdleOrDisconnected
        {
            get
            {
                bool result = true;

                lock (this)
                {
                    foreach (IDevice dev in this.Devices.Values)
                    {
                        Spectrometer.State state = dev.GetState();
                        if (state != Spectrometer.State.Idle &&
                            state != Spectrometer.State.Disconnected &&
                            state != Spectrometer.State.Unknown)
                        {
                            result = false;
                            break;
                        }
                    }
                }
                return result;
            }
        }

        public int Count
        {
            get
            {
                lock (this)
                    return this.Devices.Count;
            }
        }

        public IDevice this[string key]
        {
            get
            {
                lock (this)
                {
                    if (this.Devices.ContainsKey(key))
                        return this.Devices[key];
                    else
                        return null;
                }
            }
        }

        public bool ContainsSerial(string serial)
        {
            lock (this)
                return this.Devices.ContainsKey(serial);
        }

        public bool ContainsName(string name)
        {
            lock (this)
                return this.Devices.Values.Any(d => d.CurrentConfig.Name == name);
        }

        public IDevice GetFirstDevice()
        {
            lock (this)
                return this.Devices.Values.FirstOrDefault();
        }

        public IDevice GetByName(string name)
        {
            lock (this)
            {
                return this.Devices.Values.FirstOrDefault(d => d.CurrentConfig.Name == name);
            }
        }

        public bool Contains(IDevice dev)
        {
            lock (this)
                return this.Devices.ContainsValue(dev);
        }

        private void Dispose()
        {
            lock(this)
            {
                try
                {
                    this.DeviceFinder.Dispose();
                }
                catch(Exception ex)
                {
                    Console.WriteLine("Cannot dispose device list: {0}", ex.Message);
                }

                foreach (string serial in this.Devices.Keys.ToList())
                {
                    try
                    {
                        this.DisconnectAndRemoveDevice(serial);
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine("Cannot close device {0}: {1}", serial, ex.Message);
                    }
                }

                this.IsDisposed = true;

            }
        }

        private bool disable_timeout = false;
        public bool DisableTimeout
        {
            set 
            { 
                lock(this)
                    this.disable_timeout = value; 
            }
        }

        private bool activate_queues = false;
        public bool ActivateQueues
        {
            get
            {
                lock (this)
                    return this.activate_queues;
            }
            set
            {
                lock (this)
                {
                    foreach (IDevice dev in this.Devices.Values)
                        dev.SpectrumQueue.IsActive = value;

                    this.activate_queues = value;
                }
            }
        }

        private List<string> blacklist = new List<string>();
        public List<string> Blacklist
        {
            get
            {
                lock (this)
                    return new List<string>(this.blacklist);
            }
        }

        private Dictionary<string, IDevice> Devices { get; set; } = new Dictionary<string, IDevice>();
        private bool ConnectOnlyToRemoteDevices { get; set; } = false;
        private bool IsDisposed { get; set; } = false;
    }
}