﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Text;

namespace Oni
{
    internal abstract class Importer
    {
        private readonly ImporterFile file;
        private Dictionary<string, ImporterTask> dependencies;

        public Importer()
        {
            this.file = new ImporterFile();
        }

        protected Importer(long templateChecksum)
        {
            this.file = new ImporterFile(templateChecksum);
        }

        public ImporterFile ImporterFile => file;

        public virtual void Import(string filePath, string outputDirPath)
        {
        }

        public virtual void BeginImport()
        {
            file.BeginImport();

            dependencies = new Dictionary<string, ImporterTask>();
        }

        public BinaryWriter RawWriter => file.RawWriter;

        public void AddDependency(string filePath, TemplateTag type)
        {
            if (!dependencies.ContainsKey(filePath))
                dependencies[filePath] = new ImporterTask(filePath, type);
        }

        public ICollection<ImporterTask> Dependencies
        {
            get
            {
                if (dependencies == null)
                    return new ImporterTask[0];

                return dependencies.Values;
            }
        }

        public ImporterDescriptor CreateInstance(TemplateTag tag, string name = null) => file.CreateInstance(tag, name);

        public int WriteRawPart(byte[] data) => file.WriteRawPart(data);

        public int WriteRawPart(string text) => file.WriteRawPart(text);

        public void Write(string outputDirPath) => file.Write(outputDirPath);

        protected static string MakeInstanceName(TemplateTag tag, string name)
        {
            string tagName = tag.ToString();

            if (!name.StartsWith(tagName, StringComparison.Ordinal))
                name = tagName + name;

            return name;
        }

        public static string EncodeFileName(string name, Dictionary<string, string> fileNames = null)
        {
            foreach (char c in Path.GetInvalidFileNameChars())
                name = name.Replace(c.ToString(), string.Format(CultureInfo.InvariantCulture, "%{0:X2}", (int)c));

            if (fileNames != null)
            {
                string existingName;

                while (fileNames.TryGetValue(name, out existingName))
                {
                    int i = 0;

                    if (name.Length > 4)
                        i = 4;

                    while (i < name.Length && char.ToLowerInvariant(name[i]) != char.ToLowerInvariant(existingName[i]))
                        i++;

                    name = name.Substring(0, i) + string.Format(CultureInfo.InvariantCulture, "%{0:X2}", (int)name[i]) + name.Substring(i + 1);
                }

                fileNames[name] = name;
            }

            return name;
        }

        public static string DecodeFileName(string fileName)
        {
            fileName = Path.GetFileNameWithoutExtension(fileName);

            var buffer = new StringBuilder();

            for (int i, startIndex = 0; startIndex != -1; startIndex = i)
            {
                i = fileName.IndexOf('%', startIndex);

                if (i == -1)
                {
                    buffer.Append(fileName, startIndex, fileName.Length - startIndex);
                }
                else
                {
                    buffer.Append(fileName, startIndex, i - startIndex);
                    buffer.Append((char)Int32.Parse(fileName.Substring(i + 1, 2), NumberStyles.HexNumber));
                    i += 3;
                }
            }

            return buffer.ToString();
        }
    }
}
