using System;
using System.IO;
using System.IO.MemoryMappedFiles;

namespace XGame.Framework.Logger
{
    struct MMFileHeader
    {
        public int position;
        public int length;

        public readonly static int PositionIndex = 0;
        public readonly static int LengthIndex = PositionIndex + sizeof(int);
        public readonly static int FileIndex = LengthIndex + sizeof(int);

        public readonly static int ContextIndex = FileIndex;
    }

    class MMFile : IDisposable
    {
        private MemoryMappedFile _mmf;
        private MemoryMappedViewAccessor _accessor;

        public MMFile(string path, uint capacity = 2048)
        {
            try
            {
                if (!File.Exists(path))
                {
                    using (var filesteam = File.Create(path))
                    {
                        filesteam.SetLength(capacity);
                        _mmf = MemoryMappedFile.CreateFromFile(filesteam, null, capacity, MemoryMappedFileAccess.ReadWrite, HandleInheritability.None, true);
                    }
                }
                else 
                {
                    using (var filesteam = File.Open(path, FileMode.Open, FileAccess.ReadWrite))
                    {
                        filesteam.SetLength(capacity);
                        _mmf = MemoryMappedFile.CreateFromFile(filesteam, null, capacity, MemoryMappedFileAccess.ReadWrite, HandleInheritability.None, true);
                    }
                }
                _accessor = _mmf.CreateViewAccessor(0, capacity, MemoryMappedFileAccess.ReadWrite);
                var header = ReadHeader();
                header.length = (int)capacity;
                WriteHeader(header);
            }
            catch(System.Exception e) 
            {
                UnityEngine.Debug.LogException(e);
            }
        }

        public MMFileHeader ReadHeader() 
        {
            if (_accessor == null)
                throw new Exception("存取器尚未初始化！！！");

            var header = new MMFileHeader();

            header.position = _accessor.ReadInt32(0);
            header.length = _accessor.ReadInt32(4);
            return header;
        }

        public void WriteHeader(MMFileHeader header)
        {
            if (_accessor == null)
                throw new Exception("存取器尚未初始化！！！");

            _accessor.Write(MMFileHeader.PositionIndex, header.position);
            _accessor.Write(MMFileHeader.LengthIndex, header.length);
        }

        public byte[] ReadAll()
        {
            if (_accessor == null)
                throw new Exception("存取器尚未初始化！！！");

            var header = ReadHeader();
            var result = new byte[header.position];
            _accessor.ReadArray(MMFileHeader.ContextIndex, result, 0, header.position);
            return result;
        }

        public bool Write(byte[] souces, int offset, int length)
        {
            if (_accessor == null)
                throw new System.Exception("存取器尚未初始化");

            if (!_accessor.CanWrite)
                throw new System.Exception("存取器禁止写入");

            var header = ReadHeader();
            var absolutePosition = header.position + MMFileHeader.ContextIndex;

            if (absolutePosition + length > header.length) 
            {
                //var overflow = absolutePosition + length - header.length;
                //throw new MMFileOverflowException(overflow, "写入溢出！");
                return false;
            }

            _accessor.WriteArray(absolutePosition, souces, offset, length);
            header.position += length;
            WriteHeader(header);
            return true;
        }

        public void Reset() 
        {
            var header = ReadHeader();
            header.position = 0;
            WriteHeader(header);
        }

        public void Dispose()
        {
            _accessor?.Dispose();
            _mmf?.Dispose();
        }
    }
}
