﻿using System;
using System.Collections.Generic;
using Oni.Akira;
using Oni.Motoko;

namespace Oni.Physics
{
    internal class ObjectDatReader
    {
        public static ObjectNode ReadObjectGeometry(InstanceDescriptor ofga)
        {
            ObjectGeometry[] geometries = null;
            ObjectParticle[] particles = new ObjectParticle[0];

            if (ofga.Template.Tag == TemplateTag.OFGA)
            {
                using (var reader = ofga.OpenRead(16))
                {
                    var particlesDescriptor = reader.ReadInstance();
                    geometries = ReadGeometries(reader);

                    if (particlesDescriptor != null)
                        particles = ReadParticles(particlesDescriptor);
                }
            }
            else if (ofga.Template.Tag == TemplateTag.M3GM)
            {
                geometries = new ObjectGeometry[1];

                geometries[0] = new ObjectGeometry
                {
                    Flags = GunkFlags.NoOcclusion,
                    Geometry = GeometryDatReader.Read(ofga)
                };
            }

            return new ObjectNode(geometries, particles);
        }

        private static ObjectGeometry[] ReadGeometries(BinaryReader reader)
        {
            uint partCount = reader.ReadUInt32();

            var nodes = new ObjectGeometry[partCount];

            for (int i = 0; i < nodes.Length; i++)
                nodes[i] = ReadGeometry(reader);

            return nodes;
        }

        private static ObjectGeometry ReadGeometry(BinaryReader reader)
        {
            var node = new ObjectGeometry
            {
                Flags = (GunkFlags)reader.ReadInt32(),
                Geometry = GeometryDatReader.Read(reader.ReadInstance())
            };

            reader.Skip(4);

            return node;
        }

        private static ObjectParticle[] ReadParticles(InstanceDescriptor particlesDescriptor)
        {
            using (var reader = particlesDescriptor.OpenRead(22))
            {
                var particles = new ObjectParticle[reader.ReadUInt16()];

                for (int i = 0; i < particles.Length; i++)
                    particles[i] = ReadParticle(reader);

                return particles;
            }
        }

        private static ObjectParticle ReadParticle(BinaryReader reader)
        {
            var particle = new ObjectParticle
            {
                ParticleClass = reader.ReadString(64),
                Tag = reader.ReadString(48),
                Matrix = reader.ReadMatrix4x3(),
                DecalScale = reader.ReadVector2(),
                Flags = (Objects.ParticleFlags)reader.ReadUInt16()
            };

            reader.Skip(38);

            return particle;
        }

        public static ObjectAnimation ReadAnimation(InstanceDescriptor oban)
        {
            var animation = new ObjectAnimation
            {
                Name = oban.Name
            };

            using (var reader = oban.OpenRead(12))
            {
                animation.Flags = (ObjectAnimationFlags)reader.ReadInt32();
                reader.Skip(48);
                var scale = reader.ReadMatrix4x3().Scale;
                reader.Skip(2);
                animation.Length = reader.ReadUInt16();
                animation.Stop = reader.ReadInt16();
                animation.Keys = new ObjectAnimationKey[reader.ReadUInt16()];

                for (int i = 0; i < animation.Keys.Length; i++)
                {
                    animation.Keys[i] = new ObjectAnimationKey
                    {
                        Scale = scale,
                        Rotation = reader.ReadQuaternion(),
                        Translation = reader.ReadVector3(),
                        Time = reader.ReadInt32()
                    };
                }
            }

            return animation;
        }
    }
}
