// <auto-generated />
//
// To parse this JSON data, add NuGet 'Newtonsoft.Json' then do:
//
//    using FModel.Parser.Meshes;
//
//    var meshesParser = MeshesParser.FromJson(jsonString);

using System;
using System.Globalization;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;

namespace FModel.Parser.Meshes
{
    public partial class MeshesParser
    {
        [JsonProperty("super_object")]
        public SuperObject SuperObject { get; set; }

        [JsonProperty("imported_bounds")]
        public ImportedBounds ImportedBounds { get; set; }

        [JsonProperty("materials")]
        public Material[] Materials { get; set; }

        [JsonProperty("ref_skeleton")]
        public RefSkeleton RefSkeleton { get; set; }

        [JsonProperty("lod_models")]
        public LodModel[] LodModels { get; set; }
    }

    public class ImportedBounds
    {
        [JsonProperty("origin")]
        public BoxExtend Origin { get; set; }

        [JsonProperty("box_extend")]
        public BoxExtend BoxExtend { get; set; }

        [JsonProperty("sphere_radius")]
        public double SphereRadius { get; set; }
    }

    public class BoxExtend
    {
        [JsonProperty("x")]
        public double X { get; set; }

        [JsonProperty("y")]
        public double Y { get; set; }

        [JsonProperty("z")]
        public double Z { get; set; }

        [JsonProperty("w", NullValueHandling = NullValueHandling.Ignore)]
        public double? W { get; set; }
    }

    public class LodModel
    {
        [JsonProperty("sections")]
        public Section[] Sections { get; set; }

        [JsonProperty("indices")]
        public Indices Indices { get; set; }

        [JsonProperty("active_bone_indices")]
        public long[] ActiveBoneIndices { get; set; }

        [JsonProperty("required_bones")]
        public long[] RequiredBones { get; set; }

        [JsonProperty("position_vertex_buffer")]
        public PositionVertexBuffer PositionVertexBuffer { get; set; }

        [JsonProperty("static_mesh_vertex_buffer")]
        public StaticMeshVertexBuffer StaticMeshVertexBuffer { get; set; }

        [JsonProperty("skin_weight_vertex_buffer")]
        public SkinWeightVertexBuffer SkinWeightVertexBuffer { get; set; }

        [JsonProperty("colour_vertex_buffer")]
        public object ColourVertexBuffer { get; set; }
    }

    public class Indices
    {
        [JsonProperty("Indices16")]
        public long[] Indices16 { get; set; }
    }

    public class PositionVertexBuffer
    {
        [JsonProperty("verts")]
        public BoxExtend[] Verts { get; set; }

        [JsonProperty("stride")]
        public long Stride { get; set; }

        [JsonProperty("num_verts")]
        public long NumVerts { get; set; }
    }

    public class Section
    {
        [JsonProperty("material_index")]
        public long MaterialIndex { get; set; }

        [JsonProperty("base_index")]
        public long BaseIndex { get; set; }

        [JsonProperty("num_triangles")]
        public long NumTriangles { get; set; }

        [JsonProperty("base_vertex_index")]
        public long BaseVertexIndex { get; set; }

        [JsonProperty("cloth_mapping_data")]
        public object[] ClothMappingData { get; set; }

        [JsonProperty("bone_map")]
        public long[] BoneMap { get; set; }

        [JsonProperty("num_vertices")]
        public long NumVertices { get; set; }

        [JsonProperty("max_bone_influences")]
        public long MaxBoneInfluences { get; set; }

        [JsonProperty("clothing_data")]
        public ClothingData ClothingData { get; set; }

        [JsonProperty("disabled")]
        public bool Disabled { get; set; }
    }

    public class ClothingData
    {
        [JsonProperty("asset_guid")]
        public string AssetGuid { get; set; }

        [JsonProperty("asset_lod_index")]
        public long AssetLodIndex { get; set; }
    }

    public class SkinWeightVertexBuffer
    {
        [JsonProperty("weights")]
        public Weight[] Weights { get; set; }

        [JsonProperty("num_vertices")]
        public long NumVertices { get; set; }
    }

    public class Weight
    {
        [JsonProperty("bone_index")]
        public long[] BoneIndex { get; set; }

        [JsonProperty("bone_weight")]
        public long[] BoneWeight { get; set; }
    }

    public class StaticMeshVertexBuffer
    {
        [JsonProperty("num_tex_coords")]
        public long NumTexCoords { get; set; }

        [JsonProperty("num_vertices")]
        public long NumVertices { get; set; }

        [JsonProperty("tangents")]
        public Tangents Tangents { get; set; }

        [JsonProperty("uvs")]
        public Uvs Uvs { get; set; }
    }

    public class Tangents
    {
        [JsonProperty("Low")]
        public TangentsLow[] Low { get; set; }
    }

    public class TangentsLow
    {
        [JsonProperty("normal")]
        public BoxExtend Normal { get; set; }

        [JsonProperty("tangent")]
        public BoxExtend Tangent { get; set; }
    }

