Home Reference Source Repository

magicloud/magicloud.js

import $ from 'jquery';

/**
 * @private
 * Private function
 */
const _extendQModelOptions = Symbol('_extendQModelOptions');
/**
 * @private
 * Private function
 */
const _getAuthPart = Symbol('_getAuthPart');
/**
 * @private
 * Private function
 */
const _addAuthToken = Symbol('_addAuthToken');
/**
 * @private
 * Private function
 */
const _b64EncodeUnicode = Symbol('_b64EncodeUnicode');
/**
 * @private
 * Private function
 */
const _setDiagramImages = Symbol('_setDiagramImages');
/**
 * @private
 * Private reference to this
 */
var _this = undefined;
/**
 * @private
 */
var _applicationId = undefined;
/**
 * @private
 */
var _returnUri = undefined;
/**
 * @private
 */
var _token = undefined;
/**
 * @private
 */
var _sessionId = undefined;

export default class MagiCloud {
    /**
     * @private
     * @param {*} fingerprintService 
     * @param {*} x3dViewService 
     * @param {*} userService 
     * @param {*} authService
     * @param {*} diagramService
     * @param {*} ahuCalculationService
     */
    constructor(fingerprintService, x3dViewService, userService, authService, diagramService, ahuCalculationService) {
        /**
         * @private
         */
        this.fingerprintService = fingerprintService;
        /**
         * @private
         */
        this.x3dViewService = x3dViewService;
        /**
         * @private
         */
        this.userService = userService;
        /**
         * @private
         */
        this.authService = authService;
        /**
         * @private
         */
        this.diagramService = diagramService;
        /**
         * @private
         */
        this.ahuCalculationService = ahuCalculationService;
        /**
         * @private
         */
        _this = this;
    }

    /**
     * Return information is user logged in
     * 
     * @return boolean value is used logged in
     */
    isLoggedIn() {
        return this.authService.isLoggedIn();
    }

    /**
     * Return logged in user data { Id: string, Fullname: string }
     */
    getLoggedInUser() {
        return this.userService.data();
    }

    /**
     * Try to auto signin user if authentication cookie exists
     * 
     * @return {Promise} Successful response will contain user data {Id: string, Fullname: string, Description: string}
     */
    autoSignIn() {
        return this.authService.autoSignIn();
    }

    /**
     * Login current user. Will open MagiCloud login popup.
     * 
     * @param {object} options { applicationId: string, returnUri: string }
     * @return {Promise} Successful response will contain user data {Id: string, Fullname: string, Description: string}
     */
    login(options) {
        // If appId given then store it for later usage
        var settings = $.extend({
            applicationId: this.applicationId,
            returnUri: this.returnUri
        }, options);

        // If appId given then store it for later usage
        if (settings.applicationId)
            _applicationId = settings.applicationId;
        if (!_applicationId)
            throw "applicationId cannot be null or empty. Please contact to MagiCloud support to get own applicationId.";

        // If returnUri given then store it for later usage
        if (settings.returnUri)
            _returnUri = settings.returnUri;
        if (!_returnUri)
            throw "returnUri cannot be null or empty. Please contact to MagiCloud support to set your returnUri as trusted.";

        return this.authService.signin(settings);
    }

    /**
     * Logout current logged in user
     * 
     * @return {Promise}
     */
    logout() {
        return this.authService.signOut();
    }

    /**
     * Return release info of MagiCloud Widget SDK in example Production 2.35.0     
     */
    getReleaseInfo() {
        return `${systemconfig.ENVIRONMENT} ${systemconfig.RELEASENUMBER}`;
    }

    /**
     * Load and initialize MagiCloud Javascript Library     
     * 
     * @param  {object} options { productId: string, articleNumber: string, manufacturerId: string, applicationId: string, token: string }
     * @return {Promise} Successful response will contain product/variant data
     */
    load(options) {
        return this.fingerprintService.getFingerprint().then(fingerprintResult => {
            var token = this.userService.token();
            var settings = $.extend({
                productId: null,
                articleNumber: null,
                manufacturerId: null,
                applicationId: this.applicationId,
                sessionId: fingerprintResult,
                token: token,
                logoContainerId: null
            }, options);

            if (settings.applicationId)
                _applicationId = settings.applicationId;
            if (!_applicationId)
                throw "applicationId cannot be null or empty. Please contact to MagiCloud support to get own applicationId.";
            // Store for later usage
            _sessionId = settings.sessionId;
            _token = settings.token;

            var baseProductUrl = systemconfig.APIURL + systemconfig.PRODUCTPATH;
            var productUrl;
            if (settings.productId)
                productUrl = baseProductUrl + settings.productId;
            else if (settings.articleNumber && settings.manufacturerId)
                productUrl = baseProductUrl + settings.manufacturerId + '/' + encodeURI(settings.articleNumber);
            if (settings.logoContainerId)
                this.renderMagiCloudLogo(settings.logoContainerId);

            return $.ajax({
                url: productUrl
            }).then((data) => {
                if (!data || data.length === 0)
                    return null;

                // Finalize Attachments with auth tokens
                $.each(data.Attachments, function (i, val) {
                    val.Uri = _this[_addAuthToken](val.Uri);
                });
                // Finalize DXF resources with auth tokens
                data.DxfUrl = _this[_addAuthToken](data.DxfUrl);
                return data;
            }, (err) => {
                return err;
            });
        });
    }

