Source: D:/agents/cloudwork/23/s/Solution/PdfFormat/JsonApi_Pdf.js

var data;
/**
 * The main Anark JavaScript API object providing various data and functionality.
 * Copyright 2007-2019 Anark Corporation. All rights reserved..
 * @constructor
 * @param {bool} buildOccurrenceStructure - Optional. If true, this will provide an occurrence tree structure to use (adds parent/child object references to the occurrences).
 * @param {bool} enableProcessPlanning - Optional. If true, this will create additional objects to assist with process planning data access, specifically the processPlanning property (see {@link ProcessPlanning}).
 */
function ANARKCOREDATA(buildOccurrenceStructure, enableProcessPlanning, publishedData) {
    "use strict";
    if (publishedData == undefined) {
        this.product = data;
    }
    else {
        this.product = publishedData;
    }
    String.prototype.getNumberFromEnd = function () {
        var i, number, goodNumber;
        i = this.length - 1;
        if (i === -1)
            return NaN;
        number = parseInt(this.substring(i, this.length), 10);
        goodNumber = NaN;
        while (!isNaN(number) && i >= 0) {
            goodNumber = number;
            i = i - 1;
            number = parseInt(this.substring(i, this.length), 10);
        }
        return goodNumber;
    };
    // IE versions < 9 don't have an .indexOf() function for Array, so this is a polyfill specified by Mozilla
    if (!Array.prototype.indexOf) {
        Array.prototype.indexOf = function (searchElement, fromIndex) {
            if (this === undefined || this === null)
                throw new TypeError('"this" is null or not defined');
            var length = this.length >>> 0; // Hack to convert object.length to a UInt32
            fromIndex = +fromIndex || 0;
            if (Math.abs(fromIndex) === Infinity)
                fromIndex = 0;
            if (fromIndex < 0) {
                fromIndex += length;
                if (fromIndex < 0)
                    fromIndex = 0;
            }
            for (; fromIndex < length; fromIndex++) {
                if (this[fromIndex] === searchElement)
                    return fromIndex;
            }
            return -1;
        };
    }
    /**
     * Get the attributes in their original order without sorting.
     * @param {Entity} entity - The entity that contains the desired attributes.
     * @returns {Array} Returns an array of objects in the form of:  { name: attributeName, objectValue: attributeValue }
     */
    this.getAttributesInOriginalOrder = function (entity) {
        var attributeName;
        var list = [];
        var hash = this.getAttributesAsHash(entity);
        for (attributeName in hash) {
            if (hash.hasOwnProperty(attributeName))
                list.push({ name: attributeName, objectValue: hash[attributeName] });
        }
        return list;
    };
    /**
     * Get the attributes in a sorted array. The attributes are sorted alphabetically by name but if 2 or more attribute names are the same and end in a number, the numbers are sorted numerically rather than alphabetically.
     * @param {Entity} entity - The entity that contains the desired attributes.
     * @returns {Array} Returns a sorted array of objects in the form of:  { name: attributeName, objectValue: attributeValue }
     */
    this.getAttributesInSmartSortedOrder = function (entity) {
        return this.getAttributesInOriginalOrder(entity)
            .sort(function (a, b) {
            var bNumber;
            if (a.name === b.name)
                return 0;
            var aNumber = a.name.getNumberFromEnd();
            if (!isNaN(aNumber)) {
                bNumber = b.name.getNumberFromEnd();
                if (!isNaN(bNumber)) {
                    if (a.name.substring(0, a.name.length - aNumber.toString().length) ===
                        b.name.substring(0, b.name.length - bNumber.toString().length)) {
                        return aNumber - bNumber;
                    }
                }
            }
            if (a.name > b.name)
                return 1;
            return -1;
        });
    };
    /**
     * Get the attributes as a hash table where the attribute name is the hash key. This offers the best performance when doing random attribute lookups.
     * @param {Entity} entity - The entity that contains the desired attributes.
     * @returns {Array} Returns a hash of attributeName, attributeValue pairs.
     */
    this.getAttributesAsHash = function (entity) {
        entity.Attributes.Name = entity.typeOfEntity === "View" ? entity.originalName : entity.name;
        if (entity.useCount !== undefined)
            entity.Attributes["Use Count"] = entity.useCount;
        return entity.Attributes;
    };
    /**
     * Get a workspace attribute by name.
     * @param {string} attributeName - The name of the workspace attribute.
     * @returns {object} Returns the attribute value.
     */
    this.getWorkspaceAttribute = function (attributeName) {
        return this.getAttributesAsHash(this.product.Workspace)[attributeName];
    };
    /**
     * Get all workspace attributes.
     * @returns {Array} Returns a hash of attributeName, attributeValue pairs.
     */
    this.getWorkspaceAttributes = function () {
        return this.getAttributesAsHash(this.product.Workspace);
    };
    /**
     * @class Row
     * @classdesc A table row. You cannot instantiate this class.
     */
    /**
     * Get a cell value from a row.
     * @name Row#getCellValue
     * @function
     * @param {string} columnName - The name of the column that contains the value.
     * @returns {object} The cell value.
     */
    this.Table = /** @class */ (function () {
        // TODO add a link here for method to get table from ACDAta
        /**
         * A Table - this wraps up the raw JSON attribute data and makes it easier to work with data tables.
         * Tables can be created by passing in the an attribute value, or they can be created based on result sets from existing tables. Can also use {@link ANARKCOREDATA#getWorkspaceTableByName}
         * @class Table
         * @param {object} arg1 - Either the raw table attribute value or the table schema (columns) definition.
         * @param {object} arg2 - If arg1 is the raw table value then this argument should be omitted. If arg1 is the table schema definition then arg2 must be the table rows.
         */
        function Table(arg1, arg2) {
            var i, rawTableValue, table, getCellValue, rowIndex;
            if (arg2 === undefined) {
                rawTableValue = arg1;
            }
            else {
                rawTableValue =
                    {
                        "columns": arg1,
                        "rows": arg2
                    };
            }
            this.rowCount = rawTableValue.rows.length;
            this.rawTableValue = rawTableValue;
            this.indexHash = {};
            this.columnHash = {};
            for (i = 0; this.rawTableValue.columns.length > i; i += 1)
                this.columnHash[this.rawTableValue.columns[i].name] = i;
            table = this;
            getCellValue = function (cn) {
                return this.cells[table.columnHash[cn]];
            };
            for (rowIndex = 0; rowIndex < this.rowCount; rowIndex += 1)
                this.rawTableValue.rows[rowIndex].getCellValue = getCellValue;
        }
        /**
         * Get the table column (schema) information.
         * @memberof Table
         * @returns {Array<Column>}
         */
        Table.prototype.getColumns = function () {
            return this.rawTableValue.columns;
        };
        /**
         * Get all table rows.
         * @memberof Table
         * @returns {Array<Row>} The cell value.
         */
        Table.prototype.getRows = function () {
            return this.rawTableValue.rows;
        };
        /**
         * Get a column name by column index.
         * @memberof Table
         * @param {integer} columnIndex - The column index.
         * @returns {string} The column name.
         */
        Table.prototype.getColumnName = function (columnIndex) {
            return this.rawTableValue.columns[columnIndex].name;
        };
        /**
         * Get a cell value by row index and column name.
         * @memberof Table
         * @param {integer} rowIndex - The row index.
         * @param {string} columnName - The column name.
         * @returns {object} The cell value.
         */
        Table.prototype.getCellValueByName = function (rowIndex, columnName) {
            var columnIndex = this.columnHash[columnName];
            if (columnIndex === undefined)
                return null;
            return this.rawTableValue.rows[rowIndex].cells[columnIndex];
        };
        /**
         * Get a cell value by row index and column index.
         * @memberof Table
         * @param {integer} rowIndex - The row index.
         * @param {integer} columnIndex - The column index.
         * @returns {object} The cell value.
         */
        Table.prototype.getCellValue = function (rowIndex, columnIndex) {
            return this.rawTableValue.rows[rowIndex].cells[columnIndex];
        };
        /**
         * Creates an index on a specified column, which allows for the fast lookup of rows that match values in the specified column.
         * @memberof Table
         * @param {string} columnName - The name of the column to index.
         */
        Table.prototype.createIndex = function (columnName) {
            var columnIndex, rowIndex, hash, row;
            hash = {};
            columnIndex = this.columnHash[columnName];
            for (rowIndex = 0; rowIndex < this.rowCount; rowIndex += 1) {
                row = this.rawTableValue.rows[rowIndex];
                if (hash[row.cells[columnIndex]] === undefined)
                    hash[row.cells[columnIndex]] = [];
                hash[row.cells[columnIndex]].push(row);
            }
            this.indexHash[columnName] = hash;
        };
        /**
         * Gets the unique key values of a column index. This can be used to get all unique values in a column.
         * @memberof Table
         * @param {string} columnName - The indexed column name.
         * @returns {Array<string>} An array of strings representing the unique index keys.
         */
        Table.prototype.getIndexValues = function (columnName) {
            var hash, values, value;
            hash = this.indexHash[columnName];
            if (hash === undefined)
                throw "There is no index present on column " + columnName;
            values = [];
            for (value in hash) {
                if (hash.hasOwnProperty(value))
                    values.push(value);
            }
            return values;
        };
        /**
         * Gets the rows that exactly match a value in an indexed column. An index must exist on the column before using this.
         * @memberof Table
         * @param {string} columnName - The indexed column name.
         * @param {string} indexValue - The search string.
         * @returns {Array<Row>} An array of rows representing the unique index keys.
         */
        Table.prototype.getIndexedRows = function (columnName, indexValue) {
            if (this.indexHash[columnName] === undefined)
                throw "There is no index present on column " + columnName;
            var rows = this.indexHash[columnName][indexValue];
            if (rows === undefined)
                return [];
            return rows;
        };
        /**
         * Filter rows based on a custom function that is passed in.
         * @memberof Table
         * @param {function} matchFunction - The row matching function. The function should take a row as its argument and return true if the row matches or false if the row does not match.
         * @returns {Array<Row>} An array of rows that meet the criteria of matchFunction.
         */
        Table.prototype.filterRows = function (matchFunction) {
            var rowIndex, row, rows;
            rows = [];
            for (rowIndex = 0; rowIndex < this.rowCount; rowIndex += 1) {
                row = this.rawTableValue.rows[rowIndex];
                if (matchFunction(row))
                    rows.push(row);
            }
            return rows;
        };
        /**
         * Executes a function once for every row in the table.
         * @memberof Table
         * @param {function} func - The function to execute. The function should take the rowIndex and the row as its arguments.
         */
        Table.prototype.forEachRow = function (func) {
            var rowIndex;
            for (rowIndex = 0; rowIndex < this.rowCount; rowIndex += 1)
                func(rowIndex, this.rawTableValue.rows[rowIndex]);
        };
        /**
         * Uses a function to filter rows and then executes a function for every filtered row.
         * @memberof Table
         * @param {function} filterFunc - The filtering function to execute. The function should take the rowIndex and the row as its arguments. Pass null for this parameter to use no filtering.
         * @param {function} actionFunc - The function to execute on each filtered row. The function should take the rowIndex and the row as its arguments.
         */
        Table.prototype.forEachFilteredRow = function (filterFunc, actionFunc) {
            var rowIndex, row;
            if (filterFunc === null) {
                this.forEachRow(actionFunc);
                return;
            }
            for (rowIndex = 0; rowIndex < this.rowCount; rowIndex += 1) {
                row = this.rawTableValue.rows[rowIndex];
                if (filterFunc(rowIndex, row))
                    actionFunc(rowIndex, row);
            }
        };
        /**
         * Sorts the table using the provided sortFunction. This does not sort the table in place - it creates a new table.
         * @memberof Table
         * @param {function} sortFunction - The custom sort function - takes parameters a and b that represent table rows.
         * @returns {Table} A new table object with the rows sorted.
         */
        Table.prototype.sortCustom = function (sortFunction) {
            return new Table(this.getColumns(), this.rawTableValue.rows.sort(sortFunction));
        };
        /**
         * Sorts the table according to the data in the column specified by the columnIndex parameter, in ascending order.
         * @memberof Table
         * @param {number} columnIndex - The index of the column to sort on.
         * @returns {Table} A new table object with the rows sorted.
         */
        Table.prototype.sortAscending = function (columnIndex) {
            return this.sortCustom(function (a, b) {
                if (a.cells[columnIndex] > b.cells[columnIndex])
                    return 1;
                if (a.cells[columnIndex] < b.cells[columnIndex])
                    return -1;
                return 0;
            });
        };
        /**
         * Sorts the table according to the data in the column specified by the columnIndex parameter, in descending order.
         * @memberof Table
         * @param {number} columnIndex - The index of the column to sort on.
         * @returns {Table} A new table object with the rows sorted.
         */
        Table.prototype.sortDescending = function (columnIndex) {
            return this.sortCustom(function (a, b) {
                if (a.cells[columnIndex] > b.cells[columnIndex])
                    return -1;
                if (a.cells[columnIndex] < b.cells[columnIndex])
                    return 1;
                return 0;
            });
        };
        /**
         * Sorts the table according to the data in the column specified by the columnName parameter, in ascending order.
         * @memberof Table
         * @param {number} columnName - The name of the column to sort on.
         * @returns {Table} A new table object with the rows sorted.
         */
        Table.prototype.sortAscendingByColumnName = function (columnName) {
            var columnIndex = this.columnHash[columnName];
            if (columnIndex === undefined)
                return null;
            return this.sortAscending(columnIndex);
        };
        /**
         * Sorts the table according to the data in the column specified by the columnName parameter, in descending order.
         * @memberof Table
         * @param {number} columnName - The name of the column to sort on.
         * @returns {Table} A new table object with the rows sorted.
         */
        Table.prototype.sortDescendingByColumnName = function (columnName) {
            var columnIndex = this.columnHash[columnName];
            if (columnIndex === undefined)
                return null;
            return this.sortDescending(columnIndex);
        };
        return Table;
    }());
    /**
     * Gets a table from the workspace attributes. Creates a new table each time.
     * @param {string} tableName - The name of the workspace table attribute.
     * @returns {Table} A new table object representing the specified table attribute.
     */
    this.getWorkspaceTableByName = function (tableName) {
        var attValue = this.getAttributesAsHash(this.product.Workspace)[tableName];
        if (attValue === null || attValue === undefined)
            return undefined;
        if (attValue.objectValue !== undefined)
            return new this.Table(attValue.objectValue);
        return new this.Table(attValue);
    };
    /**
     * Gets all file attachments. Returns an empty array if there are no attachments.
     * @returns Array of file names.
     */
    this.getFileAttachments = function () {
        if (this.product.Attachments !== undefined)
            return this.product.Attachments;
        return [];
    };
    /**
     * An entity. Examples of entities are components, instances, occurrences, etc. You cannot instantiate this class.
     * @class Entity
     */
    /**
     * Get the attributes in their original order without sorting.
     * @name Entity#getAttributesInOriginalOrder
     * @function
     * @returns {Array} Returns an array of objects in the form of:  { name: attributeName, objectValue: attributeValue }
     */
    /**
     * Get the attributes in a sorted array. The attributes are sorted alphabetically by name but if 2 or more attribute names are the same and end in a number, the numbers are sorted numerically rather than alphabetically.
     * @name Entity#getAttributesInSmartSortedOrder
     * @function
     * @returns {Array} Returns a sorted array of objects in the form of:  { name: attributeName, objectValue: attributeValue }
     */
    /**
     * Get the attributes as a hash table where the attribute name is the hash key. This offers the best performance when doing random attribute lookups.
     * @name Entity#getAttributesAsHash
     * @function
     * @returns {Array} Returns a hash of attributeName, attributeValue pairs.
     */
    /**
     * @class Component
     * @augments Entity
     * @classdesc A component entity. You cannot instantiate this class.
     */
    /**
     * Get the instances of the component.
     * @name Component#getInstances
     * @function
     * @returns {Array<Entity>} The instances of the component.
     */
    /**
     * @class Occurrence
     * @augments Entity
     * @classdesc An Occurrence entity of a Component. You cannot instantiate this class.
     */
    var initComponentMaps = function (anarkCoreData) {
        var entities, entityId, entity;
        if (anarkCoreData.product.componentToInstanceMap === undefined) {
            anarkCoreData.product.componentToInstanceMap = {};
            entities = anarkCoreData.getInstances();
            for (entityId in entities) {
                if (entities.hasOwnProperty(entityId)) {
                    entity = entities[entityId];
                    if (anarkCoreData.product.componentToInstanceMap[entity.componentId] === undefined)
                        anarkCoreData.product.componentToInstanceMap[entity.componentId] = [];
                    anarkCoreData.product.componentToInstanceMap[entity.componentId].push(entity);
                }
            }
        }
        if (anarkCoreData.product.componentToOccurrenceMap === undefined) {
            anarkCoreData.product.componentToOccurrenceMap = {};
            entities = anarkCoreData.getOccurrences();
            for (entityId in entities) {
                if (entities.hasOwnProperty(entityId)) {
                    entity = entities[entityId];
                    if (anarkCoreData.product.componentToOccurrenceMap[entity.componentId] === undefined)
                        anarkCoreData.product.componentToOccurrenceMap[entity.componentId] = [];
                    anarkCoreData.product.componentToOccurrenceMap[entity.componentId].push(entity);
                }
            }
        }
    };
    /**
     * Get an entity by its unique id.
     * @param {integer} cadEntityId - The unique id of the entity.
     * @returns {Entity} The matching entity or undefined if the id was not found.
     */
    this.getEntityById = function (cadEntityId) {
        var context = this;
        var entity = this.product.Occurrences[cadEntityId];
        if (entity === undefined) {
            entity = this.product.Components[cadEntityId];
            if (entity) {
                if (entity.getInstances === undefined) {
                    initComponentMaps(this);
                    entity.getInstances = function () {
                        return context.product.componentToInstanceMap[entity.cadEntityId];
                    };
                    entity.getOccurrences = function () {
                        return context.product.componentToOccurrenceMap[entity.cadEntityId];
                    };
                }
            }
            else {
                entity = this.product.Instances[cadEntityId];
                if (!entity) {
                    entity = this.product.GdtAnnotations[cadEntityId];
                    if (!entity) {
                        entity = this.product.Supplementals[cadEntityId];
                        if (!entity) {
                            entity = this.product.Views[cadEntityId];
                            if (!entity) {
                                entity = this.product.Bodies[cadEntityId];
                                if (!entity && this.product.Workspace.cadEntityId === cadEntityId) {
                                    entity = this.product.Workspace;
                                }
                            }
                        }
                    }
                }
            }
        }
        if (entity && entity.getAttributesInOriginalOrder === undefined) {
            entity.getAttributesInOriginalOrder = function () { return context.getAttributesInOriginalOrder(this); };
            entity.getAttributesInSmartSortedOrder = function () {
                return context.getAttributesInSmartSortedOrder(this);
            };
            entity.getAttributesAsHash = function () { return context.getAttributesAsHash(this); };
        }
        return entity;
    };
    /**
     * Gets the root CAD occurrence.
     * @returns {Occurrence} The root occurrence.
     */
    this.getRootOccurrence = function () {
        return this.getEntityById(this.product.RootOccurrenceId);
    };
    var getCollectionArray = function (context, hashCollection, methodAction) {
        var arr, id, entity;
        arr = [];
        for (id in hashCollection) {
            if (hashCollection.hasOwnProperty(id)) {
                entity = hashCollection[id];
                if (entity.getAttributesInOriginalOrder === undefined) {
                    entity.getAttributesInOriginalOrder = function () {
                        return context.getAttributesInOriginalOrder(this);
                    };
                    entity.getAttributesInSmartSortedOrder = function () {
                        return context.getAttributesInSmartSortedOrder(this);
                    };
                    entity.getAttributesAsHash = function () { return context.getAttributesAsHash(this); };
                    if (methodAction !== undefined)
                        methodAction(context.product, entity);
                }
                arr.push(entity);
            }
        }
        return arr;
    };
    /**
     * Get all CAD occurrences.
     * @see The {@link ANARKCOREDATA} constructor to create a structured occurrence tree.
     * @returns {Array<Occurrence>} A flat array of occurrences.
     */
    this.getOccurrences = function () {
        return getCollectionArray(this, this.product.Occurrences);
    };
    /**
     * Get all CAD components.
     * @returns {Array<Component>} An array of components.
     */
    this.getComponents = function () {
        initComponentMaps(this);
        var methodAction = function (product, entity) {
            entity.getInstances = function () { return product.componentToInstanceMap[this.cadEntityId]; };
            entity.getOccurrences = function () { return product.componentToOccurrenceMap[this.cadEntityId]; };
        };
        return getCollectionArray(this, this.product.Components, methodAction);
    };
    /**
     * Get all CAD instances.
     * @returns {Array<Entity>} An array of instances.
     */
    this.getInstances = function () {
        return getCollectionArray(this, this.product.Instances);
    };
    /**
     * Get all CAD GD&T annotations.
     * @returns {Array<Entity>} An array of GD&T annotations.
     */
    this.getGdtAnnotations = function () {
        return getCollectionArray(this, this.product.GdtAnnotations);
    };
    /**
     * Get all CAD supplemental geometry.
     * @returns {Array<Entity>} An array of supplemental geometry entities.
     */
    this.getSupplementals = function () {
        return getCollectionArray(this, this.product.Supplementals);
    };
    this.enableViewSortingByName = false;
    /**
     * Enable/disable view sorting.
     * @param {boolean} enableSortingByName - True to enable alphabetic view sorting, false to disable view sorting.
     * @see {@link ANARKCOREDATA#getViews}
     */
    this.sortViewsByName = function (enableSortingByName) {
        this.enableViewSortingByName = enableSortingByName;
    };
    /**
     * Get all CAD views. If view sorting has been enabled, this will return the views in order according to the view name. If view sorting is disabled, this returns the views in their original order.
     * @returns {Array<Entity>} An array of views.
     * @see {@link ANARKCOREDATA#sortViewsByName}
     */
    this.getViews = function () {
        if (this.enableViewSortingByName) {
            return getCollectionArray(this, this.product.Views)
                .sort(function (a, b) {
                if (a.name < b.name)
                    return -1;
                if (a.name > b.name)
                    return 1;
                return 0;
            });
        }
        return getCollectionArray(this, this.product.Views);
    };
    /**
     * Get all visible items for a given view occurrence id.
     * @param {integer} viewOccurrenceId - The cadEntityId of the view occurrence.
     * @returns {Array<Entity>} An array of entities that are visible in the specified view.
     */
    this.getVisibleItemsByViewOccurrenceId = function (viewOccurrenceId) {
        return this.resolveVisibleItems(this.getEntityById(viewOccurrenceId).VisibleIds);
    };
    /**
     * Resolves view VisibleIds into entities.
     */
    this.resolveVisibleItems = function (visibleIds) {
        var visibleItem, i;
        var visibleItems = [];
        for (i = 0; visibleIds.length > i; i += 1) {
            visibleItem = {
                id: visibleIds[i],
                showOnlyPartOccurrence: false
            };
            if (0 > visibleItem.id) {
                visibleItem.id *= -1;
                visibleItem.showOnlyPartOccurrence = true;
            }
            visibleItems.push(visibleItem);
        }
        return visibleItems;
    };
    /**
     * Get the settings that were used to publish the content.
     * @returns The settings object, containing property/value pairs.
     */
    this.getPublishingSettings = function () {
        return this.product.Settings;
    };
    /**
     * Creates an object that represents a color using floating point notation.
     * @param {float} r - The red value.
     * @param {float} g - The green value.
     * @param {float} b - The blue value.
     * @returns {object} An object that represents the specified color in the form of:  { rgb: [r, g, b], hex: "#xrxgxb" }.
     */
    this.createColorFromFloat = function (r, g, b) {
        var xr = (r * 255).toString(16);
        if (xr.length < 2)
            xr = "0" + xr;
        var xg = (g * 255).toString(16);
        if (xg.length < 2)
            xg = "0" + xg;
        var xb = (b * 255).toString(16);
        if (xb.length < 2)
            xb = "0" + xb;
        return {
            rgb: [r, g, b],
            hex: "#" + xr + xg + xb
        };
    };
    /**
     * Creates an object that represents a color using html/web notation.
     * @param {string} hex - The html/web color strictly in the form:  '#001122'
     * @returns {object} An object that represents the specified color in the form of:  { rgb: [r, g, b], hex: "#xrxgxb" }.
     */
    this.createColorFromHexNotation = function (hex) {
        return {
            rgb: [
                parseInt(hex.substring(1, 3), 16) / 255, parseInt(hex.substring(3, 5), 16) / 255,
                parseInt(hex.substring(5, 7), 16) / 255
            ],
            hex: hex
        };
    };
    /**
     * Available font styles. These font styles can be combined using bitwise operators, example:  (NORMAL | BOLD).
     * @member
     * @public
     * @property {number}  NORMAL - Normal
     * @property {number}  BOLD
     * @property {number}  ITALIC
     * @property {number}  UNDERLINE
     * @see {@link ANARKCOREDATA#fontStyles}
     */
    var FontStyleEnum = {
        NORMAL: 0,
        BOLD: 1,
        ITALIC: 2,
        UNDERLINE: 4
    };
    /**
     * Get available font styles.
     * @returns {ANARKCOREDATA~FontStyleEnum} The available font styles.
     */
    this.fontStyles = function () {
        return FontStyleEnum;
    };
    var buildOccurrenceTree = function (data) {
        var id, occurrence, parentOccurrence;
        var occurrences = data.product.Occurrences;
        for (id in occurrences) {
            if (occurrences.hasOwnProperty(id)) {
                occurrence = occurrences[id];
                if (occurrence.Occurrences === undefined &&
                    (occurrence.typeOfEntity === "AssemblyOccurrence" ||
                        occurrence.typeOfEntity === "PartOccurrence")) {
                    occurrence.Occurrences = [];
                    occurrence.GdtAnnotations = [];
                    occurrence.Supplementals = [];
                    occurrence.Views = [];
                }
                parentOccurrence = data.getEntityById(occurrence.parentId);
                if (parentOccurrence !== undefined) {
                    occurrence.parent = parentOccurrence;
                    if (parentOccurrence.Occurrences === undefined) {
                        parentOccurrence.Occurrences = [];
                        parentOccurrence.GdtAnnotations = [];
                        parentOccurrence.Supplementals = [];
                        parentOccurrence.Views = [];
                    }
                    if (occurrence.typeOfEntity === "AssemblyOccurrence" ||
                        occurrence.typeOfEntity === "PartOccurrence") {
                        parentOccurrence.Occurrences.push(occurrence);
                    }
                    else if (occurrence.typeOfEntity === "GdtOccurrence") {
                        parentOccurrence.GdtAnnotations.push(occurrence);
                    }
                    else if (occurrence.typeOfEntity === "SupplementalGeometryOccurrence") {
                        parentOccurrence.Supplementals.push(occurrence);
                    }
                    else if (occurrence.typeOfEntity === "ViewOccurrence") {
                        parentOccurrence.Views.push(occurrence);
                    }
                }
            }
        }
    };
    // TODO needs a bit of fixing to look better in docs
    /**
     * The process planning API object. This is only available if enableProcessPlanning was set to true in the ANARKCOREDATA constructor - when enabled, there will be a property of ANARKCOREDATA called processPlanning (ex: anarkCoreData.processPlanning).
     * @class ProcessPlanning
     */
    /**
     * Called to switch from one process step to another. Provides all of the information needed to update the occurrence buildout, camera settings, annotation visibility, animations associated with the process step, etc..
     * Initially, you should pass null for lastProcessStep. Passing null for lastProcessStep is essentially like a "reset" so that you get the full hide/show list so that the visibility states can be properly initialized. Keeping track of the lastProcessStep will enable better performance because only the relevant changes between lastProcessStep and processStep will be included. If the visibility states or the scene is updated by the user or by other code, you should pass a null for lastProcessStep to get back to the correct visibility state.
     * @example
     *   var stepInfo = anarkCoreData.processPlanning.moveToStep(lastProcessStep, processStep);
     *   lastProcessStep = processStep;
     *
     *   // stepInfo.animations contains an array of animationData - you can use animationData.animation.name and animationData.index to populate a listbox
     *
     *   // Additional information from the source datatable (if present) will be available in the stepInfo.workInstructionData property.
     *   updateSafety(stepInfo.workInstructionData.Safety);
     *   updateTools(stepInfo.workInstructionData.Tools);
     *
     *   resetAllPlacement();
     *
     *   for (i = 0; i < stepInfo.entityIdsToHide.length; i += 1)
     *       hide(stepInfo.entityIdsToHide[i]);
     *   for (i = 0; i < stepInfo.entityIdsToShow.length; i += 1)
     *       show(stepInfo.entityIdsToShow[i], false);
     *
     *   if (stepInfo.camera !== null)
     *       setCamera(stepInfo.camera);
     *
     *   if (stepInfo.placement !== null)
     *       updatePlacement(stepInfo.placement);
     *
     * @name ProcessPlanning#moveToStep
     * @param {string} lastProcessStep - The current process step that is being viewed - pass null the first time or if the current visibility state does not necessarily match the process buildout.
     * @param {string} processStep - The process step to move to.
     * @function
     * @returns {Array} Returns an array of objects in the form of:  { workInstructionData: extraRowData, workInstructionCells: cells, animations: animations, entityIdsToHide: idsToHide, entityIdsToShow: idsToShow, camera: camera, placement: placementInfo }. Note that camera and placementInfo may be null if there is no change to the camera or placement.
     */
    /**
     * Gets the ids of part occurrences that are being added or removed in the specified process step.
     * @name ProcessPlanning#getIdsAssignedToProcessStep
     * @param {string} processStep - The name of a process step.
     * @function
     * @returns {Array} Returns an array of occurrence ids.
     */
    /**
     * Get the parts that are added by a process step. Does not include parts that are removed.
     * @example
     *   var listBoxItems = [];
     *   var associations = document.anarkCoreData.processPlanning.getAssociatedParts("step 1", true);
     *
     *   for (var i = 0; i < associations.length; i += 1)
     *   {
     *       var partName = associations[i].name;
     *       var id = associations[i].id;
     *       var quantity = associations[i].quantity;
     *
     *       listBoxItems.push([quantity > 1 ? partName + " (x" + quantity + ")" : partName, id]);
     *   }
     * @name ProcessPlanning#getAssociatedParts
     * @param {string} processStep - The name of a process step.
     * @param {boolean} includeSubSteps - Set to true to include parts added in sub-steps of the specified step (includes the specified step and all sub-steps). False will provide the parts that are added only in the specified step.
     * @function
     * @returns {Array} Returns an array of objects in the form of { name: componentName, id: componentCadEntityId, quantity: componentCount }
     */
    var buildProcessPlanning = function (data) {
        var stepAssignments, step, processStepOrder, i, key, ProcessPlanning, hasProcessStepAssignments, processStepAdditionalSceneInfo;
        stepAssignments = data.product.WorkInstructionStepAssignments;
        hasProcessStepAssignments = false;
        processStepOrder = {};
        processStepAdditionalSceneInfo = {};
        for (step in stepAssignments) {
            if (stepAssignments.hasOwnProperty(step)) {
                hasProcessStepAssignments = true;
                break;
            }
        }
        for (i = 0; i < data.product.WorkInstructions.rows.length; i += 1) {
            key = data.product.WorkInstructions.rows[i].cells[0];
            processStepOrder[key] = i;
            processStepAdditionalSceneInfo[i] = data.product.WorkInstructionSceneInfo[key];
        }
        ProcessPlanning = /** @class */ (function () {
            function ProcessPlanning() {
                this.hasProcessStepAssignments = hasProcessStepAssignments;
                this.workInstructionsTable = new data.Table(data.product.WorkInstructions);
                this.workInstructionsLevelColumnIndex = this.workInstructionsTable.columnHash["Level"];
                this.useEffectiveSteps = true;
                this.stepVisibilityHash = {};
                var tempRecordIndex, tempIdIndex, tempStepName, tempStepAssociations, tempIsSubtractive, tempVisibleList, tempVisibleListIndex, tempId;
                tempVisibleList = [];
                for (tempRecordIndex = 0; tempRecordIndex < this.workInstructionsTable.rowCount; tempRecordIndex += 1) {
                    tempStepName = data.product.WorkInstructions.rows[tempRecordIndex].cells[0];
                    tempStepAssociations = [];
                    if (stepAssignments[tempStepName] !== undefined)
                        tempStepAssociations = stepAssignments[tempStepName].OccurrenceIds;
                    for (tempIdIndex = 0; tempIdIndex < tempStepAssociations.length; tempIdIndex += 1) {
                        tempId = tempStepAssociations[tempIdIndex];
                        tempIsSubtractive = false;
                        if (tempId < 0) {
                            tempIsSubtractive = true;
                            tempId *= -1;
                        }
                        tempVisibleListIndex = tempVisibleList.indexOf(tempId);
                        if (tempIsSubtractive) {
                            if (tempVisibleListIndex >= 0)
                                tempVisibleList.splice(tempVisibleListIndex, 1);
                        }
                        else {
                            if (tempVisibleListIndex < 0)
                                tempVisibleList.push(tempStepAssociations[tempIdIndex]);
                        }
                    }
                    this.stepVisibilityHash[tempStepName] = tempVisibleList.slice();
                }
            }
            ProcessPlanning.prototype.getAdditionalSceneInfoForProcessStep = function (processStep) {
                var stepIndex, additionalSceneInfo;
                stepIndex = processStepOrder[processStep];
                if (stepIndex === undefined)
                    return null;
                additionalSceneInfo = null;
                while (stepIndex >= 0 && !additionalSceneInfo) {
                    additionalSceneInfo = processStepAdditionalSceneInfo[stepIndex];
                    stepIndex -= 1;
                }
                if (additionalSceneInfo === undefined)
                    additionalSceneInfo = null;
                return additionalSceneInfo;
            };
            ProcessPlanning.prototype.getIdsAssignedToProcessStep = function (processStep) {
                var c, ids, associations;
                ids = [];
                if (stepAssignments[processStep] !== undefined) {
                    associations = stepAssignments[processStep].OccurrenceIds;
                    for (c = 0; c < associations.length; c += 1) {
                        if (associations[c] < 0)
                            ids.push(associations[c] * -1);
                        else
                            ids.push(associations[c]);
                    }
                }
                return ids;
            };
            ProcessPlanning.prototype.getAssociatedParts = function (processStep, includeSubSteps) {
                var occurrenceId, isSubtractive, componentId, assignments, x, components, componentCounts, associations, currentIndex, endOfSectionIndex, originalLevel;
                if (!processStep)
                    return [];
                associations = [];
                components = {};
                componentCounts = {};
                if (this.workInstructionsLevelColumnIndex === undefined)
                    includeSubSteps = false;
                currentIndex = processStepOrder[processStep];
                endOfSectionIndex = currentIndex;
                if (includeSubSteps) {
                    originalLevel =
                        data.product.WorkInstructions.rows[endOfSectionIndex].cells[this
                            .workInstructionsLevelColumnIndex];
                    while (endOfSectionIndex + 1 < data.product.WorkInstructions.rows.length &&
                        data.product.WorkInstructions.rows[endOfSectionIndex + 1].cells[this
                            .workInstructionsLevelColumnIndex] >
                            originalLevel) {
                        endOfSectionIndex += 1;
                    }
                }
                while (currentIndex <= endOfSectionIndex) {
                    processStep = data.product.WorkInstructions.rows[currentIndex].cells[0];
                    assignments = [];
                    if (stepAssignments[processStep] !== undefined)
                        assignments = stepAssignments[processStep].OccurrenceIds;
                    for (x = 0; x < assignments.length; x += 1) {
                        occurrenceId = assignments[x];
                        isSubtractive = false;
                        if (occurrenceId < 0) {
                            isSubtractive = true;
                            occurrenceId *= -1;
                        }
                        if (!isSubtractive) {
                            componentId = data.product.Occurrences[occurrenceId].componentId;
                            if (components[componentId]) {
                                componentCounts[componentId] += 1;
                            }
                            else {
                                components[componentId] = data.product.Components[componentId];
                                componentCounts[componentId] = 1;
                            }
                        }
                    }
                    currentIndex += 1;
                }
                for (x in components) {
                    if (components.hasOwnProperty(x)) {
                        associations.push({
                            name: components[x].name,
                            id: components[x].cadEntityId,
                            quantity: componentCounts[x]
                        });
                    }
                }
                return associations;
            };
            ProcessPlanning.prototype.getEffectiveProcessStep = function (processStep) {
                var endOfSectionIndex, originalLevel;
                if (processStep === null)
                    return null;
                if (this.workInstructionsLevelColumnIndex === undefined)
                    return data.product.WorkInstructions.rows[processStepOrder[processStep]].cells[0];
                endOfSectionIndex = processStepOrder[processStep];
                originalLevel =
                    data.product.WorkInstructions.rows[endOfSectionIndex].cells[this.workInstructionsLevelColumnIndex];
                while (endOfSectionIndex + 1 < data.product.WorkInstructions.rows.length &&
                    data.product.WorkInstructions.rows[endOfSectionIndex + 1].cells[this
                        .workInstructionsLevelColumnIndex] >
                        originalLevel) {
                    endOfSectionIndex += 1;
                }
                return data.product.WorkInstructions.rows[endOfSectionIndex].cells[0];
            };
            ProcessPlanning.prototype.moveToStep = function (fromStep, toStep) {
                var extraRowData, fromStepAdditionalSceneInfo, toStepAdditionalSceneInfo, fromVisibility, toVisibility, idsToShow, idsToHide, c, animations, animationIndexes, row, tempFromAsi, tempToAsi;
                fromStepAdditionalSceneInfo = this.getAdditionalSceneInfoForProcessStep(fromStep);
                toStepAdditionalSceneInfo = this.getAdditionalSceneInfoForProcessStep(toStep);
                row = data.product.WorkInstructions.rows[processStepOrder[toStep]];
                extraRowData = {};
                for (c = 0; c < data.product.WorkInstructions.columns.length; c += 1)
                    extraRowData[data.product.WorkInstructions.columns[c].name] = row.cells[c];
                if (this.useEffectiveSteps) {
                    fromStep = this.getEffectiveProcessStep(fromStep);
                    toStep = this.getEffectiveProcessStep(toStep);
                }
                fromVisibility = fromStep === null ? [] : this.stepVisibilityHash[fromStep];
                toVisibility = this.stepVisibilityHash[toStep];
                idsToShow = [];
                idsToHide = fromStep === null ? [data.product.RootOccurrenceId] : [];
                for (c = 0; c < toVisibility.length; c += 1) {
                    if (fromVisibility.indexOf(toVisibility[c]) < 0)
                        idsToShow.push(toVisibility[c]);
                }
                for (c = 0; c < fromVisibility.length; c += 1) {
                    if (toVisibility.indexOf(fromVisibility[c]) < 0)
                        idsToHide.push(fromVisibility[c]);
                }
                tempFromAsi = fromStepAdditionalSceneInfo === null
                    ? []
                    : fromStepAdditionalSceneInfo.VisibleChildOccurrenceIds;
                tempToAsi = toStepAdditionalSceneInfo === null
                    ? []
                    : toStepAdditionalSceneInfo.VisibleChildOccurrenceIds;
                for (c = 0; c < tempToAsi.length; c += 1) {
                    if (tempFromAsi.indexOf(tempToAsi[c]) < 0)
                        idsToShow.push(tempToAsi[c]);
                }
                for (c = 0; c < tempFromAsi.length; c += 1) {
                    if (tempToAsi.indexOf(tempFromAsi[c]) < 0)
                        idsToHide.push(tempFromAsi[c]);
                }
                animations = [];
                animationIndexes = row.animations;
                if (animationIndexes) {
                    for (c = 0; c < animationIndexes.length; c += 1) {
                        animations.push({
                            animation: data.product.Animations[animationIndexes[c]],
                            index: animationIndexes[c]
                        });
                    }
                }
                return {
                    workInstructionData: extraRowData,
                    workInstructionCells: row.cells,
                    animations: animations,
                    entityIdsToHide: idsToHide,
                    entityIdsToShow: idsToShow,
                    camera: toStepAdditionalSceneInfo !== null ? toStepAdditionalSceneInfo.Camera : null,
                    placement: toStepAdditionalSceneInfo !== null ? toStepAdditionalSceneInfo.Placement : null,
                    color: toStepAdditionalSceneInfo !== null ? toStepAdditionalSceneInfo.Color : null
                };
            };
            return ProcessPlanning;
        }());
        data.processPlanning = new ProcessPlanning();
    };
    if (buildOccurrenceStructure === true) // optional parameter to ANARKCOREDATA constructor
     {
        buildOccurrenceTree(this);
    }
    if (enableProcessPlanning === true) // optional parameter to ANARKCOREDATA constructor
     {
        buildProcessPlanning(this);
    }
}
var Vector3D = /** @class */ (function () {
    /**
     * A 3D Vector.
     * @class Vector3D
     * @param {float} x - The X component of the vector.
     * @param {float} y - The Y component of the vector.
     * @param {float} z - The Z component of the vector.
     */
    function Vector3D(x, y, z) {
        this.x = x;
        this.y = y;
        this.z = z;
    }
    /**
     * Get the length of the vector.
     * @memberof Vector3D
     * @returns {float} The vector length.
     */
    Vector3D.prototype.length = function () {
        return Math.sqrt((this.x * this.x) + (this.y * this.y) + (this.z * this.z));
    };
    /**
     * Normalizes the existing vector.
     * @memberof Vector3D
     */
    Vector3D.prototype.normalize = function () {
        var len = this.length();
        if (len === 0)
            return;
        this.x = this.x / len;
        this.y = this.y / len;
        this.z = this.z / len;
    };
    /**
     * Calculate the vector cross product.
     * @memberof Vector3D
     * @param {Vector3D} other - The other vector to use in the calculation.
     * @returns {Vector3D} A new vector representing the cross product.
     */
    Vector3D.prototype.cross = function (other) {
        return new Vector3D(this.y * other.z - other.y * this.z, this.z * other.x - other.z * this.x, this.x * other.y - other.x * this.y);
    };
    /**
     * Calculate the vector dot product.
     * @memberof Vector3D
     * @param {Vector3D} other - The other vector to use in the calculation.
     * @returns {float} The dot product.
     */
    Vector3D.prototype.dot = function (other) {
        return (this.x * other.x) + (this.y * other.y) + (this.z * other.z);
    };
    /**
     * Add this vector to another.
     * @memberof Vector3D
     * @param {Vector3D} other - The other vector to use in the calculation.
     * @returns {Vector3D} A new vector representing the sum of the two vectors.
     */
    Vector3D.prototype.add = function (other) {
        return new Vector3D(this.x + other.x, this.y + other.y, this.z + other.z);
    };
    /**
     * Subtract another vector from this vector.
     * @memberof Vector3D
     * @param {Vector3D} other - The other vector to use in the calculation.
     * @returns {Vector3D} A new vector representing the difference of the two vectors (this vector - other vector).
     */
    Vector3D.prototype.subtract = function (other) {
        return new Vector3D(this.x - other.x, this.y - other.y, this.z - other.z);
    };
    /**
     * Scales the vector.
     * @memberof Vector3D
     * @param {float} factor - The scale factor.
     */
    Vector3D.prototype.scaleInPlace = function (factor) {
        this.x *= factor;
        this.y *= factor;
        this.z *= factor;
    };
    /**
     * Set the vector to the values of another vector.
     * @memberof Vector3D
     * @param {Vector3D} other - The other vector.
     */
    Vector3D.prototype.set = function (other) {
        this.x = other.x;
        this.y = other.y;
        this.z = other.z;
    };
    /**
     * Set the vector values from an array.
     * @memberof Vector3D
     * @param {Array<integer>} arr - An array in the form of [x,y,z].
     */
    Vector3D.prototype.setFromArray = function (arr) {
        this.x = arr[0];
        this.y = arr[1];
        this.z = arr[2];
    };
    /**
     * Get the vector values as an array.
     * @memberof Vector3D
     * @returns {Array<int>} An array in the form of [x,y,z].
     */
    Vector3D.prototype.asArray = function () {
        return [this.x, this.y, this.z];
    };
    return Vector3D;
}());
var Matrix4X4 = /** @class */ (function () {
    /**
     * A 4x4 3D transformation matrix.
     * @class Matrix4x4
     */
    function Matrix4X4() {
        this.mat = [
            1, 0, 0, 0,
            0, 1, 0, 0,
            0, 0, 1, 0,
            0, 0, 0, 1
        ];
    }
    /**
     * Get an element from the matrix.
     * @memberof Matrix4x4
     * @param {number} row - The row (0 - 3).
     * @param {number} col - The column (0 - 3).
     * @returns {number} The number at the specified (row, col).
     */
    Matrix4X4.prototype.getElement = function (row, col) {
        return this.mat[row * 4 + col];
    };
    /**
     * Get the translation vector from the matrix.
     * @memberof Matrix4x4
     * @returns {Vector3D} The translation.
     */
    Matrix4X4.prototype.getTranslation = function () {
        return new Vector3D(this.mat[12], this.mat[13], this.mat[14]);
    };
    Matrix4X4.prototype.transformDirection = function (vec) {
        var col, row;
        var vector = [vec.x, vec.y, vec.z, 1.0];
        var result = [0.0, 0.0, 0.0, 0.0];
        for (col = 0; col < 3; col += 1) {
            for (row = 0; row < 3; row += 1) {
                result[col] += vector[row] * this.getElement(row, col);
            }
        }
        return new Vector3D(result[0], result[1], result[2]);
    };
    /**
     * Set the matrix from an array of 16 numbers.
     * @memberof Matrix4x4
     * @param {Array<number>} ma - Numbers.
     */
    Matrix4X4.prototype.setFromArray = function (ma) {
        this.mat = [
            ma[0], ma[1], ma[2], ma[3], ma[4], ma[5], ma[6], ma[7], ma[8], ma[9], ma[10], ma[11], ma[12], ma[13],
            ma[14], ma[15]
        ];
    };
    /**
     * Set the matrix using parameters.
     * @memberof Matrix4x4
     */
    Matrix4X4.prototype.set16 = function (m1, m2, m3, m4, m5, m6, m7, m8, m9, m10, m11, m12, m13, m14, m15, m16) {
        this.mat = [m1, m2, m3, m4, m5, m6, m7, m8, m9, m10, m11, m12, m13, m14, m15, m16];
    };
    /**
     * Multiplies the matrix by another matrix.
     * @memberof Matrix4x4
     * @param {Matrix4X4} other - The other matrix.
     */
    Matrix4X4.prototype.multiplyInPlace = function (other) {
        var matrix = new Matrix4X4();
        matrix.mat[0] = this.mat[0] * other.mat[0] +
            this.mat[1] * other.mat[4] +
            this.mat[2] * other.mat[8] +
            this.mat[3] * other.mat[12];
        matrix.mat[1] = this.mat[0] * other.mat[1] +
            this.mat[1] * other.mat[5] +
            this.mat[2] * other.mat[9] +
            this.mat[3] * other.mat[13];
        matrix.mat[2] = this.mat[0] * other.mat[2] +
            this.mat[1] * other.mat[6] +
            this.mat[2] * other.mat[10] +
            this.mat[3] * other.mat[14];
        matrix.mat[3] = this.mat[0] * other.mat[3] +
            this.mat[1] * other.mat[7] +
            this.mat[2] * other.mat[11] +
            this.mat[3] * other.mat[15];
        matrix.mat[4] = this.mat[4] * other.mat[0] +
            this.mat[5] * other.mat[4] +
            this.mat[6] * other.mat[8] +
            this.mat[7] * other.mat[12];
        matrix.mat[5] = this.mat[4] * other.mat[1] +
            this.mat[5] * other.mat[5] +
            this.mat[6] * other.mat[9] +
            this.mat[7] * other.mat[13];
        matrix.mat[6] = this.mat[4] * other.mat[2] +
            this.mat[5] * other.mat[6] +
            this.mat[6] * other.mat[10] +
            this.mat[7] * other.mat[14];
        matrix.mat[7] = this.mat[4] * other.mat[3] +
            this.mat[5] * other.mat[7] +
            this.mat[6] * other.mat[11] +
            this.mat[7] * other.mat[15];
        matrix.mat[8] = this.mat[8] * other.mat[0] +
            this.mat[9] * other.mat[4] +
            this.mat[10] * other.mat[8] +
            this.mat[11] * other.mat[12];
        matrix.mat[9] = this.mat[8] * other.mat[1] +
            this.mat[9] * other.mat[5] +
            this.mat[10] * other.mat[9] +
            this.mat[11] * other.mat[13];
        matrix.mat[10] = this.mat[8] * other.mat[2] +
            this.mat[9] * other.mat[6] +
            this.mat[10] * other.mat[10] +
            this.mat[11] * other.mat[14];
        matrix.mat[11] = this.mat[8] * other.mat[3] +
            this.mat[9] * other.mat[7] +
            this.mat[10] * other.mat[11] +
            this.mat[11] * other.mat[15];
        matrix.mat[12] = this.mat[12] * other.mat[0] +
            this.mat[13] * other.mat[4] +
            this.mat[14] * other.mat[8] +
            this.mat[15] * other.mat[12];
        matrix.mat[13] = this.mat[12] * other.mat[1] +
            this.mat[13] * other.mat[5] +
            this.mat[14] * other.mat[9] +
            this.mat[15] * other.mat[13];
        matrix.mat[14] = this.mat[12] * other.mat[2] +
            this.mat[13] * other.mat[6] +
            this.mat[14] * other.mat[10] +
            this.mat[15] * other.mat[14];
        matrix.mat[15] = this.mat[12] * other.mat[3] +
            this.mat[13] * other.mat[7] +
            this.mat[14] * other.mat[11] +
            this.mat[15] * other.mat[15];
        this.setFromArray(matrix.mat);
    };
    ;
    return Matrix4X4;
}());
/// <reference path="JsonApi_COMMON_Interfaces.ts"/>
/**
 * BomApi object to create Bom Tables
 * @constructor
 * @param {ANARKCOREDATA} anarkCoreData
 */
