import { __awaiter, __generator, __values } from "tslib";
import { Http, AsyncHook, noop, warnOnce, isValue, SyncHook, } from "@intelligentgraphics/ig.utilities";
import Logger from "./Logger";
import { Float3, } from "./Types";
import * as RenderBehaviours from "./RenderBehaviours";
import * as Hierarchy from "./Hierarchy";
import { getAsIGXC, getMergedIGXC } from "./IGXCWriter";
import { State } from "./State";
// TODO 2018-08-23 strip away these constants from here and use them with Hierarchy context
export var GhostPostfix = Hierarchy.GhostPostfix;
export var PlatformPostfix = Hierarchy.PlatformPostfix;
export var RootPostfix = Hierarchy.RootPostfix;
/**
 *
 * *** API DEFINITION AND PARTIAL IMPLEMENTATION ***
 *
 * API defines an implementation-independent API to be used by the Interactor and Evaluator scripts.
 *
 * API consists of low-level functions that need to be implemented by any Driver library, and
 * high-level functions that are implemented by low-level and/or high-level functions.
 *
 * Low-level functions are in this file provided as empty, exception-throwing bodies. Any API
 * implementation must implement the whole set of functions by overloading the predefined empty functions.
 *
 * The key concept of API is a Component. Basically a Component consists of
 *
 * (1) a ComponentId, a hierarchical path that identifies the component
 *
 * (2) graphical attributes that typically can be mapped 11 to regular scene graphs, such as
 *     transform, bbox, children, etc.
 *
 * (3) other attributes that may be stored in a general key-value dictionary
 *
 * Copyright (C) 2013 - 2016 intelligentgraphics Gmbh. All rights reserved.
 *
 */
