// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.

namespace WixToolset.Dtf.Resources
{
    using System;
    using System.IO;
    using System.Text;
    using System.Reflection;
    using System.Collections;
    using System.Collections.Generic;
    using System.Globalization;
    using System.Diagnostics.CodeAnalysis;

    /// <summary>
    /// A subclass of Resource which provides specific methods for manipulating the resource data.
    /// </summary>
    /// <remarks>
    /// The resource is of type <see cref="ResourceType.GroupIcon"/> (RT_GROUPICON).
    /// </remarks>
    public sealed class GroupIconResource : Resource
    {
        internal bool dirty;
        private GroupIconInfo rawGroupIconInfo;
        private List<Resource> icons;

        /// <summary>
        /// Creates a new GroupIconResource object without any data. The data can be later loaded from a file.
        /// </summary>
        /// <param name="name">Name of the resource. For a numeric resource identifier, prefix the decimal number with a "#".</param>
        /// <param name="locale">Locale of the resource</param>
        public GroupIconResource(string name, int locale)
            : this(name, locale, null)
        {
        }

        /// <summary>
        /// Creates a new GroupIconResource object with data. The data can be later saved to a file.
        /// </summary>
        /// <param name="name">Name of the resource. For a numeric resource identifier, prefix the decimal number with a "#".</param>
        /// <param name="locale">Locale of the resource</param>
        /// <param name="data">Raw resource data</param>
        public GroupIconResource(string name, int locale, byte[] data)
            : base(ResourceType.GroupIcon, name, locale, data)
        {
            this.RefreshIconGroupInfo(data);
        }

        /// <summary>
        /// Gets or sets the raw data of the resource.  The data is in the format of the RT_GROUPICON resource structure.
        /// </summary>
        public override byte[] Data
        {
            get
            {
                if (this.dirty)
                {
                    base.Data = this.rawGroupIconInfo.GetResourceData();
                    this.dirty = false;
                }

                return base.Data;
            }
            set
            {
                this.RefreshIconGroupInfo(value);

                base.Data = value;
                this.dirty = false;
            }
        }

        /// <summary>
        /// Enumerates the the icons in the icon group.
        /// </summary>
        public IEnumerable<Resource> Icons { get { return this.icons; } }

        /// <summary>
        /// Reads the icon group from a .ico file.
        /// </summary>
        /// <param name="path">Path to an icon file (.ico).</param>
        public void ReadFromFile(string path)
        {
            this.rawGroupIconInfo = new GroupIconInfo();
            this.icons = new List<Resource>();
            using (FileStream fs = File.Open(path, FileMode.Open, FileAccess.Read, FileShare.Read))
            {
                this.rawGroupIconInfo.ReadFromFile(fs);

                // After reading the group icon info header from the file, read all the icons.
                for (int i = 0; i < this.rawGroupIconInfo.DirectoryInfo.Length; ++i)
                {
                    ushort index = this.rawGroupIconInfo.DirectoryInfo[i].imageIndex;
                    uint offset = this.rawGroupIconInfo.DirectoryInfo[i].imageOffset;
                    uint size = this.rawGroupIconInfo.DirectoryInfo[i].imageSize;
                    byte[] data = new byte[size];

                    fs.Seek(offset, SeekOrigin.Begin);
                    fs.Read(data, 0, data.Length);

                    Resource resource = new Resource(ResourceType.Icon, String.Concat("#", index), this.Locale, data);
                    this.icons.Add(resource);
                }
            }

            this.dirty = true;
        }

        private void RefreshIconGroupInfo(byte[] refreshData)
        {
            this.rawGroupIconInfo = new GroupIconInfo();
            this.icons = new List<Resource>();
            if (refreshData != null)
            {
                this.rawGroupIconInfo.ReadFromResource(refreshData);
            }

            this.dirty = true;
        }
    }
}