function BomApi(anarkCoreData) {
    // copy of anark core data fro the bom to use
    this.anarkCoreData = anarkCoreData;
    /**
     * BomTable to abstract html/pdf bom table data for easy manipulation and front end presentation <br>
     * For useful helper functions, see {@link BomFunctions}
     * @class BomTable
     */
    this.bomTable = /** @class */ (function () {
        function BomTable(arg1, arg2) {
            this.columns = arg1;
            this.rows = arg2;
        }
        /**
         * Inserts a new column into the table, with automatically generated values generated based on {@link evalFunction}
         * Requires Cad Data to be either mapped to table or bom to be built on Cad Data
         * @memberof BomTable
         * @param {string} name Name of the new column
         * @param {evalFunction} func The function to which each cell of new column will evaluate to
         * @param {integer} [index=-1] The location of the new column, default end of the table
         * @example
         * // add new column to end of the table
         * bomTable.addColumn('Quantity', getOccurrenceCount);
         * @example
         * // add new column to the front of table
         * bomTable.addColumn('Component Name', getComponentName, 0);
         */
        BomTable.prototype.addColumn = function (name, func, index) {
            // add new element to columns with new rule
            var newElem = { name: name, func: func };
            if (index === undefined) {
                index = this.columns.push(newElem);
            }
            else {
                if (this.areOccs()) {
                    try {
                        index = this.resolveColumnArg(index);
                    }
                    catch (e) {
                        throw new Error('addColumn: ' + e.message);
                    }
                    this.columns.splice(index, 0, newElem);
                }
                else {
                    throw new Error('addColumn: Cannot invoke function since no occurrences for any row');
                }
            }
            // next, modify rows with new function in column
            for (var i = 0; i < this.rows.length; i++) {
                var row = this.rows[i];
                if (row.occurrences.length !== 0) {
                    row.cells.splice(index, 0, func(this.rows[i].component, this.rows[i].occurrences));
                }
                else {
                    row.cells.splice(index, 0, undefined);
                }
            }
        };
        /**
         * Inserts a new row into the table
         * @memberof BomTable
         * @param {Array<columnIndex>} input The input for each column of the new row
         * @param {integer} [index=-1] The location of the new row, default end of the table
         * @example
         * // add a row of strings to end of a 4 column table
         * bomTable.addRow(['fee', 'fie', 'fo', 'fum'])
         * @example
         * // add row at start that doesn't tie into cad data of 3 column table with columns ['name', 'quantity', 'price']
         * bomTable.addRow(['glue', 4, 25], 0)
         */
        BomTable.prototype.addRow = function (input, index) {
            if (index === undefined) {
                index = this.rows.length;
            }
            if (input.length !== this.columns.length) {
                throw new Error('addRow: Table needed ' +
                    this.columns.length +
                    ' input cells, ' +
                    input.length +
                    ' provided');
            }
            if (index > this.rows.length || -index > this.rows.length) {
                throw new Error('addRow: Index ' + index + ' is out of range');
            }
            var cells = input;
            this.rows.splice(index, 0, { cells: cells, component: undefined, occurrences: [], groups: [] });
        };
        // Custom pretty Print table for testing purposes
        /*
        public prettyPrint(element: HTMLElement, id?: string) {
            var table: HTMLTableElement = document.createElement("table");
            if (id)
                table.id = id;
            table.style.border = '2px solid black';
            var row = table.insertRow();
            for (var i = 0; i < this.columns.length; i++) {
                var th = document.createElement('th');
                th.innerHTML = this.columns[i].name;
                row.appendChild(th);
            }
            for (var i = 0; i < this.rows.length; i++) {
                var tr = table.insertRow();
                for (var j = 0; j < this.rows[i].cells.length; j++) {
                    var cell = tr.insertCell();
                    cell.innerHTML = this.rows[i].cells[j];
                }
            }
            element.appendChild(table);
            return table;
        }
        */
        /**
         * Delete a row from the table
         * @memberof BomTable
         * @param {integer} index Index of row delete
         */
        BomTable.prototype.deleteRow = function (index) {
            try {
                this.checkRowIndex(index);
            }
            catch (e) {
                throw new Error('deleteRow: ' + e.message);
            }
            this.rows.splice(index, 1);
        };
        /**
         * Delete an entire row and its cells from a table
         * @memberof BomTable
         * @param {columnIndex} column Either the name/index of the column to delete
         */
        BomTable.prototype.deleteColumn = function (column) {
            try {
                column = this.resolveColumnArg(column);
            }
            catch (e) {
                throw new Error('deleteColumn: ' + e.message);
            }
            this.columns.splice(column, 1);
            for (var i = 0; i < this.rows.length; i++) {
                this.rows[i].cells.splice(column, 1);
            }
        };
        /**
         * Order rows of table by specific column
         * @memberof BomTable
         * @param {columnIndex} column The column name/index you wish to order by
         * @param {integer} opt 1: ascending order, -1: descending order
         */
        BomTable.prototype.orderRowsBy = function (column, opt) {
            try {
                column = this.resolveColumnArg(column);
            }
            catch (e) {
                throw new Error('orderRowsBy: ' + e.message);
            }
            this.rows.sort(function (a, b) {
                if (a.cells[column] > b.cells[column]) {
                    return opt;
                }
                else if (a.cells[column] < b.cells[column]) {
                    return -opt;
                }
                else {
                    return 0;
                }
            });
        };
        /**
         * Get the name of a column at an index
         * @memberof BomTable
         * @param {integer} index The index of the column
         */
        BomTable.prototype.getColumnName = function (index) {
            try {
                this.resolveColumnArg(index);
            }
            catch (e) {
                throw new Error('getColumnName: ' + e.message);
            }
            return this.columns[index].name;
        };
        /**
         * Get the index of a column given a name
         * @memberof BomTable
         * @param {string} name Name of the column
         */
        BomTable.prototype.getColumnIndex = function (name) {
            try {
                return this.getColIndex(name);
            }
            catch (e) {
                throw new Error('getColumnIndex: ' + e.message);
            }
        };
        BomTable.prototype.getColIndex = function (name) {
            for (var i = 0; i < this.columns.length; i++) {
                if (this.columns[i].name == name) {
                    return i;
                }
            }
            throw new Error('Column name "' + name + '" does not exist');
        };
        /**
         * Get the contents of a cell
         * @memberof BomTable
         * @param {columnIndex} colIndex The desired column name/index
         * @param {integer} rowIndex The desired row index
         */
        BomTable.prototype.getCell = function (colIndex, rowIndex) {
            try {
                colIndex = this.resolveColumnArg(colIndex);
            }
            catch (e) {
                throw new Error('getCell: ' + e.message);
            }
            try {
                this.checkRowIndex(rowIndex);
            }
            catch (e) {
                throw new Error('getCell: ' + e.message);
            }
            return this.rows[rowIndex].cells[colIndex];
        };
        /**
         * Get Occurrences associated with a row
         * @memberof BomTable
         * @param {integer} index The desired row index
         */
        BomTable.prototype.getOccurrenceIdsFromIndex = function (index) {
            try {
                this.checkRowIndex(index);
                this.checkOccurrences(index);
            }
            catch (e) {
                throw new Error('getOccurrenceIdsFromIndex: ' + e.message);
            }
            var result = [];
            for (var i = 0; i < this.rows[index].occurrences.length; i++) {
                result.push(this.rows[index].occurrences[i].cadEntityId);
            }
            return result;
        };
        /**
         * Get the index of the row matching the Occurrence Id provided. Throws exception if
         * no index matches the given Occurrence
         * @memberof BomTable
         * @param {integer} occId The Id of the Occurrence
         */
        BomTable.prototype.getIndexFromOccurrence = function (occId) {
            for (var i = 0; i < this.rows.length; i++) {
                for (var j = 0; j < this.rows[i].occurrences.length; j++) {
                    if (this.rows[i].occurrences[j].cadEntityId === occId) {
                        return i;
                    }
                }
            }
            throw new Error('getIndexFromOccurrence: Occurrence ' + occId + ' is not associated with any row');
        };
        // swaps two rows
        /**
         * Swaps two rows in the table. Moves first row to second, vice versa.
         * @memberof BomTable
         * @param {integer} currentIndex The first row
         * @param {integer} newIndex The second row
         */
        BomTable.prototype.swapRow = function (currentIndex, newIndex) {
            try {
                this.checkRowIndex(currentIndex);
                this.checkRowIndex(newIndex);
            }
            catch (e) {
                throw new Error('swapRow: ' + e.message);
            }
            var temp = this.rows[newIndex];
            this.rows[newIndex] = this.rows[currentIndex];
            this.rows[currentIndex] = temp;
        };
        // given a search mapping, with a column and accompanying function, searches for a row(s) that match
        /**
         * Get the rows that match a search array, where each element of the array is a tuple with the column and its
         * requirements to match
         * @memberof BomTable
         * @param {Array<search>} search The search Array
         * @example
         * // find a rows that have Occurrence Quantity over 1, using {@link searchQuantityOverOne}
         * var rowIndexes = bomTable.searchTableForIndexes([['quantity', searchQuantityOverOne]])
         */
        BomTable.prototype.searchTableForIndexes = function (search) {
            var results = [];
            try {
                for (var i = 0; i < this.rows.length; i++) {
                    if (this.searchPass(search, i)) {
                        results.push(i);
                    }
                }
            }
            catch (e) {
                throw new Error('searchTableForIndexes: ' + e.message);
            }
            return results;
        };
        // returns occ Ids of a given search
        /**
         * Get Occurrences that match search parameters
         * @memberof BomTable
         * @param {Array<search>} search The search Array
         * @returns {Array<integer>} The Occurrences associated with the search
         * @example
         * // gets Occs that where rows have quantity over 1 in 'quantity' column
         * var occs = bomTable.searchTableForOccurrences([['quantity', searchForQuantityOverOne]]);
         */
        BomTable.prototype.searchTableForOccurrences = function (search) {
            var results = [];
            try {
                for (var i = 0; i < this.rows.length; i++) {
                    if (this.searchPass(search, i)) {
                        for (var _i = 0, _a = this.rows[i].occurrences; _i < _a.length; _i++) {
                            var occ = _a[_i];
                            results.push(occ.cadEntityId);
                        }
                    }
                }
            }
            catch (e) {
                throw new Error('searchTableForOccurrences: ' + e.message);
            }
            return results;
        };
        // create a group by passing a filter
        /**
         * Method to create a group by searching rows for conditions
         * @memberof BomTable
         * @param {groupName} name
         * @param {Array<search>} search for each row to see if it should be added to group
         * @return {Array<integer>} the row indexes that were added to the group
         * @example
         * // create group 'quantity over 1' by searching for column 'quantity' over 1
         * bomTable.createGroupByFilter('quantity over 1', [['quantity]])
         */
        BomTable.prototype.createGroupByFilter = function (name, search) {
            this.clearOldGroup(name);
            var results = [];
            // add groupId to rows that fit filter
            for (var i = 0; i < this.rows.length; i++) {
                var row = this.rows[i];
                var pass = true;
                for (var _i = 0, search_1 = search; _i < search_1.length; _i++) {
                    var arg = search_1[_i];
                    try {
                        var column = this.resolveColumnArg(arg["0"]);
                    }
                    catch (e) {
                        throw new Error('createGroupByFilter: ' + e.message);
                    }
                    if (!arg["1"](row.cells[column])) {
                        pass = false;
                    }
                }
                if (pass) {
                    row.groups.push(name);
                    results.push(i);
                }
            }
            return results;
        };
        // create a group by passing indexes of rows
        /**
         * Method to create a group by row indexes
         * @memberof BomTable
         * @param {groupName} name Name of group
         * @param {Array<integer>} indexes row indexes to associate with group
         * @return {Array<integer>} the row indexes that were added to the group
         * @example
         * // create group 1 with rows 0, 1, 2
         * bomTable.createGroupByIndexes(1, [0, 1, 2])
         */
        BomTable.prototype.createGroupByIndexes = function (name, indexes) {
            this.clearOldGroup(name);
            var results = [];
            for (var _i = 0, indexes_1 = indexes; _i < indexes_1.length; _i++) {
                var index = indexes_1[_i];
                try {
                    this.checkRowIndex(index);
                }
                catch (e) {
                    throw new Error('createGroupByIndexes: ' + e.message);
                }
            }
            for (var _a = 0, indexes_2 = indexes; _a < indexes_2.length; _a++) {
                var index_1 = indexes_2[_a];
                this.rows[index_1].groups.push(name);
                results.push(index_1);
            }
            return results;
        };
        /**
         * Method to remove group
         * @memberof BomTable
         * @param {groupName} name group to remove
         */
        BomTable.prototype.clearOldGroup = function (name) {
            for (var _i = 0, _a = this.rows; _i < _a.length; _i++) {
                var row = _a[_i];
                for (var i = 0; i < row.groups.length; i++) {
                    if (row.groups[i] == name) {
                        row.groups.splice(i, 1);
                    }
                }
            }
        };
        // get the indexes of a group
        /**
         * Get the indexes from a group
         * @memberof BomTable
         * @param {groupName} name Name of group desired
         * @return {Array<integer>} Row Indexes from group
         */
        BomTable.prototype.getIndexesFromGroup = function (name) {
            var indexes = [];
            var result = false;
            for (var i = 0; i < this.rows.length; i++) {
                if (this.rows[i].groups.indexOf(name) > -1) {
                    indexes.push(i);
                    result = true;
                }
            }
            if (!result) {
                throw new Error('getIndexesFromGroup: group "' + name + '" does not exist in the table');
            }
            return indexes;
        };
        // get occ ids from a group
        /**
         * Get the Occurrences associated with a group
         * @memberof BomTable
         * @param {groupName} name Name of group desired
         * @return {Array<integer>} Occurrences from rows in group
         */
        BomTable.prototype.getOccurrencesFromGroup = function (groupId) {
            var occs = [];
            var pass = false;
            for (var _i = 0, _a = this.rows; _i < _a.length; _i++) {
                var row = _a[_i];
                if (row.groups.indexOf(groupId) > -1) {
                    if (row.occurrences !== undefined) {
                        pass = true;
                        for (var _b = 0, _c = row.occurrences; _b < _c.length; _b++) {
                            var occ = _c[_b];
                            occs.push(occ.cadEntityId);
                        }
                    }
                }
            }
            if (!pass) {
                throw new Error('getGroup: group ' + name + ' exists in the table');
            }
            return occs;
        };
        // adds a footer to table, given by an input cell that will go into each cell
        /**
         * Method to create a footer row at end of table. with each cell set to input
         * @memberof BomTable
         * @param {string|number} input The value to set each cell to
         */
        BomTable.prototype.addFooter = function (input) {
            var arg = [];
            for (var col in this.columns) {
                arg.push(input);
            }
            this.addRow(arg, this.rows.length);
        };
        // number of current cols
        /**
         * Get the number of columns in table
         * @memberof BomTable
         * @returns {integer} Column count
         */
        BomTable.prototype.getNumberColumns = function () {
            return this.columns.length;
        };
        // number of current rows
        /**
         * Get the number of rows in table
         * @memberof BomTable
         * @returns {integer} Row count
         */
        BomTable.prototype.getNumberRows = function () {
            return this.rows.length;
        };
        // TODO FUTURE save meta for when in es6
        BomTable.prototype.resolveColumnArg = function (arg) {
            if (typeof arg === "string") {
                try {
                    arg = this.getColIndex(arg);
                }
                catch (e) {
                    throw new Error('Column name "' + arg + '" does not exist');
                }
            }
            if (arg > this.columns.length - 1 || -arg > this.columns.length - 1) {
                throw new Error('Column index ' + arg + ' out of bounds');
            }
            return arg;
        };
        BomTable.prototype.checkRowIndex = function (index) {
            if (this.rows[index] === undefined) {
                throw new Error('Row does not exist for index ' + index);
            }
        };
        BomTable.prototype.checkOccurrences = function (index) {
            if (this.rows[index].occurrences.length === 0) {
                throw new Error('Row ' + index + ' has no occurrences');
            }
        };
        BomTable.prototype.areOccs = function () {
            var result = false;
            for (var _i = 0, _a = this.rows; _i < _a.length; _i++) {
                var row = _a[_i];
                if (row.occurrences.length !== 0) {
                    result = true;
                }
            }
            return result;
        };
        BomTable.prototype.searchPass = function (search, rowIndex) {
            var result = true;
            for (var _i = 0, search_2 = search; _i < search_2.length; _i++) {
                var s = search_2[_i];
                try {
                    s["0"] = this.resolveColumnArg(s["0"]);
                }
                catch (e) {
                    throw new Error(e.message);
                }
                if (!s["1"](this.rows[rowIndex].cells[s["0"]])) {
                    result = false;
                }
            }
            return result;
        };
        return BomTable;
    }());
    /**
     * Method to create a new {@link BomTable} based on workspace table
     * Can map each row of outside table to cad data based on a mapping function argument (optional)
     * @param {Table} table The outside workspace table. See {@link ANARKCOREDATA#getWorkspaceTableByName} for getting this table
     * @param {map} [map] Optional tuple that maps each cell in a given column to specific cad data
     * @param {filterFunction} [filter] Optional filter function to use given a mapping function
     * @returns {BomTable} A new BomTable based on above parameters
     * @example
     * // From table with no mapping
     * var table = anarkCoreData.getWorkSpaceTableByName('outsideBomTable');
     * var bomTable = bomApi.createNewBomTableFromWorkspaceTable(table, map, filter)
     * @example
     * // From table with mapping
     * var table = anarkCoreData.getWorkSpaceTableByName('outsideBomTable');
     * @example
     * // mapping with column 'name' in 'outsideBomTable' matching component name in cad data
     * var map = ['name', mapCompName];
     * var filter = basicFilter;
     * var bomTable = bomApi.createNewBomTableFromWorkspaceTable(table, map, filter);
     */
    this.createNewBomTableFromWorkspaceTable = function (table, map, filter) {
        var columns = [];
        var rows = [];
        var inputCols = table.getColumns();
        var inputRows = table.getRows();
        for (var i_1 = 0; i_1 < inputCols.length; i_1++) {
            columns.push({ name: inputCols[i_1].name, func: undefined });
        }
        // no mapping to cad data
        if (map === undefined) {
            for (var i_2 = 0; i_2 < inputRows.length; i_2++) {
                rows.push({ cells: inputRows[i_2].cells.slice(), component: undefined, occurrences: [], groups: [] });
            }
        }
        else {
            var occs = this.anarkCoreData.getOccurrences();
            var compIds = [];
            var comps = this.anarkCoreData.getComponents();
            var filteredOccs = [];
            var filteredComps = [];
            if (filter !== undefined) {
                // add all occurrences that fit the filter, with the accompanying component ids
                for (var i_3 = 0; i_3 < occs.length; i_3++) {
                    var occ = occs[i_3];
                    if (filter(occ)) {
                        filteredOccs.push(occ);
                        if (compIds.indexOf(occ.componentId) == -1)
                            compIds.push(occ.componentId);
                    }
                }
                // add components that were tagged through occs
                for (var i_4 = 0; i_4 < comps.length; i_4++) {
                    var comp = comps[i_4];
                    if (compIds.indexOf(comp.cadEntityId) == -1) {
                        comps.splice(i_4, 1);
                    }
                    filteredComps = comps.slice();
                }
            }
            else {
                filteredOccs = occs;
                filteredComps = comps;
            }
            var index;
            // get the index of the correct column to map cad data to 
            if (typeof map["0"] == "string") {
                var searchCols = table.getColumns();
                var found = false;
                for (var i = 0; i < searchCols.length; i++) {
                    if (searchCols[i].name == map["0"]) {
                        index = i;
                        found = true;
                    }
                }
                if (!found) {
                    throw new Error('createNewBomTableFromTable: ColumnName ' + map["0"] + 'provided does not exist in the given table');
                }
            }
            else {
                index = map["0"];
            }
            if (index > columns.length) {
                throw new Error('createNewBomTableFromTable: ColumnIndex ' + index + 'is not within range ' + columns.length);
            }
            // create mapping of each row to cad data
            var addedComps = false;
            // for each input row, grab cad data if possible
            for (var i_5 = 0; i_5 < inputRows.length; i_5++) {
                var comp_1 = void 0;
                var matchingOccs = filteredOccs.slice();
                var match = false;
                for (var j = 0; j < filteredComps.length; j++) {
                    comp_1 = filteredComps[j];
                    // let cell = inputRows[i].cells[index];
                    if (map["1"](comp_1, inputRows[i_5].cells[index])) {
                        addedComps = true;
                        match = true;
                        // get occs and add row to row Occs if match
                        for (var k = 0; k < matchingOccs.length; k++) {
                            if (matchingOccs[k].componentId != comp_1.cadEntityId) {
                                matchingOccs.splice(k, 1);
                                k--;
                            }
                        }
                        break;
                    }
                }
                if (match) {
                    rows.push({
                        cells: inputRows[i_5].cells.slice(),
                        component: comp_1,
                        occurrences: matchingOccs.slice(),
                        groups: []
                    });
                }
                else {
                    rows.push({
                        cells: inputRows[i_5].cells.slice(),
                        component: undefined,
                        occurrences: [],
                        groups: []
                    });
                }
            }
            if (!addedComps) {
                throw new Error('createNewBomTableFromTable: occurrence mapping failed, no occurrences match a row index');
            }
        }
        return new this.bomTable(columns, rows);
    };
    // given cad data, create a bom based on the custom functions passed into function
    // aggregation can be done by passing true to aggregate flag param
    /**
     * Create a new {@link BomTable} based on cad data
     * @param {filterFunction} filter Function to filter cad data desired
     * @param {Array<bomColumn>} cols The column definitions to populate each cell of the table
     * @returns {BomTable} A new BomTable based on above parameters
     * @example
     * // create BomTable with Bomcolumns name, quantity, and type with basic filter
     * var columns = [{name: 'name', func: getComponenetName}, {name: 'quantity', func: getOccurrenceCount}, {name: 'type', func: getType}];
     * var filterFunc = basicFilter;
     * var bomTable = bomApi.createNewBomTableFromCad(filterFunc, columns);
     */
    this.createNewBomTableFromCad = function (filter, cols) {
        var rows = [];
        cols = cols.slice();
        if (cols.length === 0) {
            throw new Error('columnsArg must be of length 1 at least');
        }
        // get occurences for this set of cad data
        var occurrences = this.anarkCoreData.getOccurrences();
        var compIds = [];
        var desiredComps = [];
        // grab occs that fit filter and tag components associated
        for (var i = 0; i < occurrences.length; i++) {
            var occ = occurrences[i];
            if (filter(occ)) {
                if (compIds.indexOf(occ.componentId) === -1) {
                    compIds.push(occ.componentId);
                    desiredComps.push(this.anarkCoreData.getEntityById(occ.componentId));
                }
            }
        }
        // for each of the comps, move it to the row that matches
        for (var i = 0; i < desiredComps.length; i++) {
            var cells = [];
            var input = void 0;
            var occs = desiredComps[i].getOccurrences();
            input = { cells: cells.slice(), component: desiredComps[i], occurrences: occs, groups: [] };
            rows.push(input);
            for (var j = 0; j < cols.length; j++) {
                // need to go through all target comps, and make sure eval cell when all ready
                rows[i].cells.push(cols[j].func(rows[i].component, rows[i].occurrences));
            }
        }
        return new this.bomTable(cols, rows);
    };
}
/**
 * Helper functions that are useful for {@link BomTable}. Range from {@link filterFunction}, {@link evalFunction}, {@link mapFunction}, {@link searchFunction}
 * <p>NOTE: THIS IS NOT A REAL NAMESPACE, it is used as a grouping for methods that can be used with {@link BomTable}</p>
 * @namespace BomFunctions
 */
