/**********************************************************************************
* Blueprint Reality Inc. CONFIDENTIAL
* 2019 Blueprint Reality Inc.
* All Rights Reserved.
*
* NOTICE:  All information contained herein is, and remains, the property of
* Blueprint Reality Inc. and its suppliers, if any.  The intellectual and
* technical concepts contained herein are proprietary to Blueprint Reality Inc.
* and its suppliers and may be covered by Patents, pending patents, and are
* protected by trade secret or copyright law.
*
* Dissemination of this information or reproduction of this material is strictly
* forbidden unless prior written permission is obtained from Blueprint Reality Inc.
***********************************************************************************/

using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using Thrift.Configuration;
using Thrift.Protocol;
using Thrift.Transport;
using UnityEngine;

namespace BlueprintReality.MixCast.Data
{
    public partial class ConnectionLookupTable : IDisposable
    {
        private string filepath;
        private FileSystemWatcher watcher;
        private Dictionary<string, ConnectionConfig> configs = new Dictionary<string, ConnectionConfig>();

        public event Action TableRebuilt;

        public ConnectionLookupTable(string filepath)
        {
            this.filepath = filepath;

            if (!string.IsNullOrEmpty(filepath))
            {
                watcher = new FileSystemWatcher(Path.GetDirectoryName(filepath), Path.GetFileName(filepath));
                watcher.Created += HandleFileCreated;
                watcher.Changed += HandleFileChanged;
                watcher.Deleted += HandleFileDeleted;
                watcher.Renamed += HandleFileRenamed;

                RebuildTable();

                watcher.EnableRaisingEvents = true;
            }
        }

        public void Dispose()
        {
            if (!string.IsNullOrEmpty(filepath))
            {
                watcher.Created -= HandleFileCreated;
                watcher.Changed -= HandleFileChanged;
                watcher.Deleted -= HandleFileDeleted;
                watcher.Renamed -= HandleFileRenamed;
                watcher.Dispose();
            }
        }

        public bool HasConnection(string configId)
        {
            lock (configs)
                return configs.ContainsKey(configId);
        }
        public ConnectionConfig GetConnection(string configId)
        {
            lock (configs)
            {
                ConnectionConfig newVal;
                if (configs.TryGetValue(configId, out newVal))
                    return newVal;
            }
            return null;
        }

        void RebuildTable()
        {
            if (File.Exists(filepath))
            {
                using (FileStream file = new FileStream(filepath, FileMode.Open))
                {
                    using (BinaryReader binary = new BinaryReader(file))
                    {
                        lock (configs)
                        {
                            configs.Clear();

                            int configCount = binary.ReadInt32();
                            for (int i = 0; i < configCount; i++)
                            {
                                string configId = binary.ReadString();
                                int configSize = binary.ReadInt32();
                                byte[] configData = binary.ReadBytes(configSize);
                                ConnectionConfig config = TMemoryBuffer.DeSerialize<TBinaryProtocol>(configData, typeof(ConnectionConfig)) as ConnectionConfig;
                                configs.Add(configId, config);
                            }
                        }
                    }
                }
            }
            else
            {
                lock (configs)
                    configs.Clear();
            }

            if (TableRebuilt != null)
                TableRebuilt();
        }

        private void HandleFileCreated(object sender, FileSystemEventArgs e)
        {
            RebuildTable();
        }
        private void HandleFileChanged(object sender, FileSystemEventArgs e)
        {
            RebuildTable();
        }
        private void HandleFileRenamed(object sender, RenamedEventArgs e)
        {
            RebuildTable();
        }
        private void HandleFileDeleted(object sender, FileSystemEventArgs e)
        {
            RebuildTable();
        }
    }
}