    /**
     * Return dimension image query url
     * 
     * @param {object} options { QModelId: Optional QModelId of model, QModelParameters: Optional QModelParameters of model, 
     *                           ViewMode: [0=Rendered, 1=DimensionLabels, 2=DimensionValues],
     *                           ViewPosition: [0=Default, 1=Front, 2=Right, 3=Left, 4=Top, 5=Bottom, 6=IsometricLeft, 7=IsometricRight] }
     */
    getDimensionImageQueryUrl(options) {
        var queryObject = this[_extendQModelOptions](options);
        var dimensionsImageQueryPath = systemconfig.APIURL + systemconfig.DIMENSIONSIMAGEQUERYPATH;
        return dimensionsImageQueryPath + this[_b64EncodeUnicode](JSON.stringify(queryObject));
    }

    /**
     * 
     * Return image query url
     * 
     * @param {object} options { QModelId: Optional QModelId of model, QModelParameters: Optional QModelParameters of model,
     *                           ViewPosition: [0=Default, 1=Front, 2=Right, 3=Left, 4=Top, 5=Bottom, 6=IsometricLeft, 7=IsometricRight] }
     */
    getImageQueryUrl(options) {
        var queryObject = this[_extendQModelOptions](options);
        var imageQueryPath = systemconfig.APIURL + systemconfig.IMAGEQUERYPATH;
        return imageQueryPath + this[_b64EncodeUnicode](JSON.stringify(queryObject));
    }

    /**
     * @private
     * Renders X3D Image container to given container
     * 
     * @param {object} options  {x3dUri: location of x3d, container: identifier of the container for x3d, imageUri: location of image }
     *                          Optionally can be set:
     *                          { QModelId: Optional QModelId of model, QModelParameters: Optional QModelParameters of model, 
     *                            ViewMode: [0=Rendered, 1=DimensionLabels, 2=DimensionValues] }
     * @param {boolean} update Update existing container with new image url
     * @return {Promise} result as promise
     */
    renderX3D(options, update) {
        var queryObject = this[_extendQModelOptions](options);
        if (queryObject.QModelId) {
            var x3dQueryPath = systemconfig.APIURL + systemconfig.X3DQUERYPATH;
            var imageQueryPath = systemconfig.APIURL + systemconfig.IMAGEQUERYPATH;

            var x3dQueryUrl = x3dQueryPath + this[_b64EncodeUnicode](JSON.stringify(queryObject));
            var imageQueryUrl = imageQueryPath + this[_b64EncodeUnicode](JSON.stringify(queryObject));
            var queryOptions = {
                x3dUri: x3dQueryUrl,
                containerId: options.containerId,
                imageUri: imageQueryUrl
            };
            return this.x3dViewService.loadX3D(queryOptions, update);
        }
        return this.x3dViewService.loadX3D(options, update);
    }

    /**
     * Render MagiCloud logo to container with specified identified
     * 
     * @param {string} containerId Container identifier
     * @param {boolean} transparent Boolean value should transparent image be used
     */
    renderMagiCloudLogo(containerId, transparent) {
        var container = $(`#${containerId}`);
        if (!container)
            return;
        container.empty();
        var data = {
            ImageUrl: transparent ?
                systemconfig.MAGICLOUDLOGOTRANSPARENT : systemconfig.MAGICLOUDLOGO,
            Alt: 'Powered by MagiCloud',
            Title: 'Powered by MagiCloud'
        };
        var html = `<img src="${data.ImageUrl}" alt="${data.Alt}" title="${data.Title}" />`;
        container.append(html);
    }