// basic functions for cell values based on data from ACdata
/**
 * Family of functions that take the component and occurrences of each row in the Bom Table
 * and return a cell value
 * @callback evalFunction
 * @param {Component} comp The component of a specific row in the Bom Table
 * @param {Array<Occurrence>} occs The occurrence(s) of a specific row in the Bom Table
 * @return {(string/number)} the evaluation of the cell
 * @example
 * function getComponentName(comp, occs) {
 *      // returns component name
 *      return comp.name;
 * }
 * @example
 * function getOccurrenceCount(comp, occs) {
 *      // returns number of occurrences associated with the row
 *      return occs.length;
 * }
 */
/**
 * A number or string representing a column by its name or index from 0 to number of columns - 1
 * @typedef {(number|string)} columnIndex
 * @example
 * // get cell at column 'name' and row 0
 * bomTable.getCell('name', 0);
 * // delete last column in table by number index
 * bomTable.deleteColumn(-1);
 */
/**
 * Object to encapsulate a column of data in a {@link BomTable}
 * @typedef bomColumn
 * @property {string} name The name of the column in the bomTable
 * @property {evalFunction} func The cell value evaluated based on cad data
 * @example
 * // bomColumn that returns the name of the component
 * {name: 'name', func: getComponentName}
 * // Array of bomColumns
 * [{name: 'name', func: getComponentName}, {name: 'count', func: getOccurrenceCount}, {name: 'type', func: getType}]
 */
