using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using Halo3Map.IO;
using System.Reflection;
using System.Collections;
using System.Xml;

namespace Halo3Map.Data
{
    public class H3Reflexive<T> : List<T> where T : Chunk
    {
        private int chunkCount;
        public int ChunkCount { get { return chunkCount; } set { chunkCount = value; } }

        private int chunkSize;
        public int ChunkSize { get { return chunkSize; } }

        private uint pointer;
        public uint Pointer { get { return pointer; } set { pointer = value; } }

        private int mapOffset;
        public int MapOffset { get { return mapOffset; } }

        private int tagOffset;
        public int TagOffset { get { return tagOffset; } }

        private Map.Map map;
        public Map.Map Map { get { return map; } set { map = value; } }       

        public H3Reflexive(EndianReader br, Map.Map Map)
        {
            map = Map;

            //Remember our offset in tag
            tagOffset = (int)br.BaseStream.Position;

            Type t = typeof(T);
            object[] attributes = t.GetCustomAttributes(typeof(SizeAttribute), false);
            if (attributes.Length > 0)
                chunkSize = ((SizeAttribute)attributes[0]).Size;
            else
                MessageBox.Show("There is no size for this! Chunk Type: " + t.ToString());

            Read(br);

            //Return to our original offset + the reflex size
            br.BaseStream.Position = tagOffset + 12;
        }

        public void Read(EndianReader br)
        {
            chunkCount = br.ReadInt32();
            pointer = br.ReadUInt32();
            mapOffset = (int)(pointer - Map.Magic);

            if (chunkCount == 0)
                return;

            br.SeekTo(mapOffset);
            for (int x = 0; x < chunkCount; x++)
            {
                T reflexive = (T)Activator.CreateInstance(typeof(T));
                reflexive.Map = Map;
                reflexive.Read(br);
                Add(reflexive);
            }
        }

        public void Write(EndianWriter bw)
        {
            bw.SeekTo(mapOffset);
            for (int x = 0; x < chunkCount; x++)
            {
                T reflexive = (T)this[x];
                reflexive.Write(bw);
            }
        }

        public void Extract(EndianWriter bw, XmlTextWriter xtw)
        {
            for (int x = 0; x < chunkCount; x++)
            {
                T reflexive = (T)this[x];
                reflexive.Extract(bw, xtw);
            }
        }
        
        public void Inject(EndianReader br)
        {
            for (int x = 0; x < chunkCount; x++)
            {
                T reflexive = (T)this[x];
                reflexive.Inject(br);
            }
        }
    }
}