    /**
     * Set specified diagram and bind click event to given elementId. Click event will add possible data to given dataElementId
     * @param {object} data Product data
     * @param {object} options example { type: diagramType, elementId: 'el', dataElementId: 'dataEl' } 
     * where diagramType = { Ventilation, Heating, Cooling, SupplyAir, ExtractAir, Radiator, Pump }
     */
    setDiagram(data, options) {
        if (!options || !options.elementId || !options.type ||
            !data.Diagrams || !data.Diagrams[options.type])
            return;

        let element = $(`#${options.elementId}`);
        if (element.length === 0)
            return;

        let img = $(`<img src="${data.Diagrams[options.type].BaseUrl}" alt="${options.type}">`);
        element.html(img);

        // Set diagram data if exists
        let hasData = data.Diagrams[options.type].HasData;
        if (hasData) {
            let baseUrl = data.Diagrams[options.type].BaseUrl;
            let dataElement = $(`#${options.dataElementId}`);
            if (dataElement.length === 0)
                return;
            if (options.operationPoint && options.operationPoint.x && options.operationPoint.y &&
                options.operationPoint.x >= 0 && options.operationPoint.y >= 0) {

                let diagram = {
                    URL: baseUrl,
                    DataURL: hasData ? baseUrl + '/data' : null,
                    operationPoint: options.operationPoint,
                    HasData: hasData
                };
                _this[_setDiagramImages](img, dataElement, diagram, options.type);
            }
            img.on('click', {
                BaseURL: baseUrl,
                HasData: hasData
            }, (event) => {
                let diagram = _this.diagramService.getDiagram(event);
                _this.diagramService.getOperatingPoint(diagram).then(() => {
                    _this[_setDiagramImages](img, dataElement, diagram, options.type);
                }, () => {
                    // Failure when performing getOperatingPoint
                });
            });
        }
    }

    /**
     * Get pressure drop of curve at specific flow.
     * @return Example {Succeed: true, Value: 27.870676}
     * @param {string} productId Product identifier (GUID)
     * @param {string} systemTypeId Value = {Unknown, AnyFluid, SupplyFluid, ReturnFluid, ColdWater, HotWater, FireHydrant, HotSupplyFluid, Sprinkler, Sewer, AnyAir, SupplyAir, ExtractAir, OutdoorSupply, OutdoorExhau}
     * @param {number} qv Specified flow
     * @param {number} fanSpeed Specified Fan Speed
     */
    getDpTot(productId, systemTypeId, qv, fanSpeed) {
        return this.ahuCalculationService.getDpTot(productId, systemTypeId, qv, fanSpeed);
    }

    /**
     * Find suitable fanSpeed for given operation point.
     * @return Example {PressureDrop: 107.4791, Succeed: true, Value: 6}
     * @param {string} productId Product identifier (GUID)
     * @param {string} systemTypeId Value = {Unknown, AnyFluid, SupplyFluid, ReturnFluid, ColdWater, HotWater, FireHydrant, HotSupplyFluid, Sprinkler, Sewer, AnyAir, SupplyAir, ExtractAir, OutdoorSupply, OutdoorExhau}
     * @param {number} qv Specified flow
     * @param {number} dpTot Pressure drop value
     */
    findOptimalSpeed(productId, systemTypeId, qv, dpTot) {
        return this.ahuCalculationService.findOptimalSpeed(productId, systemTypeId, qv, dpTot);
    }

    /**
     * @private
     * Common method to set diagram images based to given parameters
     */
    [_setDiagramImages](img, dataElement, diagram, type) {
        img.attr('src', _this.diagramService.getDiagramURL(diagram));
        var dataImg = dataElement.find('img');
        if (dataImg.length) {
            dataImg.attr('src', _this.diagramService.getDiagramDataURL(diagram));
            dataImg.attr('alt', type + ' Data');
        } else
            dataElement.html(`<img src="${_this.diagramService.getDiagramDataURL(diagram)}" alt="${type} Data">`)
    }

    /**
     * @private
     * Return authentication query string
     */
    [_getAuthPart]() {
        // Null check properties before creating query string part
        var authQuery = {};
        if (_applicationId)
            authQuery.applicationId = (systemconfig.AUTH_ALLOWED_CUSTOM_SCHEMES.indexOf(_applicationId) > -1) ?
            _applicationId :
            systemconfig.AUTH_DEFAULT_SCHEMES || 'magicloud';
        if (_token)
            authQuery.token = _token;
        if (_sessionId)
            authQuery.sessionId = _sessionId;
        return $.param(authQuery);
    }
    /**
     * @private
     * Add applicationId, token and sessionId to given url as query string parameters.     
     * 
     * @param {string} url 
     */
    [_addAuthToken](url) {
        if (!url)
            return url;
        var auth = _this[_getAuthPart]();
        return url + (url.match(/\?/) ? '&' : '?') + auth;
    }

    /**
     * @private
     * Extends given options object with QModel option parameters
     * Note: options.ViewMode is one of ['Rendered', 'DimensionLabels', 'DimensionValues'],
     *       options.ViewPosition is one of ['Default', 'Front', 'Right', 'Left', 'Top', 'Bottom', 'IsometricLeft', 'IsometricRight'] }
     * 
     * @param {object} options {QModelId: string, QModelParameters: string, ViewMode: string }
     */
    [_extendQModelOptions](options) {
        return $.extend({
            QModelId: null,
            QModelParameters: null,
            ViewMode: 'Rendered',
            ViewPosition: 'Default'
        }, options);
    }

    /**
     * @private
     * Base64 encode given input string value
     * 
     * @param {string} str input value
     */
    [_b64EncodeUnicode](str) {
        return btoa(encodeURIComponent(str).replace(/%([0-9A-F]{2})/g, function (match, p1) {
            return String.fromCharCode('0x' + p1);
        }));
    }
}