/**
 * Name/number associated with a custom group
 * @typedef {(number | string)} groupName
 */
/**
 * Function of type {@link evalFunction} cell value for componenent name
 * @memberof BomFunctions
 * @param {Component} comp
 * @param {Array<Occurrence>} occs
 * @return {string}
 */
function getComponentName(comp, occs) {
    return comp.name;
}
/**
 * Function of type {@link evalFunction}
 * @memberof BomFunctions
 * @param {Component} comp
 * @param {Array<Occurrence>} occs
 * @return {string}
 */
function getOccurrenceCount(comp, occs) {
    return occs.length;
}
/**
 * Function of type {@link evalFunction}
 * @memberof BomFunctions
 * @param {Component} comp
 * @param {Array<Occurrence>} occs
 * @return {string}
 */
function getCadEntityId(comp, occ) {
    return comp.cadEntityId;
}
/**
 * Function of type {@link evalFunction}
 * @memberof BomFunctions
 * @param {Component} comp
 * @param {Array<Occurrence>} occs
 * @return {string}
 */
function getType(comp, occs) {
    return comp.typeOfEntity;
}
/**
 * Function of type {@link evalFunction}
 * @memberof BomFunctions
 * @param {Component} comp
 * @param {Array<Occurrence>} occs
 * @return {string}
 */