    public class Uvs
    {
        [JsonProperty("Low")]
        public UvsLow[] Low { get; set; }
    }

    public class UvsLow
    {
        [JsonProperty("value")]
        public Value Value { get; set; }
    }

    public class Value
    {
        [JsonProperty("x")]
        public long X { get; set; }

        [JsonProperty("y")]
        public long Y { get; set; }
    }

    public class Material
    {
        [JsonProperty("material_interface")]
        public string MaterialInterface { get; set; }

        [JsonProperty("material_slot_name")]
        public string MaterialSlotName { get; set; }

        [JsonProperty("uv_channel_data")]
        public UvChannelData UvChannelData { get; set; }
    }

    public class UvChannelData
    {
        [JsonProperty("initialised")]
        public bool Initialised { get; set; }

        [JsonProperty("override_densities")]
        public bool OverrideDensities { get; set; }

        [JsonProperty("local_uv_densities")]
        public double[] LocalUvDensities { get; set; }
    }

    public class RefSkeleton
    {
        [JsonProperty("ref_bone_info")]
        public RefBoneInfo[] RefBoneInfo { get; set; }

        [JsonProperty("ref_bone_pose")]
        public RefBonePose[] RefBonePose { get; set; }

        [JsonProperty("name_to_index")]
        public NameToIndex[][] NameToIndex { get; set; }
    }

    public class RefBoneInfo
    {
        [JsonProperty("name")]
        public string Name { get; set; }

        [JsonProperty("parent_index")]
        public long ParentIndex { get; set; }
    }

    public class RefBonePose
    {
        [JsonProperty("rotation")]
        public BoxExtend Rotation { get; set; }

        [JsonProperty("translation")]
        public BoxExtend Translation { get; set; }

        [JsonProperty("scale_3d")]
        public BoxExtend Scale3D { get; set; }
    }

    public class SuperObject
    {
        [JsonProperty("export_type")]
        public string ExportType { get; set; }

        [JsonProperty("Skeleton")]
        public string Skeleton { get; set; }

        [JsonProperty("LODInfo")]
        public LodInfo[] LodInfo { get; set; }

        [JsonProperty("MinLod")]
        public MinLod MinLod { get; set; }

        [JsonProperty("bHasBeenSimplified")]
        public bool BHasBeenSimplified { get; set; }

        [JsonProperty("SamplingInfo")]
        public SamplingInfo SamplingInfo { get; set; }
    }

    public class LodInfo
    {
        [JsonProperty("ScreenSize")]
        public MinLod ScreenSize { get; set; }

        [JsonProperty("LODHysteresis")]
        public double LodHysteresis { get; set; }

        [JsonProperty("LODMaterialMap")]
        public object[] LodMaterialMap { get; set; }

        [JsonProperty("ReductionSettings")]
        public ReductionSettings ReductionSettings { get; set; }

        [JsonProperty("BonesToRemove")]
        public object[] BonesToRemove { get; set; }

        [JsonProperty("BonesToPrioritize")]
        public object[] BonesToPrioritize { get; set; }

        [JsonProperty("WeightOfPrioritization")]
        public long WeightOfPrioritization { get; set; }

        [JsonProperty("BakePose")]
        [JsonConverter(typeof(ParseStringConverter))]
        public long BakePose { get; set; }

        [JsonProperty("BakePoseOverride")]
        [JsonConverter(typeof(ParseStringConverter))]
        public long BakePoseOverride { get; set; }

        [JsonProperty("SourceImportFilename")]
        public string SourceImportFilename { get; set; }

        [JsonProperty("bHasBeenSimplified")]
        public bool BHasBeenSimplified { get; set; }

        [JsonProperty("bHasPerLODVertexColors")]
        public bool BHasPerLodVertexColors { get; set; }

        [JsonProperty("bAllowCPUAccess")]
        public bool BAllowCpuAccess { get; set; }

        [JsonProperty("bSupportUniformlyDistributedSampling")]
        public bool BSupportUniformlyDistributedSampling { get; set; }
    }

    public class ReductionSettings
    {
        [JsonProperty("TerminationCriterion")]
        public string TerminationCriterion { get; set; }

        [JsonProperty("NumOfTrianglesPercentage")]
        public double NumOfTrianglesPercentage { get; set; }

        [JsonProperty("NumOfVertPercentage")]
        public double NumOfVertPercentage { get; set; }

        [JsonProperty("MaxNumOfTriangles")]
        public long MaxNumOfTriangles { get; set; }

        [JsonProperty("MaxNumOfVerts")]
        public long MaxNumOfVerts { get; set; }

        [JsonProperty("MaxDeviationPercentage")]
        public double MaxDeviationPercentage { get; set; }

        [JsonProperty("ReductionMethod")]
        public string ReductionMethod { get; set; }

        [JsonProperty("SilhouetteImportance")]
        public string SilhouetteImportance { get; set; }

        [JsonProperty("TextureImportance")]
        public string TextureImportance { get; set; }

