using Ascon.Pilot.BimConverters.Core;
using Ascon.Pilot.DataClasses;
using Renga;
using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.IO;

namespace RengaToIfcConverter
{
    [Export(typeof(IConverterToIfc))]
    public class RengaToIfcConverter : IConverterToIfc
    {
        private const string VALUE_MAPPING_PROPERTY_NAME = "ValueMapping";
        private const string ENTITY_TYPE_MAPPING_PROPERTY_NAME = "EntityTypeMapping";
        private const string LAYER_MAPPING_PROPERTY_NAME = "LayerMapping";

        private Application _rengaApp;
        private string _valueMappingFilePath;
        private string _entityTypeMappingFilePath;
        private string _layerMappingFilePath;
        public string Name => "RNP to IFC converter";

        public IEnumerable<DRule> Rules => new[]
        {
            new DRule
            {
                Id = new Guid("{A9BF7CDD-C877-4F6B-97BC-10C3D5EF0621}"),
                ChangeType = ChangeType.Create,
                FileExtension = ".rnp"
            },
            new DRule
            {
                Id = new Guid("{F1327CD2-F727-4732-A03B-ECD4DA0365FD}"),
                ChangeType = ChangeType.Update,
                FileExtension = ".rnp"
            }
        };

        public IEnumerable<ConverterSettingDescriptor> Settings => new[]
        {
            new ConverterSettingDescriptor
            {
                Name = VALUE_MAPPING_PROPERTY_NAME,
                Title = "Value Mapping",
                Description = "Value Mapping"
            },
            new ConverterSettingDescriptor
            {
                Name = ENTITY_TYPE_MAPPING_PROPERTY_NAME,
                Title = "Entity Type Mapping",
                Description = "Entity Type Mapping"
            },
            new ConverterSettingDescriptor
            {
                Name = LAYER_MAPPING_PROPERTY_NAME,
                Title = "Layer Mapping",
                Description = "Layer Mapping"
            }
        };
        public bool IsConverterInstalled()
        {
            var app = new Application();
            if (app != null)
            {
                app.Quit();
                return true;
            }
            return false;
        }

        public string Convert(ConverterRequest request)
        {
            // Opening Renga

            _rengaApp = new Application();

            if (_rengaApp.OpenProject(request.Path) != 0)
            {
                throw new InvalidOperationException("Failed to open source file in Renga");
            }

            // Exporting project to IFC
            var outputPath = Path.ChangeExtension(request.Path, "ifc");

            var settings = ComposeSettings(request);
            try
            {
                _rengaApp.Project.ExportToIfc2(outputPath, true, settings);

                // Closing project
                _rengaApp.CloseProject(true);

                // Closing Renga
                _rengaApp.Quit();
                _rengaApp = null;
            }
            finally
            {
                if (File.Exists(_valueMappingFilePath))
                    File.Delete(_valueMappingFilePath);
                if (File.Exists(_entityTypeMappingFilePath))
                    File.Delete(_entityTypeMappingFilePath);
                if (File.Exists(_layerMappingFilePath))
                    File.Delete(_layerMappingFilePath);
            }

            return outputPath;
        }

        public void Initialize()
        {

        }

        public void Dispose()
        {
            _rengaApp?.Quit();
        }

        private IIfcExportSettings ComposeSettings(ConverterRequest request)
        {
            var ifcExportSettings = _rengaApp.CreateIfcExportSettings();
            ifcExportSettings.Version = IfcVersion.IfcVersion_4;

            if (request.Settings.ContainsKey(VALUE_MAPPING_PROPERTY_NAME)
                && string.IsNullOrWhiteSpace(request.Settings[VALUE_MAPPING_PROPERTY_NAME]) == false)
            {
                _valueMappingFilePath = Path.ChangeExtension(request.Path, "vmap.json");
                ifcExportSettings.ValueMappingFilePath = _valueMappingFilePath;
                File.WriteAllText(ifcExportSettings.ValueMappingFilePath, request.Settings[VALUE_MAPPING_PROPERTY_NAME]);
            }

            if (request.Settings.ContainsKey(ENTITY_TYPE_MAPPING_PROPERTY_NAME)
                &&  string.IsNullOrWhiteSpace(request.Settings[ENTITY_TYPE_MAPPING_PROPERTY_NAME]) == false)
            {
                _entityTypeMappingFilePath = Path.ChangeExtension(request.Path, "emap.json");
                ifcExportSettings.EntityTypeMappingFilePath = _entityTypeMappingFilePath;
                File.WriteAllText(ifcExportSettings.EntityTypeMappingFilePath, request.Settings[ENTITY_TYPE_MAPPING_PROPERTY_NAME]);
            }

            if (request.Settings.ContainsKey(LAYER_MAPPING_PROPERTY_NAME) 
                && string.IsNullOrWhiteSpace(request.Settings[LAYER_MAPPING_PROPERTY_NAME]) == false)
            {
                _layerMappingFilePath = Path.ChangeExtension(request.Path, "lmap.json");
                ifcExportSettings.LayerMappingFilePath = _layerMappingFilePath;
                File.WriteAllText(ifcExportSettings.LayerMappingFilePath, request.Settings[LAYER_MAPPING_PROPERTY_NAME]);
            }

            return ifcExportSettings;
        }
    }
}