function getCompId(comp, occs) {
    return comp.cadEntityId;
}
/**
 * Function of type {@link evalFunction}
 * @memberof BomFunctions
 * @param {Component} comp
 * @param {Array<Occurrence>} occs
 * @return {string}
 */
function getDescription(comp, occs) {
    return comp.Attributes.Description;
}
/**
 * Tuple to hold map function and columnIndex. JSDoc lacks tuple type, so this is a placeholder
 * @typedef {Array<Object>} map
 * @param {columnIndex} col The column you wish to map on
 * @param {mapFunction} func The mapping function
 * @example
 * // This is a valid tuple:
 * var mapTuple = ['name', mapCompName];
 * var mapTuple2 = [0, mapCompName];
 */
/**
 * Tuple to hold columnIndex and searchFunction. JSDoc lacks tuple type, so this is a placeholder
 * @typedef {Array<Object>} search
 * @param {columnIndex} col The column you wish to map on
 * @param {searchFunction} func The search function
 * @example
 * // This is a valid tuple:
 * var searchTuple = ['make', searchForMake];
 * var searchTuple2 = [0, searchQuantityOverOne];
 */
/**
 * @callback mapFunction
 * This is a family of functions that map a specific row of an outside table to a cad component
 * @param {Component} comp A specific Component to test against a cell
 * @param {number/string} cell The specific cell to which the cad component will be matched on
 * @return {boolean} True if matches, False if not
 * @example
 * function mapCompEntityId(comp, cell) {
 *      // based on what the cell value is, if it matches this component will be tied to this row of the table
 *      return (comp.cadEntityId === cell);
 * }
 */