        [JsonProperty("ShadingImportance")]
        public string ShadingImportance { get; set; }

        [JsonProperty("SkinningImportance")]
        public string SkinningImportance { get; set; }

        [JsonProperty("bRemapMorphTargets")]
        public bool BRemapMorphTargets { get; set; }

        [JsonProperty("bRecalcNormals")]
        public bool BRecalcNormals { get; set; }

        [JsonProperty("WeldingThreshold")]
        public double WeldingThreshold { get; set; }

        [JsonProperty("NormalsThreshold")]
        public long NormalsThreshold { get; set; }

        [JsonProperty("MaxBonesPerVertex")]
        public long MaxBonesPerVertex { get; set; }

        [JsonProperty("bEnforceBoneBoundaries")]
        public bool BEnforceBoneBoundaries { get; set; }

        [JsonProperty("VolumeImportance")]
        public long VolumeImportance { get; set; }

        [JsonProperty("bLockEdges")]
        public bool BLockEdges { get; set; }

        [JsonProperty("BaseLOD")]
        public long BaseLod { get; set; }
    }

    public class MinLod
    {
        [JsonProperty("cooked")]
        public bool Cooked { get; set; }

        [JsonProperty("value")]
        public double Value { get; set; }
    }

    public class SamplingInfo
    {
        [JsonProperty("BuiltData")]
        public BuiltData BuiltData { get; set; }
    }

    public class BuiltData
    {
        [JsonProperty("WholeMeshBuiltData")]
        public WholeMeshBuiltDatum[] WholeMeshBuiltData { get; set; }
    }

    public class WholeMeshBuiltDatum
    {
        [JsonProperty("prob")]
        public object[] Prob { get; set; }

        [JsonProperty("alias")]
        public object[] Alias { get; set; }

        [JsonProperty("total_weight")]
        public long TotalWeight { get; set; }
    }

    public struct NameToIndex
    {
        public long? Integer;
        public string String;

        public static implicit operator NameToIndex(long integer) => new NameToIndex { Integer = integer };
        public static implicit operator NameToIndex(string String) => new NameToIndex { String = String };
    }

    public partial class MeshesParser
    {
        public static MeshesParser[] FromJson(string json) => JsonConvert.DeserializeObject<MeshesParser[]>(json, Converter.Settings);
    }

    public static class Serialize
    {
        public static string ToJson(this MeshesParser[] self) => JsonConvert.SerializeObject(self, Converter.Settings);
    }

    internal static class Converter
    {
        public static readonly JsonSerializerSettings Settings = new JsonSerializerSettings
        {
            MetadataPropertyHandling = MetadataPropertyHandling.Ignore,
            DateParseHandling = DateParseHandling.None,
            Converters =
            {
                NameToIndexConverter.Singleton,
                new IsoDateTimeConverter { DateTimeStyles = DateTimeStyles.AssumeUniversal }
            }
        };
    }

    internal class NameToIndexConverter : JsonConverter
    {
        public override bool CanConvert(Type t) => t == typeof(NameToIndex) || t == typeof(NameToIndex?);

        public override object ReadJson(JsonReader reader, Type t, object existingValue, JsonSerializer serializer)
        {
            switch (reader.TokenType)
            {
                case JsonToken.Integer:
                    var integerValue = serializer.Deserialize<long>(reader);
                    return new NameToIndex { Integer = integerValue };
                case JsonToken.String:
                case JsonToken.Date:
                    var stringValue = serializer.Deserialize<string>(reader);
                    return new NameToIndex { String = stringValue };
            }
            throw new Exception("Cannot unmarshal type NameToIndex");
        }

        public override void WriteJson(JsonWriter writer, object untypedValue, JsonSerializer serializer)
        {
            var value = (NameToIndex)untypedValue;
            if (value.Integer != null)
            {
                serializer.Serialize(writer, value.Integer.Value);
                return;
            }
            if (value.String != null)
            {
                serializer.Serialize(writer, value.String);
                return;
            }
            throw new Exception("Cannot marshal type NameToIndex");
        }

        public static readonly NameToIndexConverter Singleton = new NameToIndexConverter();
    }

    internal class ParseStringConverter : JsonConverter
    {
        public override bool CanConvert(Type t) => t == typeof(long) || t == typeof(long?);

        public override object ReadJson(JsonReader reader, Type t, object existingValue, JsonSerializer serializer)
        {
            if (reader.TokenType == JsonToken.Null) return null;
            var value = serializer.Deserialize<string>(reader);
            long l;
            if (Int64.TryParse(value, out l))
            {
                return l;
            }
            throw new Exception("Cannot unmarshal type long");
        }

        public override void WriteJson(JsonWriter writer, object untypedValue, JsonSerializer serializer)
        {
            if (untypedValue == null)
            {
                serializer.Serialize(writer, null);
                return;
            }
            var value = (long)untypedValue;
            serializer.Serialize(writer, value.ToString());
        }

        public static readonly ParseStringConverter Singleton = new ParseStringConverter();
    }
}
