﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;

namespace Oni.Motoko
{
    internal class GeometryImporter : Importer
    {
        private readonly bool generateNormals;
        private readonly bool flatNormals;
        private readonly float shellOffset;
        private readonly bool overrideTextureName;
        private string textureName;

        public GeometryImporter(string[] args)
        {
            foreach (string arg in args)
            {
                if (arg == "-normals")
                {
                    generateNormals = true;
                }
                else if (arg == "-flat")
                {
                    flatNormals = true;
                }
                else if (arg == "-cel" || arg.StartsWith("-cel:", StringComparison.Ordinal))
                {
                    int i = arg.IndexOf(':');

                    if (i != -1)
                        shellOffset = float.Parse(arg.Substring(i + 1), CultureInfo.InvariantCulture);
                    else
                        shellOffset = 0.07f;
                }
                else if (arg.StartsWith("-tex:", StringComparison.Ordinal))
                {
                    textureName = arg.Substring(5);
                    overrideTextureName = true;
                }
            }
        }

        public ImporterDescriptor Import(string filePath, ImporterFile importer)
        {
            var scene = Dae.Reader.ReadFile(filePath);

            Dae.FaceConverter.Triangulate(scene);

            var daeInstances = new List<Dae.GeometryInstance>();

            foreach (var node in scene.Nodes)
            {
                var daeInstance = node.GeometryInstances.FirstOrDefault();

                if (daeInstance == null || daeInstance.Target == null)
                    continue;

                daeInstances.Add(daeInstance);
            }

            foreach (var daeInstance in daeInstances)
            {
                var daeGeometry = daeInstance.Target;

                var geometry = GeometryDaeReader.Read(daeGeometry, generateNormals, flatNormals, shellOffset);

                string textureFilePath = null;

                if (!overrideTextureName && daeInstance.Materials.Count > 0)
                    textureFilePath = ReadMaterial(daeInstance.Materials[0].Target);

                geometry.TextureName = Path.GetFileNameWithoutExtension(textureFilePath);

                return GeometryDatWriter.Write(geometry, importer);
            }

            return null;
        }

        public override void Import(string filePath, string outputDirPath)
        {
            var scene = Dae.Reader.ReadFile(filePath);

            Dae.FaceConverter.Triangulate(scene);

            var daeInstances = new List<Dae.GeometryInstance>();

            foreach (var node in scene.Nodes)
            {
                var daeInstance = node.GeometryInstances.FirstOrDefault();

                if (daeInstance == null || daeInstance.Target == null)
                    continue;

                daeInstances.Add(daeInstance);
            }

            foreach (var daeInstance in daeInstances)
            {
                var daeGeometry = daeInstance.Target;

                var geometry = GeometryDaeReader.Read(daeGeometry, generateNormals, flatNormals, shellOffset);
                geometry.Name = Path.GetFileNameWithoutExtension(filePath);

                if (daeInstances.Count > 1)
                    geometry.Name += daeGeometry.Name;

                string textureFilePath = null;

                if (!overrideTextureName && daeInstance.Materials.Count > 0)
                    textureFilePath = ReadMaterial(daeInstance.Materials[0].Target);

                WriteM3GM(geometry, textureFilePath, outputDirPath);
            }
        }

        private void WriteM3GM(Geometry geometry, string textureFilePath, string outputDirPath)
        {
            geometry.Name = MakeInstanceName(TemplateTag.M3GM, geometry.Name);

            if (string.IsNullOrEmpty(textureFilePath))
                geometry.TextureName = textureName;
            else
                geometry.TextureName = Path.GetFileNameWithoutExtension(textureFilePath);

            BeginImport();

            GeometryDatWriter.Write(geometry, ImporterFile);

            Write(outputDirPath);
        }

        private string ReadMaterial(Dae.Material material)
        {
            if (material == null || material.Effect == null)
                return null;

            var texture = material.Effect.Textures.FirstOrDefault(t => t.Channel == Dae.EffectTextureChannel.Diffuse);

            if (texture == null)
                return null;

            var sampler = texture.Sampler;

            if (sampler == null || sampler.Surface == null || sampler.Surface.InitFrom == null || string.IsNullOrEmpty(sampler.Surface.InitFrom.FilePath))
                return null;

            return sampler.Surface.InitFrom.FilePath;
        }
    }
}