/**
 * Function of type {@link mapFunction} that maps Components to rows based on name
 * @memberof BomFunctions
 * @param {Component} comp
 * @param {number/string} cell
 * @return {boolean}
 */
function mapCompName(comp, cell) {
    return (comp.name === cell);
}
/**
 * Function of type {@link mapFunction} that maps components to rows based on cadId
 * @memberof BomFunctions
 * @param {Component} comp
 * @param {number/string} cell
 * @return {boolean}
 */
function mapCompId(comp, cell) {
    return (comp.cadEntityId === cell);
}
/**
 * @callback searchFunction
 * @param {number} cell Specific cell to be tested in BomTable
 * @return {boolean} True if cell matches search, False if otherwise
 * @example
 * // search function to test if cell matches 'foo'
 * function isFoo(cell) {
 *      return (cell == 'foo');
 * }
 */
/**
 * Function of type {@link searchFunction} that looks for cells with number > 1
 * @memberof BomFunctions
 * @param {string/number} cell
 */
function searchForQuantityOverOne(cell) {
    return (cell > 1);
}
/**
 * function of type {@link searchFunction} that looks for cells with 'MAKE' string
 * @memberof BomFunctions
 * @param {string/number} cell
 */
function searchForMake(cell) {
    return (cell === "MAKE");
}
// filter functions that filter out occurrences not wanted
/**
 * @callback filterFunction
 * A family of functions that filters the possible occurrences/components of the Bom Table
 * based on given requirements
 * @param {Occurrence} occ a given occurrence of the cad data
 * @return {boolean} whether the occ passes the specified requirements and will be tied to
 * rows of the Bom Table
 * @example
 * function filter(occ) {
 *      // only looks at occurrences that are of type 'Part'
 *      return occ.typeOfEntity === "PartOccurrence";
 * }
 */
