baja/tag/entityDecoder.js

/**
 * @copyright 2015 Tridium, Inc. All Rights Reserved.
 * @author Gareth Johnson
 */

/**
 * @module baja/tag/entityDecoder
 */
define([ "bajaScript/sys",
        "bajaScript/baja/tag/Id",
        "bajaScript/baja/tag/Tag",
        "bajaScript/baja/tag/TagSet",
        "bajaScript/baja/tag/RelationSet",
        "bajaScript/baja/tag/Relation",
        "bajaScript/baja/tag/BasicEntity",
        "bajaPromises" ], function (
        baja,
        Id,
        Tag,
        TagSet,
        RelationSet,
        Relation,
        BasicEntity,
        Promise) {
  
  "use strict";

  function decodeTag(val, name) {
    var type = name[name.length - 1],
        Float = baja.Float,
        Double = baja.Double;

    name = name.substring(0, name.length - 1);

    switch (type) {
      case "M": return new Tag(name);
      case "B": return new Tag(name, baja.$("baja:Boolean", val));
      case "D": return new Tag(name, baja.$("baja:Double", val));
      case "I": return new Tag(name, baja.$("baja:Integer", val));
      case "F": return new Tag(name, baja.$("baja:Float", val));
      case "L": return new Tag(name, baja.$("baja:Long", val));
      case "S":
      case "J":
        return new Tag(name, baja.$("baja:String").decodeFromString(val));
      case "A": return new Tag(name, baja.$("baja:AbsTime").decodeFromString(val));
      case "O": return new Tag(name, baja.$("baja:Ord").decodeFromString(val));
      case "Y":
        return baja.$("baja:DynamicEnum").decodeAsync(val)
          .then(function (tagValue) {
            return new Tag(name, tagValue);
          });
      case "G":
        return baja.$("baja:EnumRange").decodeAsync(val)
          .then(function (tagValue) {
            return new Tag(name, tagValue);
          });
      case "R": return new Tag(name, baja.$("baja:RelTime").decodeFromString(val));
      case "U": return new Tag(name, baja.$("baja:Unit").decodeFromString(val));
      case "Z": return new Tag(name, baja.$("baja:TimeZone").decodeFromString(val));
      case "N":
        switch (val) {
          case "fNaN":  return new Tag(name, Float.NaN);
          case "fpInf": return new Tag(name, Float.POSITIVE_INFINITY);  
          case "fnInf": return new Tag(name, Float.NEGATIVE_INFINITY);  
          case "dNaN":  return new Tag(name, Double.make(Number.NaN));
          case "dpInf": return new Tag(name, Double.POSITIVE_INFINITY);  
          case "dnInf": return new Tag(name, Double.NEGATIVE_INFINITY);  
        }
        break;
      default: throw new Error("Unknown value type: " + type);
    }
  }

  /*
   * @param {Array.<String>} tags an array of string encoded tags
   * @returns {Promise.<baja.TagSet>}
   */
  function decodeTags(tags) {
    var promises = [];

    baja.iterate(tags, function (val, name) {
      promises.push(Promise.resolve(decodeTag(val, name)));
    });

    return Promise.all(promises)
      .then(function (tagsArray) {
        return new TagSet(tagsArray);
      });
  }

  /*
   * @param {Array.<Object>} relations an array of json encoded relations
   * @returns {Promise.<baja.RelationSet>}
   */
  function decodeRelations(relations) {
    var relationPromises = [];

    baja.iterate(relations, function (relationJson) {
      var tagPromises = [];
      if (relationJson.rtags) {
        baja.iterate(relationJson.rtags, function (val, name) {
          tagPromises.push(Promise.resolve(decodeTag(val, name)));
        });
      }

      relationPromises.push(
        Promise.all(tagPromises)
          .then(function (rtags) {
            return new Relation(relationJson.rId, relationJson.entityOrd, new TagSet(rtags), relationJson.inbound);
          })
      );
    });

    return Promise.all(relationPromises)
      .then(function (relationsArray) {
        return new RelationSet(relationsArray);
      });
  }

  /*
   * @param {Object} entityJson a json encoded entity
   * @returns {Promise.<baja.tag.BasicEntity>}
   */
  function decodeEntity(entityJson) {
    return Promise.all([
      entityJson.tags ? decodeTags(entityJson.tags) : new TagSet(),
      entityJson.relations ? decodeRelations(entityJson.relations) : new RelationSet()
    ])
      .then(function ([ tagSet, relationSet ]) {
        return new BasicEntity(entityJson.ord, tagSet, relationSet);
      });
  }

  return {
    decodeEntity: decodeEntity,
    decodeTags: decodeTags,
    decodeRelations: decodeRelations
  };
});