﻿using System;
using System.Collections.Generic;
using System.IO;

namespace Oni.Game
{
    internal class CharacterClass
    {
        public InstanceDescriptor Body;
        public InstanceDescriptor[] Textures;
        public IEnumerable<InstanceDescriptor> Animations;
        public InstanceDescriptor Animation;

        public static CharacterClass Read(InstanceDescriptor descriptor)
        {
            return Read(descriptor, null);
        }

        public static CharacterClass Read(InstanceDescriptor descriptor, string animationName)
        {
            if (descriptor.Template.Tag != TemplateTag.ONCC)
                throw new ArgumentException(string.Format("The specified descriptor has a wrong template {0}", descriptor.Template.Tag), "descriptor");

            var character = new CharacterClass();

            InstanceDescriptor trma;
            InstanceDescriptor trac;

            using (var reader = descriptor.OpenRead(0xC34))
            {
                character.Body = reader.ReadInstance();
                trma = reader.ReadInstance();
                reader.Skip(0x44);
                trac = reader.ReadInstance();
            }

            if (trma != null)
            {
                using (var reader = trma.OpenRead(22))
                    character.Textures = reader.ReadInstanceArray(reader.ReadUInt16());
            }

            var animationList = new List<InstanceDescriptor>();

            while (trac != null)
            {
                InstanceDescriptor childCollection;

                using (var reader = trac.OpenRead(16))
                {
                    childCollection = reader.ReadInstance();
                    reader.Skip(2);
                    int count = reader.ReadUInt16();

                    for (int i = 0; i < count; i++)
                    {
                        reader.Skip(8);
                        var tram = reader.ReadInstance();

                        if (tram != null)
                            animationList.Add(tram);
                    }
                }

                trac = childCollection;
            }

            character.Animations = animationList;

            if (string.Equals(Path.GetExtension(animationName), ".oni", StringComparison.OrdinalIgnoreCase))
            {
                var file = descriptor.File.FileManager.OpenFile(animationName);

                if (file != null && file.Descriptors[0].Template.Tag == TemplateTag.TRAM)
                    character.Animation = file.Descriptors[0];
            }
            else
            {
                if (!string.IsNullOrEmpty(animationName) && !animationName.StartsWith("TRAM", StringComparison.Ordinal))
                    animationName = "TRAM" + animationName;

                foreach (var tram in animationList)
                {
                    using (var animReader = tram.OpenRead(0x15A))
                    {
                        int type = animReader.ReadInt16();
                        animReader.Skip(2);
                        int fromState = animReader.ReadInt16();
                        int toState = animReader.ReadInt16();
                        animReader.Skip(6);
                        int varient = animReader.ReadInt16();

                        if (!string.IsNullOrEmpty(animationName))
                        {
                            if (tram.FullName == animationName)
                            {
                                character.Animation = tram;
                                break;
                            }
                        }
                        else
                        {
                            if (type == 6
                                && fromState == 7
                                && toState == 7
                                && varient == 0)
                            {
                                character.Animation = tram;
                                break;
                            }
                        }
                    }
                }

                if (!string.IsNullOrEmpty(animationName) && character.Animation == null)
                    Console.Error.WriteLine("Animation {0} was not found", animationName);
            }

            return character;
        }
    }
}
