/**
* @copyright 2015 Tridium, Inc. All Rights Reserved.
* @author Gareth Johnson
*/
/**
* Defines {@link baja.TimeZoneDatabase}.
* @module baja/obj/TimeZoneDatabase
*/
define([ 'bajaScript/sys',
'bajaScript/baja/comm/Callback',
'bajaScript/baja/obj/dateTimeUtil',
'bajaScript/baja/obj/TimeZone',
'bajaScript/baja/sys/structures/OrderedMap' ], function (
baja,
Callback,
dateTimeUtil,
TimeZone,
OrderedMap) {
'use strict';
var callbackify = baja.callbackify,
STORAGE_KEY = 'bsTimeZoneDatabase',
retrievePromise;
/**
* Clear the saved time zone database JSON from local storage.
*
* @inner
*/
function clearJsonFromStorage() {
try {
return baja.storage.removeItem(STORAGE_KEY);
} catch (ignore) {
//what to do?
}
}
/**
* Retrieve the saved time zone database JSON from local storage.
*
* @inner
* @returns {Object} retrieved and parsed object, or null if not found
*/
function getJsonFromStorage() {
try {
var str = baja.storage.getItem(STORAGE_KEY);
return str && JSON.parse(str);
} catch (ignore) {
clearJsonFromStorage();
}
}
/**
* Persist the time zone database JSON retrieved from the station into local
* storage.
*
* @param {Object} json
*/
function saveJsonToStorage(json) {
try {
return baja.storage.setItem(STORAGE_KEY, JSON.stringify(json));
} catch (ignore) {
//what to do?
}
}
/**
* Retrieve the time zone database from the station.
*
* It will make a network call to the `TimeZoneChannel` on the BOX service.
* The time zone database will be retrieved and stored in local storage.
*
* @inner
* @param {baja.comm.Batch} [batch] optional batch to use to retrieve the
* unit database
* @returns {Promise}
*/
function retrieveJson(batch) {
var cb = new Callback(baja.ok, baja.fail, batch),
fromStorage = getJsonFromStorage(),
lastKnownBuildTime = (fromStorage && fromStorage.buildTime) || 0;
cb.addOk(function (ok, fail, resp) {
baja.runAsync(function () {
var json;
if (fromStorage && !resp.db) {
//we had the database saved locally, and it hasn't been updated since
//we last retrieved it. use the existing db.
json = fromStorage;
} else {
//new unit database from the station.
json = resp;
saveJsonToStorage(json);
}
ok(json);
});
});
cb.addReq('timeZone', 'getTimeZoneDatabase', {
ifModifiedSince: lastKnownBuildTime
});
cb.autoCommit();
return cb.promise();
}
/**
* JSON structure:
*
* {
* "buildTime": {long} db last build time,
* "db":
* {
* "timeZoneId":
* {
* "v": {string} string-encoded time zone,
* "dn": {string} display name,
* "ddn": {string} dst display name,
* "sdn": {string} short display name,
* "dsdn": {string} short dst display name
* }
* }
* }
*
* @inner
* @param db
* @returns {Array}
*/
function toOrderedMap(db) {
var map = new OrderedMap(),
zone,
timeZoneId,
obj;
for (timeZoneId in db) {
if (db.hasOwnProperty(timeZoneId)) {
obj = db[timeZoneId];
zone = TimeZone.DEFAULT.decodeFromString(obj.v);
map.put(timeZoneId, TimeZone.make(
zone.getId(),
zone.getUtcOffset(),
zone.getDaylightAdjustment(),
zone.$getDaylightStartRule(),
zone.$getDaylightEndRule(),
{
displayName: obj.dn,
dstDisplayName: obj.ddn,
shortDisplayName: obj.sdn,
shortDstDisplayName: obj.dsdn
}
));
}
}
return map;
}
/**
* Queries the time zone database from the station.
*
* There is no reason to call this constructor directly; rather use the
* static accessor functions.
*
* @class
* @alias baja.TimeZoneDatabase
*/
var TimeZoneDatabase = function TimeZoneDatabase(json) {
this.$map = toOrderedMap(json.db);
};
/**
* Asynchronously retrieve the time zone database from the station. The
* network call to the station will only happen once: the same database
* instance will be resolved no matter how many times this function is called.
*
* @param {Object} callbacks
* @param {Function} callbacks.ok ok callback, will receive a
* `TimeZoneDatabase` instance populated with data retrieved from the station
* @param {Function} callbacks.fail fail callback
* @param {baja.comm.Batch} [callbacks.batch] batch to use for the network
* request
* @returns {Promise}
*/
TimeZoneDatabase.get = function (callbacks) {
callbacks = callbackify(callbacks);
if (!retrievePromise) {
retrievePromise = retrieveJson(callbacks.batch)
.then(function (json) {
return new TimeZoneDatabase(json);
});
}
retrievePromise.then(callbacks.ok, callbacks.fail);
return retrievePromise;
};
/**
* Return all time zone IDs the station knows about.
*
* @returns {Array.<String>}
*/
TimeZoneDatabase.prototype.getAllSupportedZoneIds = function () {
return this.$map.getKeys();
};
/**
* Return the `TimeZone` instance corresponding to the given ID.
* @param {String} id
* @returns {baja.TimeZone} the time zone, or `null` if not found
*/
TimeZoneDatabase.prototype.getTimeZone = function (id) {
return this.$map.get(id) || null;
};
/**
* Return all `TimeZone` instances the station knows about.
*
* @returns {Array.<baja.TimeZone>}
*/
TimeZoneDatabase.prototype.getTimeZones = function () {
var map = this.$map,
keys = map.getKeys(),
zones = [];
for (var i = 0, len = keys.length; i < len; i++) {
zones.push(map.get(keys[i]));
}
return zones;
};
/**
* Return true if the station knows about the given time zone ID.
*
* @param {string} id
* @returns {boolean}
*/
TimeZoneDatabase.prototype.isZoneIdSupported = function (id) {
return !!this.$map.get(id);
};
/**
* Return the location based TimeZone value.
* @returns {baja.TimeZone}
* @since Niagara 4.14
*/
TimeZoneDatabase.prototype.getLocalTimeZone = function () {
return this.$map.get(dateTimeUtil.getCurrentTimeZoneId()) || TimeZone.DEFAULT;
};
return TimeZoneDatabase;
});