using System.Collections.Generic;
using System.IO;
using System.Linq;
using Mafia2Tool.DataFormats.FrameResources;

namespace Mafia2Tool.DataFormats
{
    public class FrameResource
    {
        class scene
        {
            float unk_float_00;
            float unk_float_01;
            Hash unk_name_02;

            Vector3[] unk_vectors_03; // not really vectors...
            bool unk_bool_04;

            public scene(BinaryReader r)
            {
                Read(r);
            }

            public void Read(BinaryReader r)
            {
                unk_float_00 = r.ReadSingle();
                unk_float_01 = r.ReadSingle();
                unk_name_02 = new Hash(r);

                unk_vectors_03 = new Vector3[4];
                for (int i = 0; i < 4; i++)
                {
                    unk_vectors_03[i] = new Vector3(r);
                }
                unk_bool_04 = r.ReadBoolean();
            }
        }

        scene _scene;

        public FrameResourceEntryList Objects;
        
        public List<BaseComponent> TopLevelObjects1
        {
            get
            {
                var tmp = Objects.GetHierachyObjects();
                if (tmp == null) return null;
                return new List<BaseComponent>(tmp.Where(c => c.ParentIndex1 == -1));
            }
        }

        public List<BaseComponent> TopLevelObjects2
        {
            get
            {
                var tmp = Objects.GetHierachyObjects();
                if (tmp == null) return null;
                return new List<BaseComponent>(tmp.Where(c => c.ParentIndex2 == -1));
            }
        }

        public FrameResource(BinaryReader r)
        {
            Read(r);
        }

        public void Read(BinaryReader r)
        {
            bool _bScene = r.ReadBoolean();

            int _numFolderNames = r.ReadInt32();
            int _numGeometries = r.ReadInt32();
            int _numMaterialResources = r.ReadInt32();
            int _numBlendInfos = r.ReadInt32();
            int _numSkeletons = r.ReadInt32();
            int _numSkelHierachies = r.ReadInt32();
            int _numObjects = r.ReadInt32();

            if (_bScene)
            {
                _scene = new scene(r);
            }

            int countAll = _numFolderNames + _numGeometries + _numMaterialResources + _numBlendInfos + _numSkeletons + _numSkelHierachies + _numObjects;
            Objects = new FrameResourceEntryList(countAll);

            for (int i = 0; i < _numFolderNames; i++)
            {
                FolderNameEntry o = new FolderNameEntry(r, Objects);
                Objects.Add(o);
            }

            for (int i = 0; i < _numGeometries; i++)
            {
                MeshDataEntry o = new MeshDataEntry(r, Objects);
                Objects.Add(o);
            }

            for (int i = 0; i < _numMaterialResources; i++)
            {
                MaterialInfoEntry o = new MaterialInfoEntry(r, Objects);
                Objects.Add(o);
            }

            for (int i = 0; i < _numBlendInfos; i++)
            {
                SkeletonBlendInfo o = new SkeletonBlendInfo(r, Objects);
                Objects.Add(o);
            }
            
            for (int i = 0; i < _numSkeletons; i++)
            {
                SkeletonEntry o = new SkeletonEntry(r, Objects);
                Objects.Add(o);
            }

            for (int i = 0; i < _numSkelHierachies; i++)
            {
                SkeletonHierachyEntry o = new SkeletonHierachyEntry(r, Objects);
                Objects.Add(o);
            }

            if (_numObjects > 0)
            {
                int[] objectTypeCode = new int[_numObjects];
                for (int i = 0; i < objectTypeCode.Length; i++)
                {
                    objectTypeCode[i] = r.ReadInt32();
                }

                for (int i = 0; i < _numObjects; i++)
                {
                    BaseComponent o = null;

                    switch (objectTypeCode[i])
                    {
                        case 0:
                            o = new JointComponent(r, Objects);
                            break;
                        case 1:
                            o = new SingleMeshComponent(r, Objects);
                            break;
                        case 2:
                            o = new FrameComponent(r, Objects);
                            break;
                        case 3:
                            o = new LightComponent(r, Objects);
                            break;
                        case 4:
                            o = new CameraComponent(r, Objects);
                            break;
                        case 5:
                            o = new Component_U00000005(r, Objects);
                            break;
                        case 6:
                            o = new SectorComponent(r, Objects);
                            break;
                        case 7:
                            o = new DummyComponent(r, Objects);
                            break;
                        case 0x0000000a:
                            o = new ParticleDeflectorComponent(r, Objects);
                            break;
                        case 0x0000000c:
                            o = new AreaComponent(r, Objects);
                            break;
                        case 0x0000000e:
                            o = new TargetComponent(r, Objects);
                            break;
                        case 0x00000011:
                            o = new ModelComponent(r, Objects);
                            break;
                        case 0x00001d8:
                            o = new CollisionComponent(r, Objects);
                            break;

                        default:
                            break;
                    }

                    Objects.Add(o);
                }
            }
        }
    }
}
