﻿using System;
using System.Collections.Generic;
using System.IO;
using Oni.Imaging;

namespace Oni.Motoko
{
    internal class TextureDaeWriter
    {
        private readonly string outputDirPath;
        private readonly Dictionary<InstanceDescriptor, Dae.Material> materials = new Dictionary<InstanceDescriptor, Dae.Material>();

        public TextureDaeWriter(string outputDirPath)
        {
            this.outputDirPath = outputDirPath;
        }

        public Dae.Material WriteMaterial(InstanceDescriptor txmp)
        {
            Dae.Material material;

            if (!materials.TryGetValue(txmp, out material))
            {
                material = CreateMaterial(txmp);
                materials.Add(txmp, material);
            }

            return material;
        }

        private Dae.Material CreateMaterial(InstanceDescriptor txmp)
        {
            var texture = TextureDatReader.Read(txmp);

            var imageFilePath = Utils.CleanupTextureName(txmp.Name) + ".tga";
            imageFilePath = Path.Combine("images", imageFilePath);
            TgaWriter.Write(texture.Surfaces[0], Path.Combine(outputDirPath, imageFilePath));

            string name = TextureNameToId(txmp);

            var image = new Dae.Image
            {
                FilePath = "./" + imageFilePath.Replace('\\', '/'),
                Name = name
            };

            var effectSurface = new Dae.EffectSurface(image);

            var effectSampler = new Dae.EffectSampler(effectSurface)
            {
                WrapS = texture.WrapU ? Dae.EffectSamplerWrap.Wrap : Dae.EffectSamplerWrap.None,
                WrapT = texture.WrapV ? Dae.EffectSamplerWrap.Wrap : Dae.EffectSamplerWrap.None
            };

            var effectTexture = new Dae.EffectTexture(effectSampler, "diffuse_TEXCOORD");

            var effect = new Dae.Effect
            {
                Name = name,
                DiffuseValue = effectTexture,
                TransparentValue = texture.HasAlpha ? effectTexture : null,
                Parameters = {
                    new Dae.EffectParameter("surface", effectSurface),
                    new Dae.EffectParameter("sampler", effectSampler)
                }
            };

            var material = new Dae.Material
            {
                Name = name,
                Effect = effect
            };

            return material;
        }

        private static string TextureNameToId(InstanceDescriptor txmp)
        {
            string name = Utils.CleanupTextureName(txmp.Name);

            if (name.StartsWith("Iteration", StringComparison.Ordinal))
            {
                //
                // HACK: discard Iteration_NNN_ prefixes to avoid truncation of material
                // names in Blender.
                //

                name = name.Substring(9);

                if (char.IsDigit(name[0]) && char.IsDigit(name[1]) && char.IsDigit(name[2]) && name[3] == '_')
                    name = name.Substring(4);
            }

            return name;
        }
    }
}
