using System;
using System.Collections.Generic;
using Taobao.Top.Link.Channel.WebSocket;
using Top.Api;

namespace Taobao.Top.Link.Channel
{
    /// <summary>a channel pool that same uri sharing same channel
    /// </summary>
    public class ClientChannelSharedSelector : IClientChannelSelector
    {
        private static readonly int CONNECTTIMEOUT = 5000;
        private ITopLogger _logger;
        private Object _lockObject;
        private IDictionary<string, IClientChannel> _channels;

        /// <summary>get or set heartbeat interval time in milliseconds
        /// </summary>
        public int HeartbeatPeriod { get; set; }

        public ClientChannelSharedSelector() : this(Log.Instance) { }
        public ClientChannelSharedSelector(ITopLogger logger)
        {
            this._logger = logger;
            this._lockObject = new object();
            this._channels = new Dictionary<string, IClientChannel>();
        }

        public IClientChannel GetChannel(Uri uri)
        {
            if (!uri.Scheme.Equals("ws", StringComparison.InvariantCultureIgnoreCase))
                return null;

            var url = uri.ToString();

            if (!this.HaveChannel(url))
                lock (this._lockObject)
                    if (!this.HaveChannel(url))
                        this.AddChannel(url, this.WrapChannel(this.Connect(uri, CONNECTTIMEOUT)));

            return _channels[url];
        }
        public void ReturnChannel(IClientChannel channel) { }

        protected virtual IClientChannel Connect(Uri uri, int timeout)
        {
            return WebSocketClient.Connect(this._logger, uri, timeout);
        }
        private IClientChannel WrapChannel(IClientChannel channel)
        {
            if (this.HeartbeatPeriod > 0)
                channel.HeartbeatTimer = new ResetableTimer(this.HeartbeatPeriod);
            return channel;
        }
        private bool HaveChannel(string url)
        {
            return this._channels.ContainsKey(url) && this._channels[url].IsConnected;
        }
        private void AddChannel(string url, IClientChannel channel)
        {
            if (this._channels.ContainsKey(url))
                this._channels[url] = channel;
            else
                this._channels.Add(url, channel);
        }
    }
}