Mesh.js

/**
 * @module core/Mesh
 * @requires common
 * @requires events
 * @requires core/ImageFace
 * @requires core/ColorFace
**/
'use strict';

const {assign} = Object;
const {
    constant,
    findKeyWithValue,
    mapValues
} = require('./common');
const events    = require('./events');
const ImageFace = require('./ImageFace');
const ColorFace = require('./ColorFace');

const FACETYPES = {
    image: ImageFace,
    color: ColorFace
};

module.exports = Mesh;

/**
 * @name Mesh
 * @constructor
 * @fires module:core/Mesh~change
 * @param {object} faces Face data
**/
function Mesh(faces) {
    let front;
    let back;
    let left;
    let right;
    let top;
    let bottom;
    let canTriggerEvent = true;
    let isValid = face => (face !== undefined && containsFaceType(face));
    let self = assign(this, events, {
        setFront,
        setBack,
        setLeft,
        setRight,
        setTop,
        setBottom,
        setFaces,
        getFaces,
        serialize,
        getFront: () => front,
        getBack: () => back,
        getLeft: () => left,
        getRight: () => right,
        getTop: () => top,
        getBottom: () => bottom
    });
    setFaces(faces || new ImageFace());
    function getFaceKeyByType(value) {
        return findKeyWithValue(FACETYPES, value);
    }
    function containsFaceType(face) {
        return !!getFaceKeyByType(face.constructor);
    }
    function setFront(face) {
        if (isValid(face)) {
            front = face;
            front.on('change', onFaceChangeEvent);
            canTriggerEvent && triggerChangeEvent();
        }
        return self;
    }
    function setBack(face) {
        if (isValid(face)) {
            back = face;
            back.on('change', onFaceChangeEvent);
            canTriggerEvent && triggerChangeEvent();
        }
        return self;
    }
    function setLeft(face) {
        if (isValid(face)) {
            left = face;
            left.on('change', onFaceChangeEvent);
            canTriggerEvent && triggerChangeEvent();
        }
        return self;
    }
    function setRight(face) {
        if (isValid(face)) {
            right = face;
            right.on('change', onFaceChangeEvent);
            canTriggerEvent && triggerChangeEvent();
        }
        return self;
    }
    function setTop(face) {
        if (isValid(face)) {
            top = face;
            top.on('change', onFaceChangeEvent);
            canTriggerEvent && triggerChangeEvent();
        }
        return self;
    }
    function setBottom(face) {
        if (isValid(face)) {
            bottom = face;
            bottom.on('change', onFaceChangeEvent);
            canTriggerEvent && triggerChangeEvent();
        }
        return self;
    }
    function setFaces(faces) {
        var old = getFaces();
        if (faces) {
            if (containsFaceType(faces)) {
                faces = mapValues(getFaces(), constant(faces));
            }
            canTriggerEvent = false;
            let {front, back, left, right, top, bottom} = faces;
            self
                .setFront(front)
                .setBack(back)
                .setLeft(left)
                .setRight(right)
                .setTop(top)
                .setBottom(bottom);
            triggerChangeEvent();
            canTriggerEvent = true;
        }
        return old;
    }
    function getFaces() {
        return {front, back, left, right, top, bottom};
    }
    function serialize() {
        return JSON.stringify(mapValues(getFaces(), serializeFace));
    }
    function serializeFace(face) {
        return getFaceKeyByType(face.constructor) + '(' + face.serialize() + ')';
    }
    function onFaceChangeEvent() {
        triggerChangeEvent();
    }
    function triggerChangeEvent() {
        let target = self;
        let faces = getFaces();
        self.trigger('change', {target, faces});
    }
}
/**
 * @function loadFromSerial
 * @memberof module:core/Mesh~Mesh
 * @param {string} data Serialized data (JSON format string)
 * @returns {module:core/Mesh~Mesh} New Mesh instance
**/
Mesh.loadFromSerial = function LoadFromSerial(data) {
    return new Mesh(mapValues(JSON.parse(data), loadFaceFromSerial));
};
function loadFaceFromSerial(compositeSerial) {
    let index = compositeSerial.indexOf('(');
    let type = compositeSerial.slice(0, index);
    let typeSerial = compositeSerial.slice(index + 1, -1);
    return FACETYPES[type].loadFromSerial(typeSerial);
}