var _API = /** @class */ (function () {
    function _API() {
        /** handle for requested animation frame, used in postprocecssing */
        this.animationFrameHandle = undefined;
        this.Hooks = {
            afterGfxLoad: new AsyncHook(),
            afterRootTransformationChange: new SyncHook(),
            afterAnimationProgressChange: new SyncHook(),
        };
        /* PUBLIC MEMBERS */
        /** Postfix for the root objects.
         * @deprecated
         */
        this.ROOT_POSTFIX = RootPostfix;
        /** Postfix for the ghost objects.
         * @deprecated
         */
        this.GHOST_POSTFIX = GhostPostfix;
        /** Conversion from Deg to Radiant.
         * @deprecated
         */
        this.DEG2RAD = 0.017453292;
        /** Conversion from Radiant to Deg.
         * @deprecated
         */
        this.RAD2DEG = 57.29577951;
        /** Primary selection color */
        this.PRIMARY_BBOX_COLOR = {
            r: 0.3,
            g: 0.3,
            b: 1,
        };
        // : ColorRGB = new ColorRGB(...);
        /** Secondary selection color */
        this.SECONDARY_BBOX_COLOR = {
            r: 0.2,
            g: 0.2,
            b: 0.7,
        };
        // : ColorRGB = new ColorRGB(...);
        /** The global dictionary of known materials. */
        this.Materials = {};
        this.GeometryLinks = {};
        /**
         * The platform the application is running on.
         * Available values: "iOS".
         */
        this.Platform = "Undefined";
        /** Enumeration of available callback names. */
        this.CALLBACKS = {
            INSERTED: "OnInserted",
            NEIGHBOR_ADDING: "OnNeighborAdding",
            NEIGHBOR_ADDED: "OnNeighborAdded",
            SNAPPED: "OnSnapped",
        };
        /** Factor to control speed of interactions, to be redefined in Drivers on demand */
        this.MotionScale = 1.0;
        // Global Log Settings.
        /** Log component life cycle. */
        this.Log_LifeCycle = false;
        /** Log interaction. */
        this.Log_Interaction = false;
        /** Log events on abstract level. */
        this.Log_Events = false;
        /** Log events on detail level (only if Log_Events is true) */
        this.Log_EventsDetailed = false;
        /** Log events on touch level */
        this.Log_EventsTouches = false;
        /** Log highlighting. */
        this.Log_Highlighting = false;
        /** Log material handling. */
        this.Log_Material = false;
        /* CONTROL FUNCTIONS */
        /**
         * Controls selection box behavior.
         */
        this.AutoDeselectComponent = true;
        /**
         * Enables/disables standard highlighting behaviour.
         * Set it to false to handle highlighting yourself.
         */
        this.AutoHighlightComponent = true;
        this.RenderBehaviour = new RenderBehaviours.Direct();
    }
    /**
     * Default handler if a component was accessed that does not exist.
     *
     * @param componentId The id that could not be mapped to a component.
     * @param result The default result to be returned.
     *
     * @returns The passed result.
     */
    _API.prototype.NoSuchComponent = function (componentId, result) {
        Logger.error("No such component: " + componentId);
        return result;
    };
    _API.prototype.DeleteComponent = function (componentId) {
        warnOnce("API.DeleteComponent has been replaced by API.RemoveComponent. \nRemoveComponent will not delete the super root when providing a root Id. It only deletes the root component.");
        componentId = Hierarchy.isRootGfxId(componentId)
            ? Hierarchy.getSuperRootGfxId(componentId)
            : componentId;
        return this.RemoveComponent(componentId);
    };
    /**
     * Adds a child (hierarchy).
     *
     * @param componentId Id of a Component, e.g. a Product.
     * @param description An IGXC sub set containing a (hierarchical)
     * structure definition. The root object in that description must
     * have the Path . All path values will be re-written to the dynamically
     * created path of the added child root.
     *
     * @param redraw if set to false, do not redraw the scene after adding the child
     * @returns The id of the added child root, or null/undefined in case of error.
     */
    _API.prototype.AddChild = function (componentId, description, redraw) {
        if (redraw === void 0) { redraw = true; }
        return __awaiter(this, void 0, void 0, function () {
            return __generator(this, function (_a) {
                switch (_a.label) {
                    case 0:
                        this.GetComponentOrThrow(componentId);
                        return [4 /*yield*/, this.ProcessIGXC(componentId, description)];
                    case 1:
                        _a.sent();
                        if (redraw) {
                            this.RedrawScene();
                        }
                        return [2 /*return*/, componentId];
                }
            });
        });
    };
    /**
     * Returns the id of the immediate neighbor with the specified local Id.
     *
     * @param componentId Id of a Component, e.g. a Product.
     * @param localId Local path of the requested object.
     *
     * @returns The Id of the neighbor, if existing, or null.
     */
    _API.prototype.GetNeighbor = function (componentId, localId) {
        var tPath = componentId.split(".");
        if (tPath.length === 1) {
            tPath = componentId.split("__");
            return tPath[0] + "__" + localId;
        }
        tPath.pop();
        var tNborId = tPath.join(".");
        return tNborId + "." + localId;
    };
    /**
     * Returns an array of the sub components, either the immediate
     * ones or all.
     *
     * @param componentId Component id. If null, the function is applied to the root objects.
     * @param recurse = false Controls if only immediate or all sub components should be returned.
     *
     * @returns The Ids of the found Components, or empty array, or null in case of error.
     */
    _API.prototype.GetComponents = function (componentId, recurse) {
        var e_1, _a, e_2, _b;
        var _this = this;
        var tComponents = [];
        var tCollectorFunction = function (collectComponentId) {
            var e_3, _a;
            tComponents.push(collectComponentId);
            if (recurse) {
                var tChildren = _this.GetChildren(collectComponentId);
                try {
                    for (var tChildren_2 = __values(tChildren), tChildren_2_1 = tChildren_2.next(); !tChildren_2_1.done; tChildren_2_1 = tChildren_2.next()) {
                        var child = tChildren_2_1.value;
                        tCollectorFunction(child);
                    }
                }
                catch (e_3_1) { e_3 = { error: e_3_1 }; }
                finally {
                    try {
                        if (tChildren_2_1 && !tChildren_2_1.done && (_a = tChildren_2.return)) _a.call(tChildren_2);
                    }
                    finally { if (e_3) throw e_3.error; }
                }
            }
        };
        if (componentId) {
            var tComponent = document.getElementById(componentId);
            if (tComponent === null) {
                return this.NoSuchComponent(componentId, []);
            }
            var tChildren = this.GetChildren(componentId);
            try {
                for (var tChildren_1 = __values(tChildren), tChildren_1_1 = tChildren_1.next(); !tChildren_1_1.done; tChildren_1_1 = tChildren_1.next()) {
                    var child = tChildren_1_1.value;
                    tCollectorFunction(child);
                }
            }
            catch (e_1_1) { e_1 = { error: e_1_1 }; }
            finally {
                try {
                    if (tChildren_1_1 && !tChildren_1_1.done && (_a = tChildren_1.return)) _a.call(tChildren_1);
                }
                finally { if (e_1) throw e_1.error; }
            }
        }
        else {
            var tRoots = this.GetRoots();
            try {
                for (var tRoots_1 = __values(tRoots), tRoots_1_1 = tRoots_1.next(); !tRoots_1_1.done; tRoots_1_1 = tRoots_1.next()) {
                    var root = tRoots_1_1.value;
                    tCollectorFunction(root);
                }
            }
            catch (e_2_1) { e_2 = { error: e_2_1 }; }
            finally {
                try {
                    if (tRoots_1_1 && !tRoots_1_1.done && (_b = tRoots_1.return)) _b.call(tRoots_1);
                }
                finally { if (e_2) throw e_2.error; }
            }
        }
        return tComponents;
    };
    _API.prototype.TraverseComponent = function (componentId, cb) {
        var e_4, _a;
        var children = this.GetChildren(componentId);
        try {
            for (var children_1 = __values(children), children_1_1 = children_1.next(); !children_1_1.done; children_1_1 = children_1.next()) {
                var childComponentId = children_1_1.value;
                cb(childComponentId);
                this.TraverseComponent(childComponentId, cb);
            }
        }
        catch (e_4_1) { e_4 = { error: e_4_1 }; }
        finally {
            try {
                if (children_1_1 && !children_1_1.done && (_a = children_1.return)) _a.call(children_1);
            }
            finally { if (e_4) throw e_4.error; }
        }
    };
    /**
     * Sets the material of an object (tree).
     *
     * @param componentId Component id.
     * @param category Material category.
     * @param Material object or name of a loaded material.
     */
    _API.prototype.SetCategoryMaterial = function (componentId, category, material) {
        return __awaiter(this, void 0, void 0, function () {
            var tNodes, tTraverse, tPromises, tNodes_1, tNodes_1_1, childId, tResultPromise;
            var e_5, _a;
            var _this = this;
            return __generator(this, function (_b) {
                if (material === undefined) {
                    return [2 /*return*/];
                }
                tNodes = new Array();
                if (this.GetMaterialCategory(componentId) === category) {
                    tNodes.push(componentId);
                }
                tTraverse = function (childComponentId) {
                    var tChildren = _this.GetChildren(childComponentId);
                    if (tChildren) {
                        tChildren.forEach(function (childId) {
                            if (_this.GetMaterialCategory(childId) === category) {
                                tNodes.push(childId);
                            }
                            tTraverse(childId);
                            // this.SetCategoryMaterial(childId, category, material);
                        });
                    }
                };
                tTraverse(componentId);
                tPromises = new Array();
                try {
                    for (tNodes_1 = __values(tNodes), tNodes_1_1 = tNodes_1.next(); !tNodes_1_1.done; tNodes_1_1 = tNodes_1.next()) {
                        childId = tNodes_1_1.value;
                        tPromises.push(this.SetMaterial(childId, material));
                    }
                }
                catch (e_5_1) { e_5 = { error: e_5_1 }; }
                finally {
                    try {
                        if (tNodes_1_1 && !tNodes_1_1.done && (_a = tNodes_1.return)) _a.call(tNodes_1);
                    }
                    finally { if (e_5) throw e_5.error; }
                }
                tResultPromise = Promise.all(tPromises).then(noop);
                return [2 /*return*/, tResultPromise];
            });
        });
    };
    /**
     * Sets the materials of an object (tree).
     *
     * @param componentId Component id.
     * @param categories Material categories, each with a material.
     * @param materials Materials.
     */
    _API.prototype.SetCategoryMaterials = function (componentId, categories, materialDefinitions) {
        return __awaiter(this, void 0, void 0, function () {
            var tChildren, err_1;
            var _this = this;
            return __generator(this, function (_a) {
                switch (_a.label) {
                    case 0:
                        _a.trys.push([0, 4, , 5]);
                        return [4 /*yield*/, Promise.all(Object.getOwnPropertyNames(categories).map(function (categoryId) {
                                var material;
                                var categoryValue = categories[categoryId];
                                if (materialDefinitions &&
                                    typeof categoryValue === "string") {
                                    material =
                                        materialDefinitions[categoryValue] || categoryValue;
                                }
                                else {
                                    material = categoryValue;
                                }
                                if (_this.GetMaterialCategory(componentId) !== categoryId ||
                                    !material) {
                                    return;
                                }
                                return _this.SetMaterial(componentId, material);
                            }))];
                    case 1:
                        _a.sent();
                        tChildren = this.GetChildren(componentId);
                        if (!tChildren) return [3 /*break*/, 3];
                        return [4 /*yield*/, Promise.all(tChildren.map(function (childId) {
                                return _this.SetCategoryMaterials(childId, categories, materialDefinitions);
                            }))];
                    case 2:
                        _a.sent();
                        _a.label = 3;
                    case 3: return [3 /*break*/, 5];
                    case 4:
                        err_1 = _a.sent();
                        throw err_1;
                    case 5: return [2 /*return*/];
                }
            });
        });
    };
    /**
     * Returns the product categories of the Product.
     *
     * @param componentId Component id.
     *
     * @returns The categories or empty array.
     */
    _API.prototype.GetCategories = function (componentId) {
        var tComponent = this.GetComponent(componentId);
        if (tComponent === null) {
            return this.NoSuchComponent(componentId, []);
        }
        var tCategories = tComponent.userData.categories;
        if (tCategories) {
            return tCategories;
        }
        return [];
    };
    /**
     * Sets the center of rotation.
     * DEPRECATED: was never implemented correctly
     *
     * @param componentId Component id.
     * @param { x float, y: float, z: float }: The center of rotation.
     */
    _API.prototype.SetRotationCenter = function (componentId, center) { };
    /**
     * Returns the rotation angle (degrees) of an object around the y axis.
     *
     * @param componentId Component id.
     *
     * @returns The rotation angle around the y axis in degrees.
     */
    _API.prototype.GetYRotation = function (componentId) {
        return 0;
    };
    /* EVENT HANDLERS */
    /**
     * Called when a component was hit before any further processing.
     *
     * @param componentId The id of the hit component (or null).
     *
     * @returns If false, the run-time should not process the pick operation any further.
     */
    _API.prototype.PickHandler = function (componentId) {
        return true;
    };
    /**
     * Called when a component is going to be selected.
     *
     * @param componentId The id of the component to be selected (or null).
     *
     * @returns If false, the run-time should not process the select operation any further.
     */
    _API.prototype.SelectHandler = function (componentId) {
        return true;
    };
    /**
     * Called when secondary selection has changed.
     */
    _API.prototype.Select2Handler = function () { };
    /**
     * Called when an object was deleted. The object with the passed id is already gone!
     */
    _API.prototype.DeleteHandler = function (componentId) { };
    /**
     * Called when an interaction was done.
     */
    _API.prototype.InteractionDoneHandler = function () { };
    /**
     * Called after loading of a geometry.
     *
     * @param complete True if the last geometry was loaded.
     */
    _API.prototype.LoadGeometryHandler = function (complete) {
        // this.Log("LoadGeometryHandler() Complete? " + complete);
    };
    /**
     * Called after an error happended when loading a geometry.
     *
     * @param url The url that caused a load error.
     *
     * @returns void
     */
    _API.prototype.LoadGeometryErrorHandler = function (url) {
        // this.Log("LoadGeometryErrorHandler() called for Url " + url);
    };
    /**
     * The handler will be called before and after API.Highlight().
     * @param componentId Component Id for which API.Highlight() was called.
     * @param before True if before highlighting is changed, false after then.
     */
    _API.prototype.HighlightHandler = function (componentId, before) { };
    /**
     * Called to print a Log message
     *
     * @param message The log message
     *
     * @returns void
     */
    _API.prototype.LogHandler = function (message) {
        Logger.info("[IGX Log] " + message);
    };
    /* MISC FUNCTIONS */
    /**
     * Sends a message to the log handler.
     *
     * @returns void
     */
    _API.prototype.Log = function (message) {
        this.LogHandler(message);
    };
    /**
     * Redraws the scene in all associated cameras/views.
     * @param force enforce redraw
     * @param updatePostprocessing used internally for resetting postprocessing
     * @returns void
     */
    _API.prototype.RedrawScene = function (force, updatePostprocessing) {
        if (updatePostprocessing === void 0) { updatePostprocessing = true; }
        if (this.animationFrameHandle !== undefined) {
            window.cancelAnimationFrame(this.animationFrameHandle);
            this.animationFrameHandle = undefined;
        }
        if (updatePostprocessing &&
            State.postprocessingOptions.handlePostprocessingBeforeRender) {
            State.postprocessingOptions.handlePostprocessingBeforeRender();
        }
        if (this.RenderBehaviour !== undefined) {
            return this.RenderBehaviour.requestRedraw(force);
        }
    };
    /**
     * Gets the current WC position of a component.
     * @param componentId The component.
     * @returns The WC position.
     */
    _API.prototype.GetWorldPosition = function (componentId) {
        var transformation = this.GetBasicWorldTransformation(componentId);
        return transformation.position;
    };
    /* HIGH-LEVEL FUNCTIONS */
    /** Gets the collected primary and secondary selection. */
    _API.prototype.GetAllSelectedComponents = function () {
        var secondarySelection = this.GetSelectedComponents2();
        var selection = secondarySelection.slice();
        var mainSelection = this.GetSelectedComponent();
        if (isValue(mainSelection) && selection.indexOf(mainSelection) === -1) {
            selection.push(mainSelection);
        }
        return selection;
    };
    /** Checks if a component is either primarily or secondarly selected.
     * @param componentId Component id.
     * @returns True if selected
     */
    _API.prototype.IsSelected = function (componentId) {
        if (this.GetSelectedComponent() === componentId) {
            return true;
        }
        var tSelection2 = this.GetSelectedComponents2();
        if (tSelection2 && tSelection2.indexOf(componentId) !== -1) {
            return true;
        }
        return false;
    };
    /**
     * Assigns a material description to the specified Products, i.e. for every
     * Product it will be assigned recursively to all components (including the Product
     * itself) that fit the specified Category.
     *
     * @param productIds The Ids of the Products to be manipulated. If null, the Root objects will be used.
     * @param category The Category to which the material should apply.
     * @param description The material description.
     *
     * @returns void
     */
    _API.prototype.AssignMaterial = function (productIds, category, description) {
        var _this = this;
        // TODO 2018-03-13 make async
        var tProductIds = productIds;
        if (!tProductIds) {
            tProductIds = this.GetRoots();
        }
        tProductIds.forEach(function (componentId) {
            _this.SetCategoryMaterial(componentId, category, description);
        });
    };
    /**
     * Changes the visibility of a layer.
     *
     * @param productIds The Ids of the Products to be manipulated. If array is null, the roots are used.
     * @param layer The layer to be manipulated.
     * @param visible The new visibility of that layer.
     *
     * @returns void
     */
    _API.prototype.SetLayerVisibility = function (componentIds, layer, visible) {
        var _this = this;
        var tComponentIds = componentIds;
        if (tComponentIds === null) {
            tComponentIds = this.GetRoots();
        }
        var tVisibilityFunction = function (componentId) {
            var tLayer = _this.GetLayer(componentId);
            if (tLayer && tLayer === layer) {
                _this.SetVisibility(componentId, visible);
            }
            var tChildren = _this.GetChildren(componentId);
            for (var tI = 0; tI < tChildren.length; tI++) {
                tVisibilityFunction(tChildren[tI]);
            }
        };
        for (var tI = 0; tI < tComponentIds.length; tI++) {
            tVisibilityFunction(tComponentIds[tI]);
        }
    };
    /**
     * Collects all material categories in the scene.
     *
     * @returns Array of categories, possibly empty.
     */
    _API.prototype.GetAllMaterialCategories = function () {
        var e_6, _a;
        var _this = this;
        var tAllMatCategories = new Array();
        var tCollectorFunction = function (componentId) {
            var e_7, _a;
            var tCategory = _this.GetMaterialCategory(componentId);
            if (tCategory != null &&
                tAllMatCategories.lastIndexOf(tCategory) < 0) {
                tAllMatCategories.push(tCategory);
            }
            var tChildren = _this.GetChildren(componentId);
            try {
                for (var tChildren_3 = __values(tChildren), tChildren_3_1 = tChildren_3.next(); !tChildren_3_1.done; tChildren_3_1 = tChildren_3.next()) {
                    var child = tChildren_3_1.value;
                    tCollectorFunction(child);
                }
            }
            catch (e_7_1) { e_7 = { error: e_7_1 }; }
            finally {
                try {
                    if (tChildren_3_1 && !tChildren_3_1.done && (_a = tChildren_3.return)) _a.call(tChildren_3);
                }
                finally { if (e_7) throw e_7.error; }
            }
        };
        var tRoots = this.GetRoots();
        try {
            for (var tRoots_2 = __values(tRoots), tRoots_2_1 = tRoots_2.next(); !tRoots_2_1.done; tRoots_2_1 = tRoots_2.next()) {
                var root = tRoots_2_1.value;
                tCollectorFunction(root);
            }
        }
        catch (e_6_1) { e_6 = { error: e_6_1 }; }
        finally {
            try {
                if (tRoots_2_1 && !tRoots_2_1.done && (_a = tRoots_2.return)) _a.call(tRoots_2);
            }
            finally { if (e_6) throw e_6.error; }
        }
        return tAllMatCategories;
    };
    /**
     * Collects all layers in the scene.
     *
     * @returns Array of layers, possibly empty.
     */
    _API.prototype.GetAllLayers = function () {
        var e_8, _a;
        var _this = this;
        var tAllLayers = new Array();
        var tCollectorFunction = function (componentId) {
            var e_9, _a;
            var tLayer = _this.GetLayer(componentId);
            if (tLayer != null && tAllLayers.lastIndexOf(tLayer) < 0) {
                tAllLayers.push(tLayer);
            }
            var tChildren = _this.GetChildren(componentId);
            try {
                for (var tChildren_4 = __values(tChildren), tChildren_4_1 = tChildren_4.next(); !tChildren_4_1.done; tChildren_4_1 = tChildren_4.next()) {
                    var child = tChildren_4_1.value;
                    tCollectorFunction(child);
                }
            }
            catch (e_9_1) { e_9 = { error: e_9_1 }; }
            finally {
                try {
                    if (tChildren_4_1 && !tChildren_4_1.done && (_a = tChildren_4.return)) _a.call(tChildren_4);
                }
                finally { if (e_9) throw e_9.error; }
            }
        };
        var tRoots = this.GetRoots();
        try {
            for (var tRoots_3 = __values(tRoots), tRoots_3_1 = tRoots_3.next(); !tRoots_3_1.done; tRoots_3_1 = tRoots_3.next()) {
                var root = tRoots_3_1.value;
                tCollectorFunction(root);
            }
        }
        catch (e_8_1) { e_8 = { error: e_8_1 }; }
        finally {
            try {
                if (tRoots_3_1 && !tRoots_3_1.done && (_a = tRoots_3.return)) _a.call(tRoots_3);
            }
            finally { if (e_8) throw e_8.error; }
        }
        return tAllLayers;
    };
    /**
     * Checks the availability of a Callback.
     *
     * @returns Fully qualified Callback name if available, otherwise null.
     */
    _API.prototype.GetEvaluatorCallback = function (componentId, callback) {
        var tEvaluator = this.GetEvaluator(componentId);
        if (!tEvaluator) {
            return null;
        }
        var tCallback = tEvaluator["Type"] + "." + callback;
        try {
            if (eval("typeof " + tCallback) === "function") {
                return tCallback;
            }
        }
        catch (error) { }
        return null;
    };
    /**
     * Dumps a component to IGXC representation, if needed recursively.
     *
     * @param componentId The component where the dump starts.
     *
     * @param options Writer options.
     *
     * @returns An IGXC scene representation.
     */
    _API.prototype.GetAsIGXC = function (componentId, options) {
        return getAsIGXC(this, componentId, options);
    };
    /**
     * Dumps a merged IGXC representation by combining the IGXCs of the passed components.
     *
     * @param componentIds An array of components to be processed. If null, the roots are considered.
     * If component ids are provided they must be root-level sub objects (__.).
     *
     * @param options Writer options.
     *
     * @returns An IGXC scene representation.
     */
    _API.prototype.GetMergedIGXC = function (componentIds, options) {
        return getMergedIGXC(this, componentIds, options);
    };
    _API.prototype.IsPreviewIGXCLoadPossibleAndNeccessary = function (igxc, componentId) {
        return false;
    };
    _API.prototype.LoadIGXC = function (componentId, url, options) {
        var _this = this;
        var tPath = url.split("/");
        var tBasePath = url.substring(0, url.indexOf(tPath[tPath.length - 1]));
        return Http.getJSON(url).then(function (scene) {
            return _this.ProcessIGXC(componentId, scene, tBasePath, options);
        });
    };
    /** Gets the area distance. The area must be defined by two points
     * lying in one plane with regard to the specified direction.
     * @param point1 The first point.
     * @param point2 The second point.
     * @direction Must be one of the following: Down, Up.
     */
    _API.prototype.GetAreaDistance = function (point1, point2, direction) {
        var _this = this;
        // inner offset to avoid edge/epsilon issues:
        var tOffset = 0.05;
        switch (direction) {
            case "Down":
            case "Up": {
                var tX1 = point1.x;
                var tX2 = point2.x;
                if (tX2 < tX1) {
                    var tX = tX1;
                    tX1 = tX2;
                    tX2 = tX;
                }
                var tZ1 = point1.z;
                var tZ2 = point2.z;
                if (tZ2 < tZ1) {
                    var tZ = tZ1;
                    tZ1 = tZ2;
                    tZ2 = tZ;
                }
                var tPoint_1 = new Float3(0, 
                // both y's should be the same, anyway get the average:
                0.5 * (point1.y + point2.y), 0);
                var tDirection_1 = direction === "Down"
                    ? new Float3(0, -1, 0)
                    : new Float3(0, 1, 0);
                var tDistance_1 = -1;
                [
                    [tX1 + tOffset, tZ1 + tOffset],
                    [tX2 - tOffset, tZ1 + tOffset],
                    [0.5 * (tX1 + tX2), 0.5 * (tZ1 + tZ2)],
                    [tX1 + tOffset, tZ2 - tOffset],
                    [tX2 - tOffset, tZ2 - tOffset],
                ].forEach(function (point) {
                    tPoint_1.x = point[0];
                    tPoint_1.z = point[1];
                    var tRayDistance = _this.GetDistance(tPoint_1, tDirection_1);
                    if (tRayDistance === -1) {
                        return;
                    }
                    else if (tDistance_1 === -1 || tRayDistance < tDistance_1) {
                        tDistance_1 = tRayDistance;
                    }
                });
                return tDistance_1;
            }
            default:
                Logger.warn("GetAreaDistance: Unsupported direction " + direction);
                return -1;
        }
    };
    /** Default exception for abstract, i.e. un-implemented, functions. */
    _API.Exception = "Pure abstract function called!";
    return _API;
}());
export { _API };
try {
    if (typeof System === "undefined") {
        System = {
            Console: {
                WriteLine: function (text) {
                    this.Log(text);
                },
            },
        };
    }
}
catch (err) { }
