using System;
using System.Collections.ObjectModel;
using System.IO;
using Unity.Collections;
using UnityEngine;
namespace UnityEditor.U2D.Aseprite
{
    /// 
    /// Flags to define where data for a tileset is stored.
    /// 
    [Flags]
    public enum TileSetFlags
    {
        /// Includes a link to an external file
        IncludesLinkToExternal = 1,
        /// Includes a link to files in this file
        IncludesTilesInFile = 2,
        /// Misc
        Misc = 4,
    }
    /// 
    /// Parsed representation of an Aseprite Tileset chunk.
    /// Not supported yet.
    /// 
    public class TilesetChunk : BaseChunk
    {
        /// 
        public override ChunkTypes chunkType => ChunkTypes.Tileset;
        /// 
        /// The ID of the tileset.
        /// 
        public uint tileSetId { get; private set; }
        /// 
        /// Flags to define where data for a tileset is stored.
        /// 
        public TileSetFlags tileSetFlags { get; private set; }
        /// 
        /// The number of tiles in the tileset.
        /// 
        public uint noOfTiles { get; private set; }
        /// 
        /// Tile width in pixels.
        /// 
        public ushort width { get; private set; }
        /// 
        /// Tile height in pixels.
        /// 
        public ushort height { get; private set; }
        /// 
        /// The name of the tileset.
        /// 
        public string tileSetName { get; private set; }
        /// 
        /// The image data of the tiles.
        /// 
        public NativeArray[] tileImages { get; private set; }
        readonly ushort m_ColorDepth;
        readonly ReadOnlyCollection m_PaletteEntries;
        readonly byte m_AlphaPaletteEntry;
        internal TilesetChunk(uint chunkSize, ushort colorDepth, ReadOnlyCollection paletteEntries, byte alphaPaletteEntry) : base(chunkSize)
        {
            m_ColorDepth = colorDepth;
            m_PaletteEntries = paletteEntries;
            m_AlphaPaletteEntry = alphaPaletteEntry;
        }
        /// 
        /// Read and store the chunk data.
        /// 
        /// The active binary reader of the file.
        protected override void InternalRead(BinaryReader reader)
        {
            tileSetId = reader.ReadUInt32();
            tileSetFlags = (TileSetFlags)reader.ReadUInt32();
            noOfTiles = reader.ReadUInt32();
            width = reader.ReadUInt16();
            height = reader.ReadUInt16();
            var baseIndex = reader.ReadInt16();
            var reservedBytes = reader.ReadBytes(14);
            tileSetName = AsepriteUtilities.ReadString(reader);
            if (string.IsNullOrEmpty(tileSetName))
                tileSetName = $"Tileset_{tileSetId}";
            // Not supported yet.
            if ((tileSetFlags & TileSetFlags.IncludesLinkToExternal) != 0)
            {
                var idOfExternalFile = reader.ReadUInt32();
                var tileSetIdInExternal = reader.ReadUInt32();
            }
            if ((tileSetFlags & TileSetFlags.IncludesTilesInFile) != 0)
            {
                var compressedDataLength = (int)reader.ReadUInt32();
                var decompressedData = AsepriteUtilities.ReadAndDecompressedData(reader, compressedDataLength);
                using var tilemapImage = AsepriteUtilities.GenerateImageData(m_ColorDepth, decompressedData, m_PaletteEntries, m_AlphaPaletteEntry);
                tileImages = new NativeArray[noOfTiles];
                for (var i = 0; i < noOfTiles; ++i)
                {
                    var tileImage = new NativeArray(width * height, Allocator.Persistent);
                    var tileStartHeight = i * height;
                    for (var m = 0; m < height; ++m)
                    {
                        var sourceHeight = (tileStartHeight + m) * width;
                        var destHeight = m * width;
                        NativeArray.Copy(tilemapImage, sourceHeight, tileImage, destHeight, width);
                    }
                    tileImages[i] = tileImage;
                }
            }
        }
        /// 
        /// Dispose of the image data.
        /// 
        public override void Dispose()
        {
            if (tileImages == null || tileImages.Length == 0)
                return;
            for (var i = 0; i < tileImages.Length; ++i)
                tileImages[i].DisposeIfCreated();
        }
    }
}