/*
* niViz -- snow profiles visualization
* Copyright (C) 2015 WSL/SLF - Fluelastrasse 11 - 7260 Davos Dorf - Switzerland.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* eslint no-loop-func: [0], complexity: [2, 30] */
(function (niviz) {
'use strict';
// --- Module Dependencies ---
var Config = niviz.Config;
var Header = niviz.Header;
var round = niviz.util.round;
/** @module niviz */
/**
* Serialize data into CAAML format
*
* @class CAAML
* @constructor
*/
var CAAML = {};
/**
* The general settings.
*
* @property defaults
* @type Array<Object>
* @static
*/
CAAML.defaults = new Config('CAAML', [
{
name: 'profile_gmlid', type: 'string', default: 'niviz_profile'
},
{
name: 'station_gmlid', type: 'string', default: 'niviz_station'
},
{
name: 'operation_gmlid', type: 'string', default: 'niviz_operation'
},
{
name: 'observer_gmlid', type: 'string', default: 'niviz_observer'
}
]);
CAAML.defaults.load();
CAAML.precipiType = [
'-DZ', 'DZ', '+DZ', '-RA', 'RA', '+RA', '-SN', 'SN', '+SN', '-SG', 'SG', '+SG',
'-IC', 'IC', '+IC', '-PE', 'PE', '+PE', '-GR', 'GR', '+GR', '-GS', 'GS', '+GS',
'UP', 'Nil', 'RASN', 'FZRA'
];
CAAML.skyconditions = ['CLR', 'FEW', 'SCT', 'BKN', 'OVC', 'X'];
CAAML.roughness = [
{ id: 'rsm', symbol: 'U', name: 'smooth' },
{ id: 'rwa', symbol: 'V', name: 'wavy' },
{ id: 'rcv', symbol: 'W', name: 'concave furrows' },
{ id: 'rcx', symbol: 'X', name: 'convex furrows' },
{ id: 'rrd', symbol: 'Y', name: 'random furrows' }
];
CAAML.NS = {
caaml: 'http://caaml.org/Schemas/SnowProfileIACS/v6.0.3',
xs: 'http://www.w3.org/2001/XMLSchema'
};
CAAML.addNS = function (node, profile) {
node.setAttribute('xmlns:gml', 'http://www.opengis.net/gml');
node.setAttribute('xmlns:xsi', 'http://www.w3.org/2001/XMLSchema-instance');
node.setAttribute('gml:id', profile.info.profile_gmlid
|| niviz.CAAML.defaults.profile_gmlid || 'NA');
};
CAAML.addMetaData = function (station, profile, dom, node) {
var md = node.appendChild((dom.createElement('caaml:metaData')));
if (profile.info.comment && profile.info.comment.metadata)
CAAML.addNode(dom, md, profile.info.comment.metadata, 'caaml:comment');
};
CAAML.addTimeRef = function (profile, dom, node) {
var tr = node.appendChild(dom.createElement('caaml:timeRef'));
var rt = tr.appendChild((dom.createElement('caaml:recordTime')));
var ti = rt.appendChild((dom.createElement('caaml:TimeInstant')));
var tp = ti.appendChild(dom.createElement('caaml:timePosition'));
tp.textContent = profile.date.format('YYYY-MM-DDTHH:mm:ss.sssZ');
var dt = tr.appendChild((dom.createElement('caaml:dateTimeReport')));
dt.textContent = moment().format('YYYY-MM-DDTHH:mm:ss.sssZ');
};
CAAML.addSrcRef = function (profile, dom, node) {
var sr = node.appendChild((dom.createElement('caaml:srcRef')));
var pe, na, op;
if (!profile.info.operation) {
pe = sr.appendChild((dom.createElement('caaml:Person')));
pe.setAttribute('gml:id', profile.info.observer_gmlid
|| niviz.CAAML.defaults.observer_gmlid || 'NA');
na = pe.appendChild((dom.createElement('caaml:name')));
na.textContent = profile.info.observer || '';
} else {
op = sr.appendChild((dom.createElement('caaml:Operation')));
op.setAttribute('gml:id', profile.info.operation_gmlid
|| niviz.CAAML.defaults.operation_gmlid || 'NA');
na = op.appendChild((dom.createElement('caaml:name')));
na.textContent = profile.info.operation || '';
var cp = op.appendChild((dom.createElement('caaml:contactPerson')));
cp.setAttribute('gml:id', profile.info.observer_gmlid
|| niviz.CAAML.defaults.observer_gmlid || 'NA');
na = cp.appendChild((dom.createElement('caaml:name')));
na.textContent = profile.info.observer || '';
}
};
CAAML.addLocRef = function (station, dom, root) {
var lr = root.appendChild(dom.createElement('caaml:locRef'));
lr.setAttribute('gml:id', station.id || niviz.CAAML.defaults.station_gmlid || 'NA');
var md = lr.appendChild((dom.createElement('caaml:metaData')));
if (station.position && station.position.description)
CAAML.addNode(dom, md, station.position.description, 'caaml:comment');
CAAML.addNode(dom, lr, station.name, 'caaml:name');
CAAML.addNode(dom, lr, station.position.subtype || '', 'caaml:obsPointSubType');
if (station.position.altitude) {
var vh = lr.appendChild(dom.createElement('caaml:validElevation'));
var ep = vh.appendChild(dom.createElement('caaml:ElevationPosition'));
ep.setAttribute('uom', 'm');
var alt = station.position.altitude;
if (alt || alt === 0) alt = Math.round(alt);
CAAML.addNode(dom, ep, alt, 'caaml:position');
}
if (station.position.aspect) {
var va = lr.appendChild(dom.createElement('caaml:validAspect'));
var ap = va.appendChild(dom.createElement('caaml:AspectPosition'));
if (station.position.azimuth || station.position.azimuth === 0) {
var azi = station.position.azimuth;
if (!isNaN(azi)) azi = Math.round(azi);
CAAML.addNode(dom, ap, azi, 'caaml:position');
} else {
var aspect = station.position.aspect;
if (!isNaN(aspect)) aspect = Math.round(aspect);
CAAML.addNode(dom, ap, aspect, 'caaml:position');
}
}
if ((station.position.angle || station.position.angle === 0)
&& station.position.direction !== 'flat') {
var vs = lr.appendChild(dom.createElement('caaml:validSlopeAngle'));
var sp = vs.appendChild(dom.createElement('caaml:SlopeAnglePosition'));
sp.setAttribute('uom', 'deg');
var angle = station.position.angle;
if (!isNaN(angle)) angle = Math.round(angle);
CAAML.addNode(dom, sp, angle, 'caaml:position');
}
if ((station.position.latitude || station.position.latitude === 0)
&& (station.position.longitude || station.position.longitude === 0)) {
var pl = lr.appendChild(dom.createElement('caaml:pointLocation'));
var po = pl.appendChild(dom.createElement('gml:Point'));
po.setAttribute('gml:id', 'pointID');
po.setAttribute('srsName', 'urn:ogc:def:crs:OGC:1.3:CRS84');
po.setAttribute('srsDimension', '2');
var tx = station.position.longitude + ' ' + station.position.latitude;
CAAML.addNode(dom, po, tx, 'gml:pos');
}
};
CAAML.addNode = function (dom, node, parameter, cname, uom, decimals) {
if (parameter !== undefined && parameter !== null) {
var tmp = node.appendChild(dom.createElement(cname));
if (uom !== undefined) tmp.setAttribute('uom', uom);
if (decimals === undefined)
tmp.textContent = parameter;
else
tmp.textContent = parameter.toFixed(decimals);
}
};
CAAML.addPointProfile = function (dom, profile, basenode, feature, attributes, nodes) {
var mc = basenode.appendChild(dom.createElement('caaml:MeasurementComponents')), i, l;
attributes.forEach(function (attribute) {
mc.setAttribute(attribute[0], attribute[1]);
});
nodes.forEach(function (node) {
CAAML.addNode(dom, mc, 'template', node);
});
var m = basenode.appendChild(dom.createElement('caaml:Measurements'));
var ntuples = [];
for (i = feature.layers.length - 1; i >= 0; --i) {
l = feature.layers[i];
ntuples.push(round(profile.top - l.top, 10) + ',' + round(l.value, 10));
}
CAAML.addNode(dom, m, ntuples.join(' '), 'caaml:tupleList');
};
CAAML.addSnowProfile = function (station, profile, dom, root) {
var sp = root.appendChild(dom.createElement('caaml:snowProfileResultsOf'));
var sm = sp.appendChild(dom.createElement('caaml:SnowProfileMeasurements'));
sm.setAttribute('dir', 'top down');
var md = sm.appendChild((dom.createElement('caaml:metaData')));
if (profile.info.comment && profile.info.comment.SnowProfileMeasurements)
CAAML.addNode(dom, md, profile.info.comment.SnowProfileMeasurements, 'caaml:comment');
if (profile.height || profile.height === 0)
CAAML.addNode(dom, sm, profile.height, 'caaml:profileDepth', 'cm');
var wc = sm.appendChild(dom.createElement('caaml:weatherCond'));
md = wc.appendChild(dom.createElement('caaml:metaData'));
if (profile.info.comment && profile.info.comment.weather)
CAAML.addNode(dom, md, profile.info.comment.weather, 'caaml:comment');
if (profile.info.sky !== '') CAAML.addNode(dom, wc, profile.info.sky, 'caaml:skyCond');
if (profile.info.precipitation)
CAAML.addNode(dom, wc, profile.info.precipitation, 'caaml:precipTI');
if (profile.info.ta || profile.info.ta === 0)
CAAML.addNode(dom, wc, profile.info.ta, 'caaml:airTempPres', 'degC');
if (profile.info.wind) {
if (profile.info.wind.speed)
CAAML.addNode(dom, wc, round(profile.info.wind.speed, 4), 'caaml:windSpd', 'ms-1');
if (profile.info.wind.dir || profile.info.wind.angle || profile.info.wind.angle === 0) {
var dir = wc.appendChild(dom.createElement('caaml:windDir'));
var aspect = dir.appendChild(dom.createElement('caaml:AspectPosition'));
var angle = profile.info.wind.angle;
if (!isNaN(angle)) angle = Math.round(angle);
CAAML.addNode(dom, aspect, angle || profile.info.wind.dir, 'caaml:position');
}
}
var spc = sm.appendChild((dom.createElement('caaml:snowPackCond')));
if (profile.info.comment && profile.info.comment.snowpack) {
md = spc.appendChild(dom.createElement('caaml:metaData'));
CAAML.addNode(dom, md, profile.info.comment.snowpack, 'caaml:comment');
}
if (profile.hs || profile.hs === 0 || (profile.swe && profile.density)) {
var hs = spc.appendChild(dom.createElement('caaml:hS'));
var co = hs.appendChild(dom.createElement('caaml:Components'));
if (profile.info.hs === 0) {
// do nothing, outputting anything would be confusing
} else if (profile.hs && (!profile.density || !profile.density.height
|| profile.hs !== profile.density.height)) {
// this is an interesting case: it means that we that either
// density measurement and hs are out of sync or that we have a
// profile with soil; since swe is anyway calculated internally
// we have a preference for hs, it's more consistent
CAAML.addNode(dom, co, profile.hs, 'caaml:height', 'cm');
// Only output if hs not more than 10cm off density height
if (Header.checkdensity(profile))
CAAML.addNode(dom, co,
Math.round(profile.density.elements[0].average() * profile.hs / 100),
'caaml:waterEquivalent', 'kgm-2');
} else if (profile.swe && profile.density) {
CAAML.addNode(dom, co, profile.density.height, 'caaml:height', 'cm');
CAAML.addNode(dom, co, profile.swe, 'caaml:waterEquivalent', 'kgm-2');
} else {
CAAML.addNode(dom, co, profile.hs, 'caaml:height', 'cm');
}
}
if (profile.info && (profile.info.hn24 || profile.info.hn24 === 0)) {
var hn24 = spc.appendChild(dom.createElement('caaml:hN24'));
var com = hn24.appendChild(dom.createElement('caaml:Components'));
CAAML.addNode(dom, com, profile.info.hn24, 'caaml:height', 'cm');
}
var sc = sm.appendChild((dom.createElement('caaml:surfCond')));
md = sc.appendChild((dom.createElement('caaml:metaData')));
if (profile.info.comment && profile.info.comment.surface)
CAAML.addNode(dom, md, profile.info.comment.surface, 'caaml:comment');
if (profile.info.roughness) {
var sf = sc.appendChild(dom.createElement('caaml:surfFeatures'));
var sfc = sf.appendChild(dom.createElement('caaml:Components'));
CAAML.addNode(dom, sfc, profile.info.roughness, 'caaml:surfRoughness');
}
if (profile.info.penetration) {
if (profile.info.penetration.ram !== '')
CAAML.addNode(dom, sc, profile.info.penetration.ram, 'caaml:penetrationRam', 'cm');
if (profile.info.penetration.foot !== '')
CAAML.addNode(dom, sc, profile.info.penetration.foot, 'caaml:penetrationFoot', 'cm');
if (profile.info.penetration.ski !== '')
CAAML.addNode(dom, sc, profile.info.penetration.ski, 'caaml:penetrationSki', 'cm');
}
CAAML.addStratProfile(profile, dom, sm);
CAAML.addTempProfile(profile, dom, sm);
CAAML.addDensityProfile(profile, dom, sm);
CAAML.addLwcProfile(profile, dom, sm);
CAAML.addSSAProfile(profile, dom, sm);
profile.ramm && profile.ramm.elements.forEach(function (ram) {
CAAML.addRamProfile(profile, dom, sm, ram);
});
profile.smp && profile.smp.elements.forEach(function (smp) {
CAAML.addSMPProfile(profile, dom, sm, smp);
});
CAAML.addImpurityProfile(profile, dom, sm);
CAAML.addStabilityProfile(profile, dom, sm);
};
CAAML.addStratProfile = function (profile, dom, node) {
var stratigraphic = [ 'grainshape', 'grainsize', 'hardness', 'wetness' ],
param;
stratigraphic.forEach(function (parameter) {
if (profile[parameter] && profile[parameter].elements[0] &&
profile[parameter].elements[0].layers.length) {
param = parameter;
}
});
if (!param) return;
var sp = node.appendChild(dom.createElement('caaml:stratProfile')),
i = profile[param].layers.length - 1, j = 0;
sp.appendChild(dom.createElement('caaml:stratMetaData'));
for ( ; i >= 0; --i) {
++j;
var hardness, wetness, gs1, gs2, gsavg, gsmax;
var l = sp.appendChild(dom.createElement('caaml:Layer'));
var md = l.appendChild(dom.createElement('caaml:metaData'));
var comment = profile.comments && profile.comments.layers[i].value;
if (comment) CAAML.addNode(dom, md, comment, 'caaml:comment');
var depth = round(profile.top - profile[param].layers[i].top, 4);
var thickness = round(profile[param].layers[i].top - profile[param].layers[i].bottom, 4);
hardness = wetness = gs1 = gs2 = gsavg = gsmax = null;
var hlen = profile.hardness && profile.hardness.layers.length,
wlen = profile.wetness && profile.wetness.elements[0] && profile.wetness.layers.length,
gflen = profile.grainshape && profile.grainshape.layers.length,
gslen = profile.grainsize && profile.grainsize.layers.length;
if (profile.hardness && profile.hardness.layers[hlen - j])
hardness = profile.hardness.layers[hlen - j].caamlcode;
if (profile.wetness && profile.wetness.elements[0] && profile.wetness.layers[wlen - j])
wetness = profile.wetness.layers[wlen - j].code;
if (profile.grainshape && profile.grainshape.layers[gflen - j]) {
gs1 = profile.grainshape.layers[gflen - j].value.primary;
gs2 = profile.grainshape.layers[gflen - j].value.secondary;
}
if (profile.grainsize && profile.grainsize.layers[gslen - j]
&& profile.grainsize.layers[gslen - j].value) {
gsavg = profile.grainsize.layers[gslen - j].value.avg;
gsmax = profile.grainsize.layers[gslen - j].value.max;
}
CAAML.addNode(dom, l, depth, 'caaml:depthTop', 'cm');
CAAML.addNode(dom, l, thickness, 'caaml:thickness', 'cm');
if (gs1) CAAML.addNode(dom, l, gs1, 'caaml:grainFormPrimary');
if (gs1 && gs2) CAAML.addNode(dom, l, gs2, 'caaml:grainFormSecondary');
if (gsavg || gsmax) {
var gs = l.appendChild(dom.createElement('caaml:grainSize'));
gs.setAttribute('uom', 'mm');
var co = gs.appendChild(dom.createElement('caaml:Components'));
if (gsavg) CAAML.addNode(dom, co, gsavg, 'caaml:avg');
if (gsmax) CAAML.addNode(dom, co, gsmax, 'caaml:avgMax');
}
if (hardness) CAAML.addNode(dom, l, hardness, 'caaml:hardness', '');
if (wetness) CAAML.addNode(dom, l, wetness, 'caaml:wetness', '');
}
};
CAAML.addTempProfile = function (profile, dom, node) {
if (!profile.temperature) return;
var tp = node.appendChild(dom.createElement('caaml:tempProfile')), i;
var tpmd = tp.appendChild(dom.createElement('caaml:tempMetaData'));
if (profile.temperature.info.comment)
CAAML.addNode(dom, tpmd, profile.temperature.info.comment, 'caaml:comment');
for (i = profile.temperature.layers.length - 1; i >= 0; --i) {
var l = profile.temperature.layers[i];
// Skip null values
if (!l.value && l.value !== 0) continue;
var ob = tp.appendChild(dom.createElement('caaml:Obs'));
CAAML.addNode(dom, ob, round(profile.top - l.top, 4), 'caaml:depth', 'cm');
CAAML.addNode(dom, ob, round(l.value, 4), 'caaml:snowTemp', 'degC');
}
};
CAAML.addDensityProfile = function (profile, dom, node) {
if (!profile.density || !profile.density.elements.length) return;
profile.density.elements.forEach(function (density) {
var tp = node.appendChild(dom.createElement('caaml:densityProfile')), i;
var tpmd = tp.appendChild(dom.createElement('caaml:densityMetaData'));
if (density.info.comment)
CAAML.addNode(dom, tpmd, density.info.comment, 'caaml:comment');
CAAML.addNode(dom, tpmd, density.info.method || 'other', 'caaml:methodOfMeas');
for (i = density.layers.length - 1; i >= 0; --i) {
var l = density.layers[i];
// Skip null values
if (!l.value && l.value !== 0) continue;
var ob = tp.appendChild(dom.createElement('caaml:Layer'));
CAAML.addNode(dom, ob, round(profile.top - l.top, 4), 'caaml:depthTop', 'cm');
CAAML.addNode(dom, ob, round(l.top - l.bottom, 4), 'caaml:thickness', 'cm');
CAAML.addNode(dom, ob, round(l.value, 4), 'caaml:density', 'kgm-3');
}
});
};
CAAML.addImpurityProfile = function (profile, dom, node) {
if (!profile.impurity || !profile.impurity.elements.length) return;
profile.impurity.elements.forEach(function (impurity) {
var tp = node.appendChild(dom.createElement('caaml:impurityProfile')), i;
var tpmd = tp.appendChild(dom.createElement('caaml:impurityMetaData'));
if (impurity.info.comment)
CAAML.addNode(dom, tpmd, impurity.info.comment, 'caaml:comment');
CAAML.addNode(dom, tpmd, impurity.info.impuritytype || 'other', 'caaml:impurity');
CAAML.addNode(dom, tpmd, impurity.info.method || 'other', 'caaml:methodOfMeas');
var fractiontype = impurity.info.fractiontype;
for (i = impurity.layers.length - 1; i >= 0; --i) {
var l = impurity.layers[i];
// Skip null values
if (!l.value && l.value !== 0) continue;
var ob = tp.appendChild(dom.createElement('caaml:Layer'));
CAAML.addNode(dom, ob, round(profile.top - l.top, 4), 'caaml:depthTop', 'cm');
CAAML.addNode(dom, ob, round(l.top - l.bottom, 4), 'caaml:thickness', 'cm');
CAAML.addNode(dom, ob, round(l.value, 4), 'caaml:' + fractiontype, '%');
}
});
};
CAAML.addRamProfile = function (profile, dom, node, feature) {
if (!feature) return;
var hp = node.appendChild(dom.createElement('caaml:hardnessProfile')), i;
hp.setAttribute('uomWeightHammer', 'kg');
hp.setAttribute('uomWeightTube', 'kg');
hp.setAttribute('uomDropHeight', 'cm');
var md = hp.appendChild(dom.createElement('caaml:hardnessMetaData'));
if (feature.info.comment)
CAAML.addNode(dom, md, feature.info.comment, 'caaml:comment');
CAAML.addNode(dom, md, 'Ram Sonde', 'caaml:methodOfMeas');
for (i = feature.layers.length - 1; i >= 0; --i) {
var l = feature.layers[i];
var ob = hp.appendChild(dom.createElement('caaml:Layer'));
CAAML.addNode(dom, ob, round(profile.top - l.top, 4), 'caaml:depthTop', 'cm');
CAAML.addNode(dom, ob, round(l.top - l.bottom, 4), 'caaml:thickness', 'cm');
CAAML.addNode(dom, ob, round(l.value, 4), 'caaml:hardness', 'N');
CAAML.addNode(dom, ob, l.weightHammer, 'caaml:weightHammer');
CAAML.addNode(dom, ob, l.weightTube, 'caaml:weightTube');
CAAML.addNode(dom, ob, l.nDrops, 'caaml:nDrops');
CAAML.addNode(dom, ob, l.dropHeight, 'caaml:dropHeight');
}
};
CAAML.addSMPProfile = function (profile, dom, node, feature) {
if (!feature || !feature.layers || !feature.layers.length) return;
var hp = node.appendChild(dom.createElement('caaml:hardnessProfile'));
var md = hp.appendChild(dom.createElement('caaml:hardnessMetaData'));
if (feature.info.comment)
CAAML.addNode(dom, md, feature.info.comment, 'caaml:comment');
CAAML.addNode(dom, md, 'SnowMicroPen', 'caaml:methodOfMeas');
if (feature.info.uncertainty || feature.info.uncertainty === 0)
CAAML.addNode(dom, md, feature.info.uncertainty, 'caaml:uncertaintyOfMeas', 'N');
if (feature.info.surf || feature.info.surf === 0)
CAAML.addNode(dom, md, feature.info.surf, 'caaml:surfOfIndentation', 'm2');
CAAML.addPointProfile(
dom, profile, hp, feature,
[['uomDepth', 'cm'], ['uomHardness', 'N']],
['caaml:depth', 'caaml:penRes']
);
};
CAAML.addLwcProfile = function (profile, dom, node) {
if (!profile.wetness || profile.wetness.elements.length <= 1) return;
var i, j;
for (j = 1; j < profile.wetness.elements.length; ++j) {
var lp = node.appendChild(dom.createElement('caaml:lwcProfile')),
feature = profile.wetness.elements[j];
var lpmd = lp.appendChild(dom.createElement('caaml:lwcMetaData'));
if (feature.info.comment)
CAAML.addNode(dom, lpmd, feature.info.comment, 'caaml:comment');
CAAML.addNode(dom, lpmd, feature.info.method || 'other', 'caaml:methodOfMeas');
for (i = feature.layers.length - 1; i >= 0; --i) {
var l = feature.layers[i];
// Skip null values
if (!l.value && l.value !== 0) continue;
var ob = lp.appendChild(dom.createElement('caaml:Layer'));
CAAML.addNode(dom, ob, round(profile.top - l.top, 4), 'caaml:depthTop', 'cm');
CAAML.addNode(dom, ob, round(l.top - l.bottom, 4), 'caaml:thickness', 'cm');
CAAML.addNode(dom, ob, l.value, 'caaml:lwc', '% by Vol');
}
}
};
CAAML.addSSAProfile = function (profile, dom, node) {
if (!profile.ssa || !profile.ssa.elements.length) return;
profile.ssa.elements.forEach(function (feature) {
var sp = node.appendChild(dom.createElement('caaml:specSurfAreaProfile')), i, l;
var spmd = sp.appendChild(dom.createElement('caaml:specSurfAreaMetaData'));
if (feature.info.comment)
CAAML.addNode(dom, spmd, feature.info.comment, 'caaml:comment');
CAAML.addNode(dom, spmd, feature.info.method || 'other', 'caaml:methodOfMeas');
if (feature.info.uncertainty || feature.info.uncertainty === 0)
CAAML.addNode(dom, spmd, feature.info.uncertainty, 'caaml:uncertaintyOfMeas', 'm2kg-1');
if (feature.info.thickness || feature.info.thickness === 0)
CAAML.addNode(dom, spmd, feature.info.thickness, 'caaml:probedThickness', 'cm');
if (feature.info.pointprofile) {
CAAML.addPointProfile(dom, profile, sp, feature,
[['uomDepth', 'cm'], ['uomSpecSurfArea', 'm2kg-1']],
['caaml:depth', 'caaml:specSurfArea']
);
return;
}
for (i = feature.layers.length - 1; i >= 0; --i) {
l = feature.layers[i];
// Skip null values
if (!l.value && l.value !== 0) continue;
var ob = sp.appendChild(dom.createElement('caaml:Layer'));
CAAML.addNode(dom, ob, round(profile.top - l.top, 4), 'caaml:depthTop', 'cm');
CAAML.addNode(dom, ob, round(l.top - l.bottom, 4), 'caaml:thickness', 'cm');
CAAML.addNode(dom, ob, round(l.value, 4), 'caaml:specSurfArea', 'm2kg-1');
}
});
};
CAAML.addStabilityProfile = function (profile, dom, node) {
if (!profile.ct && !profile.rb && !profile.ect && !profile.saw && !profile.sf) return;
var st = node.appendChild(dom.createElement('caaml:stbTests'));
if (profile.ct) CAAML.addCT(profile, dom, st);
if (profile.ect) CAAML.addECT(profile, dom, st);
if (profile.rb) CAAML.addRB(profile, dom, st);
if (profile.sf) CAAML.addSF(profile, dom, st);
if (profile.saw) CAAML.addSAW(profile, dom, st);
};
CAAML.addCT = function (profile, dom, node) {
profile.ct.elements.forEach(function (test) {
var ct = node.appendChild(dom.createElement('caaml:ComprTest'));
for (var i = test.layers.length - 1; i >= 0; --i) {
var l = test.layers[i];
if (l.nofailure) {
ct.appendChild(dom.createElement('caaml:noFailure'));
continue;
}
var fo = ct.appendChild(dom.createElement('caaml:failedOn'));
var cl = fo.appendChild(dom.createElement('caaml:Layer'));
if (l.comment) {
var md = cl.appendChild((dom.createElement('caaml:metaData')));
CAAML.addNode(dom, md, l.comment, 'caaml:comment');
}
CAAML.addNode(dom, cl, round(profile.top - l.top, 4), 'caaml:depthTop', 'cm');
var re = fo.appendChild(dom.createElement('caaml:Results'));
if (l.character) CAAML.addNode(dom, re, l.character, 'caaml:fractureCharacter');
CAAML.addNode(dom, re, l.value ? Math.round(l.value) : 'CTV', 'caaml:testScore');
}
});
};
CAAML.addECT = function (profile, dom, node) {
profile.ect.elements.forEach(function (test) {
var ect = node.appendChild(dom.createElement('caaml:ExtColumnTest'));
for (var i = test.layers.length - 1; i >= 0; --i) {
var l = test.layers[i];
if (l.nofailure) {
ect.appendChild(dom.createElement('caaml:noFailure'));
continue;
}
var fo = ect.appendChild(dom.createElement('caaml:failedOn'));
var el = fo.appendChild(dom.createElement('caaml:Layer'));
if (l.comment) {
var md = el.appendChild(dom.createElement('caaml:metaData'));
CAAML.addNode(dom, md, l.comment, 'caaml:comment');
}
CAAML.addNode(dom, el, round(profile.top - l.top, 4), 'caaml:depthTop', 'cm');
var re = fo.appendChild(dom.createElement('caaml:Results'));
CAAML.addNode(dom, re, l.text, 'caaml:testScore');
}
});
};
CAAML.addRB = function (profile, dom, node) {
profile.rb.elements.forEach(function (test) {
var rb = node.appendChild(dom.createElement('caaml:RBlockTest'));
for (var i = test.layers.length - 1; i >= 0; --i) {
var l = test.layers[i];
if (l.nofailure) {
rb.appendChild(dom.createElement('caaml:noFailure'));
continue;
}
var fo = rb.appendChild(dom.createElement('caaml:failedOn'));
var cl = fo.appendChild(dom.createElement('caaml:Layer'));
if (l.comment) {
var md = cl.appendChild(dom.createElement('caaml:metaData'));
CAAML.addNode(dom, md, l.comment, 'caaml:comment');
}
CAAML.addNode(dom, cl, round(profile.top - l.top, 4), 'caaml:depthTop', 'cm');
var re = fo.appendChild(dom.createElement('caaml:Results'));
if (l.character) CAAML.addNode(dom, re, l.character, 'caaml:fractureCharacter');
if (l.releasetype) CAAML.addNode(dom, re, l.releasetype, 'caaml:releaseType');
CAAML.addNode(dom, re, l.text, 'caaml:testScore');
}
});
};
CAAML.addSF = function (profile, dom, node) {
profile.sf.elements.forEach(function (test) {
var sf = node.appendChild(dom.createElement('caaml:ShearFrameTest'));
for (var i = test.layers.length - 1; i >= 0; --i) {
var l = test.layers[i];
if (l.nofailure) {
sf.appendChild(dom.createElement('caaml:noFailure'));
continue;
}
var fo = sf.appendChild(dom.createElement('caaml:failedOn'));
var cl = fo.appendChild(dom.createElement('caaml:Layer'));
if (l.comment) {
var md = cl.appendChild(dom.createElement('caaml:metaData'));
CAAML.addNode(dom, md, l.comment, 'caaml:comment');
}
CAAML.addNode(dom, cl, round(profile.top - l.top, 4), 'caaml:depthTop', 'cm');
var re = fo.appendChild(dom.createElement('caaml:Results'));
if (l.character) CAAML.addNode(dom, re, l.character, 'caaml:fractureCharacter');
CAAML.addNode(dom, re, l.value, 'caaml:failureForce', 'N');
}
});
};
CAAML.addSAW = function (profile, dom, node) {
profile.saw.elements.forEach(function (test) {
var saw = node.appendChild(dom.createElement('caaml:PropSawTest'));
for (var i = test.layers.length - 1; i >= 0; --i) {
var l = test.layers[i];
var fo = saw.appendChild(dom.createElement('caaml:failedOn'));
var cl = fo.appendChild(dom.createElement('caaml:Layer'));
if (l.comment) {
var md = cl.appendChild(dom.createElement('caaml:metaData'));
CAAML.addNode(dom, md, l.comment, 'caaml:comment');
}
CAAML.addNode(dom, cl, round(profile.top - l.top, 4), 'caaml:depthTop', 'cm');
var re = fo.appendChild(dom.createElement('caaml:Results'));
CAAML.addNode(dom, re, l.text, 'caaml:fracturePropagation');
CAAML.addNode(dom, re, l.cutlength, 'caaml:cutLength', 'cm');
CAAML.addNode(dom, re, l.columnlength, 'caaml:columnLength', 'cm');
}
});
};
CAAML.addAppInfo = function (dom, node) {
CAAML.addNode(dom, node, 'niViz', 'caaml:application');
CAAML.addNode(dom, node, '1.0', 'caaml:applicationVersion');
};
/**
* Serialize Graph object
*
* @method serialize
* @static
*
* @param {Object} data The profile graph, e.g. SimpleProfile, SLFProfile.
* @returns {String} The serialized result.
*/
CAAML.serialize = function (data) {
var result = '<?xml version="1.0" encoding="UTF-8"?>\n', serializer = new XMLSerializer();
var station = data.station, profile = data.profile;
var dom = document.implementation.createDocument('', '', null);
var root = dom.appendChild(dom.createElementNS(CAAML.NS.caaml, 'caaml:SnowProfile'));
var gmlid = station.gmlid || niviz.CAAML.defaults.default_profile_gmlid || 'NA';
gmlid.replace(' ', '');
CAAML.addNS(root, profile);
CAAML.addMetaData(station, profile, dom, root);
CAAML.addTimeRef(profile, dom, root);
CAAML.addSrcRef(profile, dom, root);
CAAML.addLocRef(station, dom, root);
CAAML.addSnowProfile(station, profile, dom, root);
CAAML.addAppInfo(dom, root);
result += serializer.serializeToString(root);
result = format(result);
return result;
};
function format (xml) {
var formatted = '', reg = /(>)(<)(\/*)/g, pad = 0, indent, padding;
xml = xml.replace(reg, '$1\r\n$2$3');
xml.split('\r\n').forEach(function(node, index) {
indent = 0;
if (node.match( /.+<\/\w[^>]*>$/ )) {
indent = 0;
} else if (node.match( /^<\/\w/ )) {
if (pad !== 0) {
pad -= 1;
}
} else if (node.match( /^<\w[^>]*[^\/]>.*$/ )) {
indent = 1;
} else {
indent = 0;
}
padding = '';
for (var i = 0; i < pad; i++) padding += ' ';
formatted += padding + node + '\r\n';
pad += indent;
});
return formatted;
}
// --- Module Exports ---
niviz.CAAML = CAAML;
}(niviz));