/**
 * Function of type {@link filterFunction} that is commonly used for only getting Assembly/Part occs with depth 2
 * @memberof BomFunctions
 * @param {Occurrence} occ
 * @return {boolean}
 */
function basicFilter(occ) {
    return occ.Attributes["Product Structure Depth"] === 2 && (occ.typeOfEntity === "PartOccurrence" || occ.typeOfEntity === "AssemblyOccurrence");
}
/**
 * Function that builds a {@link filterFunction}
 * @memberof BomFunctions
 * @param {integer} depth The tree depth desired for Occurrences
 * @param {Array<string>} types The type of Occurrences you are looking for
 * @return {filterFunction} A filter to use when building Bom
 */
function createFilter(depth, types) {
    var listTypes = '[';
    for (var i = 0; i < types.length - 1; i++) {
        console.log(types[i]);
        listTypes = listTypes + "'" + types[i] + "',";
    }
    listTypes = listTypes + "'" + types[i] + "']";
    console.log(listTypes);
    var func = new Function('occ', 'var types = ' + listTypes + ';' +
        'var depth = ' + depth + ';' +
        'var flag = false;' +
        'for (type of types) {' +
        'if (occ.typeOfEntity === type) {' +
        'flag = true;}' +
        '}' +
        'return occ.Attributes["Product Structure Depth"] === depth && flag;');
    return func;
}
/**
 * Function that builds a {@link evalFunction} based on getting a component attribute name
 * @memberof BomFunctions
 * @param {string} attributeName Desired attribute
 * @return {evalFunction} A function that returns the value at 'attributeName' of component
 */
function getAttributeFunction(attributeName) {
    return new Function('comp', 'occs', 'return comp.Attributes.' + attributeName + ';');
}
//# sourceMappingURL=JsonApi_Pdf.js.map
//# sourceMappingURL=JsonApi_Pdf.js.map