Author: lgiessmann Date: Wed Jun 15 09:05:52 2011 New Revision: 483
Log: implemented a small example that accesses the javascript Topic Maps engine tmjs via the GWT JSNI interface
Added: branches/gdl-frontend/playground/GWT-JSNI/GWT-JSNI-example/lib/tm.js branches/gdl-frontend/playground/GWT-JSNI/GWT-JSNI-example/lib/tm.min.js Replaced: branches/gdl-frontend/playground/GWT-JSNI/GWT-JSNI-example/war/gwt_jsni_example/external/tm.js - copied unchanged from r482, branches/gdl-frontend/playground/GWT-JSNI/GWT-JSNI-example/war/gwt_jsni_example/external/tm.js branches/gdl-frontend/playground/GWT-JSNI/GWT-JSNI-example/war/gwt_jsni_example/external/tm.min.js - copied unchanged from r482, branches/gdl-frontend/playground/GWT-JSNI/GWT-JSNI-example/war/gwt_jsni_example/external/tm.min.js Deleted: branches/gdl-frontend/playground/GWT-JSNI/GWT-JSNI-example/lib/tinytim-2.0.0.jar branches/gdl-frontend/playground/GWT-JSNI/GWT-JSNI-example/lib/tmapi-2.0.2.jar
Added: branches/gdl-frontend/playground/GWT-JSNI/GWT-JSNI-example/lib/tm.js ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ branches/gdl-frontend/playground/GWT-JSNI/GWT-JSNI-example/lib/tm.js Wed Jun 15 09:05:52 2011 (r483) @@ -0,0 +1,3926 @@ +// tmjs, version 0.4.0 +// http://github.com/jansc/tmjs +// Copyright (c) 2010 Jan Schreiber jans@ravn.no +// Licensed under the MIT-License. +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +/*jslint browser: true, devel: true, onevar: true, undef: true, + nomen: false, eqeqeq: true, plusplus: true, bitwise: true, + regexp: true, newcap: true, immed: true, indent: 4 */ +/*global exports*/ + +var TM, TopicMapSystemFactory; + +/** + * @namespace Global namespace that holds all Topic Maps related objects. + * @author Jan Schreiber jans@ravn.no + * @copyright 2010 Jan Schreiber http://purl.org/net/jans + * Date: Wed Dec 1 08:39:28 2010 +0100 + */ +TM = (function () { + var Version, Hash, XSD, TMDM, Locator, EventType, Topic, Association, + Scoped, Construct, Typed, Reifiable, + DatatypeAware, TopicMap, Role, Name, + Variant, Occurrence, TopicMapSystemMemImpl, + Index, TypeInstanceIndex, ScopedIndex, + SameTopicMapHelper, ArrayHelper, IndexHelper, addScope, + DuplicateRemover, + SignatureGenerator, MergeHelper, CopyHelper, + TypeInstanceHelper; + + Version = '0.4.0'; + + // ----------------------------------------------------------------------- + // Our swiss army knife for mixin of functions. + // See http://javascript.crockford.com/inheritance.html + Function.prototype.swiss = function (parnt) { + var i, name; + for (i = 1; i < arguments.length; i += 1) { + name = arguments[i]; + this.prototype[name] = parnt.prototype[name]; + } + return this; + }; + + // ----------------------------------------------------------------------- + // Simple hash table for lookup tables + Hash = function () { + this.hash = {}; + this.length = 0; + }; + + /** + * @class Simple hash implementation. + */ + Hash.prototype = { + /** + * Returns the object belonging to the key key or undefined if the + * key does not exist. + * @param key {String} The hash key. + * @returns {object} The stored object or undefined. + */ + get: function (key) { + return this.hash[key]; + }, + + /** + * Checks if the key exists in the hash table. + * @param key {String} The hash key. + * @returns {boolean} True if key exists in the hash table. False + * otherwise. + */ + contains: function (key) { + return this.get(key) !== undefined; + }, + + /** + * Stores an object in the hash table. + * @param key {String} The hash key. + * @param val {object} The value to be stored in the hash table. + * @returns val {object} A reference to the stored object. + */ + put: function (key, val) { + if (!this.hash[key]) { + this.length += 1; + } + this.hash[key] = val; + return val; + }, + + /** + * Removes the key and the corresponding value from the hash table. + * @param key {String} Removes value corresponding to key and the key + * from the hash table + * @returns {Hash} The hash table itself. + */ + remove: function (key) { + delete this.hash[key]; + this.length -= 1; + return this; + }, + + /** + * Returns an array with keys of the hash table. + * @returns {Array} An array with strings. + */ + keys: function () { + var ret = [], key; + for (key in this.hash) { + if (this.hash.hasOwnProperty(key)) { + ret.push(key); + } + } + return ret; + }, + + /** + * Returns an array with all values of the hash table. + * @returns {Array} An array with all objects stored as a value in + * the hash table. + */ + values: function () { + var ret = [], key; + for (key in this.hash) { + if (this.hash.hasOwnProperty(key)) { + ret.push(this.hash[key]); + } + } + return ret; + }, + + /** + * Empties the hash table by removing the reference to all objects. + * Note that the store objects themselves are not touched. + * @returns undefined + */ + empty: function () { + this.hash = {}; + this.length = 0; + }, + + /** + * Returns the size of the hash table, that is the count of all + * key/value pairs. + * @returns {Number} The count of all key/value pairs stored in the + * hash table. + */ + size: function () { + return this.length; + } + }; + + // ----------------------------------------------------------------------- + // Internal event handling system + EventType = {}; + EventType.ADD_ASSOCIATION = 1; + EventType.ADD_NAME = 2; + EventType.ADD_OCCURRENCE = 3; + EventType.ADD_ROLE = 4; + EventType.ADD_THEME = 5; + EventType.ADD_TOPIC = 6; + EventType.ADD_TYPE = 7; + EventType.REMOVE_ASSOCIATION = 8; + EventType.REMOVE_NAME = 9; + EventType.REMOVE_OCCURRENCE = 10; + EventType.REMOVE_ROLE = 11; + EventType.REMOVE_THEME = 12; + EventType.REMOVE_TOPIC = 13; + EventType.REMOVE_TYPE = 14; + EventType.SET_TYPE = 15; + + /** + * @namespace Namespace for XML Schema URIs. // FIXME!! + */ + XSD = { + 'string': "http://www.w3.org/2001/XMLSchema#string", + 'integer': "http://www.w3.org/2001/XMLSchema#integer", + 'anyURI': "http://www.w3.org/2001/XMLSchema#anyURI" + + // TODO: Add all build-in types + }; + + TMDM = { + 'TYPE_INSTANCE': 'http://psi.topicmaps.org/iso13250/model/type-instance', + 'TYPE': 'http://psi.topicmaps.org/iso13250/model/type', + 'INSTANCE': 'http://psi.topicmaps.org/iso13250/model/instance', + 'TOPIC_NAME': 'http://psi.topicmaps.org/iso13250/model/topic-name' + }; + + // ----------------------------------------------------------------------- + // TODO: The locator functions need some more work. Implement resolve() + // and toExternalForm() + + /** + * @class Immutable representation of an IRI. + */ + Locator = function (parnt, iri) { + this.parnt = parnt; + this.iri = iri; + }; + + /** + * Returns the IRI. + * @returns {String} A lexical representation of the IRI. + */ + Locator.prototype.getReference = function () { + return this.iri; + }; + + /** + * Returns true if the other object is equal to this one. + * @param other The object to compare this object against. + * @returns <code>(other instanceof Locator && + * this.getReference().equals(((Locator)other).getReference()))</code> + */ + Locator.prototype.equals = function (other) { + return (this.iri === other.getReference()); + }; + + /** + * Returns the external form of the IRI. Any special character will be + * escaped using the escaping conventions of RFC 3987. + * @returns {String} A string representation of this locator suitable for + * output or passing to APIs which will parse the locator anew. + */ + Locator.prototype.toExternalForm = function () { + throw {name: 'NotImplemented', message: 'Locator.toExternalForm() not implemented'}; + }; + + + // ----------------------------------------------------------------------- + /** + * @class Represents a Topic Maps construct. + */ + Construct = function () {}; + + /** + * Adds an item identifier. + * @param {Locator} itemIdentifier The item identifier to add. + * @returns {Construct} The construct itself (for chaining support) + * @throws {ModelConstraintException} If the itemidentifier is null. + * @throws {IdentityConstraintException} If another Topic Maps construct with + * the same item identifier exists. + */ + Construct.prototype.addItemIdentifier = function (itemIdentifier) { + var existing; + if (itemIdentifier === null) { + throw {name: 'ModelConstraintException', + message: 'addItemIdentifier(null) is illegal'}; + } + existing = this.getTopicMap()._ii2construct.get(itemIdentifier.getReference()); + if (existing) { + throw {name: 'IdentityConstraintException', + message: 'Topic Maps constructs with the same item identifier ' + + 'are not allowed', + reporter: this, + existing: existing, + locator: itemIdentifier}; + } + this.itemIdentifiers.push(itemIdentifier); + this.getTopicMap()._ii2construct.put(itemIdentifier.getReference(), this); + return this; + }; + + /** + * Returns true if the other object is equal to this one. Equality must be + * the result of comparing the identity (<code>this == other</code>) of the + * two objects. + * Note: This equality test does not reflect any equality rule according to + * the Topic Maps - Data Model (TMDM) by intention. + * @param {String} other The object to compare this object against. + */ + Construct.prototype.equals = function (other) { + return (this.id === other.id); + }; + + /** + * Returns the identifier of this construct. This property has no + * representation in the Topic Maps - Data Model. + * + * The ID can be anything, so long as no other Construct in the same topic + * map has the same ID. + * @returns {String} An identifier which identifies this construct uniquely + * within a topic map. + */ + Construct.prototype.getId = function () { + return this.id; + }; + + /** + * Returns the item identifiers of this Topic Maps construct. The return + * value may be empty but must never be <code>null</code>. + * @returns {Array} An array of Locators representing the item identifiers. + * The array MUST NOT be modified. + */ + Construct.prototype.getItemIdentifiers = function () { + return this.itemIdentifiers; + }; + + /** + * Returns the parent of this construct. This method returns + * <code>null</code> iff this construct is a TopicMap instance. + * @returns {Construct} The parent of this construct or <code>null</code> + * iff the construct is an instance of TopicMap. + */ + Construct.prototype.getParent = function () { + return this.parnt; + }; + + /** + * Returns the TopicMap instance to which this Topic Maps construct belongs. + * A TopicMap instance returns itself. + * @returns {Construct} The topic map instance to which this construct belongs. + */ + Construct.prototype.getTopicMap = function () { + throw {name: 'NotImplemented', message: 'getTopicMap() not implemented'}; + }; + + /** + * Returns the hash code value. + * TODO: Is this needed? + */ + Construct.prototype.hashCode = function () { + throw {name: 'NotImplemented', message: 'hashCode() not implemented'}; + }; + + /** + * Returns the parent of this construct. This method returns + * <code>null</code> iff this construct is a TopicMap instance. + * @returns {Construct} The parent of this construct or <code>null</code> + * iff the construct is an instance of {@link TopicMap}. + */ + Construct.prototype.remove = function () { + throw {name: 'NotImplemented', message: 'remove() not implemented'}; + }; + + /** + * Removes an item identifier. + * @param {Locator} itemIdentifier The item identifier to be removed from + * this construct, if present (<code>null</code> is ignored). + * @returns {Construct} The construct itself (for chaining support) + */ + Construct.prototype.removeItemIdentifier = function (itemIdentifier) { + if (itemIdentifier === null) { + return; + } + for (var i = 0; i < this.itemIdentifiers.length; i += 1) { + if (this.itemIdentifiers[i].getReference() === + itemIdentifier.getReference()) { + this.itemIdentifiers.splice(i, 1); + break; + } + } + this.getTopicMap()._ii2construct.remove(itemIdentifier.getReference()); + return this; + }; + + /** + * Returns true if the construct is a {@link TopicMap}-object + * @returns <code>true</code> if the construct is a {@link TopicMap}-object, + * <code>false</code> otherwise. + */ + Construct.prototype.isTopicMap = function () { + return false; + }; + + /** + * Returns true if the construct is a {@link Topic}-object + * @returns <code>true</code> if the construct is a {@link Topic}-object, + * <code>false</code> otherwise. + */ + Construct.prototype.isTopic = function () { + return false; + }; + + /** + * Returns true if the construct is an {@link Association}-object + * @returns <code>true</code> if the construct is an {@link Association}- + * object, <code>false</code> otherwise. + */ + Construct.prototype.isAssociation = function () { + return false; + }; + + /** + * Returns true if the construct is a {@link Role}-object + * @returns <code>true</code> if the construct is a {@link Role}-object, + * <code>false</code> otherwise. + */ + Construct.prototype.isRole = function () { + return false; + }; + + /** + * Returns true if the construct is a {@link Name}-object + * @returns <code>true</code> if the construct is a {@link Name}-object, + * <code>false</code> otherwise. + */ + Construct.prototype.isName = function () { + return false; + }; + + /** + * Returns true if the construct is an {@link Occurrenct}-object + * @returns <code>true</code> if the construct is an {@link Occurrence}-object, + * <code>false</code> otherwise. + */ + Construct.prototype.isOccurrence = function () { + return false; + }; + + /** + * Returns true if the construct is a {@link Variant}-object + * @returns <code>true</code> if the construct is a {@link Variant}-object, + * <code>false</code> otherwise. + */ + Construct.prototype.isVariant = function () { + return false; + }; + + // -------------------------------------------------------------------------- + Typed = function () {}; + + // Returns the type of this construct. + Typed.prototype.getType = function () { + return this.type; + }; + + /** + * Sets the type of this construct. + * @throws {ModelConstraintException} If type is null. + * @returns {Typed} The type itself (for chaining support) + */ + Typed.prototype.setType = function (type) { + if (type === null) { + throw {name: 'ModelConstraintException', + message: 'Topic.setType cannot be called without type'}; + } + SameTopicMapHelper.assertBelongsTo(this.getTopicMap(), type); + this.getTopicMap().setTypeEvent.fire(this, {old: this.type, type: type}); + this.type = type; + return this; + }; + + // -------------------------------------------------------------------------- + /** + * @class Indicates that a statement (Topic Maps construct) has a scope. + * Associations, Occurrences, Names, and Variants are scoped. + */ + Scoped = function () {}; + + /** + * Adds a topic to the scope. + * @throws {ModelConstraintException} If theme is null. + * @returns {Typed} The type itself (for chaining support) + */ + Scoped.prototype.addTheme = function (theme) { + if (theme === null) { + throw {name: 'ModelConstraintException', + message: 'addTheme(null) is illegal'}; + } + // Check if theme is part of the scope + for (var i = 0; i < this.scope.length; i += 1) { + if (this.scope[i] === theme) { + return false; + } + } + SameTopicMapHelper.assertBelongsTo(this.getTopicMap(), theme); + this.scope.push(theme); + this.getTopicMap().addThemeEvent.fire(this, {theme: theme}); + // Special case for names: add the theme to all variants + if (this.isName()) { + for (i = 0; i < this.variants.length; i += 1) { + this.getTopicMap().addThemeEvent.fire(this.variants[i], {theme: theme}); + } + } + return this; + }; + + /** + * Returns the topics which define the scope. + * @returns {Array} A possible empty Array with Topic objects. + */ + Scoped.prototype.getScope = function () { + if (this.isVariant()) { + var i, tmp = new Hash(), parent_scope = this.parnt.getScope(); + for (i = 0; i < parent_scope.length; i += 1) { + tmp.put(parent_scope[i].getId(), parent_scope[i]); + } + for (i = 0; i < this.scope.length; i += 1) { + tmp.put(this.scope[i].getId(), this.scope[i]); + } + return tmp.values(); + } + return this.scope; + }; + + /** + * Removes a topic from the scope. + * @returns {Scoped} The scoped object itself (for chaining support) + */ + Scoped.prototype.removeTheme = function (theme) { + var i, j, scope, found; + for (i = 0; i < this.scope.length; i += 1) { + if (this.scope[i] === theme) { + this.getTopicMap().removeThemeEvent.fire(this, {theme: this.scope[i]}); + this.scope.splice(i, 1); + break; + } + } + // Special case for names: remove the theme from index for all variants + if (this.isName()) { + for (i = 0; i < this.variants.length; i += 1) { + scope = this.variants[i].scope; + // Check if the the variant has theme as scope + found = false; + for (j = 0; j < scope.length; j += 1) { + if (theme.equals(scope[j])) { + found = true; + } + } + if (!found) { + this.getTopicMap().removeThemeEvent.fire(this.variants[i], {theme: theme}); + } + } + } + return this; + }; + + + // -------------------------------------------------------------------------- + /** + * @class Indicates that a Construct is reifiable. Every Topic Maps + * construct that is not a Topic is reifiable. + */ + Reifiable = function () {}; + + /** + * Returns the reifier of this construct. + */ + Reifiable.prototype.getReifier = function () { + return this.reifier; + }; + + /** + * Sets the reifier of the construct. + * @throws {ModelConstraintException} If reifier already reifies another + * construct. + * @returns {Reifiable} The reified object itself (for chaining support) + */ + Reifiable.prototype.setReifier = function (reifier) { + if (reifier && reifier.getReified() !== null) { + throw {name: 'ModelConstraintException', + message: 'Reifies already another construct'}; + } + SameTopicMapHelper.assertBelongsTo(this.getTopicMap(), reifier); + if (this.reifier) { + this.reifier._setReified(null); + } + if (reifier) { + reifier._setReified(this); + } + this.reifier = reifier; + return this; + }; + + // -------------------------------------------------------------------------- + /** + * @class Common base interface for Occurrences and Variants. + * Inherits Scoped, Reifiable + */ + DatatypeAware = function () {}; + + /** + * Returns the BigDecimal representation of the value. + */ + DatatypeAware.prototype.decimalValue = function () { + // FIXME Implement! + }; + + /** + * Returns the float representation of the value. + * @throws {NumberFormatException} If the value is not convertable to float. + */ + DatatypeAware.prototype.floatValue = function () { + var ret = parseFloat(this.value); + if (isNaN(ret)) { + throw {name: 'NumberFormatException', + message: '"' + this.value + '" is not a float'}; + } + return ret; + }; + + /** + * Returns the Locator identifying the datatype of the value. + */ + DatatypeAware.prototype.getDatatype = function () { + return this.datatype; + }; + + /** + * Returns the lexical representation of the value. + */ + DatatypeAware.prototype.getValue = function () { + if (typeof this.value === 'object' && this.value instanceof Locator) { + return this.value.getReference(); + } + return this.value.toString(); + }; + + /** + * Returns the BigInteger representation of the value. + * @throws {NumberFormatException} If the value cannot be parsed as an int. + */ + DatatypeAware.prototype.integerValue = function () { + var ret = parseInt(this.value, 10); + if (isNaN(ret)) { + throw {name: 'NumberFormatException', + message: '"' + this.value + '" is not an integer'}; + } + return ret; + }; + + /** + * Returns the Locator representation of the value. + * @throws {ModelConstraintException} If the value is not an Locator + * object. + */ + DatatypeAware.prototype.locatorValue = function () { + if (!(typeof this.value === 'object' && this.value instanceof Locator)) { + throw {name: 'ModelConstraintException', + message: '"' + this.value + '" is not a locator'}; + } + return this.value; + }; + + /** + * Returns the long representation of the value. + */ + DatatypeAware.prototype.longValue = function () { + // FIXME Implement! + }; + + /** + * Sets the value and the datatype. + * @throws {ModelConstraintException} If datatype or value is null. + */ + DatatypeAware.prototype.setValue = function (value, datatype) { + var tm = this.getTopicMap(); + if (datatype === null) { + throw {name: 'ModelConstraintException', message: 'Invalid datatype'}; + } + if (value === null) { + throw {name: 'ModelConstraintException', message: 'Invalid value'}; + } + this.value = value; + this.datatype = datatype || + this.getTopicMap().createLocator(XSD.string); + if (datatype && datatype.getReference() === XSD.anyURI) { + this.value = tm.createLocator(value); + } + if (!datatype) { + if (typeof value === 'number') { + // FIXME Could be XSD.float as well + this.datatype = tm.createLocator(XSD.integer); + } + } + if (typeof value === 'object' && value instanceof Locator) { + this.datatype = tm.createLocator(XSD.anyURI); + } + }; + + // -------------------------------------------------------------------------- + /** + * Constructs a new Topic Map System Factoy. The constructor should not be + * called directly. Use the {TM.TopicMapSystemFactory.newInstance} instead. + * @class Represents a Topic Maps construct. + * @memberOf TM + */ + TopicMapSystemFactory = function () { + this.properties = {}; + this.features = {}; + }; + + /** + * Returns the particular feature requested for in the underlying implementation + * of TopicMapSystem. + */ + TopicMapSystemFactory.prototype.getFeature = function (featureName) { + return this.features; + }; + + /** + * Gets the value of a property in the underlying implementation of + * TopicMapSystem. + */ + TopicMapSystemFactory.prototype.getProperty = function (propertyName) { + return this.properties[propertyName]; + }; + + /** + * Returns if the particular feature is supported by the TopicMapSystem. + */ + TopicMapSystemFactory.prototype.hasFeature = function (featureName) { + return false; + }; + + /** + * Obtain a new instance of a TopicMapSystemFactory. + * @static + * @returns {TopicMapSystemFactory} + */ + TopicMapSystemFactory.newInstance = function () { + return new TopicMapSystemFactory(); + }; + + /** + * Creates a new TopicMapSystem instance using the currently configured + * factory parameters. + */ + TopicMapSystemFactory.prototype.newTopicMapSystem = function () { + var backend = this.properties['com.semanticheadache.tmjs.backend'] || 'memory'; + if (backend === 'memory') { + return new TopicMapSystemMemImpl(); + } + }; + + /** + * Sets a particular feature in the underlying implementation of TopicMapSystem. + */ + TopicMapSystemFactory.prototype.setFeature = function (featureName, enable) { + this.features[featureName] = enable; + }; + + /** + * Sets a property in the underlying implementation of TopicMapSystem. + */ + TopicMapSystemFactory.prototype.setProperty = function (propertyName, value) { + this.properties[propertyName] = value; + }; + + /** + * Creates a new instance of TopicMamSystem. + * @class Implementation of the TopicMapSystem interface. + */ + TopicMapSystemMemImpl = function () { + this.topicmaps = {}; + }; + + /** + * @throws {TopicMapExistsException} If a topic map with the given locator + * already exists. + */ + TopicMapSystemMemImpl.prototype.createTopicMap = function (locator) { + if (this.topicmaps[locator.getReference()]) { + throw {name: 'TopicMapExistsException', + message: 'A topic map under the same IRI already exists'}; + } + var tm = new TopicMap(this, locator); + this.topicmaps[locator.getReference()] = tm; + return tm; + }; + + TopicMapSystemMemImpl.prototype.getLocators = function () { + var locators = [], key; + for (key in this.topicmaps) { + if (this.topicmaps.hasOwnProperty(key)) { + locators.push(this.createLocator(key)); + } + } + return locators; + }; + + TopicMapSystemMemImpl.prototype.getTopicMap = function (locator) { + var tm; + if (locator instanceof Locator) { + tm = this.topicmaps[locator.getReference()]; + } else { + tm = this.topicmaps[locator]; + } + if (!tm) { + return null; + } + return tm; + }; + + /** + * @param {String} iri + */ + TopicMapSystemMemImpl.prototype.createLocator = function (iri) { + return new Locator(this, iri); + }; + + TopicMapSystemMemImpl.prototype.getFeature = function (featureName) { + return false; + }; + + TopicMapSystemMemImpl.prototype._removeTopicMap = function (tm) { + var key; + for (key in this.topicmaps) { + if (this.topicmaps.hasOwnProperty(key) && + key === tm.locator.getReference()) { + delete this.topicmaps[key]; + } + } + }; + + TopicMapSystemMemImpl.prototype.close = function () { + this.topicmaps = null; // release references + }; + + TopicMap = function (tms, locator) { + this.topicmapsystem = tms; + this.itemIdentifiers = []; + this.locator = locator; + this.topics = []; + this.associations = []; + this._constructId = 1; + this._si2topic = new Hash(); // Index for subject identifiers + this._sl2topic = new Hash(); // Index for subject locators + this._ii2construct = new Hash(); // Index for item identifiers + this._id2construct = new Hash(); // Index for object ids + + // The topic map object always get the id 0 + this.id = 0; + this._id2construct.put(this.id, this); + + this.reifier = null; + this.handlers = []; + + // Our own event handling mechanism + var EventHandler = function (eventtype) { + this.eventtype = eventtype; + this.handlers = []; + }; + EventHandler.prototype = { + registerHandler: function (handler) { + this.handlers.push(handler); + }, + removeHandler: function (handler) { + for (var i = 0; i < this.handlers.length; i += 1) { + if (handler.toString() === + this.handlers[i].toString()) { + this.handlers.splice(i, 1); + } + } + }, + fire: function (source, obj) { + obj = obj || {}; + for (var i = 0; i < this.handlers.length; i += 1) { + this.handlers[i](this.eventtype, source, obj); + } + } + }; + this.addAssociationEvent = new EventHandler(EventType.ADD_ASSOCIATION); + this.addNameEvent = new EventHandler(EventType.ADD_NAME); + this.addOccurrenceEvent = new EventHandler(EventType.ADD_OCCURRENCE); + this.addRoleEvent = new EventHandler(EventType.ADD_ROLE); + this.addThemeEvent = new EventHandler(EventType.ADD_THEME); + this.addTopicEvent = new EventHandler(EventType.ADD_TOPIC); + this.addTypeEvent = new EventHandler(EventType.ADD_TYPE); + this.removeAssociationEvent = new EventHandler(EventType.REMOVE_ASSOCIATION); + this.removeNameEvent = new EventHandler(EventType.REMOVE_NAME); + this.removeOccurrenceEvent = new EventHandler(EventType.REMOVE_OCCURRENCE); + this.removeRoleEvent = new EventHandler(EventType.REMOVE_ROLE); + this.removeThemeEvent = new EventHandler(EventType.REMOVE_THEME); + this.removeTopicEvent = new EventHandler(EventType.REMOVE_TOPIC); + this.removeTypeEvent = new EventHandler(EventType.REMOVE_TYPE); + this.setTypeEvent = new EventHandler(EventType.SET_TYPE); + this.typeInstanceIndex = new TypeInstanceIndex(this); + this.scopedIndex = new ScopedIndex(this); + }; + + /** + * @returns {TopicMap} The topic map object itself (for chaining support) + */ + TopicMap.prototype.register_event_handler = function (type, handler) { + switch (type) { + case EventType.ADD_ASSOCIATION: + this.addAssociationEvent.registerHandler(handler); + break; + case EventType.ADD_NAME: + this.addNameEvent.registerHandler(handler); + break; + case EventType.ADD_OCCURRENCE: + this.addOccurrenceEvent.registerHandler(handler); + break; + case EventType.ADD_ROLE: + this.addRoleEvent.registerHandler(handler); + break; + case EventType.ADD_THEME: + this.addThemeEvent.registerHandler(handler); + break; + case EventType.ADD_TOPIC: + this.addTopicEvent.registerHandler(handler); + break; + case EventType.ADD_TYPE: + this.addTypeEvent.registerHandler(handler); + break; + case EventType.REMOVE_ASSOCIATION: + this.removeAssociationEvent.registerHandler(handler); + break; + case EventType.REMOVE_NAME: + this.removeNameEvent.registerHandler(handler); + break; + case EventType.REMOVE_OCCURRENCE: + this.removeOccurrenceEvent.registerHandler(handler); + break; + case EventType.REMOVE_ROLE: + this.removeRoleEvent.registerHandler(handler); + break; + case EventType.REMOVE_THEME: + this.removeThemeEvent.registerHandler(handler); + break; + case EventType.REMOVE_TOPIC: + this.removeTopicEvent.registerHandler(handler); + break; + case EventType.REMOVE_TYPE: + this.removeTypeEvent.registerHandler(handler); + break; + case EventType.SET_TYPE: + this.setTypeEvent.registerHandler(handler); + break; + } + return this; + }; + + TopicMap.swiss(Reifiable, 'getReifier', 'setReifier'); + TopicMap.swiss(Construct, 'addItemIdentifier', 'getItemIdentifiers', + 'removeItemIdentifier', 'isTopic', 'isAssociation', 'isRole', + 'isOccurrence', 'isName', 'isVariant', 'isTopicMap'); + /** + * Removes duplicate topic map objects. This function is quite expensive, + * so it should not be called too often. It is meant to remove duplicates + * after imports of topic maps. + * @returns {TopicMap} The topic map object itself (for chaining support) + */ + TopicMap.prototype.sanitize = function () { + DuplicateRemover.removeTopicMapDuplicates(this); + TypeInstanceHelper.convertAssociationsToType(this); + return this; + }; + + TopicMap.prototype.isTopicMap = function () { + return true; + }; + + TopicMap.prototype._getConstructId = function () { + this._constructId = this._constructId + 1; + return this._constructId; + }; + + TopicMap.prototype.remove = function () { + if (this.topicmapsystem === null) { + return null; + } + this.topicmapsystem._removeTopicMap(this); + this.topicmapsystem = null; + this.itemIdentifiers = null; + this.locator = null; + this.topics = null; + this.associations = null; + this._si2topic = null; + this._sl2topic = null; + this._ii2construct = null; + this._id2construct = null; + this.reifier = null; + this.id = null; + this.typeInstanceIndex = null; + return null; + }; + + /** + * @throws {ModelConstraintException} If type or scope is null. + */ + TopicMap.prototype.createAssociation = function (type, scope) { + var a; + if (type === null) { + throw {name: 'ModelConstraintException', + message: 'Creating an association with type == null is not allowed'}; + } + if (scope === null) { + throw {name: 'ModelConstraintException', + message: 'Creating an association with scope == null is not allowed'}; + } + SameTopicMapHelper.assertBelongsTo(this, type); + SameTopicMapHelper.assertBelongsTo(this, scope); + + a = new Association(this); + this.associations.push(a); + if (type) { + a.setType(type); + } + addScope(a, scope); + this.addAssociationEvent.fire(a); + return a; + }; + + TopicMap.prototype.createLocator = function (iri) { + return new Locator(this, iri); + }; + + TopicMap.prototype._createEmptyTopic = function () { + var t = new Topic(this); + this.addTopicEvent.fire(t); + this.topics.push(t); + return t; + }; + + TopicMap.prototype.createTopic = function () { + var t = this._createEmptyTopic(); + t.addItemIdentifier(this.createLocator('urn:x-tmjs:' + t.getId())); + return t; + }; + + /** + * @throws {ModelConstraintException} If no itemIdentifier is given. + * @throws {IdentityConstraintException} If another construct with the + * specified item identifier exists which is not a Topic. + */ + TopicMap.prototype.createTopicByItemIdentifier = function (itemIdentifier) { + if (!itemIdentifier) { + throw {name: 'ModelConstraintException', + message: 'createTopicByItemIdentifier() needs an item identifier'}; + } + var t = this.getConstructByItemIdentifier(itemIdentifier); + if (t) { + if (!t.isTopic()) { + throw {name: 'IdentityConstraintException', + message: 'Another construct with the specified item identifier ' + + 'exists which is not a Topic.'}; + } + return t; + } + t = this._createEmptyTopic(); + t.addItemIdentifier(itemIdentifier); + return t; + }; + + /** + * @throws {ModelConstraintException} If no subjectIdentifier is given. + */ + TopicMap.prototype.createTopicBySubjectIdentifier = function (subjectIdentifier) { + if (!subjectIdentifier) { + throw {name: 'ModelConstraintException', + message: 'createTopicBySubjectIdentifier() needs a subject identifier'}; + } + var t = this.getTopicBySubjectIdentifier(subjectIdentifier); + if (t) { + return t; + } + t = this._createEmptyTopic(); + t.addSubjectIdentifier(subjectIdentifier); + return t; + }; + + /** + * @throws {ModelConstraintException} If no subjectLocator is given. + */ + TopicMap.prototype.createTopicBySubjectLocator = function (subjectLocator) { + if (!subjectLocator) { + throw {name: 'ModelConstraintException', + message: 'createTopicBySubjectLocator() needs a subject locator'}; + } + var t = this.getTopicBySubjectLocator(subjectLocator); + if (t) { + return t; + } + t = this._createEmptyTopic(); + t.addSubjectLocator(subjectLocator); + return t; + }; + + TopicMap.prototype.getAssociations = function () { + return this.associations; + }; + + /** + * @throws {ModelConstraintException} If id is null. + */ + TopicMap.prototype.getConstructById = function (id) { + if (id === null) { + throw {name: 'ModelConstraintException', + message: 'getConstructById(null) is illegal'}; + } + var ret = this._id2construct.get(id); + if (!ret) { + return null; + } + return ret; + }; + + /** + * @throws {ModelConstraintException} If itemIdentifier is null. + */ + TopicMap.prototype.getConstructByItemIdentifier = function (itemIdentifier) { + if (itemIdentifier === null) { + throw {name: 'ModelConstraintException', + message: 'getConstructByItemIdentifier(null) is illegal'}; + } + var ret = this._ii2construct.get(itemIdentifier.getReference()); + if (!ret) { + return null; + } + return ret; + }; + + /** + * @throws {UnsupportedOperationException} If the index type is not + * supported. + */ + TopicMap.prototype.getIndex = function (className) { + var index; + if (className === 'TypeInstanceIndex') { + index = this.typeInstanceIndex; + return index; + } else if (className === 'ScopedIndex') { + index = new ScopedIndex(this); + return index; + } + // TODO: Should we throw an exception that indicates that the + // index is not known? Check the TMAPI docs! + throw {name: 'UnsupportedOperationException', + message: 'getIndex ist not (yet) supported'}; + }; + + TopicMap.prototype.getParent = function () { + return null; + }; + + TopicMap.prototype.getTopicBySubjectIdentifier = function (subjectIdentifier) { + var res = this._si2topic.get(subjectIdentifier.getReference()); + if (res) { + return res; + } + return null; // Make sure that the result is not undefined + }; + + TopicMap.prototype.getTopicBySubjectLocator = function (subjectLocator) { + var res = this._sl2topic.get(subjectLocator.getReference()); + if (res) { + return res; + } + return null; // Make sure that the result is not undefined + }; + + TopicMap.prototype.getLocator = function () { + return this.locator; + }; + + TopicMap.prototype.getTopics = function () { + return this.topics; + }; + + TopicMap.prototype.mergeIn = function (topicmap) { + // TODO implement! + throw {name: 'NotImplemented', message: 'TopicMap.mergeIn() not implemented'}; + }; + + TopicMap.prototype.equals = function (topicmap) { + return this.locator.equals(topicmap.locator); + }; + + TopicMap.prototype.getId = function () { + return this.id; + }; + + TopicMap.prototype.getTopicMap = function () { + return this; + }; + + // Remove item identifiers + TopicMap.prototype._removeConstruct = function (construct) { + var iis = construct.getItemIdentifiers(), i; + for (i = 0; i < iis.length; i += 1) { + this._ii2construct.remove(iis[i].getReference()); + } + this._id2construct.remove(construct.getId()); + }; + + TopicMap.prototype._removeTopic = function (topic) { + var i, sis = topic.getSubjectIdentifiers(), + slos = topic.getSubjectLocators(); + // remove subject identifiers from TopicMap._si2topic + for (i = 0; i < sis.length; i += 1) { + this._si2topic.remove(sis[i].getReference()); + } + // remove subject locators from TopicMap._sl2topic + for (i = 0; i < slos.length; i += 1) { + this._sl2topic.remove(slos[i].getReference()); + } + this._removeConstruct(topic); + // remove topic from TopicMap.topics + for (i = 0; i < this.topics.length; i += 1) { + if (topic.id === this.topics[i].id) { + this.topics.splice(i, 1); + break; + } + } + }; + + TopicMap.prototype._removeAssociation = function (association) { + var i; + // remove association from TopicMap.associations + for (i = 0; i < this.associations.length; i += 1) { + if (association.id === this.associations[i].id) { + this.associations.splice(i, 1); + break; + } + } + this._removeConstruct(association); + // remove association from TopicMap.associations + for (i = 0; i < this.associations.length; i += 1) { + if (association.id === this.associations[i].id) { + this.associations.splice(i, 1); + break; + } + } + }; + + TopicMap.prototype._removeRole = function (role) { + this._removeConstruct(role); + }; + + TopicMap.prototype._removeOccurrence = function (occ) { + this._removeConstruct(occ); + }; + + TopicMap.prototype._removeName = function (name) { + this._removeConstruct(name); + }; + + TopicMap.prototype._removeVariant = function (variant) { + this._removeConstruct(variant); + }; + + // hashCode, remove + + // -------------------------------------------------------------------------- + + Topic = function (parnt) { + this.subjectIdentifiers = []; + this.subjectLocators = []; + this.itemIdentifiers = []; + this.parnt = parnt; + this.id = parnt._getConstructId(); + this.getTopicMap()._id2construct.put(this.id, this); + this.types = []; + this.rolesPlayed = []; + this.occurrences = []; + this.names = []; + this.reified = null; + }; + + Topic.swiss(Construct, 'addItemIdentifier', 'equals', 'getId', + 'getItemIdentifiers', 'getParent', 'getTopicMap', 'hashCode', 'remove', + 'removeItemIdentifier', 'isTopic', 'isAssociation', 'isRole', + 'isOccurrence', 'isName', 'isVariant', 'isTopicMap'); + + Topic.prototype.isTopic = function () { + return true; + }; + + Topic.prototype.getTopicMap = function () { + return this.parnt; + }; + + /** + * Adds a subject identifier to this topic. + * @throws {ModelConstraintException} If subjectIdentifier is null or + * not defined. + * @returns {Topic} The topic itself (for chaining support) + */ + Topic.prototype.addSubjectIdentifier = function (subjectIdentifier) { + if (!subjectIdentifier) { + throw {name: 'ModelConstraintException', + message: 'addSubjectIdentifier() needs subject identifier'}; + } + // Ignore if the identifier already exists + for (var i = 0; i < this.subjectIdentifiers.length; i += 1) { + if (this.subjectIdentifiers[i].getReference() === + subjectIdentifier.getReference()) { + return; + } + } + this.subjectIdentifiers.push(subjectIdentifier); + this.parnt._si2topic.put(subjectIdentifier.getReference(), this); + return this; + }; + + /** + * Adds a subject locator to this topic. + * @throws {ModelConstraintException} If subjectLocator is null or + * not defined. + * @returns {Topic} The topic itself (for chaining support) + */ + Topic.prototype.addSubjectLocator = function (subjectLocator) { + if (!subjectLocator) { + throw {name: 'ModelConstraintException', + message: 'addSubjectLocator() needs subject locator'}; + } + // Ignore if the identifier already exists + for (var i = 0; i < this.subjectLocators.length; i += 1) { + if (this.subjectLocators[i].getReference() === + subjectLocator.getReference()) { + return; + } + } + this.subjectLocators.push(subjectLocator); + this.parnt._sl2topic.put(subjectLocator.getReference(), this); + return this; + }; + + /** + * Adds a type to this topic. + * @throws {ModelConstraintException} If type is null or not defined. + * @returns {Topic} The topic itself (for chaining support) + */ + Topic.prototype.addType = function (type) { + if (!type) { + throw {name: 'ModelConstraintException', + message: 'addType() needs type'}; + } + SameTopicMapHelper.assertBelongsTo(this.parnt, type); + this.parnt.addTypeEvent.fire(this, {type: type}); + this.types.push(type); + return this; + }; + + // TODO: @type is optional In TMAPI 2.0 + // Creates a Name for this topic with the specified value, and scope. + // Creates a Name for this topic with the specified type, value, and scope. + Topic.prototype.createName = function (value, type, scope) { + var name; + if (type) { + SameTopicMapHelper.assertBelongsTo(this.parnt, type); + } + if (scope) { + SameTopicMapHelper.assertBelongsTo(this.parnt, scope); + } + if (typeof scope === 'undefined') { + scope = null; + } + + name = new Name(this, value, type); + addScope(name, scope); + this.names.push(name); + return name; + }; + + // TODO: @datatype is optional in TMAPI, value may be string or locator. + // Creates an Occurrence for this topic with the specified type, IRI value, and + // scope. + // createOccurrence(Topic type, java.lang.String value, Locator datatype, + // java.util.Collection<Topic> scope) + // Creates an Occurrence for this topic with the specified type, string value, + // and scope. + Topic.prototype.createOccurrence = function (type, value, datatype, scope) { + var occ; + SameTopicMapHelper.assertBelongsTo(this.parnt, type); + SameTopicMapHelper.assertBelongsTo(this.parnt, scope); + + occ = new Occurrence(this, type, value, datatype); + this.parnt.addOccurrenceEvent.fire(occ, {type: type, value: value}); + addScope(occ, scope); + this.occurrences.push(occ); + return occ; + }; + + /** + * Returns the Names of this topic where the name type is type. + *type is optional. + */ + Topic.prototype.getNames = function (type) { + var ret = [], i; + + for (i = 0; i < this.names.length; i += 1) { + if (type && this.names[i].getType().equals(type)) { + ret.push(this.names[i]); + } else if (!type) { + ret.push(this.names[i]); + } + } + return ret; + }; + + /** + * Returns the Occurrences of this topic where the occurrence type is type. type + * is optional. + * @throws {IllegalArgumentException} If type is null. + */ + Topic.prototype.getOccurrences = function (type) { + var ret = [], i; + if (type === null) { + throw {name: 'IllegalArgumentException', + message: 'Topic.getOccurrences cannot be called without type'}; + } + for (i = 0; i < this.occurrences.length; i += 1) { + if (type && this.occurrences[i].getType().equals(type)) { + ret.push(this.occurrences[i]); + } else if (!type) { + ret.push(this.occurrences[i]); + } + } + return ret; + }; + + Topic.prototype._removeOccurrence = function (occ) { + // remove this from TopicMap.topics + for (var i = 0; i < this.occurrences.length; i += 1) { + if (this.occurrences[i].equals(occ)) { + this.occurrences.splice(i, 1); + break; + } + } + this.getTopicMap()._removeOccurrence(occ); + }; + + // Returns the Construct which is reified by this topic. + Topic.prototype.getReified = function (type) { + return this.reified; + }; + + Topic.prototype._setReified = function (reified) { + this.reified = reified; + }; + + /** + * Returns the roles played by this topic. + * Returns the roles played by this topic where the role type is type. + * assocType is optional + * @throws {IllegalArgumentException} If type or assocType is null. + */ + Topic.prototype.getRolesPlayed = function (type, assocType) { + if (type === null) { + throw {name: 'IllegalArgumentException', + message: 'Topic.getRolesPlayed cannot be called without type'}; + } + if (assocType === null) { + throw {name: 'IllegalArgumentException', + message: 'Topic.getRolesPlayed cannot be called with assocType===null'}; + } + var ret = [], i; + for (i = 0; i < this.rolesPlayed.length; i += 1) { + if (!type) { + ret.push(this.rolesPlayed[i]); + } else if (this.rolesPlayed[i].getType().equals(type)) { + if (assocType && + this.rolesPlayed[i].getParent().getType().equals(assocType) || + !assocType) { + ret.push(this.rolesPlayed[i]); + } + } + } + return ret; + }; + + // @private Registers role as a role played + // TODO: Rename to _addRolePlayed + Topic.prototype.addRolePlayed = function (role) { + this.rolesPlayed.push(role); + }; + + // TODO: Rename to _removeRolePlayed + Topic.prototype.removeRolePlayed = function (role) { + for (var i = 0; i < this.rolesPlayed.length; i += 1) { + if (this.rolesPlayed[i].id === role.id) { + this.rolesPlayed.splice(i, 1); + } + } + }; + + /** + * Returns the subject identifiers assigned to this topic. + */ + Topic.prototype.getSubjectIdentifiers = function () { + return this.subjectIdentifiers; + }; + + /** + * Returns the subject locators assigned to this topic. + */ + Topic.prototype.getSubjectLocators = function () { + return this.subjectLocators; + }; + + /** + * Returns the types of which this topic is an instance of. + */ + Topic.prototype.getTypes = function () { + return this.types; + }; + + /** + * Merges another topic into this topic. + * @throws {ModelConstraintException} If the topics reify different + * information items. + * @returns {Topic} The topic itself (for chaining support) + */ + Topic.prototype.mergeIn = function (other) { + var arr, i, tmp, tmp2, signatures, tiidx, sidx; + if (this.equals(other)) { + return true; + } + + SameTopicMapHelper.assertBelongsTo(this.getTopicMap(), other); + if (this.getReified() && other.getReified() && + !this.getReified().equals(other.getReified())) { + throw {name: 'ModelConstraintException', + message: 'The topics reify different Topic Maps constructs and cannot be merged!' + }; + } + + if (!this.getReified() && other.getReified()) { + tmp = other.getReified(); + tmp.setReifier(this); + } + + // Change all constructs that use other as type + tiidx = this.parnt.typeInstanceIndex; + MergeHelper.moveTypes(tiidx.getOccurrences(other), this); + MergeHelper.moveTypes(tiidx.getNames(other), this); + MergeHelper.moveTypes(tiidx.getAssociations(other), this); + MergeHelper.moveTypes(tiidx.getRoles(other), this); + + // Change all topics that have other as type + arr = tiidx.getTopics(other); + for (i = 0; i < arr.length; i += 1) { + arr[i].removeType(other); + arr[i].addType(this); + } + + // Change all constructs that use other as theme + sidx = this.parnt.scopedIndex; + MergeHelper.moveThemes(sidx.getAssociations(other), other, this); + MergeHelper.moveThemes(sidx.getOccurrences(other), other, this); + MergeHelper.moveThemes(sidx.getNames(other), other, this); + MergeHelper.moveThemes(sidx.getVariants(other), other, this); + + MergeHelper.moveItemIdentifiers(other, this); + + arr = other.getSubjectLocators(); + while (arr.length) { + tmp = arr[arr.length - 1]; + other.removeSubjectLocator(tmp); + this.addSubjectLocator(tmp); + } + + arr = other.getSubjectIdentifiers(); + while (arr.length) { + tmp = arr[arr.length - 1]; + other.removeSubjectIdentifier(tmp); + this.addSubjectIdentifier(tmp); + } + + arr = other.getTypes(); + while (arr.length) { + tmp = arr[arr.length - 1]; + other.removeType(tmp); + this.addType(tmp); + } + + // merge roles played + arr = this.getRolesPlayed(); + signatures = {}; + for (i = 0; i < arr.length; i += 1) { + tmp2 = arr[i].getParent(); + signatures[SignatureGenerator.makeAssociationSignature(tmp2)] = tmp2; + } + arr = other.getRolesPlayed(); + for (i = 0; i < arr.length; i += 1) { + tmp = arr[i]; + tmp.setPlayer(this); + if ((tmp2 = signatures[SignatureGenerator.makeAssociationSignature(tmp.getParent())])) { + MergeHelper.moveItemIdentifiers(tmp.getParent(), tmp2); + MergeHelper.moveReifier(tmp.getParent(), tmp2); + tmp.getParent().remove(); + } + } + + // merge names + arr = this.getNames(); + signatures = {}; + for (i = 0; i < arr.length; i += 1) { + signatures[SignatureGenerator.makeNameSignature(arr[i])] = arr[i]; + } + arr = other.getNames(); + for (i = 0; i < arr.length; i += 1) { + tmp = arr[i]; + if ((tmp2 = signatures[SignatureGenerator.makeNameSignature(arr[i])])) { + MergeHelper.moveItemIdentifiers(tmp, tmp2); + MergeHelper.moveReifier(tmp, tmp2); + MergeHelper.moveVariants(tmp, tmp2); + tmp.remove(); + } else { + tmp2 = this.createName(tmp.getValue(), tmp.getType(), tmp.getScope()); + MergeHelper.moveVariants(tmp, tmp2); + } + } + + // merge occurrences + arr = this.getOccurrences(); + signatures = {}; + for (i = 0; i < arr.length; i += 1) { + signatures[SignatureGenerator.makeOccurrenceSignature(arr[i])] = arr[i]; + } + arr = other.getOccurrences(); + for (i = 0; i < arr.length; i += 1) { + tmp = arr[i]; + if ((tmp2 = signatures[SignatureGenerator.makeOccurrenceSignature(arr[i])])) { + MergeHelper.moveItemIdentifiers(tmp, tmp2); + MergeHelper.moveReifier(tmp, tmp2); + tmp.remove(); + } else { + tmp2 = this.createOccurrence(tmp.getType(), tmp.getValue(), + tmp.getDatatype(), tmp.getScope()); + MergeHelper.moveReifier(tmp, tmp2); + } + } + + other.remove(); + return this; + }; + + /** + * Removes this topic from the containing TopicMap instance. + * @throws {TopicInUseException} If the topics is used as reifier, + * occurrence type, name type, association type, role type, topic type, + * association theme, occurrence theme, name theme, variant theme, + * or if it is used as a role player. + */ + Topic.prototype.remove = function () { + var tiidx = this.parnt.typeInstanceIndex, + sidx = this.parnt.scopedIndex; + if (this.getReified() || + tiidx.getOccurrences(this).length || + tiidx.getNames(this).length || + tiidx.getAssociations(this).length || + tiidx.getRoles(this).length || + tiidx.getTopics(this).length || + sidx.getAssociations(this).length || + sidx.getOccurrences(this).length || + sidx.getNames(this).length || + sidx.getVariants(this).length || + this.getRolesPlayed().length) { + throw {name: 'TopicInUseException', + message: '', reporter: this}; + } + this.parnt._removeTopic(this); + this.parnt._id2construct.remove(this.id); + this.parnt.removeTopicEvent.fire(this); + this.id = null; + return this.parnt; + }; + + /** + * Removes a subject identifier from this topic. + * @returns {Topic} The topic itself (for chaining support) + */ + Topic.prototype.removeSubjectIdentifier = function (subjectIdentifier) { + for (var i = 0; i < this.subjectIdentifiers.length; i += 1) { + if (this.subjectIdentifiers[i].getReference() === + subjectIdentifier.getReference()) { + this.subjectIdentifiers.splice(i, 1); + break; + } + } + this.parnt._sl2topic.remove(subjectIdentifier.getReference()); + return this; + }; + + /** + * Removes a subject locator from this topic. + * @returns {Topic} The topic itself (for chaining support) + */ + Topic.prototype.removeSubjectLocator = function (subjectLocator) { + for (var i = 0; i < this.subjectLocators.length; i += 1) { + if (this.subjectLocators[i].getReference() === + subjectLocator.getReference()) { + this.subjectLocators.splice(i, 1); + break; + } + } + this.parnt._sl2topic.remove(subjectLocator.getReference()); + return this; + }; + + /** + * Removes a type from this topic. + * @returns {Topic} The topic itself (for chaining support) + */ + Topic.prototype.removeType = function (type) { + for (var i = 0; i < this.types.length; i += 1) { + if (this.types[i].equals(type)) { + this.types.splice(i, 1); + this.parnt.removeTypeEvent.fire(this, {type: type}); + break; + } + } + }; + + Topic.prototype._removeName = function (name) { + for (var i = 0; i < this.names.length; i += 1) { + if (this.names[i].equals(name)) { + this.names.splice(i, 1); + break; + } + } + this.getTopicMap()._removeName(name); + }; + + // -------------------------------------------------------------------------- + Occurrence = function (parnt, type, value, datatype) { + this.itemIdentifiers = []; + this.parnt = parnt; + this.type = type; + this.value = value; + this.datatype = datatype ? datatype : this.getTopicMap().createLocator(XSD.string); + this.scope = []; + this.reifier = null; + this.id = this.getTopicMap()._getConstructId(); + this.getTopicMap()._id2construct.put(this.id, this); + }; + + // mergein Typed, DatatypeAware, Reifiable, Scoped, Construct + Occurrence.swiss(Typed, 'getType', 'setType'); + Occurrence.swiss(DatatypeAware, 'decimalValue', 'floatValue', + 'getDatatype', 'getValue', 'integerValue', 'locatorValue', 'longValue', + 'setValue'); + Occurrence.swiss(Reifiable, 'getReifier', 'setReifier'); + Occurrence.swiss(Scoped, 'addTheme', 'getScope', 'removeTheme'); + Occurrence.swiss(Construct, 'addItemIdentifier', 'equals', 'getId', + 'getItemIdentifiers', 'getParent', 'getTopicMap', 'hashCode', 'remove', + 'removeItemIdentifier', 'isTopic', 'isAssociation', 'isRole', + 'isOccurrence', 'isName', 'isVariant', 'isTopicMap'); + + Occurrence.prototype.isOccurrence = function () { + return true; + }; + + Occurrence.prototype.getTopicMap = function () { + return this.parnt.getParent(); + }; + + Occurrence.prototype.remove = function () { + var i; + for (i = 0; i < this.scope.length; i += 1) { + this.parnt.parnt.removeThemeEvent.fire(this, {theme: this.scope[i]}); + } + this.parnt.parnt.removeOccurrenceEvent.fire(this); + this.parnt._removeOccurrence(this); + this.id = null; + return this.parnt; + }; + + Name = function (parnt, value, type) { + this.itemIdentifiers = []; + this.parnt = parnt; + this.value = value; + this.scope = []; + this.id = this.getTopicMap()._getConstructId(); + this.type = type || + parnt.parnt.createTopicBySubjectIdentifier( + parnt.parnt.createLocator('http://psi.topicmaps.org/iso13250/model/topic-name')); + this.reifier = null; + this.variants = []; + this.getTopicMap()._id2construct.put(this.id, this); + this.parnt.parnt.addNameEvent.fire(this, {type: this.type, value: value}); + }; + + // mergein Typed, DatatypeAware, Reifiable, Scoped, Construct + Name.swiss(Typed, 'getType', 'setType'); + Name.swiss(Reifiable, 'getReifier', 'setReifier'); + Name.swiss(Scoped, 'addTheme', 'getScope', 'removeTheme'); + Name.swiss(Construct, 'addItemIdentifier', 'equals', 'getId', + 'getItemIdentifiers', 'getParent', 'getTopicMap', 'hashCode', 'remove', + 'removeItemIdentifier', 'isTopic', 'isAssociation', 'isRole', + 'isOccurrence', 'isName', 'isVariant', 'isTopicMap'); + + Name.prototype.isName = function () { + return true; + }; + + Name.prototype.getTopicMap = function () { + return this.parnt.parnt; + }; + + /** + * @throws {ModelConstraintException} If scope is null. + */ + Name.prototype.createVariant = function (value, datatype, scope) { + var scope_length = 0, i, variant; + if (typeof scope === 'undefined' || scope === null) { + throw {name: 'ModelConstraintException', + message: 'Creation of a variant with a null scope is not allowed'}; + } + if (scope && typeof scope === 'object') { + if (scope instanceof Array) { + scope_length = scope.length; + } else if (scope instanceof Topic) { + scope_length = 1; + } + } + /* + TODO: Compare scope of Name and Variant + if (scope_length <= this.getScope().length) { + // check if the variants scope contains more scoping topics + throw {name: 'ModelConstraintException', + message: 'The variant would be in the same scope as the parent'}; + }*/ + variant = new Variant(this, value, datatype); + addScope(variant, scope); + for (i = 0; i < this.scope.length; i += 1) { + this.getTopicMap().addThemeEvent.fire(variant, + {theme: this.scope[i]}); + } + this.variants.push(variant); + return variant; + }; + + /** + * @throws {ModelConstraintException} If value is null. + * @returns {Name} The name itself (for chaining support) + */ + Name.prototype.setValue = function (value) { + if (!value) { + throw {name: 'ModelConstraintException', + message: 'Name.setValue(null) is not allowed'}; + } + this.value = value; + return this; + }; + + Name.prototype.getValue = function (value) { + return this.value; + }; + + Name.prototype.remove = function () { + var i; + for (i = 0; i < this.scope.length; i += 1) { + this.parnt.parnt.removeThemeEvent.fire(this, {theme: this.scope[i]}); + } + this.parnt.parnt.removeNameEvent.fire(this); + this.parnt._removeName(this); + this.id = null; + return this.parnt; + }; + + Name.prototype._removeVariant = function (variant) { + for (var i = 0; i < this.variants.length; i += 1) { + if (this.variants[i].equals(variant)) { + this.variants.splice(i, 1); + break; + } + } + this.getTopicMap()._removeVariant(variant); + }; + + Name.prototype.getVariants = function () { + return this.variants; + }; + + /** + * @throws {ModelConstraintException} If value or datatype is null. + */ + Variant = function (parnt, value, datatype) { + if (value === null) { + throw {name: 'ModelConstraintException', + message: 'Creation of a variant with null value is not allowed'}; + } + if (datatype === null) { + throw {name: 'ModelConstraintException', + message: 'Creation of a variant with datatype == null is not allowed'}; + } + this.itemIdentifiers = []; + this.scope = []; + this.parnt = parnt; + if (typeof value === 'object' && value instanceof Locator) { + this.datatype = this.getTopicMap().createLocator('http://www.w3.org/2001/XMLSchema#anyURI'); + } else { + this.datatype = + this.getTopicMap().createLocator(XSD.string); + } + this.datatype = datatype; + this.reifier = null; + this.value = value; + this.id = this.getTopicMap()._getConstructId(); + this.getTopicMap()._id2construct.put(this.id, this); + }; + + Variant.swiss(Reifiable, 'getReifier', 'setReifier'); + Variant.swiss(Scoped, 'addTheme', 'getScope', 'removeTheme'); + Variant.swiss(Construct, 'addItemIdentifier', 'equals', 'getId', + 'getItemIdentifiers', 'getParent', 'getTopicMap', 'hashCode', 'remove', + 'removeItemIdentifier', 'isTopic', 'isAssociation', 'isRole', + 'isOccurrence', 'isName', 'isVariant', 'isTopicMap'); + Variant.swiss(DatatypeAware, 'decimalValue', 'floatValue', 'getDatatype', + 'getValue', 'integerValue', 'locatorValue', 'longValue', 'setValue'); + + Variant.prototype.isVariant = function () { + return true; + }; + + Variant.prototype.getTopicMap = function () { + return this.getParent().getParent().getParent(); + }; + + Variant.prototype.remove = function () { + var i; + for (i = 0; i < this.scope.length; i += 1) { + this.getTopicMap().removeThemeEvent.fire(this, {theme: this.scope[i]}); + } + this.getParent()._removeVariant(this); + this.id = null; + return this.parnt; + }; + + + Role = function (parnt, type, player) { + this.itemIdentifiers = []; + this.parnt = parnt; + this.type = type; + this.player = player; + this.id = this.getTopicMap()._getConstructId(); + this.reifier = null; + this.getTopicMap()._id2construct.put(this.id, this); + }; + + Role.swiss(Typed, 'getType', 'setType'); + Role.swiss(Reifiable, 'getReifier', 'setReifier'); + Role.swiss(Construct, 'addItemIdentifier', 'equals', 'getId', + 'getItemIdentifiers', 'getParent', 'getTopicMap', 'hashCode', 'remove', + 'removeItemIdentifier', 'isTopic', 'isAssociation', 'isRole', + 'isOccurrence', 'isName', 'isVariant', 'isTopicMap'); + + Role.prototype.isRole = function () { + return true; + }; + + Role.prototype.getTopicMap = function () { + return this.getParent().getParent(); + }; + + Role.prototype.remove = function () { + var parnt = this.parnt; + this.parnt.parnt.removeRoleEvent.fire(this); + this.parnt._removeRole(this); + this.itemIdentifiers = null; + this.parnt = null; + this.type = null; + this.player = null; + this.reifier = null; + this.id = null; + return parnt; + }; + + Role.prototype.getPlayer = function () { + return this.player; + }; + + /** + * @throws {ModelConstraintException} If player is null. + * @returns {Role} The role itself (for chaining support) + */ + Role.prototype.setPlayer = function (player) { + if (!player) { + throw {name: 'ModelConstraintException', + message: 'player i Role.setPlayer cannot be null'}; + } + SameTopicMapHelper.assertBelongsTo(this.parnt.parnt, player); + if (this.player.equals(player)) { + return; + } + this.player.removeRolePlayed(this); + player.addRolePlayed(this); + this.player = player; + return this; + }; + + Association = function (par) { + this.itemIdentifiers = []; + this.parnt = par; + this.id = this.getTopicMap()._getConstructId(); + this.getTopicMap()._id2construct.put(this.id, this); + this.roles = []; + this.scope = []; + this.type = null; + this.reifier = null; + }; + + Association.swiss(Typed, 'getType', 'setType'); + Association.swiss(Reifiable, 'getReifier', 'setReifier'); + Association.swiss(Scoped, 'addTheme', 'getScope', 'removeTheme'); + Association.swiss(Construct, 'addItemIdentifier', 'equals', 'getId', + 'getItemIdentifiers', 'getParent', 'getTopicMap', 'hashCode', 'remove', + 'removeItemIdentifier', 'isTopic', 'isAssociation', 'isRole', + 'isOccurrence', 'isName', 'isVariant', 'isTopicMap'); + + Association.prototype.isAssociation = function () { + return true; + }; + + Association.prototype.getTopicMap = function () { + return this.parnt; + }; + + /** + * Creates a new Role representing a role in this association. + * @throws {ModelConstraintException} If type or player is null. + */ + Association.prototype.createRole = function (type, player) { + if (!type) { + throw {name: 'ModelConstraintException', + message: 'type i Role.createPlayer cannot be null'}; + } + if (!player) { + throw {name: 'ModelConstraintException', + message: 'player i Role.createRole cannot be null'}; + } + SameTopicMapHelper.assertBelongsTo(this.parnt, type); + SameTopicMapHelper.assertBelongsTo(this.parnt, player); + var role = new Role(this, type, player); + player.addRolePlayed(role); + this.roles.push(role); + this.parnt.addRoleEvent.fire(role, {type: type, player: player}); + return role; + }; + + Association.prototype._removeRole = function (role) { + for (var i = 0; i < this.roles.length; i += 1) { + if (role.id === this.roles[i].id) { + this.roles.splice(i, 1); + break; + } + } + role.getPlayer().removeRolePlayed(role); + this.getTopicMap()._removeRole(role); + }; + + Association.prototype.remove = function () { + var i; + for (i = 0; i < this.scope.length; i += 1) { + this.parnt.removeThemeEvent.fire(this, {theme: this.scope[i]}); + } + this.parnt.removeAssociationEvent.fire(this); + while (this.roles.length) { + this.roles[0].remove(); + } + this.id = null; + this.roles = null; + this.parnt._removeAssociation(this); + this.getTopicMap()._ii2construct.remove(this.id); + this.item_identifiers = null; + this.scope = null; + this.type = null; + this.reifier = null; + return this.parnt; + }; + + /** + * Returns the roles participating in this association, or, if type + * is given, all roles with the specified type. + * @throws {IllegalArgumentException} If type is null. + */ + Association.prototype.getRoles = function (type) { + if (type === null) { + throw {name: 'IllegalArgumentException', + message: 'Topic.getRoles cannot be called with type null'}; + } + if (!type) { + return this.roles; + } + var ret = [], i; + for (i = 0; i < this.roles.length; i += 1) { + if (this.roles[i].getType().equals(type)) { + ret.push(this.roles[i]); + } + } + return ret; + }; + + /** + * Returns the role types participating in this association. + */ + Association.prototype.getRoleTypes = function () { + // Create a hash with the object ids as keys to avoid duplicates + var types = {}, typearr = [], i, t; + for (i = 0; i < this.roles.length; i += 1) { + types[this.roles[i].getType().getId()] = + this.roles[i].getType(); + } + for (t in types) { + if (types.hasOwnProperty(t)) { + typearr.push(types[t]); + } + } + return typearr; + }; + + // ------ ---------------------------------------------------------------- + /** @class */ + Index = function () { + this.opened = false; + }; + + /** + * Close the index. + */ + Index.prototype.close = function () { + return; + }; + + /** + * Indicates whether the index is updated automatically. + * @returns {boolean} + */ + Index.prototype.isAutoUpdated = function () { + return true; + }; + + /** Indicates if the index is open. + * @returns {boolean} true if index is already opened, false otherwise. + */ + Index.prototype.isOpen = function () { + return this.opened; + }; + + /** + * Opens the index. This method must be invoked before using any other + * method (aside from isOpen()) exported by this interface or derived + * interfaces. + */ + Index.prototype.open = function () { + this.opened = true; + }; + + /** + * Synchronizes the index with data in the topic map. + */ + Index.prototype.reindex = function () { + return; + }; + + /** + * Creates a new instance of TypeInstanceIndex. + * @class Implementation of the TypeInstanceIndex interface. + */ + TypeInstanceIndex = function (tm) { + var eventHandler, that = this; + this.tm = tm; + // we use hash tables of hash tables for our index + this.type2topics = new Hash(); + this.type2associations = new Hash(); + this.type2roles = new Hash(); + this.type2occurrences = new Hash(); + this.type2names = new Hash(); + this.type2variants = new Hash(); + this.opened = false; + + eventHandler = function (eventtype, source, obj) { + var existing, untyped, types, type, i; + switch (eventtype) { + case EventType.ADD_ASSOCIATION: + break; + case EventType.ADD_NAME: + existing = that.type2names.get(obj.type.getId()); + if (typeof existing === 'undefined') { + existing = new Hash(); + } + existing.put(source.getId(), source); + that.type2names.put(obj.type.getId(), existing); + break; + case EventType.ADD_OCCURRENCE: + existing = that.type2occurrences.get(obj.type.getId()); + if (typeof existing === 'undefined') { + existing = new Hash(); + } + existing.put(source.getId(), source); + that.type2occurrences.put(obj.type.getId(), existing); + break; + case EventType.ADD_ROLE: + existing = that.type2roles.get(obj.type.getId()); + if (typeof existing === 'undefined') { + existing = new Hash(); + } + existing.put(source.getId(), source); + that.type2roles.put(obj.type.getId(), existing); + break; + case EventType.ADD_TOPIC: + existing = that.type2topics.get('null'); + if (typeof existing === 'undefined') { + existing = new Hash(); + } + existing.put(source.getId(), source); + that.type2topics.put('null', existing); + break; + case EventType.ADD_TYPE: + // check if source exists with type null, remove it there + untyped = that.type2topics.get('null'); + if (untyped && untyped.get(source.getId())) { + untyped.remove(source.getId()); + that.type2topics.put('null', untyped); + } + + existing = that.type2topics.get(obj.type.getId()); + if (typeof existing === 'undefined') { + existing = new Hash(); + } + existing.put(source.getId(), source); + that.type2topics.put(obj.type.getId(), existing); + break; + case EventType.REMOVE_ASSOCIATION: + type = source.getType(); + if (!type) { + break; + } + existing = that.type2associations.get(type.getId()); + for (i = 0; i < existing.length; i += 1) { + if (existing[i].equals(source)) { + existing.splice(i, 1); + break; + } + } + if (existing.length > 0) { + that.type2associations.put(type.getId(), + existing); + } else { + that.type2associations.remove(type.getId()); + } + break; + case EventType.REMOVE_NAME: + type = source.getType(); + existing = that.type2names.get(type.getId()); + existing.remove(source.getId()); + if (existing.length > 0) { + that.type2names.put(type.getId(), existing); + } else { + that.type2names.remove(type.getId()); + } + break; + case EventType.REMOVE_OCCURRENCE: + type = source.getType(); + existing = that.type2occurrences.get(type.getId()); + existing.remove(source.getId()); + if (existing.length > 0) { + that.type2occurrences.put(type.getId(), existing); + } else { + that.type2occurrences.remove(type.getId()); + } + break; + case EventType.REMOVE_ROLE: + type = source.getType(); + existing = that.type2roles.get(type.getId()); + existing.remove(source.getId()); + if (existing.length > 0) { + that.type2roles.put(type.getId(), existing); + } else { + that.type2roles.remove(type.getId()); + } + break; + case EventType.REMOVE_TOPIC: + // two cases: + // topic has types + types = source.getTypes(); + for (i = 0; i < types.length; i += 1) { + existing = that.type2topics.get(types[i].getId()); + existing.remove(source.getId()); + if (!existing.size()) { + that.type2topics.remove(types[i].getId()); + } + } + // topic used as type + that.type2topics.remove(source.getId()); + that.type2associations.remove(source.getId()); + that.type2roles.remove(source.getId()); + that.type2occurrences.remove(source.getId()); + that.type2variants.remove(source.getId()); + break; + case EventType.REMOVE_TYPE: + existing = that.type2topics.get(obj.type.getId()); + existing.remove(source.getId()); + if (!existing.size()) { + that.type2topics.remove(obj.type.getId()); + } + if (source.getTypes().length === 0) { + untyped = that.type2topics.get('null'); + if (typeof untyped === 'undefined') { + untyped = new Hash(); + } + untyped.put(source.getId(), source); + } + break; + case EventType.SET_TYPE: + if (source.isAssociation()) { + // remove source from type2associations(obj.old.getId()); + if (obj.old) { + existing = that.type2associations.get(obj.old.getId()); + for (i = 0; i < existing.length; i += 1) { + if (existing[i].equals(source)) { + existing.splice(i, 1); + break; + } + } + if (existing.length > 0) { + that.type2associations.put(obj.old.getId(), + existing); + } else { + that.type2associations.remove(obj.old.getId()); + } + } + existing = that.type2associations.get(obj.type.getId()); + if (typeof existing === 'undefined') { + existing = []; + } + existing.push(source); + that.type2associations.put(obj.type.getId(), existing); + } else if (source.isName()) { + existing = that.type2names.get(obj.old.getId()); + if (existing) { + existing.remove(source.getId()); + if (existing.length > 0) { + that.type2names.put(obj.old.getId(), existing); + } else { + that.type2names.remove(obj.old.getId()); + } + } + existing = that.type2names.get(obj.type.getId()); + if (typeof existing === 'undefined') { + existing = new Hash(); + } + existing.put(source.getId(), source); + that.type2names.put(obj.type.getId(), existing); + } else if (source.isOccurrence()) { + existing = that.type2occurrences.get(obj.old.getId()); + if (existing) { + existing.remove(source.getId()); + if (existing.length > 0) { + that.type2occurrences.put(obj.old.getId(), existing); + } else { + that.type2occurrences.remove(obj.old.getId()); + } + } + existing = that.type2occurrences.get(obj.type.getId()); + if (typeof existing === 'undefined') { + existing = new Hash(); + } + existing.put(source.getId(), source); + that.type2occurrences.put(obj.type.getId(), existing); + } else if (source.isRole()) { + existing = that.type2roles.get(obj.old.getId()); + if (existing) { + existing.remove(source.getId()); + if (existing.length > 0) { + that.type2roles.put(obj.old.getId(), existing); + } else { + that.type2roles.remove(obj.old.getId()); + } + } + existing = that.type2roles.get(obj.type.getId()); + if (typeof existing === 'undefined') { + existing = new Hash(); + } + existing.put(source.getId(), source); + that.type2roles.put(obj.type.getId(), existing); + } + break; + } + }; + tm.addAssociationEvent.registerHandler(eventHandler); + tm.addNameEvent.registerHandler(eventHandler); + tm.addOccurrenceEvent.registerHandler(eventHandler); + tm.addRoleEvent.registerHandler(eventHandler); + tm.addTopicEvent.registerHandler(eventHandler); + tm.addTypeEvent.registerHandler(eventHandler); + tm.removeAssociationEvent.registerHandler(eventHandler); + tm.removeNameEvent.registerHandler(eventHandler); + tm.removeOccurrenceEvent.registerHandler(eventHandler); + tm.removeRoleEvent.registerHandler(eventHandler); + tm.removeTopicEvent.registerHandler(eventHandler); + tm.removeTypeEvent.registerHandler(eventHandler); + tm.setTypeEvent.registerHandler(eventHandler); + }; + + TypeInstanceIndex.swiss(Index, 'close', 'isAutoUpdated', + 'isOpen', 'open', 'reindex'); + + /** + * Returns the associations in the topic map whose type property equals type. + * + * @param {Topic} type + * @returns {Array} A list of all associations in the topic map with the given type. + */ + TypeInstanceIndex.prototype.getAssociations = function (type) { + var ret = this.type2associations.get(type.getId()); + if (!ret) { + return []; + } + return ret; + }; + + /** + * Returns the topics in the topic map used in the type property of Associations. + * + * @returns {Array} A list of all topics that are used as an association type. + */ + TypeInstanceIndex.prototype.getAssociationTypes = function () { + var ret = [], keys = this.type2associations.keys(), i; + for (i = 0; i < keys.length; i += 1) { + ret.push(this.tm.getConstructById(keys[i])); + } + return ret; + }; + + /** + * Returns the topic names in the topic map whose type property equals type. + * + * @param {Topic} type + * @returns {Array} + */ + TypeInstanceIndex.prototype.getNames = function (type) { + var ret = this.type2names.get(type.getId()); + if (!ret) { + return []; + } + return ret.values(); + }; + + /** + * Returns the topics in the topic map used in the type property of Names. + * + * @returns {Array} An array of topic types. Note that the array contains + * a reference to the actual topics, not copies of them. + */ + TypeInstanceIndex.prototype.getNameTypes = function () { + var ret = [], keys = this.type2names.keys(), i; + for (i = 0; i < keys.length; i += 1) { + ret.push(this.tm.getConstructById(keys[i])); + } + return ret; + }; + + /** + * Returns the occurrences in the topic map whose type property equals type. + * + * @returns {Array} + */ + TypeInstanceIndex.prototype.getOccurrences = function (type) { + var ret = this.type2occurrences.get(type.getId()); + if (!ret) { + return []; + } + return ret.values(); + }; + + /** + * Returns the topics in the topic map used in the type property of + * Occurrences. + * + * @returns {Array} An array of topic types. Note that the array contains + * a reference to the actual topics, not copies of them. + */ + TypeInstanceIndex.prototype.getOccurrenceTypes = function () { + var ret = [], keys = this.type2occurrences.keys(), i; + for (i = 0; i < keys.length; i += 1) { + ret.push(this.tm.getConstructById(keys[i])); + } + return ret; + }; + + + /** + * Returns the roles in the topic map whose type property equals type. + * + * @returns {Array} + */ + TypeInstanceIndex.prototype.getRoles = function (type) { + var ret = this.type2roles.get(type.getId()); + if (!ret) { + return []; + } + return ret.values(); + }; + + /** + * Returns the topics in the topic map used in the type property of Roles. + * + * @returns {Array} An array of topic types. Note that the array contains + * a reference to the actual topics, not copies of them. + */ + TypeInstanceIndex.prototype.getRoleTypes = function () { + var ret = [], keys = this.type2roles.keys(), i; + for (i = 0; i < keys.length; i += 1) { + ret.push(this.tm.getConstructById(keys[i])); + } + return ret; + }; + + /** + * Returns the topics which are an instance of the specified type. + */ + TypeInstanceIndex.prototype.getTopics = function (type) { + var ret = this.type2topics.get((type ? type.getId() : 'null')); + if (!ret) { + return []; + } + return ret.values(); + }; + + /** + * Returns the topics which are an instance of the specified types. + * If matchall is true only topics that have all of the listed types + * are returned. + * @returns {Array} A list of Topic objects + */ + TypeInstanceIndex.prototype.getTopicsByTypes = function (types, matchall) { + var instances, i, j; + instances = IndexHelper.getForKeys(this.type2topics, types); + if (!matchall) { + return instances; + } + // If matchall is true, we check all values for all types in {types} + // It's a hack, but will do for now + for (i = 0; i < instances.length; i += 1) { + for (j = 0; j < types.length; j += 1) { + if (!ArrayHelper.contains(instances[i].getTypes(), types[j])) { + instances.splice(i, 1); + i -= 1; + break; + } + } + } + return instances; + }; + + /** + * Returns the topics in topic map which are used as type in an + * "type-instance"-relationship. + */ + TypeInstanceIndex.prototype.getTopicTypes = function () { + var ret = [], keys = this.type2topics.keys(), i; + for (i = 0; i < keys.length; i += 1) { + if (keys[i] !== 'null') { + ret.push(this.tm.getConstructById(keys[i])); + } + } + return ret; + }; + + TypeInstanceIndex.prototype.close = function () { + return; + }; + + + /** + * Index for Scoped statements and their scope. This index provides access + * to Associations, Occurrences, Names, and Variants by their scope + * property and to Topics which are used as theme in a scope. + */ + ScopedIndex = function (tm) { + var that = this, eventHandler; + this.tm = tm; + this.theme2associations = new Hash(); + this.theme2names = new Hash(); + this.theme2occurrences = new Hash(); + this.theme2variants = new Hash(); + eventHandler = function (eventtype, source, obj) { + var existing, key, unscoped, remove_from_index, add_to_index; + add_to_index = function (hash, source, obj) { + key = (obj.theme ? obj.theme.getId() : 'null'); + + // check if source exists with theme null, remove it there + // this is the case iff source now has one scoping topic + if (source.getScope().length === 1) { + unscoped = hash.get('null'); + if (unscoped && unscoped.get(source.getId())) { + unscoped.remove(source.getId()); + hash.put('null', unscoped); + } + } + existing = hash.get(key); + if (typeof existing === 'undefined') { + existing = new Hash(); + } + existing.put(source.getId(), source); + hash.put(key, existing); + }; + remove_from_index = function (hash, source, obj) { + key = obj.theme.getId(); + existing = hash.get(key); + if (typeof existing !== 'undefined') { + existing.remove(source.getId()); + if (!existing.size()) { + hash.remove(key); + } + } + }; + switch (eventtype) { + case EventType.ADD_THEME: + if (source.isAssociation()) { + add_to_index(that.theme2associations, source, obj); + } else if (source.isName()) { + add_to_index(that.theme2names, source, obj); + } else if (source.isOccurrence()) { + add_to_index(that.theme2occurrences, source, obj); + } else if (source.isVariant()) { + add_to_index(that.theme2variants, source, obj); + } + break; + case EventType.REMOVE_THEME: + if (source.isAssociation()) { + remove_from_index(that.theme2associations, source, obj); + } else if (source.isName()) { + remove_from_index(that.theme2names, source, obj); + } else if (source.isOccurrence()) { + remove_from_index(that.theme2occurrences, source, obj); + } else if (source.isVariant()) { + remove_from_index(that.theme2variants, source, obj); + } + break; + } + }; + tm.addThemeEvent.registerHandler(eventHandler); + tm.removeThemeEvent.registerHandler(eventHandler); + }; + + ScopedIndex.swiss(Index, 'close', 'isAutoUpdated', + 'isOpen', 'open', 'reindex'); + + ScopedIndex.prototype.close = function () { + return; + }; + + /** + * Returns the Associations in the topic map whose scope property contains + * the specified theme. The return value may be empty but must never be null. + * @param theme can be array or {Topic} + * @param [matchall] boolean + */ + ScopedIndex.prototype.getAssociations = function (theme) { + var ret = this.theme2associations.get((theme ? theme.getId() : 'null')); + if (!ret) { + return []; + } + return ret.values(); + }; + + /** + * Returns the Associations in the topic map whose scope property contains + * the specified theme. The return value may be empty but must never be null. + * @param theme can be array or {Topic} + * @param [matchall] boolean + * @throws {IllegalArgumentException} If themes is null. + */ + ScopedIndex.prototype.getAssociationsByThemes = function (themes, matchall) { + if (themes === null) { + throw {name: 'IllegalArgumentException', + message: 'ScopedIndex.getAssociationsByThemes cannot be called without themes'}; + } + return IndexHelper.getConstructsByThemes(this.theme2associations, + themes, matchall); + }; + + /** + * Returns the topics in the topic map used in the scope property of + * Associations. + */ + ScopedIndex.prototype.getAssociationThemes = function () { + return IndexHelper.getConstructThemes(this.tm, this.theme2associations); + }; + + /** + * Returns the Names in the topic map whose scope property contains the + * specified theme. + */ + ScopedIndex.prototype.getNames = function (theme) { + var ret = this.theme2names.get((theme ? theme.getId() : 'null')); + if (!ret) { + return []; + } + return ret.values(); + }; + + /** + * Returns the Names in the topic map whose scope property equals one of + * those themes at least. + * @throws {IllegalArgumentException} If themes is null. + */ + ScopedIndex.prototype.getNamesByThemes = function (themes, matchall) { + if (themes === null) { + throw {name: 'IllegalArgumentException', + message: 'ScopedIndex.getNamesByThemes cannot be called without themes'}; + } + return IndexHelper.getConstructsByThemes(this.theme2names, + themes, matchall); + }; + + /** + * Returns the topics in the topic map used in the scope property of Names. + */ + ScopedIndex.prototype.getNameThemes = function () { + return IndexHelper.getConstructThemes(this.tm, this.theme2names); + }; + + /** + * Returns the Occurrences in the topic map whose scope property contains the + * specified theme. + */ + ScopedIndex.prototype.getOccurrences = function (theme) { + var ret = this.theme2occurrences.get((theme ? theme.getId() : 'null')); + if (!ret) { + return []; + } + return ret.values(); + }; + + /** + * Returns the Occurrences in the topic map whose scope property equals one + * of those themes at least. + * @throws {IllegalArgumentException} If themes is null. + */ + ScopedIndex.prototype.getOccurrencesByThemes = function (themes, matchall) { + if (themes === null) { + throw {name: 'IllegalArgumentException', + message: 'ScopedIndex.getOccurrencesByThemes cannot be called without themes'}; + } + return IndexHelper.getConstructsByThemes(this.theme2occurrences, + themes, matchall); + }; + + /** + * Returns the topics in the topic map used in the scope property of + * Occurrences. + */ + ScopedIndex.prototype.getOccurrenceThemes = function () { + return IndexHelper.getConstructThemes(this.tm, this.theme2occurrences); + }; + + /** + * Returns the Variants in the topic map whose scope property contains the + * specified theme. The return value may be empty but must never be null. + * @param {Topic} The Topic which must be part of the scope. This must not be + * null. + * @returns {Array} An array of Variants. + * @throws {IllegalArgumentException} If theme is null. + */ + ScopedIndex.prototype.getVariants = function (theme) { + if (theme === null) { + throw {name: 'IllegalArgumentException', + message: 'ScopedIndex.getVariants cannot be called without themes'}; + } + var ret = this.theme2variants.get((theme ? theme.getId() : 'null')); + if (!ret) { + return []; + } + return ret.values(); + }; + + /** + * Returns the Variants in the topic map whose scope property equals one of + * those themes at least. + * @param {Array} themes Scope of the Variants to be returned. + * @param {boolean} If true the scope property of a variant must match all + * themes, if false one theme must be matched at least. + * @returns {Array} An array of variants + * @throws {IllegalArgumentException} If themes is null. + */ + ScopedIndex.prototype.getVariantsByThemes = function (themes, matchall) { + if (themes === null) { + throw {name: 'IllegalArgumentException', + message: 'ScopedIndex.getVariantsByThemes cannot be called without themes'}; + } + return IndexHelper.getConstructsByThemes(this.theme2variants, + themes, matchall); + }; + + /** + * Returns the topics in the topic map used in the scope property of Variants. + * The return value may be empty but must never be null. + * @returns {Array} An array of Topics. + */ + ScopedIndex.prototype.getVariantThemes = function () { + return IndexHelper.getConstructThemes(this.tm, this.theme2variants); + }; + + + + + /** + * @class Helper class that is used to check if constructs belong to + * a given topic map. + */ + SameTopicMapHelper = { + /** + * Checks if topic belongs to the topicmap 'topicmap'. + * topic can be instance of Topic or an Array with topics. + * topic map be null. + * @static + * @throws ModelConstraintException if the topic(s) don't + * belong to the same topic map. + * @returns false if the topic was null or true otherwise. + */ + assertBelongsTo: function (topicmap, topic) { + var i; + if (!topic) { + return false; + } + if (topic && topic instanceof Topic && + !topicmap.equals(topic.getTopicMap())) { + throw {name: 'ModelConstraintException', + message: 'scope topic belongs to different topic map'}; + } + if (topic && topic instanceof Array) { + for (i = 0; i < topic.length; i += 1) { + if (!topicmap.equals(topic[i].getTopicMap())) { + throw {name: 'ModelConstraintException', + message: 'scope topic belong to different topic maps'}; + } + } + } + return true; + } + }; + + /** + * Helper functions for hashes of hashes + * @ignore + */ + IndexHelper = { + getForKeys: function (hash, keys) { + var i, j, tmp = new Hash(), value_hash, value_keys; + for (i = 0; i < keys.length; i += 1) { + value_hash = hash.get(keys[i].getId()); + if (value_hash) { + value_keys = value_hash.keys(); + // we use a hash to store instances to avoid duplicates + for (j = 0; j < value_keys.length; j += 1) { + tmp.put(value_hash.get(value_keys[j]).getId(), + value_hash.get(value_keys[j])); + } + } + } + return tmp.values(); + }, + + getConstructThemes: function (tm, hash) { + var ret = [], keys = hash.keys(), i; + for (i = 0; i < keys.length; i += 1) { + if (keys[i] !== 'null') { + ret.push(tm.getConstructById(keys[i])); + } + } + return ret; + }, + + getConstructsByThemes: function (hash, themes, matchall) { + var constructs, i, j; + constructs = IndexHelper.getForKeys(hash, themes); + if (!matchall) { + return constructs; + } + // If matchall is true, we check all values for all types in {types} + // It's a hack, but will do for now + for (i = 0; i < constructs.length; i += 1) { + for (j = 0; j < themes.length; j += 1) { + if (!ArrayHelper.contains(constructs[i].getScope(), themes[j])) { + constructs.splice(i, 1); + i -= 1; + break; + } + } + } + return constructs; + } + }; + + /** + * Helper functions for arrays. We don't modify the global array + * object to avoid conflicts with other libraries. + * @ignore + */ + ArrayHelper = { + /** Checks if arr contains elem */ + contains: function (arr, elem) { + for (var key in arr) { + if (arr.hasOwnProperty(key)) { + if (arr[key].equals(elem)) { + return true; + } + } + } + return false; + } + }; + + /** + * Internal function to add scope. scope may be Array, Topic or null. + * @ignore + * FIXME: Move to a class + */ + addScope = function (construct, scope) { + var i; + if (scope && typeof scope === 'object') { + if (scope instanceof Array) { + for (i = 0; i < scope.length; i += 1) { + construct.addTheme(scope[i]); + } + } else if (scope instanceof Topic) { + construct.addTheme(scope); + } + } else { + construct.getTopicMap().addThemeEvent.fire(construct, {theme: null}); + } + }; + + /** + * Helper class for generating signatures of Topic Maps constructs. + */ + SignatureGenerator = { + makeNameValueSignature: function (name) { + return name.getValue(); + }, + + makeNameSignature: function (name) { + return SignatureGenerator.makeNameValueSignature(name) + + '#' + SignatureGenerator.makeTypeSignature(name) + + '#' + SignatureGenerator.makeScopeSignature(name); + }, + + makeOccurrenceSignature: function (occ) { + return SignatureGenerator.makeOccurrenceValueSignature(occ) + + '#' + SignatureGenerator.makeTypeSignature(occ) + + '#' + SignatureGenerator.makeScopeSignature(occ); + }, + + makeOccurrenceValueSignature: function (occ) { + return '#' + occ.getValue() + '#' + + (occ.getDatatype() ? occ.getDatatype().getReference() : 'null'); + }, + + makeTypeSignature: function (obj) { + var type = obj.getType(); + if (type) { + return type.getId(); + } else { + return ''; + } + }, + + makeScopeSignature: function (scope) { + var i, arr = []; + for (i = 0; i < scope.length; i += 1) { + arr.push(scope[i].getId()); + } + arr.sort(); + return arr.join('#'); + }, + + makeAssociationSignature: function (ass) { + var roles, i, tmp = []; + roles = ass.getRoles(); + for (i = 0; i < roles.length; i += 1) { + tmp.push(SignatureGenerator.makeRoleSignature(roles[i])); + } + tmp.sort(); + + return '#' + SignatureGenerator.makeTypeSignature(ass) + '#' + tmp.join('#') + + SignatureGenerator.makeScopeSignature(ass); + }, + + makeRoleSignature: function (role) { + return SignatureGenerator.makeTypeSignature(role) + '#' + + role.getPlayer().getId(); + }, + + makeVariantValueSignature: function (variant) { + return '#' + variant.getValue() + '#' + variant.getDatatype().getReference(); + }, + + makeVariantSignature: function (variant) { + return SignatureGenerator.makeVariantValueSignature(variant) + + '#' + SignatureGenerator.makeScopeSignature(variant); + } + }; + + /** + * Utility class that removes duplicates according to the TMDM. + */ + DuplicateRemover = { + removeTopicMapDuplicates: function (tm) { + var i, topics, associations, sig2ass = new Hash(), sig, existing; + topics = tm.getTopics(); + for (i = 0; i < topics.length; i += 1) { + DuplicateRemover.removeOccurrencesDuplicates(topics[i].getOccurrences()); + DuplicateRemover.removeNamesDuplicates(topics[i].getNames()); + } + associations = tm.getAssociations(); + for (i = 0; i < associations.length; i += 1) { + DuplicateRemover.removeAssociationDuplicates(associations[i]); + sig = SignatureGenerator.makeAssociationSignature(associations[i]); + if ((existing = sig2ass.get(sig))) { + MergeHelper.moveConstructCharacteristics(associations[i], existing); + MergeHelper.moveRoleCharacteristics(associations[i], existing); + associations[i].remove(); + } else { + sig2ass.put(sig, associations[i]); + } + } + sig2ass.empty(); + }, + + removeOccurrencesDuplicates: function (occurrences) { + var i, sig2occ = new Hash(), occ, sig, existing; + for (i = 0; i < occurrences.length; i += 1) { + occ = occurrences[i]; + sig = SignatureGenerator.makeOccurrenceSignature(occ); + if ((existing = sig2occ.get(sig))) { + MergeHelper.moveConstructCharacteristics(occ, existing); + occ.remove(); + } else { + sig2occ.put(sig, occ); + } + } + sig2occ.empty(); + }, + + removeNamesDuplicates: function (names) { + var i, sig2names = new Hash(), name, sig, existing; + for (i = 0; i < names.length; i += 1) { + name = names[i]; + DuplicateRemover.removeVariantsDuplicates(name.getVariants()); + sig = SignatureGenerator.makeNameSignature(name); + if ((existing = sig2names.get(sig))) { + MergeHelper.moveConstructCharacteristics(name, existing); + MergeHelper.moveVariants(name, existing); + name.remove(); + } else { + sig2names.put(sig, name); + } + } + sig2names.empty(); + }, + + removeVariantsDuplicates: function (variants) { + var i, sig2variants = new Hash(), variant, sig, existing; + for (i = 0; i < variants.length; i += 1) { + variant = variants[i]; + sig = SignatureGenerator.makeVariantSignature(variant); + if ((existing = sig2variants.get(sig))) { + MergeHelper.moveConstructCharacteristics(variant, existing); + variant.remove(); + } else { + sig2variants.put(sig, variant); + } + } + sig2variants.empty(); + }, + + removeAssociationDuplicates: function (assoc) { + var i, roles = assoc.getRoles(), sig2role = new Hash(), sig, existing; + for (i = 0; i < roles.length; i += 1) { + sig = SignatureGenerator.makeRoleSignature(roles[i]); + if ((existing = sig2role.get(sig))) { + MergeHelper.moveConstructCharacteristics(roles[i], existing); + roles[i].remove(); + } else { + sig2role.put(sig, roles[i]); + } + } + } + }; + + MergeHelper = { + moveTypes: function (arr, target) { + var i; + for (i = 0; i < arr.length; i += 1) { + arr[i].setType(target); + } + }, + + moveThemes: function (arr, source, target) { + for (var i = 0; i < arr.length; i += 1) { + arr[i].removeTheme(source); + arr[i].addTheme(target); + } + }, + + moveItemIdentifiers: function (source, target) { + var iis, ii; + iis = source.getItemIdentifiers(); + while (iis.length) { + ii = iis[iis.length - 1]; + source.removeItemIdentifier(ii); + target.addItemIdentifier(ii); + } + }, + + /** + * Moves variants from the name source to the name target + */ + moveVariants: function (source, target) { + var arr, i, tmp, tmp2, signatures; + arr = target.getVariants(); + signatures = {}; + for (i = 0; i < arr.length; i += 1) { + signatures[SignatureGenerator.makeVariantSignature(arr[i])] = arr[i]; + } + arr = source.getVariants(); + for (i = 0; i < arr.length; i += 1) { + tmp = arr[i]; + if ((tmp2 = signatures[SignatureGenerator.makeVariantSignature(arr[i])])) { + MergeHelper.moveItemIdentifiers(tmp, tmp2); + MergeHelper.moveReifier(tmp, tmp2); + tmp.remove(); + } else { + target.createVariant(tmp.getValue(), tmp.getDatatype(), tmp.getScope()); + } + } + }, + + moveReifier: function (source, target) { + var r1, r2; + if (source.getReifier() === null) { + return; + } else if (target.getReifier() === null) { + target.setReifier(source.getReifier()); + } else { + r1 = source.getReifier(); + r2 = target.getReifier(); + source.setReifier(null); + r1.mergeIn(r2); + } + }, + + moveRoleCharacteristics: function (source, target) { + var i, roles, sigs = new Hash(); + roles = target.getRoles(); + for (i = 0; i < roles.length; i += 1) { + sigs.put(roles[i], SignatureGenerator.makeRoleSignature(roles[i])); + } + roles = source.getRoles(); + for (i = 0; i < roles.length; i += 1) { + MergeHelper.moveItemIdentifiers(roles[i], + sigs.get(SignatureGenerator.makeRoleSignature(roles[i]))); + roles[i].remove(); + } + }, + + moveConstructCharacteristics: function (source, target) { + MergeHelper.moveReifier(source, target); + MergeHelper.moveItemIdentifiers(source, target); + } + }; + + CopyHelper = { + copyAssociations: function (source, target, mergeMap) { + }, + copyItemIdentifiers: function (source, target) { + }, + copyReifier: function (source, target, mergeMap) { + }, + copyScope: function (source, target, mergeMap) { + }, + copyTopicMap: function (source, target) { + }, + copyTopic: function (sourcetm, targettm, mergeMap) { + }, + copyType: function (source, target, mergeMap) { + } + }; + + TypeInstanceHelper = { + convertAssociationsToType: function (tm) { + var typeInstance, type, instance, associations, index, i, ass, roles; + typeInstance = tm.getTopicBySubjectIdentifier( + tm.createLocator(TMDM.TYPE_INSTANCE)); + type = tm.getTopicBySubjectIdentifier( + tm.createLocator(TMDM.TYPE)); + instance = tm.getTopicBySubjectIdentifier( + tm.createLocator(TMDM.INSTANCE)); + if (!typeInstance || !type || !instance) { + return; + } + index = tm.getIndex('TypeInstanceIndex'); + if (!index) { + return; + } + if (!index.isAutoUpdated()) { + index.reindex(); + } + associations = index.getAssociations(typeInstance); + for (i = 0; i < associations.length; i += 1) { + ass = associations[i]; + if (ass.getScope().length > 0 || + ass.getReifier() !== null || + ass.getItemIdentifiers().length > 0) { + continue; + } + roles = ass.getRoles(); + if (roles.length !== 2) { + continue; + } + if (roles[0].getType().equals(type) && roles[1].getType().equals(instance)) { + roles[1].getPlayer().addType(roles[0].getPlayer()); + } else + if (roles[1].getType().equals(type) && roles[0].getType().equals(instance)) { + roles[0].getPlayer().addType(roles[1].getPlayer()); + } else { + continue; + } + ass.remove(); + } + } + }; + + // Export objects into the TM namespace + return { + TopicMapSystemFactory: TopicMapSystemFactory, + XSD: XSD, + TMDM: TMDM, + Hash: Hash, // needed by CXTM export + Version: Version + }; +}()); + +// Pollute the global namespace +TopicMapSystemFactory = TM.TopicMapSystemFactory; + +// Check if we are in a CommonJS environment (e.g. node.js) +if (typeof exports === 'object' && exports !== null) { + exports.TopicMapSystemFactory = TopicMapSystemFactory; + exports.TM = TM; +} + +/*jslint browser: true, devel: true, onevar: true, undef: true, nomen: false, eqeqeq: true, plusplus: true, bitwise: true, + regexp: true, newcap: true, immed: true, indent: 4 */ +/*global TM, window, DOMParser, ActiveXObject*/ + +TM.JTM = (function () { + var ReaderImpl, WriterImpl; + + ReaderImpl = function (tm) { + var that = this; + this.tm = tm; + this.version = null; // Keep the JTM version number + this.prefixes = {}; + this.defaultDatatype = this.tm.createLocator(TM.XSD.string); + + this.curieToLocator = function (loc) { + var curie, prefix, pos; + if (that.version === '1.1' && + loc.substr(0, 1) === '[') { + if (loc.substr(loc.length - 1, 1) !== ']') { + throw {name: 'InvalidFormat', + message: 'Invaild CURIE: missing tailing bracket'}; + } + curie = loc.substr(1, loc.length - 2); + pos = curie.indexOf(':'); + if (pos !== -1) { + // Lookup prefix and replace with URL + prefix = curie.substr(0, pos); + if (that.prefixes[prefix]) { + loc = that.prefixes[prefix] + + curie.substr(pos + 1, curie.length - 1); + return loc; + } else { + throw {name: 'InvalidFormat', + message: 'Missing prefix declaration: ' + prefix}; + } + } else { + throw {name: 'InvalidFormat', + message: 'Invaild CURIE: missing colon'}; + } + } + return loc; + }; + + /** + * Internal function that takes a JTM-identifier string as a parameter + * and returns a topic object - either an existing topic or a new topic + * if the requested topic did not exist + * @param {String} locator JTM-identifier + * @throws {InvalidFormat} If the locator could not be parsed. + */ + this.getTopicByReference = function (locator) { + if (typeof locator === 'undefined' || locator === null) { + return null; + } + switch (locator.substr(0, 3)) { + case 'si:' : + return this.tm.createTopicBySubjectIdentifier( + this.tm.createLocator(this.curieToLocator(locator.substr(3)))); + case 'sl:' : + return this.tm.createTopicBySubjectLocator( + this.tm.createLocator(this.curieToLocator(locator.substr(3)))); + case 'ii:' : + return this.tm.createTopicByItemIdentifier( + this.tm.createLocator(this.curieToLocator(locator.substr(3)))); + } + throw {name: 'InvalidFormat', + message: 'Invaild topic reference '' + locator + '''}; + }; + }; + + /** + * Imports a JTM topic map or JTM fragment from a JSON-string. + * name, variant, occurrence and role fragments need the optional parent + * construct as a parameter. + * TODO: Decide if this should be part of tmjs. Add functions for decoding/ + * encoding JSON if so. + * + * @param {String} str JSON encoded JTM + * @param {Construct} [parent] Parent construct if the JTM fragment contains + * a name, variant, occurrence or role. + */ + ReaderImpl.prototype.fromString = function (str, parent) { + var obj = JSON.parse(str); + return this.fromObject(obj); + }; + + /** + * Imports a JTM topic map or JTM fragment. + * name, variant, occurrence and role fragments need the parent construct + * as a parameter. + * + * @param {object} obj with JTM properties + * @param {Construct} [parent] Parent construct if the JTM fragment contains + * a name, variant, occurrence or role. + */ + ReaderImpl.prototype.fromObject = function (obj, parent) { + var ret; + parent = parent || null; + if (obj.version !== '1.0' && obj.version !== '1.1') { + throw {name: 'InvalidFormat', + message: 'Unknown version of JTM: ' + obj.version}; + } + this.version = obj.version; + if (obj.version === '1.1' && obj.prefixes) { + this.prefixes = obj.prefixes; + // Check if xsd is defined and if it is valid: + if (obj.prefixes && obj.prefixes.xsd && + obj.prefixes.xsd !== 'http://www.w3.org/2001/XMLSchema#') { + throw {name: 'InvalidFormat', + message: 'The XSD prefix MUST have the value "http://www.w3.org/2001/XMLSchema#%22%27%7D; + } + } else if (obj.prefixes) { + throw {name: 'InvalidFormat', + message: 'Prefixes are invalid in JTM 1.0: ' + obj.version}; + } + if (!this.prefixes.xsd) { + this.prefixes.xsd = 'http://www.w3.org/2001/XMLSchema#'; + } + if (!obj.item_type) { + throw {name: 'InvalidFormat', + message: 'Missing item_type'}; + } + switch (obj.item_type.toLowerCase()) { + case "topicmap": + ret = this.parseTopicMap(obj); + break; + case "topic": + ret = this.parseTopic(obj); + break; + case "name": + ret = this.parseName(parent, obj); + break; + case "variant": + ret = this.parseVariant(parent, obj); + break; + case "occurrence": + ret = this.parseOccurrence(parent, obj); + break; + case "association": + ret = this.parseAssociation(obj); + break; + case "role": + ret = this.parseRole(parent, obj); + break; + default: + throw {name: 'InvalidFormat', + message: 'Unknown item_type property'}; + } + return ret; + }; + + /** + * FIXME: Work in progress. We have to specify *how* the information + * item can be created. + * + * Internal function that parses a parent field. From the JTM spec: + * "The value of the parent member is an array of item identifiers, + * each prefixed by "ii:". For occurrences and names the parent array + * may as well contain subject identifiers prefixed by "si:" and + * subject locators prefixed by "sl:". + */ + ReaderImpl.prototype.parseParentAsTopic = function (obj, allowTopic) { + var parent = null, tmp, i; + if (!obj.parent) { + parent = this.tm.createTopic(); + } else if (!(obj.parent instanceof Array) || obj.parent.length === 0) { + throw {name: 'InvalidFormat', + message: 'Missing parent topic reference in occurrence'}; + } + if (obj.parent) { + for (i = 0; i < obj.parent.length; i += 1) { + tmp = this.getTopicByReference(obj.parent[i]); + if (!parent) { + parent = tmp; + } else { + parent.mergeIn(tmp); + } + } + } + return parent; + }; + + ReaderImpl.prototype.parseTopicMap = function (obj) { + var i, len, arr; + this.parseItemIdentifiers(this.tm, obj.item_identifiers); + this.parseReifier(this.tm, obj.reifier); + if (obj.topics && typeof obj.topics === 'object' && obj.topics instanceof Array) { + arr = obj.topics; + len = arr.length; + for (i = 0; i < len; i += 1) { + this.parseTopic(arr[i]); + } + arr = null; + } + if (obj.associations && typeof obj.associations === 'object' && + obj.associations instanceof Array) { + arr = obj.associations; + len = arr.length; + for (i = 0; i < len; i += 1) { + this.parseAssociation(arr[i]); + } + arr = null; + } + this.tm.sanitize(); // remove duplicates and convert type-instance associations to types + return true; + }; + + ReaderImpl.prototype.parseTopic = function (obj) { + var that = this, topic = null, parseIdentifier, arr, i, identifier, type; + parseIdentifier = function (tm, topic, arr, getFunc, createFunc, addFunc) { + var i, len, tmp; + if (arr && typeof arr === 'object' && arr instanceof Array) { + len = arr.length; + for (i = 0; i < len; i += 1) { + identifier = decodeURI(that.curieToLocator(arr[i])); + if (!topic) { + topic = createFunc.apply(tm, [tm.createLocator(identifier)]); + } else { + tmp = getFunc.apply(tm, [tm.createLocator(identifier)]); + if (tmp && tmp.isTopic() && !topic.equals(tmp)) { + topic.mergeIn(tmp); + } else if (!(tmp && tmp.isTopic() && topic.equals(tmp))) { + topic[addFunc](tm.createLocator(identifier)); + } + } + } + } + return topic; + }; + topic = parseIdentifier(this.tm, topic, obj.subject_identifiers, + this.tm.getTopicBySubjectIdentifier, + this.tm.createTopicBySubjectIdentifier, 'addSubjectIdentifier'); + topic = parseIdentifier(this.tm, topic, obj.subject_locators, + this.tm.getTopicBySubjectLocator, + this.tm.createTopicBySubjectLocator, 'addSubjectLocator'); + topic = parseIdentifier(this.tm, topic, obj.item_identifiers, + this.tm.getConstructByItemIdentifier, + this.tm.createTopicByItemIdentifier, 'addItemIdentifier'); + + if ((arr = obj.instance_of) && this.version === '1.1') { + for (i = 0; i < arr.length; i += 1) { + type = this.getTopicByReference(arr[i]); + topic.addType(type); + } + } else if (obj.instance_of && this.version === '1.0') { + throw {name: 'InvalidFormat', + message: 'instance_of is invalid in JTM 1.0'}; + } + + arr = obj.names; + if (arr && typeof arr === 'object' && arr instanceof Array) { + for (i = 0; i < arr.length; i += 1) { + this.parseName(topic, arr[i]); + } + } + arr = obj.occurrences; + if (arr && typeof arr === 'object' && arr instanceof Array) { + for (i = 0; i < arr.length; i += 1) { + this.parseOccurrence(topic, arr[i]); + } + } + }; + + ReaderImpl.prototype.parseName = function (parent, obj) { + var name, type, scope, arr, i; + if (!parent) { + parent = this.parseParentAsTopic(obj); + } + scope = this.parseScope(obj.scope); + type = this.getTopicByReference(obj.type); + name = parent.createName(obj.value, type, scope); + arr = obj.variants; + if (arr && typeof arr === 'object' && arr instanceof Array) { + for (i = 0; i < arr.length; i += 1) { + this.parseVariant(name, arr[i]); + } + } + this.parseItemIdentifiers(name, obj.item_identifiers); + this.parseReifier(name, obj.reifier); + }; + + ReaderImpl.prototype.parseVariant = function (parent, obj) { + var variant, scope; + scope = this.parseScope(obj.scope); + variant = parent.createVariant(obj.value, + obj.datatype ? + this.tm.createLocator(this.curieToLocator(obj.datatype)) : + this.defaultDatatype, scope); + this.parseItemIdentifiers(variant, obj.item_identifiers); + this.parseReifier(variant, obj.reifier); + }; + + ReaderImpl.prototype.parseOccurrence = function (parent, obj) { + var occurrence, type, scope; + if (!parent) { + parent = this.parseParentAsTopic(obj); + } + scope = this.parseScope(obj.scope); + type = this.getTopicByReference(obj.type); + occurrence = parent.createOccurrence(type, obj.value, + obj.datatype ? + this.tm.createLocator(this.curieToLocator(obj.datatype)) : + this.defaultDatatype, scope); + this.parseItemIdentifiers(occurrence, obj.item_identifiers); + this.parseReifier(occurrence, obj.reifier); + }; + + ReaderImpl.prototype.parseAssociation = function (obj) { + var association, type, scope, arr, i; + scope = this.parseScope(obj.scope); + type = this.getTopicByReference(obj.type); + association = this.tm.createAssociation(type, scope); + arr = obj.roles; + if (arr && typeof arr === 'object' && arr instanceof Array) { + if (arr.length === 0) { + throw {name: 'InvalidFormat', + message: 'Association needs roles'}; + } + for (i = 0; i < arr.length; i += 1) { + this.parseRole(association, arr[i]); + } + } else { + throw {name: 'InvalidFormat', + message: 'Association needs roles'}; + } + this.parseItemIdentifiers(association, obj.item_identifiers); + this.parseReifier(association, obj.reifier); + }; + + ReaderImpl.prototype.parseRole = function (parent, obj) { + var role, type, player; + type = this.getTopicByReference(obj.type); + player = this.getTopicByReference(obj.player); + role = parent.createRole(type, player); + this.parseItemIdentifiers(role, obj.item_identifiers); + this.parseReifier(role, obj.reifier); + }; + + ReaderImpl.prototype.parseScope = function (arr) { + var i, scope = []; + if (arr && typeof arr === 'object' && arr instanceof Array) { + for (i = 0; i < arr.length; i += 1) { + scope.push(this.getTopicByReference(arr[i])); + } + } + return scope; + }; + + + ReaderImpl.prototype.parseItemIdentifiers = function (construct, arr) { + var i, tm, identifier; + tm = construct.getTopicMap(); + if (arr && typeof arr === 'object' && arr instanceof Array) { + for (i = 0; i < arr.length; i += 1) { + identifier = this.curieToLocator(arr[i]); + if (!tm.getConstructByItemIdentifier(tm.createLocator(identifier))) { + construct.addItemIdentifier(tm.createLocator(identifier)); + } + } + } + }; + + ReaderImpl.prototype.parseReifier = function (construct, reifier) { + var reifierTopic = this.getTopicByReference(reifier); + if (reifierTopic && reifierTopic.getReified() === null || !reifierTopic) { + construct.setReifier(reifierTopic); + } // else: Ignore the case that reifierTopic reifies another item + }; + + /** + * @class Exports topic maps constructs as JTM 1.0 JavaScript objects. + * See http://www.cerny-online.com/jtm/1.0/ for the JSON Topic Maps specification. + * JSON 1.1 is described at http://www.cerny-online.com/jtm/1.1/ + * @param {String} version Version number of the JTM export. Valid values are '1.0' + * and '1.1'. Version 1.1 produces more compact files. The default + * value is '1.0', but this may change in the future. + */ + WriterImpl = function (version) { + var that = this, referenceToCURIEorURI; + this.defaultDatatype = TM.XSD.string; + this.prefixes = new TM.Hash(); + this.version = version || '1.0'; + + referenceToCURIEorURI = function (reference) { + var key, keys, i, value; + if (that.version === '1.0') { + return reference; + } + // TODO Sort keys after descending value length - longest first + // to find the best prefix + keys = that.prefixes.keys(); + for (i = 0; i < keys.length; i += 1) { + key = keys[i]; + value = that.prefixes.get(key); + if (reference.substring(0, value.length) === value) { + return '[' + key + ':' + + reference.substr(value.length) + ']'; + } + } + return reference; + }; + + /** + * Sets prefixes for JTM 1.1 export. prefixes is an object with the + * prefix as key and its corresponding reference as value. + */ + this.setPrefixes = function (prefixes) { + var key; + for (key in prefixes) { + if (prefixes.hasOwnProperty(key)) { + this.prefixes.put(key, prefixes[key]); + } + } + }; + + /** + * Generates a JTM reference based on the topics subject identifier, + * subject locator or item identifier (whatever is set, tested in this + * order). + * @returns {string} Representing the topic t, e.g. + * "si:http://psi.topicmaps.org/iso13250/model/type + */ + this.getTopicReference = function (t) { + var arr; + arr = t.getSubjectIdentifiers(); + if (arr.length > 0) { + return 'si:' + referenceToCURIEorURI(arr[0].getReference()); + } + arr = t.getSubjectLocators(); + if (arr.length > 0) { + return 'sl:' + referenceToCURIEorURI(arr[0].getReference()); + } + arr = t.getItemIdentifiers(); + if (arr.length > 0) { + return 'ii:' + referenceToCURIEorURI(arr[0].getReference()); + } + // ModelConstraintExeption: TMDM says that t MUST have on of these + }; + + this.exportIdentifiers = function (obj, arr, attr) { + var i, len = arr.length; + if (len > 0) { + obj[attr] = []; + for (i = 0; i < len; i += 1) { + obj[attr].push(referenceToCURIEorURI(arr[i].getReference())); + } + } + + }; + + this.exportScope = function (obj, construct) { + var i, arr = construct.getScope(); + if (arr.length > 0) { + obj.scope = []; + for (i = 0; i < arr.length; i += 1) { + obj.scope.push(that.getTopicReference(arr[i])); + } + } + }; + + this.exportParent = function (obj, construct) { + var parent = construct.getParent(); + that.exportIdentifiers(obj, parent.getItemIdentifiers(), 'parent'); + }; + + this.exportTopicMap = function (m) { + var arr, i, len, obj; + obj = { + topics: [], + associations: [] + }; + arr = m.getTopics(); + len = arr.length; + for (i = 0; i < len; i += 1) { + obj.topics.push(that.exportTopic(arr[i])); + } + arr = m.getAssociations(); + len = arr.length; + for (i = 0; i < len; i += 1) { + obj.associations.push(that.exportAssociation(arr[i])); + } + return obj; + }; + + this.exportTopic = function (t) { + var arr, i, len, obj; + obj = {}; + that.exportIdentifiers(obj, t.getSubjectIdentifiers(), 'subject_identifiers'); + that.exportIdentifiers(obj, t.getSubjectLocators(), 'subject_locators'); + that.exportIdentifiers(obj, t.getItemIdentifiers(), 'item_identifiers'); + arr = t.getNames(); + len = arr.length; + if (len > 0) { + obj.names = []; + for (i = 0; i < len; i += 1) { + obj.names.push(that.exportName(arr[i])); + } + } + arr = t.getOccurrences(); + len = arr.length; + if (len > 0) { + obj.occurrences = []; + for (i = 0; i < len; i += 1) { + obj.occurrences.push(that.exportOccurrence(arr[i])); + } + } + arr = t.getTypes(); + len = arr.length; + if (len > 0) { + obj.instance_of = []; + for (i = 0; i < len; i += 1) { + obj.instance_of.push(that.getTopicReference(arr[i])); + } + } + return obj; + }; + + this.exportName = function (name) { + var arr, i, len, obj, tmp; + obj = { + 'value': name.getValue() + }; + tmp = name.getType(); + if (tmp) { + obj.type = that.getTopicReference(tmp); + } + tmp = name.getReifier(); + if (tmp) { + obj.reifier = that.getTopicReference(tmp); + } + + that.exportIdentifiers(obj, name.getItemIdentifiers(), 'item_identifiers'); + that.exportScope(obj, name); + arr = name.getVariants(); + len = arr.length; + if (len > 0) { + obj.variants = []; + for (i = 0; i < len; i += 1) { + obj.variants.push(that.exportVariant(arr[i])); + } + } + return obj; + }; + + this.exportVariant = function (variant) { + var obj, tmp; + obj = { + 'value': variant.getValue() + }; + tmp = variant.getDatatype(); + if (tmp && tmp !== variant.getTopicMap().createLocator(that.defaultDatatype)) { + obj.datatype = referenceToCURIEorURI(tmp.getReference()); + } + tmp = variant.getReifier(); + if (tmp) { + obj.reifier = that.getTopicReference(tmp); + } + + that.exportIdentifiers(obj, variant.getItemIdentifiers(), 'item_identifiers'); + that.exportScope(obj, variant); + }; + + this.exportOccurrence = function (occ) { + var obj, tmp; + obj = { + value: occ.getValue(), + type: that.getTopicReference(occ.getType()) + }; + tmp = occ.getDatatype(); + if (tmp && tmp !== occ.getTopicMap().createLocator(that.defaultDatatype)) { + obj.datatype = referenceToCURIEorURI(tmp.getReference()); + } + tmp = occ.getReifier(); + if (tmp) { + obj.reifier = that.getTopicReference(tmp); + } + + that.exportIdentifiers(obj, occ.getItemIdentifiers(), 'item_identifiers'); + that.exportScope(obj, occ); + return obj; + }; + + this.exportAssociation = function (association) { + var arr, i, obj, tmp; + obj = { + type: that.getTopicReference(association.getType()), + roles: [] + }; + tmp = association.getReifier(); + if (tmp) { + obj.reifier = that.getTopicReference(tmp); + } + that.exportIdentifiers(obj, association.getItemIdentifiers(), 'item_identifiers'); + that.exportScope(obj, association); + arr = association.getRoles(); + for (i = 0; i < arr.length; i += 1) { + obj.roles.push(that.exportRole(arr[i])); + } + return obj; + }; + + this.exportRole = function (role) { + var obj, tmp; + obj = { + player: that.getTopicReference(role.getPlayer()), + type: that.getTopicReference(role.getType()) + }; + tmp = role.getReifier(); + if (tmp) { + obj.reifier = that.getTopicReference(tmp); + } + that.exportIdentifiers(obj, role.getItemIdentifiers(), 'item_identifiers'); + return obj; + }; + }; + + /** + * Returns a JTM JavaScript object representation of construct. + * @param {Construct} construct The topic map construct to be exported. Can be + * TopicMap, Topic, Occurrence, Name, Variant, Association or Role. + * @param {boolean} [includeParent] If true the optional JTM element 'parent' is + * included. Refers to the parent via its item identifier. If undefined or false, + * the parent element is dropped. + */ + WriterImpl.prototype.toObject = function (construct, includeParent) { + var obj, tm, keys, i; + includeParent = includeParent || false; + tm = construct.getTopicMap(); + + if (construct.isTopicMap()) { + obj = this.exportTopicMap(construct); + obj.item_type = 'topicmap'; + } else if (construct.isRole()) { + obj = this.exportRole(construct); + obj.item_type = 'role'; + } else if (construct.isTopic()) { + obj = this.exportTopic(construct); + obj.item_type = 'topic'; + } else if (construct.isAssociation()) { + obj = this.exportAssociation(construct); + obj.item_type = 'association'; + } else if (construct.isOccurrence()) { + obj = this.exportOccurrence(construct); + obj.item_type = 'occurrence'; + } else if (construct.isName()) { + obj = this.exportName(construct); + obj.item_type = 'name'; + } else if (construct.isVariant()) { + obj = this.exportVariant(construct); + obj.item_type = 'variant'; + } + obj.version = this.version; + if (this.version === '1.1' && this.prefixes) { + if (this.prefixes.size()) { + keys = this.prefixes.keys(); + obj.prefixes = {}; + for (i = 0; i < keys.length; i += 1) { + obj.prefixes[keys[i]] = this.prefixes.get(keys[i]); + } + } + } + if (!construct.isTopic() && construct.getReifier()) { + obj.reifier = this.getTopicReference(construct.getReifier()); + } + if (includeParent && !construct.isTopicMap()) { + this.exportParent(obj, construct); + } + return obj; + }; + + return { + Reader: ReaderImpl, + Writer: WriterImpl + }; +}());
Added: branches/gdl-frontend/playground/GWT-JSNI/GWT-JSNI-example/lib/tm.min.js ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ branches/gdl-frontend/playground/GWT-JSNI/GWT-JSNI-example/lib/tm.min.js Wed Jun 15 09:05:52 2011 (r483) @@ -0,0 +1,116 @@ +// tmjs, version 0.4.0 +// http://github.com/jansc/tmjs +// Copyright (c) 2010 Jan Schreiber jans@ravn.no +// Licensed under the MIT-License. + +var TM,TopicMapSystemFactory; +TM=function(){var n,C,h,g,e,f,i,l,m,o,t,u,p,D,x,A,B,v,y,w,z,O,E,J,H,s,q,P;Function.prototype.swiss=function(a){var b,c;for(b=1;b<arguments.length;b+=1){c=arguments[b];this.prototype[c]=a.prototype[c]}return this};n=function(){this.hash={};this.length=0};n.prototype={get:function(a){return this.hash[a]},contains:function(a){return this.get(a)!==undefined},put:function(a,b){this.hash[a]||(this.length+=1);return this.hash[a]=b},remove:function(a){delete this.hash[a];this.length-=1;return this},keys:function(){var a= +[],b;for(b in this.hash)this.hash.hasOwnProperty(b)&&a.push(b);return a},values:function(){var a=[],b;for(b in this.hash)this.hash.hasOwnProperty(b)&&a.push(this.hash[b]);return a},empty:function(){this.hash={};this.length=0},size:function(){return this.length}};e={};e.ADD_ASSOCIATION=1;e.ADD_NAME=2;e.ADD_OCCURRENCE=3;e.ADD_ROLE=4;e.ADD_THEME=5;e.ADD_TOPIC=6;e.ADD_TYPE=7;e.REMOVE_ASSOCIATION=8;e.REMOVE_NAME=9;e.REMOVE_OCCURRENCE=10;e.REMOVE_ROLE=11;e.REMOVE_THEME=12;e.REMOVE_TOPIC=13;e.REMOVE_TYPE= +14;e.SET_TYPE=15;C={string:"http://www.w3.org/2001/XMLSchema#string%22,integer:%22http://www.w3.org/2001... this.iri}; +g.prototype.equals=function(a){return this.iri===a.getReference()};g.prototype.toExternalForm=function(){throw{name:"NotImplemented",message:"Locator.toExternalForm() not implemented"};};m=function(){};m.prototype.addItemIdentifier=function(a){var b;if(a===null)throw{name:"ModelConstraintException",message:"addItemIdentifier(null) is illegal"};if(b=this.getTopicMap()._ii2construct.get(a.getReference()))throw{name:"IdentityConstraintException",message:"Topic Maps constructs with the same item identifier are not allowed", +reporter:this,existing:b,locator:a};this.itemIdentifiers.push(a);this.getTopicMap()._ii2construct.put(a.getReference(),this);return this};m.prototype.equals=function(a){return this.id===a.id};m.prototype.getId=function(){return this.id};m.prototype.getItemIdentifiers=function(){return this.itemIdentifiers};m.prototype.getParent=function(){return this.parnt};m.prototype.getTopicMap=function(){throw{name:"NotImplemented",message:"getTopicMap() not implemented"};};m.prototype.hashCode=function(){throw{name:"NotImplemented", +message:"hashCode() not implemented"};};m.prototype.remove=function(){throw{name:"NotImplemented",message:"remove() not implemented"};};m.prototype.removeItemIdentifier=function(a){if(a!==null){for(var b=0;b<this.itemIdentifiers.length;b+=1)if(this.itemIdentifiers[b].getReference()===a.getReference()){this.itemIdentifiers.splice(b,1);break}this.getTopicMap()._ii2construct.remove(a.getReference());return this}};m.prototype.isTopicMap=function(){return false};m.prototype.isTopic=function(){return false}; +m.prototype.isAssociation=function(){return false};m.prototype.isRole=function(){return false};m.prototype.isName=function(){return false};m.prototype.isOccurrence=function(){return false};m.prototype.isVariant=function(){return false};o=function(){};o.prototype.getType=function(){return this.type};o.prototype.setType=function(a){if(a===null)throw{name:"ModelConstraintException",message:"Topic.setType cannot be called without type"};z.assertBelongsTo(this.getTopicMap(),a);this.getTopicMap().setTypeEvent.fire(this, +{old:this.type,type:a});this.type=a;return this};l=function(){};l.prototype.addTheme=function(a){if(a===null)throw{name:"ModelConstraintException",message:"addTheme(null) is illegal"};for(var b=0;b<this.scope.length;b+=1)if(this.scope[b]===a)return false;z.assertBelongsTo(this.getTopicMap(),a);this.scope.push(a);this.getTopicMap().addThemeEvent.fire(this,{theme:a});if(this.isName())for(b=0;b<this.variants.length;b+=1)this.getTopicMap().addThemeEvent.fire(this.variants[b],{theme:a});return this};l.prototype.getScope= +function(){if(this.isVariant()){var a,b=new n,c=this.parnt.getScope();for(a=0;a<c.length;a+=1)b.put(c[a].getId(),c[a]);for(a=0;a<this.scope.length;a+=1)b.put(this.scope[a].getId(),this.scope[a]);return b.values()}return this.scope};l.prototype.removeTheme=function(a){var b,c,d,j;for(b=0;b<this.scope.length;b+=1)if(this.scope[b]===a){this.getTopicMap().removeThemeEvent.fire(this,{theme:this.scope[b]});this.scope.splice(b,1);break}if(this.isName())for(b=0;b<this.variants.length;b+=1){d=this.variants[b].scope; +j=false;for(c=0;c<d.length;c+=1)if(a.equals(d[c]))j=true;j||this.getTopicMap().removeThemeEvent.fire(this.variants[b],{theme:a})}return this};t=function(){};t.prototype.getReifier=function(){return this.reifier};t.prototype.setReifier=function(a){if(a&&a.getReified()!==null)throw{name:"ModelConstraintException",message:"Reifies already another construct"};z.assertBelongsTo(this.getTopicMap(),a);this.reifier&&this.reifier._setReified(null);a&&a._setReified(this);this.reifier=a;return this};u=function(){}; +u.prototype.decimalValue=function(){};u.prototype.floatValue=function(){var a=parseFloat(this.value);if(isNaN(a))throw{name:"NumberFormatException",message:'"'+this.value+'" is not a float'};return a};u.prototype.getDatatype=function(){return this.datatype};u.prototype.getValue=function(){if(typeof this.value==="object"&&this.value instanceof g)return this.value.getReference();return this.value.toString()};u.prototype.integerValue=function(){var a=parseInt(this.value,10);if(isNaN(a))throw{name:"NumberFormatException", +message:'"'+this.value+'" is not an integer'};return a};u.prototype.locatorValue=function(){if(!(typeof this.value==="object"&&this.value instanceof g))throw{name:"ModelConstraintException",message:'"'+this.value+'" is not a locator'};return this.value};u.prototype.longValue=function(){};u.prototype.setValue=function(a,b){var c=this.getTopicMap();if(b===null)throw{name:"ModelConstraintException",message:"Invalid datatype"};if(a===null)throw{name:"ModelConstraintException",message:"Invalid value"}; +this.value=a;this.datatype=b||this.getTopicMap().createLocator(C.string);if(b&&b.getReference()===C.anyURI)this.value=c.createLocator(a);if(!b)if(typeof a==="number")this.datatype=c.createLocator(C.integer);if(typeof a==="object"&&a instanceof g)this.datatype=c.createLocator(C.anyURI)};TopicMapSystemFactory=function(){this.properties={};this.features={}};TopicMapSystemFactory.prototype.getFeature=function(){return this.features};TopicMapSystemFactory.prototype.getProperty=function(a){return this.properties[a]}; +TopicMapSystemFactory.prototype.hasFeature=function(){return false};TopicMapSystemFactory.newInstance=function(){return new TopicMapSystemFactory};TopicMapSystemFactory.prototype.newTopicMapSystem=function(){if((this.properties["com.semanticheadache.tmjs.backend"]||"memory")==="memory")return new v};TopicMapSystemFactory.prototype.setFeature=function(a,b){this.features[a]=b};TopicMapSystemFactory.prototype.setProperty=function(a,b){this.properties[a]=b};v=function(){this.topicmaps={}};v.prototype.createTopicMap= +function(a){if(this.topicmaps[a.getReference()])throw{name:"TopicMapExistsException",message:"A topic map under the same IRI already exists"};var b=new p(this,a);return this.topicmaps[a.getReference()]=b};v.prototype.getLocators=function(){var a=[],b;for(b in this.topicmaps)this.topicmaps.hasOwnProperty(b)&&a.push(this.createLocator(b));return a};v.prototype.getTopicMap=function(a){a=a instanceof g?this.topicmaps[a.getReference()]:this.topicmaps[a];if(!a)return null;return a};v.prototype.createLocator= +function(a){return new g(this,a)};v.prototype.getFeature=function(){return false};v.prototype._removeTopicMap=function(a){var b;for(b in this.topicmaps)this.topicmaps.hasOwnProperty(b)&&b===a.locator.getReference()&&delete this.topicmaps[b]};v.prototype.close=function(){this.topicmaps=null};p=function(a,b){this.topicmapsystem=a;this.itemIdentifiers=[];this.locator=b;this.topics=[];this.associations=[];this._constructId=1;this._si2topic=new n;this._sl2topic=new n;this._ii2construct=new n;this._id2construct= +new n;this.id=0;this._id2construct.put(this.id,this);this.reifier=null;this.handlers=[];a=function(c){this.eventtype=c;this.handlers=[]};a.prototype={registerHandler:function(c){this.handlers.push(c)},removeHandler:function(c){for(var d=0;d<this.handlers.length;d+=1)c.toString()===this.handlers[d].toString()&&this.handlers.splice(d,1)},fire:function(c,d){d=d||{};for(var j=0;j<this.handlers.length;j+=1)this.handlers[j](this.eventtype,c,d)}};this.addAssociationEvent=new a(e.ADD_ASSOCIATION);this.addNameEvent= +new a(e.ADD_NAME);this.addOccurrenceEvent=new a(e.ADD_OCCURRENCE);this.addRoleEvent=new a(e.ADD_ROLE);this.addThemeEvent=new a(e.ADD_THEME);this.addTopicEvent=new a(e.ADD_TOPIC);this.addTypeEvent=new a(e.ADD_TYPE);this.removeAssociationEvent=new a(e.REMOVE_ASSOCIATION);this.removeNameEvent=new a(e.REMOVE_NAME);this.removeOccurrenceEvent=new a(e.REMOVE_OCCURRENCE);this.removeRoleEvent=new a(e.REMOVE_ROLE);this.removeThemeEvent=new a(e.REMOVE_THEME);this.removeTopicEvent=new a(e.REMOVE_TOPIC);this.removeTypeEvent= +new a(e.REMOVE_TYPE);this.setTypeEvent=new a(e.SET_TYPE);this.typeInstanceIndex=new y(this);this.scopedIndex=new w(this)};p.prototype.register_event_handler=function(a,b){switch(a){case e.ADD_ASSOCIATION:this.addAssociationEvent.registerHandler(b);break;case e.ADD_NAME:this.addNameEvent.registerHandler(b);break;case e.ADD_OCCURRENCE:this.addOccurrenceEvent.registerHandler(b);break;case e.ADD_ROLE:this.addRoleEvent.registerHandler(b);break;case e.ADD_THEME:this.addThemeEvent.registerHandler(b);break; +case e.ADD_TOPIC:this.addTopicEvent.registerHandler(b);break;case e.ADD_TYPE:this.addTypeEvent.registerHandler(b);break;case e.REMOVE_ASSOCIATION:this.removeAssociationEvent.registerHandler(b);break;case e.REMOVE_NAME:this.removeNameEvent.registerHandler(b);break;case e.REMOVE_OCCURRENCE:this.removeOccurrenceEvent.registerHandler(b);break;case e.REMOVE_ROLE:this.removeRoleEvent.registerHandler(b);break;case e.REMOVE_THEME:this.removeThemeEvent.registerHandler(b);break;case e.REMOVE_TOPIC:this.removeTopicEvent.registerHandler(b); +break;case e.REMOVE_TYPE:this.removeTypeEvent.registerHandler(b);break;case e.SET_TYPE:this.setTypeEvent.registerHandler(b);break}return this};p.swiss(t,"getReifier","setReifier");p.swiss(m,"addItemIdentifier","getItemIdentifiers","removeItemIdentifier","isTopic","isAssociation","isRole","isOccurrence","isName","isVariant","isTopicMap");p.prototype.sanitize=function(){H.removeTopicMapDuplicates(this);P.convertAssociationsToType(this);return this};p.prototype.isTopicMap=function(){return true};p.prototype._getConstructId= +function(){this._constructId+=1;return this._constructId};p.prototype.remove=function(){if(this.topicmapsystem===null)return null;this.topicmapsystem._removeTopicMap(this);return this.typeInstanceIndex=this.id=this.reifier=this._id2construct=this._ii2construct=this._sl2topic=this._si2topic=this.associations=this.topics=this.locator=this.itemIdentifiers=this.topicmapsystem=null};p.prototype.createAssociation=function(a,b){var c;if(a===null)throw{name:"ModelConstraintException",message:"Creating an association with type == null is not allowed"}; +if(b===null)throw{name:"ModelConstraintException",message:"Creating an association with scope == null is not allowed"};z.assertBelongsTo(this,a);z.assertBelongsTo(this,b);c=new i(this);this.associations.push(c);a&&c.setType(a);J(c,b);this.addAssociationEvent.fire(c);return c};p.prototype.createLocator=function(a){return new g(this,a)};p.prototype._createEmptyTopic=function(){var a=new f(this);this.addTopicEvent.fire(a);this.topics.push(a);return a};p.prototype.createTopic=function(){var a=this._createEmptyTopic(); +a.addItemIdentifier(this.createLocator("urn:x-tmjs:"+a.getId()));return a};p.prototype.createTopicByItemIdentifier=function(a){if(!a)throw{name:"ModelConstraintException",message:"createTopicByItemIdentifier() needs an item identifier"};var b=this.getConstructByItemIdentifier(a);if(b){if(!b.isTopic())throw{name:"IdentityConstraintException",message:"Another construct with the specified item identifier exists which is not a Topic."};return b}b=this._createEmptyTopic();b.addItemIdentifier(a);return b}; +p.prototype.createTopicBySubjectIdentifier=function(a){if(!a)throw{name:"ModelConstraintException",message:"createTopicBySubjectIdentifier() needs a subject identifier"};var b=this.getTopicBySubjectIdentifier(a);if(b)return b;b=this._createEmptyTopic();b.addSubjectIdentifier(a);return b};p.prototype.createTopicBySubjectLocator=function(a){if(!a)throw{name:"ModelConstraintException",message:"createTopicBySubjectLocator() needs a subject locator"};var b=this.getTopicBySubjectLocator(a);if(b)return b; +b=this._createEmptyTopic();b.addSubjectLocator(a);return b};p.prototype.getAssociations=function(){return this.associations};p.prototype.getConstructById=function(a){if(a===null)throw{name:"ModelConstraintException",message:"getConstructById(null) is illegal"};a=this._id2construct.get(a);if(!a)return null;return a};p.prototype.getConstructByItemIdentifier=function(a){if(a===null)throw{name:"ModelConstraintException",message:"getConstructByItemIdentifier(null) is illegal"};a=this._ii2construct.get(a.getReference()); +if(!a)return null;return a};p.prototype.getIndex=function(a){if(a==="TypeInstanceIndex")return a=this.typeInstanceIndex;else if(a==="ScopedIndex")return a=new w(this);throw{name:"UnsupportedOperationException",message:"getIndex ist not (yet) supported"};};p.prototype.getParent=function(){return null};p.prototype.getTopicBySubjectIdentifier=function(a){if(a=this._si2topic.get(a.getReference()))return a;return null};p.prototype.getTopicBySubjectLocator=function(a){if(a=this._sl2topic.get(a.getReference()))return a; +return null};p.prototype.getLocator=function(){return this.locator};p.prototype.getTopics=function(){return this.topics};p.prototype.mergeIn=function(){throw{name:"NotImplemented",message:"TopicMap.mergeIn() not implemented"};};p.prototype.equals=function(a){return this.locator.equals(a.locator)};p.prototype.getId=function(){return this.id};p.prototype.getTopicMap=function(){return this};p.prototype._removeConstruct=function(a){var b=a.getItemIdentifiers(),c;for(c=0;c<b.length;c+=1)this._ii2construct.remove(b[c].getReference()); +this._id2construct.remove(a.getId())};p.prototype._removeTopic=function(a){var b,c=a.getSubjectIdentifiers(),d=a.getSubjectLocators();for(b=0;b<c.length;b+=1)this._si2topic.remove(c[b].getReference());for(b=0;b<d.length;b+=1)this._sl2topic.remove(d[b].getReference());this._removeConstruct(a);for(b=0;b<this.topics.length;b+=1)if(a.id===this.topics[b].id){this.topics.splice(b,1);break}};p.prototype._removeAssociation=function(a){var b;for(b=0;b<this.associations.length;b+=1)if(a.id===this.associations[b].id){this.associations.splice(b, +1);break}this._removeConstruct(a);for(b=0;b<this.associations.length;b+=1)if(a.id===this.associations[b].id){this.associations.splice(b,1);break}};p.prototype._removeRole=function(a){this._removeConstruct(a)};p.prototype._removeOccurrence=function(a){this._removeConstruct(a)};p.prototype._removeName=function(a){this._removeConstruct(a)};p.prototype._removeVariant=function(a){this._removeConstruct(a)};f=function(a){this.subjectIdentifiers=[];this.subjectLocators=[];this.itemIdentifiers=[];this.parnt= +a;this.id=a._getConstructId();this.getTopicMap()._id2construct.put(this.id,this);this.types=[];this.rolesPlayed=[];this.occurrences=[];this.names=[];this.reified=null};f.swiss(m,"addItemIdentifier","equals","getId","getItemIdentifiers","getParent","getTopicMap","hashCode","remove","removeItemIdentifier","isTopic","isAssociation","isRole","isOccurrence","isName","isVariant","isTopicMap");f.prototype.isTopic=function(){return true};f.prototype.getTopicMap=function(){return this.parnt};f.prototype.addSubjectIdentifier= +function(a){if(!a)throw{name:"ModelConstraintException",message:"addSubjectIdentifier() needs subject identifier"};for(var b=0;b<this.subjectIdentifiers.length;b+=1)if(this.subjectIdentifiers[b].getReference()===a.getReference())return;this.subjectIdentifiers.push(a);this.parnt._si2topic.put(a.getReference(),this);return this};f.prototype.addSubjectLocator=function(a){if(!a)throw{name:"ModelConstraintException",message:"addSubjectLocator() needs subject locator"};for(var b=0;b<this.subjectLocators.length;b+= +1)if(this.subjectLocators[b].getReference()===a.getReference())return;this.subjectLocators.push(a);this.parnt._sl2topic.put(a.getReference(),this);return this};f.prototype.addType=function(a){if(!a)throw{name:"ModelConstraintException",message:"addType() needs type"};z.assertBelongsTo(this.parnt,a);this.parnt.addTypeEvent.fire(this,{type:a});this.types.push(a);return this};f.prototype.createName=function(a,b,c){b&&z.assertBelongsTo(this.parnt,b);c&&z.assertBelongsTo(this.parnt,c);if(typeof c==="undefined")c= +null;a=new x(this,a,b);J(a,c);this.names.push(a);return a};f.prototype.createOccurrence=function(a,b,c,d){z.assertBelongsTo(this.parnt,a);z.assertBelongsTo(this.parnt,d);c=new B(this,a,b,c);this.parnt.addOccurrenceEvent.fire(c,{type:a,value:b});J(c,d);this.occurrences.push(c);return c};f.prototype.getNames=function(a){var b=[],c;for(c=0;c<this.names.length;c+=1)if(a&&this.names[c].getType().equals(a))b.push(this.names[c]);else a||b.push(this.names[c]);return b};f.prototype.getOccurrences=function(a){var b= +[],c;if(a===null)throw{name:"IllegalArgumentException",message:"Topic.getOccurrences cannot be called without type"};for(c=0;c<this.occurrences.length;c+=1)if(a&&this.occurrences[c].getType().equals(a))b.push(this.occurrences[c]);else a||b.push(this.occurrences[c]);return b};f.prototype._removeOccurrence=function(a){for(var b=0;b<this.occurrences.length;b+=1)if(this.occurrences[b].equals(a)){this.occurrences.splice(b,1);break}this.getTopicMap()._removeOccurrence(a)};f.prototype.getReified=function(){return this.reified}; +f.prototype._setReified=function(a){this.reified=a};f.prototype.getRolesPlayed=function(a,b){if(a===null)throw{name:"IllegalArgumentException",message:"Topic.getRolesPlayed cannot be called without type"};if(b===null)throw{name:"IllegalArgumentException",message:"Topic.getRolesPlayed cannot be called with assocType===null"};var c=[],d;for(d=0;d<this.rolesPlayed.length;d+=1)if(a){if(this.rolesPlayed[d].getType().equals(a))if(b&&this.rolesPlayed[d].getParent().getType().equals(b)||!b)c.push(this.rolesPlayed[d])}else c.push(this.rolesPlayed[d]); +return c};f.prototype.addRolePlayed=function(a){this.rolesPlayed.push(a)};f.prototype.removeRolePlayed=function(a){for(var b=0;b<this.rolesPlayed.length;b+=1)this.rolesPlayed[b].id===a.id&&this.rolesPlayed.splice(b,1)};f.prototype.getSubjectIdentifiers=function(){return this.subjectIdentifiers};f.prototype.getSubjectLocators=function(){return this.subjectLocators};f.prototype.getTypes=function(){return this.types};f.prototype.mergeIn=function(a){var b,c,d,j,k;if(this.equals(a))return true;z.assertBelongsTo(this.getTopicMap(), +a);if(this.getReified()&&a.getReified()&&!this.getReified().equals(a.getReified()))throw{name:"ModelConstraintException",message:"The topics reify different Topic Maps constructs and cannot be merged!"};if(!this.getReified()&&a.getReified()){d=a.getReified();d.setReifier(this)}b=this.parnt.typeInstanceIndex;q.moveTypes(b.getOccurrences(a),this);q.moveTypes(b.getNames(a),this);q.moveTypes(b.getAssociations(a),this);q.moveTypes(b.getRoles(a),this);b=b.getTopics(a);for(c=0;c<b.length;c+=1){b[c].removeType(a); +b[c].addType(this)}b=this.parnt.scopedIndex;q.moveThemes(b.getAssociations(a),a,this);q.moveThemes(b.getOccurrences(a),a,this);q.moveThemes(b.getNames(a),a,this);q.moveThemes(b.getVariants(a),a,this);q.moveItemIdentifiers(a,this);for(b=a.getSubjectLocators();b.length;){d=b[b.length-1];a.removeSubjectLocator(d);this.addSubjectLocator(d)}for(b=a.getSubjectIdentifiers();b.length;){d=b[b.length-1];a.removeSubjectIdentifier(d);this.addSubjectIdentifier(d)}for(b=a.getTypes();b.length;){d=b[b.length-1]; +a.removeType(d);this.addType(d)}b=this.getRolesPlayed();k={};for(c=0;c<b.length;c+=1){j=b[c].getParent();k[s.makeAssociationSignature(j)]=j}b=a.getRolesPlayed();for(c=0;c<b.length;c+=1){d=b[c];d.setPlayer(this);if(j=k[s.makeAssociationSignature(d.getParent())]){q.moveItemIdentifiers(d.getParent(),j);q.moveReifier(d.getParent(),j);d.getParent().remove()}}b=this.getNames();k={};for(c=0;c<b.length;c+=1)k[s.makeNameSignature(b[c])]=b[c];b=a.getNames();for(c=0;c<b.length;c+=1){d=b[c];if(j=k[s.makeNameSignature(b[c])]){q.moveItemIdentifiers(d, +j);q.moveReifier(d,j);q.moveVariants(d,j);d.remove()}else{j=this.createName(d.getValue(),d.getType(),d.getScope());q.moveVariants(d,j)}}b=this.getOccurrences();k={};for(c=0;c<b.length;c+=1)k[s.makeOccurrenceSignature(b[c])]=b[c];b=a.getOccurrences();for(c=0;c<b.length;c+=1){d=b[c];if(j=k[s.makeOccurrenceSignature(b[c])]){q.moveItemIdentifiers(d,j);q.moveReifier(d,j);d.remove()}else{j=this.createOccurrence(d.getType(),d.getValue(),d.getDatatype(),d.getScope());q.moveReifier(d,j)}}a.remove();return this}; +f.prototype.remove=function(){var a=this.parnt.typeInstanceIndex,b=this.parnt.scopedIndex;if(this.getReified()||a.getOccurrences(this).length||a.getNames(this).length||a.getAssociations(this).length||a.getRoles(this).length||a.getTopics(this).length||b.getAssociations(this).length||b.getOccurrences(this).length||b.getNames(this).length||b.getVariants(this).length||this.getRolesPlayed().length)throw{name:"TopicInUseException",message:"",reporter:this};this.parnt._removeTopic(this);this.parnt._id2construct.remove(this.id); +this.parnt.removeTopicEvent.fire(this);this.id=null;return this.parnt};f.prototype.removeSubjectIdentifier=function(a){for(var b=0;b<this.subjectIdentifiers.length;b+=1)if(this.subjectIdentifiers[b].getReference()===a.getReference()){this.subjectIdentifiers.splice(b,1);break}this.parnt._sl2topic.remove(a.getReference());return this};f.prototype.removeSubjectLocator=function(a){for(var b=0;b<this.subjectLocators.length;b+=1)if(this.subjectLocators[b].getReference()===a.getReference()){this.subjectLocators.splice(b, +1);break}this.parnt._sl2topic.remove(a.getReference());return this};f.prototype.removeType=function(a){for(var b=0;b<this.types.length;b+=1)if(this.types[b].equals(a)){this.types.splice(b,1);this.parnt.removeTypeEvent.fire(this,{type:a});break}};f.prototype._removeName=function(a){for(var b=0;b<this.names.length;b+=1)if(this.names[b].equals(a)){this.names.splice(b,1);break}this.getTopicMap()._removeName(a)};B=function(a,b,c,d){this.itemIdentifiers=[];this.parnt=a;this.type=b;this.value=c;this.datatype= +d?d:this.getTopicMap().createLocator(C.string);this.scope=[];this.reifier=null;this.id=this.getTopicMap()._getConstructId();this.getTopicMap()._id2construct.put(this.id,this)};B.swiss(o,"getType","setType");B.swiss(u,"decimalValue","floatValue","getDatatype","getValue","integerValue","locatorValue","longValue","setValue");B.swiss(t,"getReifier","setReifier");B.swiss(l,"addTheme","getScope","removeTheme");B.swiss(m,"addItemIdentifier","equals","getId","getItemIdentifiers","getParent","getTopicMap", +"hashCode","remove","removeItemIdentifier","isTopic","isAssociation","isRole","isOccurrence","isName","isVariant","isTopicMap");B.prototype.isOccurrence=function(){return true};B.prototype.getTopicMap=function(){return this.parnt.getParent()};B.prototype.remove=function(){var a;for(a=0;a<this.scope.length;a+=1)this.parnt.parnt.removeThemeEvent.fire(this,{theme:this.scope[a]});this.parnt.parnt.removeOccurrenceEvent.fire(this);this.parnt._removeOccurrence(this);this.id=null;return this.parnt};x=function(a, +b,c){this.itemIdentifiers=[];this.parnt=a;this.value=b;this.scope=[];this.id=this.getTopicMap()._getConstructId();this.type=c||a.parnt.createTopicBySubjectIdentifier(a.parnt.createLocator("http://psi.topicmaps.org/iso13250/model/topic-name%22));this.reifier=null;th..."); +x.swiss(m,"addItemIdentifier","equals","getId","getItemIdentifiers","getParent","getTopicMap","hashCode","remove","removeItemIdentifier","isTopic","isAssociation","isRole","isOccurrence","isName","isVariant","isTopicMap");x.prototype.isName=function(){return true};x.prototype.getTopicMap=function(){return this.parnt.parnt};x.prototype.createVariant=function(a,b,c){if(typeof c==="undefined"||c===null)throw{name:"ModelConstraintException",message:"Creation of a variant with a null scope is not allowed"}; +a=new A(this,a,b);J(a,c);for(c=0;c<this.scope.length;c+=1)this.getTopicMap().addThemeEvent.fire(a,{theme:this.scope[c]});this.variants.push(a);return a};x.prototype.setValue=function(a){if(!a)throw{name:"ModelConstraintException",message:"Name.setValue(null) is not allowed"};this.value=a;return this};x.prototype.getValue=function(){return this.value};x.prototype.remove=function(){var a;for(a=0;a<this.scope.length;a+=1)this.parnt.parnt.removeThemeEvent.fire(this,{theme:this.scope[a]});this.parnt.parnt.removeNameEvent.fire(this); +this.parnt._removeName(this);this.id=null;return this.parnt};x.prototype._removeVariant=function(a){for(var b=0;b<this.variants.length;b+=1)if(this.variants[b].equals(a)){this.variants.splice(b,1);break}this.getTopicMap()._removeVariant(a)};x.prototype.getVariants=function(){return this.variants};A=function(a,b,c){if(b===null)throw{name:"ModelConstraintException",message:"Creation of a variant with null value is not allowed"};if(c===null)throw{name:"ModelConstraintException",message:"Creation of a variant with datatype == null is not allowed"}; +this.itemIdentifiers=[];this.scope=[];this.parnt=a;this.datatype=typeof b==="object"&&b instanceof g?this.getTopicMap().createLocator("http://www.w3.org/2001/XMLSchema#anyURI%22):this.getTopicMap().createLocator...", +"getParent","getTopicMap","hashCode","remove","removeItemIdentifier","isTopic","isAssociation","isRole","isOccurrence","isName","isVariant","isTopicMap");A.swiss(u,"decimalValue","floatValue","getDatatype","getValue","integerValue","locatorValue","longValue","setValue");A.prototype.isVariant=function(){return true};A.prototype.getTopicMap=function(){return this.getParent().getParent().getParent()};A.prototype.remove=function(){var a;for(a=0;a<this.scope.length;a+=1)this.getTopicMap().removeThemeEvent.fire(this, +{theme:this.scope[a]});this.getParent()._removeVariant(this);this.id=null;return this.parnt};D=function(a,b,c){this.itemIdentifiers=[];this.parnt=a;this.type=b;this.player=c;this.id=this.getTopicMap()._getConstructId();this.reifier=null;this.getTopicMap()._id2construct.put(this.id,this)};D.swiss(o,"getType","setType");D.swiss(t,"getReifier","setReifier");D.swiss(m,"addItemIdentifier","equals","getId","getItemIdentifiers","getParent","getTopicMap","hashCode","remove","removeItemIdentifier","isTopic", +"isAssociation","isRole","isOccurrence","isName","isVariant","isTopicMap");D.prototype.isRole=function(){return true};D.prototype.getTopicMap=function(){return this.getParent().getParent()};D.prototype.remove=function(){var a=this.parnt;this.parnt.parnt.removeRoleEvent.fire(this);this.parnt._removeRole(this);this.id=this.reifier=this.player=this.type=this.parnt=this.itemIdentifiers=null;return a};D.prototype.getPlayer=function(){return this.player};D.prototype.setPlayer=function(a){if(!a)throw{name:"ModelConstraintException", +message:"player i Role.setPlayer cannot be null"};z.assertBelongsTo(this.parnt.parnt,a);if(!this.player.equals(a)){this.player.removeRolePlayed(this);a.addRolePlayed(this);this.player=a;return this}};i=function(a){this.itemIdentifiers=[];this.parnt=a;this.id=this.getTopicMap()._getConstructId();this.getTopicMap()._id2construct.put(this.id,this);this.roles=[];this.scope=[];this.reifier=this.type=null};i.swiss(o,"getType","setType");i.swiss(t,"getReifier","setReifier");i.swiss(l,"addTheme","getScope", +"removeTheme");i.swiss(m,"addItemIdentifier","equals","getId","getItemIdentifiers","getParent","getTopicMap","hashCode","remove","removeItemIdentifier","isTopic","isAssociation","isRole","isOccurrence","isName","isVariant","isTopicMap");i.prototype.isAssociation=function(){return true};i.prototype.getTopicMap=function(){return this.parnt};i.prototype.createRole=function(a,b){if(!a)throw{name:"ModelConstraintException",message:"type i Role.createPlayer cannot be null"};if(!b)throw{name:"ModelConstraintException", +message:"player i Role.createRole cannot be null"};z.assertBelongsTo(this.parnt,a);z.assertBelongsTo(this.parnt,b);var c=new D(this,a,b);b.addRolePlayed(c);this.roles.push(c);this.parnt.addRoleEvent.fire(c,{type:a,player:b});return c};i.prototype._removeRole=function(a){for(var b=0;b<this.roles.length;b+=1)if(a.id===this.roles[b].id){this.roles.splice(b,1);break}a.getPlayer().removeRolePlayed(a);this.getTopicMap()._removeRole(a)};i.prototype.remove=function(){var a;for(a=0;a<this.scope.length;a+= +1)this.parnt.removeThemeEvent.fire(this,{theme:this.scope[a]});for(this.parnt.removeAssociationEvent.fire(this);this.roles.length;)this.roles[0].remove();this.roles=this.id=null;this.parnt._removeAssociation(this);this.getTopicMap()._ii2construct.remove(this.id);this.reifier=this.type=this.scope=this.item_identifiers=null;return this.parnt};i.prototype.getRoles=function(a){if(a===null)throw{name:"IllegalArgumentException",message:"Topic.getRoles cannot be called with type null"};if(!a)return this.roles; +var b=[],c;for(c=0;c<this.roles.length;c+=1)this.roles[c].getType().equals(a)&&b.push(this.roles[c]);return b};i.prototype.getRoleTypes=function(){var a={},b=[],c,d;for(c=0;c<this.roles.length;c+=1)a[this.roles[c].getType().getId()]=this.roles[c].getType();for(d in a)a.hasOwnProperty(d)&&b.push(a[d]);return b};l=function(){this.opened=false};l.prototype.close=function(){};l.prototype.isAutoUpdated=function(){return true};l.prototype.isOpen=function(){return this.opened};l.prototype.open=function(){this.opened= +true};l.prototype.reindex=function(){};y=function(a){var b,c=this;this.tm=a;this.type2topics=new n;this.type2associations=new n;this.type2roles=new n;this.type2occurrences=new n;this.type2names=new n;this.type2variants=new n;this.opened=false;b=function(d,j,k){var r;switch(d){case e.ADD_ASSOCIATION:break;case e.ADD_NAME:d=c.type2names.get(k.type.getId());if(typeof d==="undefined")d=new n;d.put(j.getId(),j);c.type2names.put(k.type.getId(),d);break;case e.ADD_OCCURRENCE:d=c.type2occurrences.get(k.type.getId()); +if(typeof d==="undefined")d=new n;d.put(j.getId(),j);c.type2occurrences.put(k.type.getId(),d);break;case e.ADD_ROLE:d=c.type2roles.get(k.type.getId());if(typeof d==="undefined")d=new n;d.put(j.getId(),j);c.type2roles.put(k.type.getId(),d);break;case e.ADD_TOPIC:d=c.type2topics.get("null");if(typeof d==="undefined")d=new n;d.put(j.getId(),j);c.type2topics.put("null",d);break;case e.ADD_TYPE:if((d=c.type2topics.get("null"))&&d.get(j.getId())){d.remove(j.getId());c.type2topics.put("null",d)}d=c.type2topics.get(k.type.getId()); +if(typeof d==="undefined")d=new n;d.put(j.getId(),j);c.type2topics.put(k.type.getId(),d);break;case e.REMOVE_ASSOCIATION:k=j.getType();if(!k)break;d=c.type2associations.get(k.getId());for(r=0;r<d.length;r+=1)if(d[r].equals(j)){d.splice(r,1);break}d.length>0?c.type2associations.put(k.getId(),d):c.type2associations.remove(k.getId());break;case e.REMOVE_NAME:k=j.getType();d=c.type2names.get(k.getId());d.remove(j.getId());d.length>0?c.type2names.put(k.getId(),d):c.type2names.remove(k.getId());break;case e.REMOVE_OCCURRENCE:k= +j.getType();d=c.type2occurrences.get(k.getId());d.remove(j.getId());d.length>0?c.type2occurrences.put(k.getId(),d):c.type2occurrences.remove(k.getId());break;case e.REMOVE_ROLE:k=j.getType();d=c.type2roles.get(k.getId());d.remove(j.getId());d.length>0?c.type2roles.put(k.getId(),d):c.type2roles.remove(k.getId());break;case e.REMOVE_TOPIC:k=j.getTypes();for(r=0;r<k.length;r+=1){d=c.type2topics.get(k[r].getId());d.remove(j.getId());d.size()||c.type2topics.remove(k[r].getId())}c.type2topics.remove(j.getId()); +c.type2associations.remove(j.getId());c.type2roles.remove(j.getId());c.type2occurrences.remove(j.getId());c.type2variants.remove(j.getId());break;case e.REMOVE_TYPE:d=c.type2topics.get(k.type.getId());d.remove(j.getId());d.size()||c.type2topics.remove(k.type.getId());if(j.getTypes().length===0){d=c.type2topics.get("null");if(typeof d==="undefined")d=new n;d.put(j.getId(),j)}break;case e.SET_TYPE:if(j.isAssociation()){if(k.old){d=c.type2associations.get(k.old.getId());for(r=0;r<d.length;r+=1)if(d[r].equals(j)){d.splice(r, +1);break}d.length>0?c.type2associations.put(k.old.getId(),d):c.type2associations.remove(k.old.getId())}d=c.type2associations.get(k.type.getId());if(typeof d==="undefined")d=[];d.push(j);c.type2associations.put(k.type.getId(),d)}else if(j.isName()){if(d=c.type2names.get(k.old.getId())){d.remove(j.getId());d.length>0?c.type2names.put(k.old.getId(),d):c.type2names.remove(k.old.getId())}d=c.type2names.get(k.type.getId());if(typeof d==="undefined")d=new n;d.put(j.getId(),j);c.type2names.put(k.type.getId(), +d)}else if(j.isOccurrence()){if(d=c.type2occurrences.get(k.old.getId())){d.remove(j.getId());d.length>0?c.type2occurrences.put(k.old.getId(),d):c.type2occurrences.remove(k.old.getId())}d=c.type2occurrences.get(k.type.getId());if(typeof d==="undefined")d=new n;d.put(j.getId(),j);c.type2occurrences.put(k.type.getId(),d)}else if(j.isRole()){if(d=c.type2roles.get(k.old.getId())){d.remove(j.getId());d.length>0?c.type2roles.put(k.old.getId(),d):c.type2roles.remove(k.old.getId())}d=c.type2roles.get(k.type.getId()); +if(typeof d==="undefined")d=new n;d.put(j.getId(),j);c.type2roles.put(k.type.getId(),d)}break}};a.addAssociationEvent.registerHandler(b);a.addNameEvent.registerHandler(b);a.addOccurrenceEvent.registerHandler(b);a.addRoleEvent.registerHandler(b);a.addTopicEvent.registerHandler(b);a.addTypeEvent.registerHandler(b);a.removeAssociationEvent.registerHandler(b);a.removeNameEvent.registerHandler(b);a.removeOccurrenceEvent.registerHandler(b);a.removeRoleEvent.registerHandler(b);a.removeTopicEvent.registerHandler(b); +a.removeTypeEvent.registerHandler(b);a.setTypeEvent.registerHandler(b)};y.swiss(l,"close","isAutoUpdated","isOpen","open","reindex");y.prototype.getAssociations=function(a){a=this.type2associations.get(a.getId());if(!a)return[];return a};y.prototype.getAssociationTypes=function(){var a=[],b=this.type2associations.keys(),c;for(c=0;c<b.length;c+=1)a.push(this.tm.getConstructById(b[c]));return a};y.prototype.getNames=function(a){a=this.type2names.get(a.getId());if(!a)return[];return a.values()};y.prototype.getNameTypes= +function(){var a=[],b=this.type2names.keys(),c;for(c=0;c<b.length;c+=1)a.push(this.tm.getConstructById(b[c]));return a};y.prototype.getOccurrences=function(a){a=this.type2occurrences.get(a.getId());if(!a)return[];return a.values()};y.prototype.getOccurrenceTypes=function(){var a=[],b=this.type2occurrences.keys(),c;for(c=0;c<b.length;c+=1)a.push(this.tm.getConstructById(b[c]));return a};y.prototype.getRoles=function(a){a=this.type2roles.get(a.getId());if(!a)return[];return a.values()};y.prototype.getRoleTypes= +function(){var a=[],b=this.type2roles.keys(),c;for(c=0;c<b.length;c+=1)a.push(this.tm.getConstructById(b[c]));return a};y.prototype.getTopics=function(a){a=this.type2topics.get(a?a.getId():"null");if(!a)return[];return a.values()};y.prototype.getTopicsByTypes=function(a,b){var c,d;c=E.getForKeys(this.type2topics,a);if(!b)return c;for(b=0;b<c.length;b+=1)for(d=0;d<a.length;d+=1)if(!O.contains(c[b].getTypes(),a[d])){c.splice(b,1);b-=1;break}return c};y.prototype.getTopicTypes=function(){var a=[],b= +this.type2topics.keys(),c;for(c=0;c<b.length;c+=1)b[c]!=="null"&&a.push(this.tm.getConstructById(b[c]));return a};y.prototype.close=function(){};w=function(a){var b=this,c;this.tm=a;this.theme2associations=new n;this.theme2names=new n;this.theme2occurrences=new n;this.theme2variants=new n;c=function(d,j,k){var r,I,M,K,L;L=function(F,G,N){I=N.theme?N.theme.getId():"null";if(G.getScope().length===1)if((M=F.get("null"))&&M.get(G.getId())){M.remove(G.getId());F.put("null",M)}r=F.get(I);if(typeof r=== +"undefined")r=new n;r.put(G.getId(),G);F.put(I,r)};K=function(F,G,N){I=N.theme.getId();r=F.get(I);if(typeof r!=="undefined"){r.remove(G.getId());r.size()||F.remove(I)}};switch(d){case e.ADD_THEME:if(j.isAssociation())L(b.theme2associations,j,k);else if(j.isName())L(b.theme2names,j,k);else if(j.isOccurrence())L(b.theme2occurrences,j,k);else j.isVariant()&&L(b.theme2variants,j,k);break;case e.REMOVE_THEME:if(j.isAssociation())K(b.theme2associations,j,k);else if(j.isName())K(b.theme2names,j,k);else if(j.isOccurrence())K(b.theme2occurrences, +j,k);else j.isVariant()&&K(b.theme2variants,j,k);break}};a.addThemeEvent.registerHandler(c);a.removeThemeEvent.registerHandler(c)};w.swiss(l,"close","isAutoUpdated","isOpen","open","reindex");w.prototype.close=function(){};w.prototype.getAssociations=function(a){a=this.theme2associations.get(a?a.getId():"null");if(!a)return[];return a.values()};w.prototype.getAssociationsByThemes=function(a,b){if(a===null)throw{name:"IllegalArgumentException",message:"ScopedIndex.getAssociationsByThemes cannot be called without themes"}; +return E.getConstructsByThemes(this.theme2associations,a,b)};w.prototype.getAssociationThemes=function(){return E.getConstructThemes(this.tm,this.theme2associations)};w.prototype.getNames=function(a){a=this.theme2names.get(a?a.getId():"null");if(!a)return[];return a.values()};w.prototype.getNamesByThemes=function(a,b){if(a===null)throw{name:"IllegalArgumentException",message:"ScopedIndex.getNamesByThemes cannot be called without themes"};return E.getConstructsByThemes(this.theme2names,a,b)};w.prototype.getNameThemes= +function(){return E.getConstructThemes(this.tm,this.theme2names)};w.prototype.getOccurrences=function(a){a=this.theme2occurrences.get(a?a.getId():"null");if(!a)return[];return a.values()};w.prototype.getOccurrencesByThemes=function(a,b){if(a===null)throw{name:"IllegalArgumentException",message:"ScopedIndex.getOccurrencesByThemes cannot be called without themes"};return E.getConstructsByThemes(this.theme2occurrences,a,b)};w.prototype.getOccurrenceThemes=function(){return E.getConstructThemes(this.tm, +this.theme2occurrences)};w.prototype.getVariants=function(a){if(a===null)throw{name:"IllegalArgumentException",message:"ScopedIndex.getVariants cannot be called without themes"};a=this.theme2variants.get(a?a.getId():"null");if(!a)return[];return a.values()};w.prototype.getVariantsByThemes=function(a,b){if(a===null)throw{name:"IllegalArgumentException",message:"ScopedIndex.getVariantsByThemes cannot be called without themes"};return E.getConstructsByThemes(this.theme2variants,a,b)};w.prototype.getVariantThemes= +function(){return E.getConstructThemes(this.tm,this.theme2variants)};z={assertBelongsTo:function(a,b){var c;if(!b)return false;if(b&&b instanceof f&&!a.equals(b.getTopicMap()))throw{name:"ModelConstraintException",message:"scope topic belongs to different topic map"};if(b&&b instanceof Array)for(c=0;c<b.length;c+=1)if(!a.equals(b[c].getTopicMap()))throw{name:"ModelConstraintException",message:"scope topic belong to different topic maps"};return true}};E={getForKeys:function(a,b){var c,d,j=new n,k, +r;for(c=0;c<b.length;c+=1)if(k=a.get(b[c].getId())){r=k.keys();for(d=0;d<r.length;d+=1)j.put(k.get(r[d]).getId(),k.get(r[d]))}return j.values()},getConstructThemes:function(a,b){var c=[];b=b.keys();var d;for(d=0;d<b.length;d+=1)b[d]!=="null"&&c.push(a.getConstructById(b[d]));return c},getConstructsByThemes:function(a,b,c){var d;a=E.getForKeys(a,b);if(!c)return a;for(c=0;c<a.length;c+=1)for(d=0;d<b.length;d+=1)if(!O.contains(a[c].getScope(),b[d])){a.splice(c,1);c-=1;break}return a}};O={contains:function(a, +b){for(var c in a)if(a.hasOwnProperty(c))if(a[c].equals(b))return true;return false}};J=function(a,b){var c;if(b&&typeof b==="object")if(b instanceof Array)for(c=0;c<b.length;c+=1)a.addTheme(b[c]);else b instanceof f&&a.addTheme(b);else a.getTopicMap().addThemeEvent.fire(a,{theme:null})};s={makeNameValueSignature:function(a){return a.getValue()},makeNameSignature:function(a){return s.makeNameValueSignature(a)+"#"+s.makeTypeSignature(a)+"#"+s.makeScopeSignature(a)},makeOccurrenceSignature:function(a){return s.makeOccurrenceValueSignature(a)+ +"#"+s.makeTypeSignature(a)+"#"+s.makeScopeSignature(a)},makeOccurrenceValueSignature:function(a){return"#"+a.getValue()+"#"+(a.getDatatype()?a.getDatatype().getReference():"null")},makeTypeSignature:function(a){return(a=a.getType())?a.getId():""},makeScopeSignature:function(a){var b,c=[];for(b=0;b<a.length;b+=1)c.push(a[b].getId());c.sort();return c.join("#")},makeAssociationSignature:function(a){var b,c,d=[];b=a.getRoles();for(c=0;c<b.length;c+=1)d.push(s.makeRoleSignature(b[c]));d.sort();return"#"+ +s.makeTypeSignature(a)+"#"+d.join("#")+s.makeScopeSignature(a)},makeRoleSignature:function(a){return s.makeTypeSignature(a)+"#"+a.getPlayer().getId()},makeVariantValueSignature:function(a){return"#"+a.getValue()+"#"+a.getDatatype().getReference()},makeVariantSignature:function(a){return s.makeVariantValueSignature(a)+"#"+s.makeScopeSignature(a)}};H={removeTopicMapDuplicates:function(a){var b,c,d=new n,j;c=a.getTopics();for(b=0;b<c.length;b+=1){H.removeOccurrencesDuplicates(c[b].getOccurrences()); +H.removeNamesDuplicates(c[b].getNames())}a=a.getAssociations();for(b=0;b<a.length;b+=1){H.removeAssociationDuplicates(a[b]);c=s.makeAssociationSignature(a[b]);if(j=d.get(c)){q.moveConstructCharacteristics(a[b],j);q.moveRoleCharacteristics(a[b],j);a[b].remove()}else d.put(c,a[b])}d.empty()},removeOccurrencesDuplicates:function(a){var b,c=new n,d,j,k;for(b=0;b<a.length;b+=1){d=a[b];j=s.makeOccurrenceSignature(d);if(k=c.get(j)){q.moveConstructCharacteristics(d,k);d.remove()}else c.put(j,d)}c.empty()}, +removeNamesDuplicates:function(a){var b,c=new n,d,j,k;for(b=0;b<a.length;b+=1){d=a[b];H.removeVariantsDuplicates(d.getVariants());j=s.makeNameSignature(d);if(k=c.get(j)){q.moveConstructCharacteristics(d,k);q.moveVariants(d,k);d.remove()}else c.put(j,d)}c.empty()},removeVariantsDuplicates:function(a){var b,c=new n,d,j,k;for(b=0;b<a.length;b+=1){d=a[b];j=s.makeVariantSignature(d);if(k=c.get(j)){q.moveConstructCharacteristics(d,k);d.remove()}else c.put(j,d)}c.empty()},removeAssociationDuplicates:function(a){var b= +a.getRoles(),c=new n,d,j;for(a=0;a<b.length;a+=1){d=s.makeRoleSignature(b[a]);if(j=c.get(d)){q.moveConstructCharacteristics(b[a],j);b[a].remove()}else c.put(d,b[a])}}};q={moveTypes:function(a,b){var c;for(c=0;c<a.length;c+=1)a[c].setType(b)},moveThemes:function(a,b,c){for(var d=0;d<a.length;d+=1){a[d].removeTheme(b);a[d].addTheme(c)}},moveItemIdentifiers:function(a,b){var c,d;for(c=a.getItemIdentifiers();c.length;){d=c[c.length-1];a.removeItemIdentifier(d);b.addItemIdentifier(d)}},moveVariants:function(a, +b){var c,d,j,k;c=b.getVariants();k={};for(d=0;d<c.length;d+=1)k[s.makeVariantSignature(c[d])]=c[d];c=a.getVariants();for(d=0;d<c.length;d+=1){a=c[d];if(j=k[s.makeVariantSignature(c[d])]){q.moveItemIdentifiers(a,j);q.moveReifier(a,j);a.remove()}else b.createVariant(a.getValue(),a.getDatatype(),a.getScope())}},moveReifier:function(a,b){var c;if(a.getReifier()!==null)if(b.getReifier()===null)b.setReifier(a.getReifier());else{c=a.getReifier();b=b.getReifier();a.setReifier(null);c.mergeIn(b)}},moveRoleCharacteristics:function(a, +b){var c,d=new n;c=b.getRoles();for(b=0;b<c.length;b+=1)d.put(c[b],s.makeRoleSignature(c[b]));c=a.getRoles();for(b=0;b<c.length;b+=1){q.moveItemIdentifiers(c[b],d.get(s.makeRoleSignature(c[b])));c[b].remove()}},moveConstructCharacteristics:function(a,b){q.moveReifier(a,b);q.moveItemIdentifiers(a,b)}};P={convertAssociationsToType:function(a){var b,c,d,j,k;b=a.getTopicBySubjectIdentifier(a.createLocator(h.TYPE_INSTANCE));c=a.getTopicBySubjectIdentifier(a.createLocator(h.TYPE));d=a.getTopicBySubjectIdentifier(a.createLocator(h.INSTANCE)); +if(!(!b||!c||!d))if(a=a.getIndex("TypeInstanceIndex")){a.isAutoUpdated()||a.reindex();b=a.getAssociations(b);for(a=0;a<b.length;a+=1){j=b[a];if(!(j.getScope().length>0||j.getReifier()!==null||j.getItemIdentifiers().length>0)){k=j.getRoles();if(k.length===2){if(k[0].getType().equals(c)&&k[1].getType().equals(d))k[1].getPlayer().addType(k[0].getPlayer());else if(k[1].getType().equals(c)&&k[0].getType().equals(d))k[0].getPlayer().addType(k[1].getPlayer());else continue;j.remove()}}}}}};return{TopicMapSystemFactory:TopicMapSystemFactory, +XSD:C,TMDM:h,Hash:n,Version:"0.4.0"}}();TopicMapSystemFactory=TM.TopicMapSystemFactory;if(typeof exports==="object"&&exports!==null){exports.TopicMapSystemFactory=TopicMapSystemFactory;exports.TM=TM} +TM.JTM=function(){var n,C;n=function(h){var g=this;this.tm=h;this.version=null;this.prefixes={};this.defaultDatatype=this.tm.createLocator(TM.XSD.string);this.curieToLocator=function(e){var f,i;if(g.version==="1.1"&&e.substr(0,1)==="["){if(e.substr(e.length-1,1)!=="]")throw{name:"InvalidFormat",message:"Invaild CURIE: missing tailing bracket"};e=e.substr(1,e.length-2);i=e.indexOf(":");if(i!==-1){f=e.substr(0,i);if(g.prefixes[f])return e=g.prefixes[f]+e.substr(i+1,e.length-1);else throw{name:"InvalidFormat", +message:"Missing prefix declaration: "+f};}else throw{name:"InvalidFormat",message:"Invaild CURIE: missing colon"};}return e};this.getTopicByReference=function(e){if(typeof e==="undefined"||e===null)return null;switch(e.substr(0,3)){case "si:":return this.tm.createTopicBySubjectIdentifier(this.tm.createLocator(this.curieToLocator(e.substr(3))));case "sl:":return this.tm.createTopicBySubjectLocator(this.tm.createLocator(this.curieToLocator(e.substr(3))));case "ii:":return this.tm.createTopicByItemIdentifier(this.tm.createLocator(this.curieToLocator(e.substr(3))))}throw{name:"InvalidFormat", +message:"Invaild topic reference '"+e+"'"};}};n.prototype.fromString=function(h){return this.fromObject(JSON.parse(h))};n.prototype.fromObject=function(h,g){g=g||null;if(h.version!=="1.0"&&h.version!=="1.1")throw{name:"InvalidFormat",message:"Unknown version of JTM: "+h.version};this.version=h.version;if(h.version==="1.1"&&h.prefixes){if((this.prefixes=h.prefixes)&&h.prefixes.xsd&&h.prefixes.xsd!=="http://www.w3.org/2001/XMLSchema#%22)throw%7Bname:%22InvalidFormat%22,messag... XSD prefix MUST have the value "http://www.w3.org/2001/XMLSchema#%22%27%7D; +}else if(h.prefixes)throw{name:"InvalidFormat",message:"Prefixes are invalid in JTM 1.0: "+h.version};if(!this.prefixes.xsd)this.prefixes.xsd="http://www.w3.org/2001/XMLSchema#%22;if(!h.item_type)throw%7Bname:%22Invalid... item_type"};switch(h.item_type.toLowerCase()){case "topicmap":h=this.parseTopicMap(h);break;case "topic":h=this.parseTopic(h);break;case "name":h=this.parseName(g,h);break;case "variant":h=this.parseVariant(g,h);break;case "occurrence":h=this.parseOccurrence(g,h); +break;case "association":h=this.parseAssociation(h);break;case "role":h=this.parseRole(g,h);break;default:throw{name:"InvalidFormat",message:"Unknown item_type property"};}return h};n.prototype.parseParentAsTopic=function(h){var g=null,e,f;if(h.parent){if(!(h.parent instanceof Array)||h.parent.length===0)throw{name:"InvalidFormat",message:"Missing parent topic reference in occurrence"};}else g=this.tm.createTopic();if(h.parent)for(f=0;f<h.parent.length;f+=1){e=this.getTopicByReference(h.parent[f]); +if(g)g.mergeIn(e);else g=e}return g};n.prototype.parseTopicMap=function(h){var g,e,f;this.parseItemIdentifiers(this.tm,h.item_identifiers);this.parseReifier(this.tm,h.reifier);if(h.topics&&typeof h.topics==="object"&&h.topics instanceof Array){f=h.topics;e=f.length;for(g=0;g<e;g+=1)this.parseTopic(f[g])}if(h.associations&&typeof h.associations==="object"&&h.associations instanceof Array){f=h.associations;e=f.length;for(g=0;g<e;g+=1)this.parseAssociation(f[g])}this.tm.sanitize();return true};n.prototype.parseTopic= +function(h){var g=this,e=null,f,i,l,m;f=function(o,t,u,p,D,x){var A,B,v;if(u&&typeof u==="object"&&u instanceof Array){B=u.length;for(A=0;A<B;A+=1){l=decodeURI(g.curieToLocator(u[A]));if(t)if((v=p.apply(o,[o.createLocator(l)]))&&v.isTopic()&&!t.equals(v))t.mergeIn(v);else v&&v.isTopic()&&t.equals(v)||t[x](o.createLocator(l));else t=D.apply(o,[o.createLocator(l)])}}return t};e=f(this.tm,e,h.subject_identifiers,this.tm.getTopicBySubjectIdentifier,this.tm.createTopicBySubjectIdentifier,"addSubjectIdentifier"); +e=f(this.tm,e,h.subject_locators,this.tm.getTopicBySubjectLocator,this.tm.createTopicBySubjectLocator,"addSubjectLocator");e=f(this.tm,e,h.item_identifiers,this.tm.getConstructByItemIdentifier,this.tm.createTopicByItemIdentifier,"addItemIdentifier");if((f=h.instance_of)&&this.version==="1.1")for(i=0;i<f.length;i+=1){m=this.getTopicByReference(f[i]);e.addType(m)}else if(h.instance_of&&this.version==="1.0")throw{name:"InvalidFormat",message:"instance_of is invalid in JTM 1.0"};if((f=h.names)&&typeof f=== +"object"&&f instanceof Array)for(i=0;i<f.length;i+=1)this.parseName(e,f[i]);if((f=h.occurrences)&&typeof f==="object"&&f instanceof Array)for(i=0;i<f.length;i+=1)this.parseOccurrence(e,f[i])};n.prototype.parseName=function(h,g){var e,f;h||(h=this.parseParentAsTopic(g));f=this.parseScope(g.scope);e=this.getTopicByReference(g.type);h=h.createName(g.value,e,f);if((e=g.variants)&&typeof e==="object"&&e instanceof Array)for(f=0;f<e.length;f+=1)this.parseVariant(h,e[f]);this.parseItemIdentifiers(h,g.item_identifiers); +this.parseReifier(h,g.reifier)};n.prototype.parseVariant=function(h,g){var e;e=this.parseScope(g.scope);h=h.createVariant(g.value,g.datatype?this.tm.createLocator(this.curieToLocator(g.datatype)):this.defaultDatatype,e);this.parseItemIdentifiers(h,g.item_identifiers);this.parseReifier(h,g.reifier)};n.prototype.parseOccurrence=function(h,g){var e,f;h||(h=this.parseParentAsTopic(g));f=this.parseScope(g.scope);e=this.getTopicByReference(g.type);h=h.createOccurrence(e,g.value,g.datatype?this.tm.createLocator(this.curieToLocator(g.datatype)): +this.defaultDatatype,f);this.parseItemIdentifiers(h,g.item_identifiers);this.parseReifier(h,g.reifier)};n.prototype.parseAssociation=function(h){var g,e,f;g=this.parseScope(h.scope);g=this.tm.createAssociation(this.getTopicByReference(h.type),g);if((e=h.roles)&&typeof e==="object"&&e instanceof Array){if(e.length===0)throw{name:"InvalidFormat",message:"Association needs roles"};for(f=0;f<e.length;f+=1)this.parseRole(g,e[f])}else throw{name:"InvalidFormat",message:"Association needs roles"};this.parseItemIdentifiers(g, +h.item_identifiers);this.parseReifier(g,h.reifier)};n.prototype.parseRole=function(h,g){var e,f;e=this.getTopicByReference(g.type);f=this.getTopicByReference(g.player);h=h.createRole(e,f);this.parseItemIdentifiers(h,g.item_identifiers);this.parseReifier(h,g.reifier)};n.prototype.parseScope=function(h){var g,e=[];if(h&&typeof h==="object"&&h instanceof Array)for(g=0;g<h.length;g+=1)e.push(this.getTopicByReference(h[g]));return e};n.prototype.parseItemIdentifiers=function(h,g){var e,f,i;f=h.getTopicMap(); +if(g&&typeof g==="object"&&g instanceof Array)for(e=0;e<g.length;e+=1){i=this.curieToLocator(g[e]);f.getConstructByItemIdentifier(f.createLocator(i))||h.addItemIdentifier(f.createLocator(i))}};n.prototype.parseReifier=function(h,g){if((g=this.getTopicByReference(g))&&g.getReified()===null||!g)h.setReifier(g)};C=function(h){var g=this,e;this.defaultDatatype=TM.XSD.string;this.prefixes=new TM.Hash;this.version=h||"1.0";e=function(f){var i,l,m,o;if(g.version==="1.0")return f;l=g.prefixes.keys();for(m= +0;m<l.length;m+=1){i=l[m];o=g.prefixes.get(i);if(f.substring(0,o.length)===o)return"["+i+":"+f.substr(o.length)+"]"}return f};this.setPrefixes=function(f){var i;for(i in f)f.hasOwnProperty(i)&&this.prefixes.put(i,f[i])};this.getTopicReference=function(f){var i;i=f.getSubjectIdentifiers();if(i.length>0)return"si:"+e(i[0].getReference());i=f.getSubjectLocators();if(i.length>0)return"sl:"+e(i[0].getReference());i=f.getItemIdentifiers();if(i.length>0)return"ii:"+e(i[0].getReference())};this.exportIdentifiers= +function(f,i,l){var m,o=i.length;if(o>0){f[l]=[];for(m=0;m<o;m+=1)f[l].push(e(i[m].getReference()))}};this.exportScope=function(f,i){var l=i.getScope();if(l.length>0){f.scope=[];for(i=0;i<l.length;i+=1)f.scope.push(g.getTopicReference(l[i]))}};this.exportParent=function(f,i){i=i.getParent();g.exportIdentifiers(f,i.getItemIdentifiers(),"parent")};this.exportTopicMap=function(f){var i,l,m,o;o={topics:[],associations:[]};i=f.getTopics();m=i.length;for(l=0;l<m;l+=1)o.topics.push(g.exportTopic(i[l])); +i=f.getAssociations();m=i.length;for(l=0;l<m;l+=1)o.associations.push(g.exportAssociation(i[l]));return o};this.exportTopic=function(f){var i,l,m,o;o={};g.exportIdentifiers(o,f.getSubjectIdentifiers(),"subject_identifiers");g.exportIdentifiers(o,f.getSubjectLocators(),"subject_locators");g.exportIdentifiers(o,f.getItemIdentifiers(),"item_identifiers");i=f.getNames();m=i.length;if(m>0){o.names=[];for(l=0;l<m;l+=1)o.names.push(g.exportName(i[l]))}i=f.getOccurrences();m=i.length;if(m>0){o.occurrences= +[];for(l=0;l<m;l+=1)o.occurrences.push(g.exportOccurrence(i[l]))}i=f.getTypes();m=i.length;if(m>0){o.instance_of=[];for(l=0;l<m;l+=1)o.instance_of.push(g.getTopicReference(i[l]))}return o};this.exportName=function(f){var i,l,m;m={value:f.getValue()};if(i=f.getType())m.type=g.getTopicReference(i);if(i=f.getReifier())m.reifier=g.getTopicReference(i);g.exportIdentifiers(m,f.getItemIdentifiers(),"item_identifiers");g.exportScope(m,f);f=f.getVariants();l=f.length;if(l>0){m.variants=[];for(i=0;i<l;i+=1)m.variants.push(g.exportVariant(f[i]))}return m}; +this.exportVariant=function(f){var i,l;i={value:f.getValue()};if((l=f.getDatatype())&&l!==f.getTopicMap().createLocator(g.defaultDatatype))i.datatype=e(l.getReference());if(l=f.getReifier())i.reifier=g.getTopicReference(l);g.exportIdentifiers(i,f.getItemIdentifiers(),"item_identifiers");g.exportScope(i,f)};this.exportOccurrence=function(f){var i,l;i={value:f.getValue(),type:g.getTopicReference(f.getType())};if((l=f.getDatatype())&&l!==f.getTopicMap().createLocator(g.defaultDatatype))i.datatype=e(l.getReference()); +if(l=f.getReifier())i.reifier=g.getTopicReference(l);g.exportIdentifiers(i,f.getItemIdentifiers(),"item_identifiers");g.exportScope(i,f);return i};this.exportAssociation=function(f){var i,l;l={type:g.getTopicReference(f.getType()),roles:[]};if(i=f.getReifier())l.reifier=g.getTopicReference(i);g.exportIdentifiers(l,f.getItemIdentifiers(),"item_identifiers");g.exportScope(l,f);f=f.getRoles();for(i=0;i<f.length;i+=1)l.roles.push(g.exportRole(f[i]));return l};this.exportRole=function(f){var i,l;i={player:g.getTopicReference(f.getPlayer()), +type:g.getTopicReference(f.getType())};if(l=f.getReifier())i.reifier=g.getTopicReference(l);g.exportIdentifiers(i,f.getItemIdentifiers(),"item_identifiers");return i}};C.prototype.toObject=function(h,g){var e,f,i;g=g||false;h.getTopicMap();if(h.isTopicMap()){e=this.exportTopicMap(h);e.item_type="topicmap"}else if(h.isRole()){e=this.exportRole(h);e.item_type="role"}else if(h.isTopic()){e=this.exportTopic(h);e.item_type="topic"}else if(h.isAssociation()){e=this.exportAssociation(h);e.item_type="association"}else if(h.isOccurrence()){e= +this.exportOccurrence(h);e.item_type="occurrence"}else if(h.isName()){e=this.exportName(h);e.item_type="name"}else if(h.isVariant()){e=this.exportVariant(h);e.item_type="variant"}e.version=this.version;if(this.version==="1.1"&&this.prefixes)if(this.prefixes.size()){f=this.prefixes.keys();e.prefixes={};for(i=0;i<f.length;i+=1)e.prefixes[f[i]]=this.prefixes.get(f[i])}if(!h.isTopic()&&h.getReifier())e.reifier=this.getTopicReference(h.getReifier());g&&!h.isTopicMap()&&this.exportParent(e,h);return e}; +return{Reader:n,Writer:C}}();
Copied: branches/gdl-frontend/playground/GWT-JSNI/GWT-JSNI-example/war/gwt_jsni_example/external/tm.js (from r482, branches/gdl-frontend/playground/GWT-JSNI/GWT-JSNI-example/war/gwt_jsni_example/external/tm.js) ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ branches/gdl-frontend/playground/GWT-JSNI/GWT-JSNI-example/war/gwt_jsni_example/external/tm.js Wed Jun 15 09:05:52 2011 (r483, copy of r482, branches/gdl-frontend/playground/GWT-JSNI/GWT-JSNI-example/war/gwt_jsni_example/external/tm.js) @@ -0,0 +1,3926 @@ +// tmjs, version 0.4.0 +// http://github.com/jansc/tmjs +// Copyright (c) 2010 Jan Schreiber jans@ravn.no +// Licensed under the MIT-License. +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +/*jslint browser: true, devel: true, onevar: true, undef: true, + nomen: false, eqeqeq: true, plusplus: true, bitwise: true, + regexp: true, newcap: true, immed: true, indent: 4 */ +/*global exports*/ + +var TM, TopicMapSystemFactory; + +/** + * @namespace Global namespace that holds all Topic Maps related objects. + * @author Jan Schreiber jans@ravn.no + * @copyright 2010 Jan Schreiber http://purl.org/net/jans + * Date: Wed Dec 1 08:39:28 2010 +0100 + */ +TM = (function () { + var Version, Hash, XSD, TMDM, Locator, EventType, Topic, Association, + Scoped, Construct, Typed, Reifiable, + DatatypeAware, TopicMap, Role, Name, + Variant, Occurrence, TopicMapSystemMemImpl, + Index, TypeInstanceIndex, ScopedIndex, + SameTopicMapHelper, ArrayHelper, IndexHelper, addScope, + DuplicateRemover, + SignatureGenerator, MergeHelper, CopyHelper, + TypeInstanceHelper; + + Version = '0.4.0'; + + // ----------------------------------------------------------------------- + // Our swiss army knife for mixin of functions. + // See http://javascript.crockford.com/inheritance.html + Function.prototype.swiss = function (parnt) { + var i, name; + for (i = 1; i < arguments.length; i += 1) { + name = arguments[i]; + this.prototype[name] = parnt.prototype[name]; + } + return this; + }; + + // ----------------------------------------------------------------------- + // Simple hash table for lookup tables + Hash = function () { + this.hash = {}; + this.length = 0; + }; + + /** + * @class Simple hash implementation. + */ + Hash.prototype = { + /** + * Returns the object belonging to the key key or undefined if the + * key does not exist. + * @param key {String} The hash key. + * @returns {object} The stored object or undefined. + */ + get: function (key) { + return this.hash[key]; + }, + + /** + * Checks if the key exists in the hash table. + * @param key {String} The hash key. + * @returns {boolean} True if key exists in the hash table. False + * otherwise. + */ + contains: function (key) { + return this.get(key) !== undefined; + }, + + /** + * Stores an object in the hash table. + * @param key {String} The hash key. + * @param val {object} The value to be stored in the hash table. + * @returns val {object} A reference to the stored object. + */ + put: function (key, val) { + if (!this.hash[key]) { + this.length += 1; + } + this.hash[key] = val; + return val; + }, + + /** + * Removes the key and the corresponding value from the hash table. + * @param key {String} Removes value corresponding to key and the key + * from the hash table + * @returns {Hash} The hash table itself. + */ + remove: function (key) { + delete this.hash[key]; + this.length -= 1; + return this; + }, + + /** + * Returns an array with keys of the hash table. + * @returns {Array} An array with strings. + */ + keys: function () { + var ret = [], key; + for (key in this.hash) { + if (this.hash.hasOwnProperty(key)) { + ret.push(key); + } + } + return ret; + }, + + /** + * Returns an array with all values of the hash table. + * @returns {Array} An array with all objects stored as a value in + * the hash table. + */ + values: function () { + var ret = [], key; + for (key in this.hash) { + if (this.hash.hasOwnProperty(key)) { + ret.push(this.hash[key]); + } + } + return ret; + }, + + /** + * Empties the hash table by removing the reference to all objects. + * Note that the store objects themselves are not touched. + * @returns undefined + */ + empty: function () { + this.hash = {}; + this.length = 0; + }, + + /** + * Returns the size of the hash table, that is the count of all + * key/value pairs. + * @returns {Number} The count of all key/value pairs stored in the + * hash table. + */ + size: function () { + return this.length; + } + }; + + // ----------------------------------------------------------------------- + // Internal event handling system + EventType = {}; + EventType.ADD_ASSOCIATION = 1; + EventType.ADD_NAME = 2; + EventType.ADD_OCCURRENCE = 3; + EventType.ADD_ROLE = 4; + EventType.ADD_THEME = 5; + EventType.ADD_TOPIC = 6; + EventType.ADD_TYPE = 7; + EventType.REMOVE_ASSOCIATION = 8; + EventType.REMOVE_NAME = 9; + EventType.REMOVE_OCCURRENCE = 10; + EventType.REMOVE_ROLE = 11; + EventType.REMOVE_THEME = 12; + EventType.REMOVE_TOPIC = 13; + EventType.REMOVE_TYPE = 14; + EventType.SET_TYPE = 15; + + /** + * @namespace Namespace for XML Schema URIs. // FIXME!! + */ + XSD = { + 'string': "http://www.w3.org/2001/XMLSchema#string", + 'integer': "http://www.w3.org/2001/XMLSchema#integer", + 'anyURI': "http://www.w3.org/2001/XMLSchema#anyURI" + + // TODO: Add all build-in types + }; + + TMDM = { + 'TYPE_INSTANCE': 'http://psi.topicmaps.org/iso13250/model/type-instance', + 'TYPE': 'http://psi.topicmaps.org/iso13250/model/type', + 'INSTANCE': 'http://psi.topicmaps.org/iso13250/model/instance', + 'TOPIC_NAME': 'http://psi.topicmaps.org/iso13250/model/topic-name' + }; + + // ----------------------------------------------------------------------- + // TODO: The locator functions need some more work. Implement resolve() + // and toExternalForm() + + /** + * @class Immutable representation of an IRI. + */ + Locator = function (parnt, iri) { + this.parnt = parnt; + this.iri = iri; + }; + + /** + * Returns the IRI. + * @returns {String} A lexical representation of the IRI. + */ + Locator.prototype.getReference = function () { + return this.iri; + }; + + /** + * Returns true if the other object is equal to this one. + * @param other The object to compare this object against. + * @returns <code>(other instanceof Locator && + * this.getReference().equals(((Locator)other).getReference()))</code> + */ + Locator.prototype.equals = function (other) { + return (this.iri === other.getReference()); + }; + + /** + * Returns the external form of the IRI. Any special character will be + * escaped using the escaping conventions of RFC 3987. + * @returns {String} A string representation of this locator suitable for + * output or passing to APIs which will parse the locator anew. + */ + Locator.prototype.toExternalForm = function () { + throw {name: 'NotImplemented', message: 'Locator.toExternalForm() not implemented'}; + }; + + + // ----------------------------------------------------------------------- + /** + * @class Represents a Topic Maps construct. + */ + Construct = function () {}; + + /** + * Adds an item identifier. + * @param {Locator} itemIdentifier The item identifier to add. + * @returns {Construct} The construct itself (for chaining support) + * @throws {ModelConstraintException} If the itemidentifier is null. + * @throws {IdentityConstraintException} If another Topic Maps construct with + * the same item identifier exists. + */ + Construct.prototype.addItemIdentifier = function (itemIdentifier) { + var existing; + if (itemIdentifier === null) { + throw {name: 'ModelConstraintException', + message: 'addItemIdentifier(null) is illegal'}; + } + existing = this.getTopicMap()._ii2construct.get(itemIdentifier.getReference()); + if (existing) { + throw {name: 'IdentityConstraintException', + message: 'Topic Maps constructs with the same item identifier ' + + 'are not allowed', + reporter: this, + existing: existing, + locator: itemIdentifier}; + } + this.itemIdentifiers.push(itemIdentifier); + this.getTopicMap()._ii2construct.put(itemIdentifier.getReference(), this); + return this; + }; + + /** + * Returns true if the other object is equal to this one. Equality must be + * the result of comparing the identity (<code>this == other</code>) of the + * two objects. + * Note: This equality test does not reflect any equality rule according to + * the Topic Maps - Data Model (TMDM) by intention. + * @param {String} other The object to compare this object against. + */ + Construct.prototype.equals = function (other) { + return (this.id === other.id); + }; + + /** + * Returns the identifier of this construct. This property has no + * representation in the Topic Maps - Data Model. + * + * The ID can be anything, so long as no other Construct in the same topic + * map has the same ID. + * @returns {String} An identifier which identifies this construct uniquely + * within a topic map. + */ + Construct.prototype.getId = function () { + return this.id; + }; + + /** + * Returns the item identifiers of this Topic Maps construct. The return + * value may be empty but must never be <code>null</code>. + * @returns {Array} An array of Locators representing the item identifiers. + * The array MUST NOT be modified. + */ + Construct.prototype.getItemIdentifiers = function () { + return this.itemIdentifiers; + }; + + /** + * Returns the parent of this construct. This method returns + * <code>null</code> iff this construct is a TopicMap instance. + * @returns {Construct} The parent of this construct or <code>null</code> + * iff the construct is an instance of TopicMap. + */ + Construct.prototype.getParent = function () { + return this.parnt; + }; + + /** + * Returns the TopicMap instance to which this Topic Maps construct belongs. + * A TopicMap instance returns itself. + * @returns {Construct} The topic map instance to which this construct belongs. + */ + Construct.prototype.getTopicMap = function () { + throw {name: 'NotImplemented', message: 'getTopicMap() not implemented'}; + }; + + /** + * Returns the hash code value. + * TODO: Is this needed? + */ + Construct.prototype.hashCode = function () { + throw {name: 'NotImplemented', message: 'hashCode() not implemented'}; + }; + + /** + * Returns the parent of this construct. This method returns + * <code>null</code> iff this construct is a TopicMap instance. + * @returns {Construct} The parent of this construct or <code>null</code> + * iff the construct is an instance of {@link TopicMap}. + */ + Construct.prototype.remove = function () { + throw {name: 'NotImplemented', message: 'remove() not implemented'}; + }; + + /** + * Removes an item identifier. + * @param {Locator} itemIdentifier The item identifier to be removed from + * this construct, if present (<code>null</code> is ignored). + * @returns {Construct} The construct itself (for chaining support) + */ + Construct.prototype.removeItemIdentifier = function (itemIdentifier) { + if (itemIdentifier === null) { + return; + } + for (var i = 0; i < this.itemIdentifiers.length; i += 1) { + if (this.itemIdentifiers[i].getReference() === + itemIdentifier.getReference()) { + this.itemIdentifiers.splice(i, 1); + break; + } + } + this.getTopicMap()._ii2construct.remove(itemIdentifier.getReference()); + return this; + }; + + /** + * Returns true if the construct is a {@link TopicMap}-object + * @returns <code>true</code> if the construct is a {@link TopicMap}-object, + * <code>false</code> otherwise. + */ + Construct.prototype.isTopicMap = function () { + return false; + }; + + /** + * Returns true if the construct is a {@link Topic}-object + * @returns <code>true</code> if the construct is a {@link Topic}-object, + * <code>false</code> otherwise. + */ + Construct.prototype.isTopic = function () { + return false; + }; + + /** + * Returns true if the construct is an {@link Association}-object + * @returns <code>true</code> if the construct is an {@link Association}- + * object, <code>false</code> otherwise. + */ + Construct.prototype.isAssociation = function () { + return false; + }; + + /** + * Returns true if the construct is a {@link Role}-object + * @returns <code>true</code> if the construct is a {@link Role}-object, + * <code>false</code> otherwise. + */ + Construct.prototype.isRole = function () { + return false; + }; + + /** + * Returns true if the construct is a {@link Name}-object + * @returns <code>true</code> if the construct is a {@link Name}-object, + * <code>false</code> otherwise. + */ + Construct.prototype.isName = function () { + return false; + }; + + /** + * Returns true if the construct is an {@link Occurrenct}-object + * @returns <code>true</code> if the construct is an {@link Occurrence}-object, + * <code>false</code> otherwise. + */ + Construct.prototype.isOccurrence = function () { + return false; + }; + + /** + * Returns true if the construct is a {@link Variant}-object + * @returns <code>true</code> if the construct is a {@link Variant}-object, + * <code>false</code> otherwise. + */ + Construct.prototype.isVariant = function () { + return false; + }; + + // -------------------------------------------------------------------------- + Typed = function () {}; + + // Returns the type of this construct. + Typed.prototype.getType = function () { + return this.type; + }; + + /** + * Sets the type of this construct. + * @throws {ModelConstraintException} If type is null. + * @returns {Typed} The type itself (for chaining support) + */ + Typed.prototype.setType = function (type) { + if (type === null) { + throw {name: 'ModelConstraintException', + message: 'Topic.setType cannot be called without type'}; + } + SameTopicMapHelper.assertBelongsTo(this.getTopicMap(), type); + this.getTopicMap().setTypeEvent.fire(this, {old: this.type, type: type}); + this.type = type; + return this; + }; + + // -------------------------------------------------------------------------- + /** + * @class Indicates that a statement (Topic Maps construct) has a scope. + * Associations, Occurrences, Names, and Variants are scoped. + */ + Scoped = function () {}; + + /** + * Adds a topic to the scope. + * @throws {ModelConstraintException} If theme is null. + * @returns {Typed} The type itself (for chaining support) + */ + Scoped.prototype.addTheme = function (theme) { + if (theme === null) { + throw {name: 'ModelConstraintException', + message: 'addTheme(null) is illegal'}; + } + // Check if theme is part of the scope + for (var i = 0; i < this.scope.length; i += 1) { + if (this.scope[i] === theme) { + return false; + } + } + SameTopicMapHelper.assertBelongsTo(this.getTopicMap(), theme); + this.scope.push(theme); + this.getTopicMap().addThemeEvent.fire(this, {theme: theme}); + // Special case for names: add the theme to all variants + if (this.isName()) { + for (i = 0; i < this.variants.length; i += 1) { + this.getTopicMap().addThemeEvent.fire(this.variants[i], {theme: theme}); + } + } + return this; + }; + + /** + * Returns the topics which define the scope. + * @returns {Array} A possible empty Array with Topic objects. + */ + Scoped.prototype.getScope = function () { + if (this.isVariant()) { + var i, tmp = new Hash(), parent_scope = this.parnt.getScope(); + for (i = 0; i < parent_scope.length; i += 1) { + tmp.put(parent_scope[i].getId(), parent_scope[i]); + } + for (i = 0; i < this.scope.length; i += 1) { + tmp.put(this.scope[i].getId(), this.scope[i]); + } + return tmp.values(); + } + return this.scope; + }; + + /** + * Removes a topic from the scope. + * @returns {Scoped} The scoped object itself (for chaining support) + */ + Scoped.prototype.removeTheme = function (theme) { + var i, j, scope, found; + for (i = 0; i < this.scope.length; i += 1) { + if (this.scope[i] === theme) { + this.getTopicMap().removeThemeEvent.fire(this, {theme: this.scope[i]}); + this.scope.splice(i, 1); + break; + } + } + // Special case for names: remove the theme from index for all variants + if (this.isName()) { + for (i = 0; i < this.variants.length; i += 1) { + scope = this.variants[i].scope; + // Check if the the variant has theme as scope + found = false; + for (j = 0; j < scope.length; j += 1) { + if (theme.equals(scope[j])) { + found = true; + } + } + if (!found) { + this.getTopicMap().removeThemeEvent.fire(this.variants[i], {theme: theme}); + } + } + } + return this; + }; + + + // -------------------------------------------------------------------------- + /** + * @class Indicates that a Construct is reifiable. Every Topic Maps + * construct that is not a Topic is reifiable. + */ + Reifiable = function () {}; + + /** + * Returns the reifier of this construct. + */ + Reifiable.prototype.getReifier = function () { + return this.reifier; + }; + + /** + * Sets the reifier of the construct. + * @throws {ModelConstraintException} If reifier already reifies another + * construct. + * @returns {Reifiable} The reified object itself (for chaining support) + */ + Reifiable.prototype.setReifier = function (reifier) { + if (reifier && reifier.getReified() !== null) { + throw {name: 'ModelConstraintException', + message: 'Reifies already another construct'}; + } + SameTopicMapHelper.assertBelongsTo(this.getTopicMap(), reifier); + if (this.reifier) { + this.reifier._setReified(null); + } + if (reifier) { + reifier._setReified(this); + } + this.reifier = reifier; + return this; + }; + + // -------------------------------------------------------------------------- + /** + * @class Common base interface for Occurrences and Variants. + * Inherits Scoped, Reifiable + */ + DatatypeAware = function () {}; + + /** + * Returns the BigDecimal representation of the value. + */ + DatatypeAware.prototype.decimalValue = function () { + // FIXME Implement! + }; + + /** + * Returns the float representation of the value. + * @throws {NumberFormatException} If the value is not convertable to float. + */ + DatatypeAware.prototype.floatValue = function () { + var ret = parseFloat(this.value); + if (isNaN(ret)) { + throw {name: 'NumberFormatException', + message: '"' + this.value + '" is not a float'}; + } + return ret; + }; + + /** + * Returns the Locator identifying the datatype of the value. + */ + DatatypeAware.prototype.getDatatype = function () { + return this.datatype; + }; + + /** + * Returns the lexical representation of the value. + */ + DatatypeAware.prototype.getValue = function () { + if (typeof this.value === 'object' && this.value instanceof Locator) { + return this.value.getReference(); + } + return this.value.toString(); + }; + + /** + * Returns the BigInteger representation of the value. + * @throws {NumberFormatException} If the value cannot be parsed as an int. + */ + DatatypeAware.prototype.integerValue = function () { + var ret = parseInt(this.value, 10); + if (isNaN(ret)) { + throw {name: 'NumberFormatException', + message: '"' + this.value + '" is not an integer'}; + } + return ret; + }; + + /** + * Returns the Locator representation of the value. + * @throws {ModelConstraintException} If the value is not an Locator + * object. + */ + DatatypeAware.prototype.locatorValue = function () { + if (!(typeof this.value === 'object' && this.value instanceof Locator)) { + throw {name: 'ModelConstraintException', + message: '"' + this.value + '" is not a locator'}; + } + return this.value; + }; + + /** + * Returns the long representation of the value. + */ + DatatypeAware.prototype.longValue = function () { + // FIXME Implement! + }; + + /** + * Sets the value and the datatype. + * @throws {ModelConstraintException} If datatype or value is null. + */ + DatatypeAware.prototype.setValue = function (value, datatype) { + var tm = this.getTopicMap(); + if (datatype === null) { + throw {name: 'ModelConstraintException', message: 'Invalid datatype'}; + } + if (value === null) { + throw {name: 'ModelConstraintException', message: 'Invalid value'}; + } + this.value = value; + this.datatype = datatype || + this.getTopicMap().createLocator(XSD.string); + if (datatype && datatype.getReference() === XSD.anyURI) { + this.value = tm.createLocator(value); + } + if (!datatype) { + if (typeof value === 'number') { + // FIXME Could be XSD.float as well + this.datatype = tm.createLocator(XSD.integer); + } + } + if (typeof value === 'object' && value instanceof Locator) { + this.datatype = tm.createLocator(XSD.anyURI); + } + }; + + // -------------------------------------------------------------------------- + /** + * Constructs a new Topic Map System Factoy. The constructor should not be + * called directly. Use the {TM.TopicMapSystemFactory.newInstance} instead. + * @class Represents a Topic Maps construct. + * @memberOf TM + */ + TopicMapSystemFactory = function () { + this.properties = {}; + this.features = {}; + }; + + /** + * Returns the particular feature requested for in the underlying implementation + * of TopicMapSystem. + */ + TopicMapSystemFactory.prototype.getFeature = function (featureName) { + return this.features; + }; + + /** + * Gets the value of a property in the underlying implementation of + * TopicMapSystem. + */ + TopicMapSystemFactory.prototype.getProperty = function (propertyName) { + return this.properties[propertyName]; + }; + + /** + * Returns if the particular feature is supported by the TopicMapSystem. + */ + TopicMapSystemFactory.prototype.hasFeature = function (featureName) { + return false; + }; + + /** + * Obtain a new instance of a TopicMapSystemFactory. + * @static + * @returns {TopicMapSystemFactory} + */ + TopicMapSystemFactory.newInstance = function () { + return new TopicMapSystemFactory(); + }; + + /** + * Creates a new TopicMapSystem instance using the currently configured + * factory parameters. + */ + TopicMapSystemFactory.prototype.newTopicMapSystem = function () { + var backend = this.properties['com.semanticheadache.tmjs.backend'] || 'memory'; + if (backend === 'memory') { + return new TopicMapSystemMemImpl(); + } + }; + + /** + * Sets a particular feature in the underlying implementation of TopicMapSystem. + */ + TopicMapSystemFactory.prototype.setFeature = function (featureName, enable) { + this.features[featureName] = enable; + }; + + /** + * Sets a property in the underlying implementation of TopicMapSystem. + */ + TopicMapSystemFactory.prototype.setProperty = function (propertyName, value) { + this.properties[propertyName] = value; + }; + + /** + * Creates a new instance of TopicMamSystem. + * @class Implementation of the TopicMapSystem interface. + */ + TopicMapSystemMemImpl = function () { + this.topicmaps = {}; + }; + + /** + * @throws {TopicMapExistsException} If a topic map with the given locator + * already exists. + */ + TopicMapSystemMemImpl.prototype.createTopicMap = function (locator) { + if (this.topicmaps[locator.getReference()]) { + throw {name: 'TopicMapExistsException', + message: 'A topic map under the same IRI already exists'}; + } + var tm = new TopicMap(this, locator); + this.topicmaps[locator.getReference()] = tm; + return tm; + }; + + TopicMapSystemMemImpl.prototype.getLocators = function () { + var locators = [], key; + for (key in this.topicmaps) { + if (this.topicmaps.hasOwnProperty(key)) { + locators.push(this.createLocator(key)); + } + } + return locators; + }; + + TopicMapSystemMemImpl.prototype.getTopicMap = function (locator) { + var tm; + if (locator instanceof Locator) { + tm = this.topicmaps[locator.getReference()]; + } else { + tm = this.topicmaps[locator]; + } + if (!tm) { + return null; + } + return tm; + }; + + /** + * @param {String} iri + */ + TopicMapSystemMemImpl.prototype.createLocator = function (iri) { + return new Locator(this, iri); + }; + + TopicMapSystemMemImpl.prototype.getFeature = function (featureName) { + return false; + }; + + TopicMapSystemMemImpl.prototype._removeTopicMap = function (tm) { + var key; + for (key in this.topicmaps) { + if (this.topicmaps.hasOwnProperty(key) && + key === tm.locator.getReference()) { + delete this.topicmaps[key]; + } + } + }; + + TopicMapSystemMemImpl.prototype.close = function () { + this.topicmaps = null; // release references + }; + + TopicMap = function (tms, locator) { + this.topicmapsystem = tms; + this.itemIdentifiers = []; + this.locator = locator; + this.topics = []; + this.associations = []; + this._constructId = 1; + this._si2topic = new Hash(); // Index for subject identifiers + this._sl2topic = new Hash(); // Index for subject locators + this._ii2construct = new Hash(); // Index for item identifiers + this._id2construct = new Hash(); // Index for object ids + + // The topic map object always get the id 0 + this.id = 0; + this._id2construct.put(this.id, this); + + this.reifier = null; + this.handlers = []; + + // Our own event handling mechanism + var EventHandler = function (eventtype) { + this.eventtype = eventtype; + this.handlers = []; + }; + EventHandler.prototype = { + registerHandler: function (handler) { + this.handlers.push(handler); + }, + removeHandler: function (handler) { + for (var i = 0; i < this.handlers.length; i += 1) { + if (handler.toString() === + this.handlers[i].toString()) { + this.handlers.splice(i, 1); + } + } + }, + fire: function (source, obj) { + obj = obj || {}; + for (var i = 0; i < this.handlers.length; i += 1) { + this.handlers[i](this.eventtype, source, obj); + } + } + }; + this.addAssociationEvent = new EventHandler(EventType.ADD_ASSOCIATION); + this.addNameEvent = new EventHandler(EventType.ADD_NAME); + this.addOccurrenceEvent = new EventHandler(EventType.ADD_OCCURRENCE); + this.addRoleEvent = new EventHandler(EventType.ADD_ROLE); + this.addThemeEvent = new EventHandler(EventType.ADD_THEME); + this.addTopicEvent = new EventHandler(EventType.ADD_TOPIC); + this.addTypeEvent = new EventHandler(EventType.ADD_TYPE); + this.removeAssociationEvent = new EventHandler(EventType.REMOVE_ASSOCIATION); + this.removeNameEvent = new EventHandler(EventType.REMOVE_NAME); + this.removeOccurrenceEvent = new EventHandler(EventType.REMOVE_OCCURRENCE); + this.removeRoleEvent = new EventHandler(EventType.REMOVE_ROLE); + this.removeThemeEvent = new EventHandler(EventType.REMOVE_THEME); + this.removeTopicEvent = new EventHandler(EventType.REMOVE_TOPIC); + this.removeTypeEvent = new EventHandler(EventType.REMOVE_TYPE); + this.setTypeEvent = new EventHandler(EventType.SET_TYPE); + this.typeInstanceIndex = new TypeInstanceIndex(this); + this.scopedIndex = new ScopedIndex(this); + }; + + /** + * @returns {TopicMap} The topic map object itself (for chaining support) + */ + TopicMap.prototype.register_event_handler = function (type, handler) { + switch (type) { + case EventType.ADD_ASSOCIATION: + this.addAssociationEvent.registerHandler(handler); + break; + case EventType.ADD_NAME: + this.addNameEvent.registerHandler(handler); + break; + case EventType.ADD_OCCURRENCE: + this.addOccurrenceEvent.registerHandler(handler); + break; + case EventType.ADD_ROLE: + this.addRoleEvent.registerHandler(handler); + break; + case EventType.ADD_THEME: + this.addThemeEvent.registerHandler(handler); + break; + case EventType.ADD_TOPIC: + this.addTopicEvent.registerHandler(handler); + break; + case EventType.ADD_TYPE: + this.addTypeEvent.registerHandler(handler); + break; + case EventType.REMOVE_ASSOCIATION: + this.removeAssociationEvent.registerHandler(handler); + break; + case EventType.REMOVE_NAME: + this.removeNameEvent.registerHandler(handler); + break; + case EventType.REMOVE_OCCURRENCE: + this.removeOccurrenceEvent.registerHandler(handler); + break; + case EventType.REMOVE_ROLE: + this.removeRoleEvent.registerHandler(handler); + break; + case EventType.REMOVE_THEME: + this.removeThemeEvent.registerHandler(handler); + break; + case EventType.REMOVE_TOPIC: + this.removeTopicEvent.registerHandler(handler); + break; + case EventType.REMOVE_TYPE: + this.removeTypeEvent.registerHandler(handler); + break; + case EventType.SET_TYPE: + this.setTypeEvent.registerHandler(handler); + break; + } + return this; + }; + + TopicMap.swiss(Reifiable, 'getReifier', 'setReifier'); + TopicMap.swiss(Construct, 'addItemIdentifier', 'getItemIdentifiers', + 'removeItemIdentifier', 'isTopic', 'isAssociation', 'isRole', + 'isOccurrence', 'isName', 'isVariant', 'isTopicMap'); + /** + * Removes duplicate topic map objects. This function is quite expensive, + * so it should not be called too often. It is meant to remove duplicates + * after imports of topic maps. + * @returns {TopicMap} The topic map object itself (for chaining support) + */ + TopicMap.prototype.sanitize = function () { + DuplicateRemover.removeTopicMapDuplicates(this); + TypeInstanceHelper.convertAssociationsToType(this); + return this; + }; + + TopicMap.prototype.isTopicMap = function () { + return true; + }; + + TopicMap.prototype._getConstructId = function () { + this._constructId = this._constructId + 1; + return this._constructId; + }; + + TopicMap.prototype.remove = function () { + if (this.topicmapsystem === null) { + return null; + } + this.topicmapsystem._removeTopicMap(this); + this.topicmapsystem = null; + this.itemIdentifiers = null; + this.locator = null; + this.topics = null; + this.associations = null; + this._si2topic = null; + this._sl2topic = null; + this._ii2construct = null; + this._id2construct = null; + this.reifier = null; + this.id = null; + this.typeInstanceIndex = null; + return null; + }; + + /** + * @throws {ModelConstraintException} If type or scope is null. + */ + TopicMap.prototype.createAssociation = function (type, scope) { + var a; + if (type === null) { + throw {name: 'ModelConstraintException', + message: 'Creating an association with type == null is not allowed'}; + } + if (scope === null) { + throw {name: 'ModelConstraintException', + message: 'Creating an association with scope == null is not allowed'}; + } + SameTopicMapHelper.assertBelongsTo(this, type); + SameTopicMapHelper.assertBelongsTo(this, scope); + + a = new Association(this); + this.associations.push(a); + if (type) { + a.setType(type); + } + addScope(a, scope); + this.addAssociationEvent.fire(a); + return a; + }; + + TopicMap.prototype.createLocator = function (iri) { + return new Locator(this, iri); + }; + + TopicMap.prototype._createEmptyTopic = function () { + var t = new Topic(this); + this.addTopicEvent.fire(t); + this.topics.push(t); + return t; + }; + + TopicMap.prototype.createTopic = function () { + var t = this._createEmptyTopic(); + t.addItemIdentifier(this.createLocator('urn:x-tmjs:' + t.getId())); + return t; + }; + + /** + * @throws {ModelConstraintException} If no itemIdentifier is given. + * @throws {IdentityConstraintException} If another construct with the + * specified item identifier exists which is not a Topic. + */ + TopicMap.prototype.createTopicByItemIdentifier = function (itemIdentifier) { + if (!itemIdentifier) { + throw {name: 'ModelConstraintException', + message: 'createTopicByItemIdentifier() needs an item identifier'}; + } + var t = this.getConstructByItemIdentifier(itemIdentifier); + if (t) { + if (!t.isTopic()) { + throw {name: 'IdentityConstraintException', + message: 'Another construct with the specified item identifier ' + + 'exists which is not a Topic.'}; + } + return t; + } + t = this._createEmptyTopic(); + t.addItemIdentifier(itemIdentifier); + return t; + }; + + /** + * @throws {ModelConstraintException} If no subjectIdentifier is given. + */ + TopicMap.prototype.createTopicBySubjectIdentifier = function (subjectIdentifier) { + if (!subjectIdentifier) { + throw {name: 'ModelConstraintException', + message: 'createTopicBySubjectIdentifier() needs a subject identifier'}; + } + var t = this.getTopicBySubjectIdentifier(subjectIdentifier); + if (t) { + return t; + } + t = this._createEmptyTopic(); + t.addSubjectIdentifier(subjectIdentifier); + return t; + }; + + /** + * @throws {ModelConstraintException} If no subjectLocator is given. + */ + TopicMap.prototype.createTopicBySubjectLocator = function (subjectLocator) { + if (!subjectLocator) { + throw {name: 'ModelConstraintException', + message: 'createTopicBySubjectLocator() needs a subject locator'}; + } + var t = this.getTopicBySubjectLocator(subjectLocator); + if (t) { + return t; + } + t = this._createEmptyTopic(); + t.addSubjectLocator(subjectLocator); + return t; + }; + + TopicMap.prototype.getAssociations = function () { + return this.associations; + }; + + /** + * @throws {ModelConstraintException} If id is null. + */ + TopicMap.prototype.getConstructById = function (id) { + if (id === null) { + throw {name: 'ModelConstraintException', + message: 'getConstructById(null) is illegal'}; + } + var ret = this._id2construct.get(id); + if (!ret) { + return null; + } + return ret; + }; + + /** + * @throws {ModelConstraintException} If itemIdentifier is null. + */ + TopicMap.prototype.getConstructByItemIdentifier = function (itemIdentifier) { + if (itemIdentifier === null) { + throw {name: 'ModelConstraintException', + message: 'getConstructByItemIdentifier(null) is illegal'}; + } + var ret = this._ii2construct.get(itemIdentifier.getReference()); + if (!ret) { + return null; + } + return ret; + }; + + /** + * @throws {UnsupportedOperationException} If the index type is not + * supported. + */ + TopicMap.prototype.getIndex = function (className) { + var index; + if (className === 'TypeInstanceIndex') { + index = this.typeInstanceIndex; + return index; + } else if (className === 'ScopedIndex') { + index = new ScopedIndex(this); + return index; + } + // TODO: Should we throw an exception that indicates that the + // index is not known? Check the TMAPI docs! + throw {name: 'UnsupportedOperationException', + message: 'getIndex ist not (yet) supported'}; + }; + + TopicMap.prototype.getParent = function () { + return null; + }; + + TopicMap.prototype.getTopicBySubjectIdentifier = function (subjectIdentifier) { + var res = this._si2topic.get(subjectIdentifier.getReference()); + if (res) { + return res; + } + return null; // Make sure that the result is not undefined + }; + + TopicMap.prototype.getTopicBySubjectLocator = function (subjectLocator) { + var res = this._sl2topic.get(subjectLocator.getReference()); + if (res) { + return res; + } + return null; // Make sure that the result is not undefined + }; + + TopicMap.prototype.getLocator = function () { + return this.locator; + }; + + TopicMap.prototype.getTopics = function () { + return this.topics; + }; + + TopicMap.prototype.mergeIn = function (topicmap) { + // TODO implement! + throw {name: 'NotImplemented', message: 'TopicMap.mergeIn() not implemented'}; + }; + + TopicMap.prototype.equals = function (topicmap) { + return this.locator.equals(topicmap.locator); + }; + + TopicMap.prototype.getId = function () { + return this.id; + }; + + TopicMap.prototype.getTopicMap = function () { + return this; + }; + + // Remove item identifiers + TopicMap.prototype._removeConstruct = function (construct) { + var iis = construct.getItemIdentifiers(), i; + for (i = 0; i < iis.length; i += 1) { + this._ii2construct.remove(iis[i].getReference()); + } + this._id2construct.remove(construct.getId()); + }; + + TopicMap.prototype._removeTopic = function (topic) { + var i, sis = topic.getSubjectIdentifiers(), + slos = topic.getSubjectLocators(); + // remove subject identifiers from TopicMap._si2topic + for (i = 0; i < sis.length; i += 1) { + this._si2topic.remove(sis[i].getReference()); + } + // remove subject locators from TopicMap._sl2topic + for (i = 0; i < slos.length; i += 1) { + this._sl2topic.remove(slos[i].getReference()); + } + this._removeConstruct(topic); + // remove topic from TopicMap.topics + for (i = 0; i < this.topics.length; i += 1) { + if (topic.id === this.topics[i].id) { + this.topics.splice(i, 1); + break; + } + } + }; + + TopicMap.prototype._removeAssociation = function (association) { + var i; + // remove association from TopicMap.associations + for (i = 0; i < this.associations.length; i += 1) { + if (association.id === this.associations[i].id) { + this.associations.splice(i, 1); + break; + } + } + this._removeConstruct(association); + // remove association from TopicMap.associations + for (i = 0; i < this.associations.length; i += 1) { + if (association.id === this.associations[i].id) { + this.associations.splice(i, 1); + break; + } + } + }; + + TopicMap.prototype._removeRole = function (role) { + this._removeConstruct(role); + }; + + TopicMap.prototype._removeOccurrence = function (occ) { + this._removeConstruct(occ); + }; + + TopicMap.prototype._removeName = function (name) { + this._removeConstruct(name); + }; + + TopicMap.prototype._removeVariant = function (variant) { + this._removeConstruct(variant); + }; + + // hashCode, remove + + // -------------------------------------------------------------------------- + + Topic = function (parnt) { + this.subjectIdentifiers = []; + this.subjectLocators = []; + this.itemIdentifiers = []; + this.parnt = parnt; + this.id = parnt._getConstructId(); + this.getTopicMap()._id2construct.put(this.id, this); + this.types = []; + this.rolesPlayed = []; + this.occurrences = []; + this.names = []; + this.reified = null; + }; + + Topic.swiss(Construct, 'addItemIdentifier', 'equals', 'getId', + 'getItemIdentifiers', 'getParent', 'getTopicMap', 'hashCode', 'remove', + 'removeItemIdentifier', 'isTopic', 'isAssociation', 'isRole', + 'isOccurrence', 'isName', 'isVariant', 'isTopicMap'); + + Topic.prototype.isTopic = function () { + return true; + }; + + Topic.prototype.getTopicMap = function () { + return this.parnt; + }; + + /** + * Adds a subject identifier to this topic. + * @throws {ModelConstraintException} If subjectIdentifier is null or + * not defined. + * @returns {Topic} The topic itself (for chaining support) + */ + Topic.prototype.addSubjectIdentifier = function (subjectIdentifier) { + if (!subjectIdentifier) { + throw {name: 'ModelConstraintException', + message: 'addSubjectIdentifier() needs subject identifier'}; + } + // Ignore if the identifier already exists + for (var i = 0; i < this.subjectIdentifiers.length; i += 1) { + if (this.subjectIdentifiers[i].getReference() === + subjectIdentifier.getReference()) { + return; + } + } + this.subjectIdentifiers.push(subjectIdentifier); + this.parnt._si2topic.put(subjectIdentifier.getReference(), this); + return this; + }; + + /** + * Adds a subject locator to this topic. + * @throws {ModelConstraintException} If subjectLocator is null or + * not defined. + * @returns {Topic} The topic itself (for chaining support) + */ + Topic.prototype.addSubjectLocator = function (subjectLocator) { + if (!subjectLocator) { + throw {name: 'ModelConstraintException', + message: 'addSubjectLocator() needs subject locator'}; + } + // Ignore if the identifier already exists + for (var i = 0; i < this.subjectLocators.length; i += 1) { + if (this.subjectLocators[i].getReference() === + subjectLocator.getReference()) { + return; + } + } + this.subjectLocators.push(subjectLocator); + this.parnt._sl2topic.put(subjectLocator.getReference(), this); + return this; + }; + + /** + * Adds a type to this topic. + * @throws {ModelConstraintException} If type is null or not defined. + * @returns {Topic} The topic itself (for chaining support) + */ + Topic.prototype.addType = function (type) { + if (!type) { + throw {name: 'ModelConstraintException', + message: 'addType() needs type'}; + } + SameTopicMapHelper.assertBelongsTo(this.parnt, type); + this.parnt.addTypeEvent.fire(this, {type: type}); + this.types.push(type); + return this; + }; + + // TODO: @type is optional In TMAPI 2.0 + // Creates a Name for this topic with the specified value, and scope. + // Creates a Name for this topic with the specified type, value, and scope. + Topic.prototype.createName = function (value, type, scope) { + var name; + if (type) { + SameTopicMapHelper.assertBelongsTo(this.parnt, type); + } + if (scope) { + SameTopicMapHelper.assertBelongsTo(this.parnt, scope); + } + if (typeof scope === 'undefined') { + scope = null; + } + + name = new Name(this, value, type); + addScope(name, scope); + this.names.push(name); + return name; + }; + + // TODO: @datatype is optional in TMAPI, value may be string or locator. + // Creates an Occurrence for this topic with the specified type, IRI value, and + // scope. + // createOccurrence(Topic type, java.lang.String value, Locator datatype, + // java.util.Collection<Topic> scope) + // Creates an Occurrence for this topic with the specified type, string value, + // and scope. + Topic.prototype.createOccurrence = function (type, value, datatype, scope) { + var occ; + SameTopicMapHelper.assertBelongsTo(this.parnt, type); + SameTopicMapHelper.assertBelongsTo(this.parnt, scope); + + occ = new Occurrence(this, type, value, datatype); + this.parnt.addOccurrenceEvent.fire(occ, {type: type, value: value}); + addScope(occ, scope); + this.occurrences.push(occ); + return occ; + }; + + /** + * Returns the Names of this topic where the name type is type. + *type is optional. + */ + Topic.prototype.getNames = function (type) { + var ret = [], i; + + for (i = 0; i < this.names.length; i += 1) { + if (type && this.names[i].getType().equals(type)) { + ret.push(this.names[i]); + } else if (!type) { + ret.push(this.names[i]); + } + } + return ret; + }; + + /** + * Returns the Occurrences of this topic where the occurrence type is type. type + * is optional. + * @throws {IllegalArgumentException} If type is null. + */ + Topic.prototype.getOccurrences = function (type) { + var ret = [], i; + if (type === null) { + throw {name: 'IllegalArgumentException', + message: 'Topic.getOccurrences cannot be called without type'}; + } + for (i = 0; i < this.occurrences.length; i += 1) { + if (type && this.occurrences[i].getType().equals(type)) { + ret.push(this.occurrences[i]); + } else if (!type) { + ret.push(this.occurrences[i]); + } + } + return ret; + }; + + Topic.prototype._removeOccurrence = function (occ) { + // remove this from TopicMap.topics + for (var i = 0; i < this.occurrences.length; i += 1) { + if (this.occurrences[i].equals(occ)) { + this.occurrences.splice(i, 1); + break; + } + } + this.getTopicMap()._removeOccurrence(occ); + }; + + // Returns the Construct which is reified by this topic. + Topic.prototype.getReified = function (type) { + return this.reified; + }; + + Topic.prototype._setReified = function (reified) { + this.reified = reified; + }; + + /** + * Returns the roles played by this topic. + * Returns the roles played by this topic where the role type is type. + * assocType is optional + * @throws {IllegalArgumentException} If type or assocType is null. + */ + Topic.prototype.getRolesPlayed = function (type, assocType) { + if (type === null) { + throw {name: 'IllegalArgumentException', + message: 'Topic.getRolesPlayed cannot be called without type'}; + } + if (assocType === null) { + throw {name: 'IllegalArgumentException', + message: 'Topic.getRolesPlayed cannot be called with assocType===null'}; + } + var ret = [], i; + for (i = 0; i < this.rolesPlayed.length; i += 1) { + if (!type) { + ret.push(this.rolesPlayed[i]); + } else if (this.rolesPlayed[i].getType().equals(type)) { + if (assocType && + this.rolesPlayed[i].getParent().getType().equals(assocType) || + !assocType) { + ret.push(this.rolesPlayed[i]); + } + } + } + return ret; + }; + + // @private Registers role as a role played + // TODO: Rename to _addRolePlayed + Topic.prototype.addRolePlayed = function (role) { + this.rolesPlayed.push(role); + }; + + // TODO: Rename to _removeRolePlayed + Topic.prototype.removeRolePlayed = function (role) { + for (var i = 0; i < this.rolesPlayed.length; i += 1) { + if (this.rolesPlayed[i].id === role.id) { + this.rolesPlayed.splice(i, 1); + } + } + }; + + /** + * Returns the subject identifiers assigned to this topic. + */ + Topic.prototype.getSubjectIdentifiers = function () { + return this.subjectIdentifiers; + }; + + /** + * Returns the subject locators assigned to this topic. + */ + Topic.prototype.getSubjectLocators = function () { + return this.subjectLocators; + }; + + /** + * Returns the types of which this topic is an instance of. + */ + Topic.prototype.getTypes = function () { + return this.types; + }; + + /** + * Merges another topic into this topic. + * @throws {ModelConstraintException} If the topics reify different + * information items. + * @returns {Topic} The topic itself (for chaining support) + */ + Topic.prototype.mergeIn = function (other) { + var arr, i, tmp, tmp2, signatures, tiidx, sidx; + if (this.equals(other)) { + return true; + } + + SameTopicMapHelper.assertBelongsTo(this.getTopicMap(), other); + if (this.getReified() && other.getReified() && + !this.getReified().equals(other.getReified())) { + throw {name: 'ModelConstraintException', + message: 'The topics reify different Topic Maps constructs and cannot be merged!' + }; + } + + if (!this.getReified() && other.getReified()) { + tmp = other.getReified(); + tmp.setReifier(this); + } + + // Change all constructs that use other as type + tiidx = this.parnt.typeInstanceIndex; + MergeHelper.moveTypes(tiidx.getOccurrences(other), this); + MergeHelper.moveTypes(tiidx.getNames(other), this); + MergeHelper.moveTypes(tiidx.getAssociations(other), this); + MergeHelper.moveTypes(tiidx.getRoles(other), this); + + // Change all topics that have other as type + arr = tiidx.getTopics(other); + for (i = 0; i < arr.length; i += 1) { + arr[i].removeType(other); + arr[i].addType(this); + } + + // Change all constructs that use other as theme + sidx = this.parnt.scopedIndex; + MergeHelper.moveThemes(sidx.getAssociations(other), other, this); + MergeHelper.moveThemes(sidx.getOccurrences(other), other, this); + MergeHelper.moveThemes(sidx.getNames(other), other, this); + MergeHelper.moveThemes(sidx.getVariants(other), other, this); + + MergeHelper.moveItemIdentifiers(other, this); + + arr = other.getSubjectLocators(); + while (arr.length) { + tmp = arr[arr.length - 1]; + other.removeSubjectLocator(tmp); + this.addSubjectLocator(tmp); + } + + arr = other.getSubjectIdentifiers(); + while (arr.length) { + tmp = arr[arr.length - 1]; + other.removeSubjectIdentifier(tmp); + this.addSubjectIdentifier(tmp); + } + + arr = other.getTypes(); + while (arr.length) { + tmp = arr[arr.length - 1]; + other.removeType(tmp); + this.addType(tmp); + } + + // merge roles played + arr = this.getRolesPlayed(); + signatures = {}; + for (i = 0; i < arr.length; i += 1) { + tmp2 = arr[i].getParent(); + signatures[SignatureGenerator.makeAssociationSignature(tmp2)] = tmp2; + } + arr = other.getRolesPlayed(); + for (i = 0; i < arr.length; i += 1) { + tmp = arr[i]; + tmp.setPlayer(this); + if ((tmp2 = signatures[SignatureGenerator.makeAssociationSignature(tmp.getParent())])) { + MergeHelper.moveItemIdentifiers(tmp.getParent(), tmp2); + MergeHelper.moveReifier(tmp.getParent(), tmp2); + tmp.getParent().remove(); + } + } + + // merge names + arr = this.getNames(); + signatures = {}; + for (i = 0; i < arr.length; i += 1) { + signatures[SignatureGenerator.makeNameSignature(arr[i])] = arr[i]; + } + arr = other.getNames(); + for (i = 0; i < arr.length; i += 1) { + tmp = arr[i]; + if ((tmp2 = signatures[SignatureGenerator.makeNameSignature(arr[i])])) { + MergeHelper.moveItemIdentifiers(tmp, tmp2); + MergeHelper.moveReifier(tmp, tmp2); + MergeHelper.moveVariants(tmp, tmp2); + tmp.remove(); + } else { + tmp2 = this.createName(tmp.getValue(), tmp.getType(), tmp.getScope()); + MergeHelper.moveVariants(tmp, tmp2); + } + } + + // merge occurrences + arr = this.getOccurrences(); + signatures = {}; + for (i = 0; i < arr.length; i += 1) { + signatures[SignatureGenerator.makeOccurrenceSignature(arr[i])] = arr[i]; + } + arr = other.getOccurrences(); + for (i = 0; i < arr.length; i += 1) { + tmp = arr[i]; + if ((tmp2 = signatures[SignatureGenerator.makeOccurrenceSignature(arr[i])])) { + MergeHelper.moveItemIdentifiers(tmp, tmp2); + MergeHelper.moveReifier(tmp, tmp2); + tmp.remove(); + } else { + tmp2 = this.createOccurrence(tmp.getType(), tmp.getValue(), + tmp.getDatatype(), tmp.getScope()); + MergeHelper.moveReifier(tmp, tmp2); + } + } + + other.remove(); + return this; + }; + + /** + * Removes this topic from the containing TopicMap instance. + * @throws {TopicInUseException} If the topics is used as reifier, + * occurrence type, name type, association type, role type, topic type, + * association theme, occurrence theme, name theme, variant theme, + * or if it is used as a role player. + */ + Topic.prototype.remove = function () { + var tiidx = this.parnt.typeInstanceIndex, + sidx = this.parnt.scopedIndex; + if (this.getReified() || + tiidx.getOccurrences(this).length || + tiidx.getNames(this).length || + tiidx.getAssociations(this).length || + tiidx.getRoles(this).length || + tiidx.getTopics(this).length || + sidx.getAssociations(this).length || + sidx.getOccurrences(this).length || + sidx.getNames(this).length || + sidx.getVariants(this).length || + this.getRolesPlayed().length) { + throw {name: 'TopicInUseException', + message: '', reporter: this}; + } + this.parnt._removeTopic(this); + this.parnt._id2construct.remove(this.id); + this.parnt.removeTopicEvent.fire(this); + this.id = null; + return this.parnt; + }; + + /** + * Removes a subject identifier from this topic. + * @returns {Topic} The topic itself (for chaining support) + */ + Topic.prototype.removeSubjectIdentifier = function (subjectIdentifier) { + for (var i = 0; i < this.subjectIdentifiers.length; i += 1) { + if (this.subjectIdentifiers[i].getReference() === + subjectIdentifier.getReference()) { + this.subjectIdentifiers.splice(i, 1); + break; + } + } + this.parnt._sl2topic.remove(subjectIdentifier.getReference()); + return this; + }; + + /** + * Removes a subject locator from this topic. + * @returns {Topic} The topic itself (for chaining support) + */ + Topic.prototype.removeSubjectLocator = function (subjectLocator) { + for (var i = 0; i < this.subjectLocators.length; i += 1) { + if (this.subjectLocators[i].getReference() === + subjectLocator.getReference()) { + this.subjectLocators.splice(i, 1); + break; + } + } + this.parnt._sl2topic.remove(subjectLocator.getReference()); + return this; + }; + + /** + * Removes a type from this topic. + * @returns {Topic} The topic itself (for chaining support) + */ + Topic.prototype.removeType = function (type) { + for (var i = 0; i < this.types.length; i += 1) { + if (this.types[i].equals(type)) { + this.types.splice(i, 1); + this.parnt.removeTypeEvent.fire(this, {type: type}); + break; + } + } + }; + + Topic.prototype._removeName = function (name) { + for (var i = 0; i < this.names.length; i += 1) { + if (this.names[i].equals(name)) { + this.names.splice(i, 1); + break; + } + } + this.getTopicMap()._removeName(name); + }; + + // -------------------------------------------------------------------------- + Occurrence = function (parnt, type, value, datatype) { + this.itemIdentifiers = []; + this.parnt = parnt; + this.type = type; + this.value = value; + this.datatype = datatype ? datatype : this.getTopicMap().createLocator(XSD.string); + this.scope = []; + this.reifier = null; + this.id = this.getTopicMap()._getConstructId(); + this.getTopicMap()._id2construct.put(this.id, this); + }; + + // mergein Typed, DatatypeAware, Reifiable, Scoped, Construct + Occurrence.swiss(Typed, 'getType', 'setType'); + Occurrence.swiss(DatatypeAware, 'decimalValue', 'floatValue', + 'getDatatype', 'getValue', 'integerValue', 'locatorValue', 'longValue', + 'setValue'); + Occurrence.swiss(Reifiable, 'getReifier', 'setReifier'); + Occurrence.swiss(Scoped, 'addTheme', 'getScope', 'removeTheme'); + Occurrence.swiss(Construct, 'addItemIdentifier', 'equals', 'getId', + 'getItemIdentifiers', 'getParent', 'getTopicMap', 'hashCode', 'remove', + 'removeItemIdentifier', 'isTopic', 'isAssociation', 'isRole', + 'isOccurrence', 'isName', 'isVariant', 'isTopicMap'); + + Occurrence.prototype.isOccurrence = function () { + return true; + }; + + Occurrence.prototype.getTopicMap = function () { + return this.parnt.getParent(); + }; + + Occurrence.prototype.remove = function () { + var i; + for (i = 0; i < this.scope.length; i += 1) { + this.parnt.parnt.removeThemeEvent.fire(this, {theme: this.scope[i]}); + } + this.parnt.parnt.removeOccurrenceEvent.fire(this); + this.parnt._removeOccurrence(this); + this.id = null; + return this.parnt; + }; + + Name = function (parnt, value, type) { + this.itemIdentifiers = []; + this.parnt = parnt; + this.value = value; + this.scope = []; + this.id = this.getTopicMap()._getConstructId(); + this.type = type || + parnt.parnt.createTopicBySubjectIdentifier( + parnt.parnt.createLocator('http://psi.topicmaps.org/iso13250/model/topic-name')); + this.reifier = null; + this.variants = []; + this.getTopicMap()._id2construct.put(this.id, this); + this.parnt.parnt.addNameEvent.fire(this, {type: this.type, value: value}); + }; + + // mergein Typed, DatatypeAware, Reifiable, Scoped, Construct + Name.swiss(Typed, 'getType', 'setType'); + Name.swiss(Reifiable, 'getReifier', 'setReifier'); + Name.swiss(Scoped, 'addTheme', 'getScope', 'removeTheme'); + Name.swiss(Construct, 'addItemIdentifier', 'equals', 'getId', + 'getItemIdentifiers', 'getParent', 'getTopicMap', 'hashCode', 'remove', + 'removeItemIdentifier', 'isTopic', 'isAssociation', 'isRole', + 'isOccurrence', 'isName', 'isVariant', 'isTopicMap'); + + Name.prototype.isName = function () { + return true; + }; + + Name.prototype.getTopicMap = function () { + return this.parnt.parnt; + }; + + /** + * @throws {ModelConstraintException} If scope is null. + */ + Name.prototype.createVariant = function (value, datatype, scope) { + var scope_length = 0, i, variant; + if (typeof scope === 'undefined' || scope === null) { + throw {name: 'ModelConstraintException', + message: 'Creation of a variant with a null scope is not allowed'}; + } + if (scope && typeof scope === 'object') { + if (scope instanceof Array) { + scope_length = scope.length; + } else if (scope instanceof Topic) { + scope_length = 1; + } + } + /* + TODO: Compare scope of Name and Variant + if (scope_length <= this.getScope().length) { + // check if the variants scope contains more scoping topics + throw {name: 'ModelConstraintException', + message: 'The variant would be in the same scope as the parent'}; + }*/ + variant = new Variant(this, value, datatype); + addScope(variant, scope); + for (i = 0; i < this.scope.length; i += 1) { + this.getTopicMap().addThemeEvent.fire(variant, + {theme: this.scope[i]}); + } + this.variants.push(variant); + return variant; + }; + + /** + * @throws {ModelConstraintException} If value is null. + * @returns {Name} The name itself (for chaining support) + */ + Name.prototype.setValue = function (value) { + if (!value) { + throw {name: 'ModelConstraintException', + message: 'Name.setValue(null) is not allowed'}; + } + this.value = value; + return this; + }; + + Name.prototype.getValue = function (value) { + return this.value; + }; + + Name.prototype.remove = function () { + var i; + for (i = 0; i < this.scope.length; i += 1) { + this.parnt.parnt.removeThemeEvent.fire(this, {theme: this.scope[i]}); + } + this.parnt.parnt.removeNameEvent.fire(this); + this.parnt._removeName(this); + this.id = null; + return this.parnt; + }; + + Name.prototype._removeVariant = function (variant) { + for (var i = 0; i < this.variants.length; i += 1) { + if (this.variants[i].equals(variant)) { + this.variants.splice(i, 1); + break; + } + } + this.getTopicMap()._removeVariant(variant); + }; + + Name.prototype.getVariants = function () { + return this.variants; + }; + + /** + * @throws {ModelConstraintException} If value or datatype is null. + */ + Variant = function (parnt, value, datatype) { + if (value === null) { + throw {name: 'ModelConstraintException', + message: 'Creation of a variant with null value is not allowed'}; + } + if (datatype === null) { + throw {name: 'ModelConstraintException', + message: 'Creation of a variant with datatype == null is not allowed'}; + } + this.itemIdentifiers = []; + this.scope = []; + this.parnt = parnt; + if (typeof value === 'object' && value instanceof Locator) { + this.datatype = this.getTopicMap().createLocator('http://www.w3.org/2001/XMLSchema#anyURI'); + } else { + this.datatype = + this.getTopicMap().createLocator(XSD.string); + } + this.datatype = datatype; + this.reifier = null; + this.value = value; + this.id = this.getTopicMap()._getConstructId(); + this.getTopicMap()._id2construct.put(this.id, this); + }; + + Variant.swiss(Reifiable, 'getReifier', 'setReifier'); + Variant.swiss(Scoped, 'addTheme', 'getScope', 'removeTheme'); + Variant.swiss(Construct, 'addItemIdentifier', 'equals', 'getId', + 'getItemIdentifiers', 'getParent', 'getTopicMap', 'hashCode', 'remove', + 'removeItemIdentifier', 'isTopic', 'isAssociation', 'isRole', + 'isOccurrence', 'isName', 'isVariant', 'isTopicMap'); + Variant.swiss(DatatypeAware, 'decimalValue', 'floatValue', 'getDatatype', + 'getValue', 'integerValue', 'locatorValue', 'longValue', 'setValue'); + + Variant.prototype.isVariant = function () { + return true; + }; + + Variant.prototype.getTopicMap = function () { + return this.getParent().getParent().getParent(); + }; + + Variant.prototype.remove = function () { + var i; + for (i = 0; i < this.scope.length; i += 1) { + this.getTopicMap().removeThemeEvent.fire(this, {theme: this.scope[i]}); + } + this.getParent()._removeVariant(this); + this.id = null; + return this.parnt; + }; + + + Role = function (parnt, type, player) { + this.itemIdentifiers = []; + this.parnt = parnt; + this.type = type; + this.player = player; + this.id = this.getTopicMap()._getConstructId(); + this.reifier = null; + this.getTopicMap()._id2construct.put(this.id, this); + }; + + Role.swiss(Typed, 'getType', 'setType'); + Role.swiss(Reifiable, 'getReifier', 'setReifier'); + Role.swiss(Construct, 'addItemIdentifier', 'equals', 'getId', + 'getItemIdentifiers', 'getParent', 'getTopicMap', 'hashCode', 'remove', + 'removeItemIdentifier', 'isTopic', 'isAssociation', 'isRole', + 'isOccurrence', 'isName', 'isVariant', 'isTopicMap'); + + Role.prototype.isRole = function () { + return true; + }; + + Role.prototype.getTopicMap = function () { + return this.getParent().getParent(); + }; + + Role.prototype.remove = function () { + var parnt = this.parnt; + this.parnt.parnt.removeRoleEvent.fire(this); + this.parnt._removeRole(this); + this.itemIdentifiers = null; + this.parnt = null; + this.type = null; + this.player = null; + this.reifier = null; + this.id = null; + return parnt; + }; + + Role.prototype.getPlayer = function () { + return this.player; + }; + + /** + * @throws {ModelConstraintException} If player is null. + * @returns {Role} The role itself (for chaining support) + */ + Role.prototype.setPlayer = function (player) { + if (!player) { + throw {name: 'ModelConstraintException', + message: 'player i Role.setPlayer cannot be null'}; + } + SameTopicMapHelper.assertBelongsTo(this.parnt.parnt, player); + if (this.player.equals(player)) { + return; + } + this.player.removeRolePlayed(this); + player.addRolePlayed(this); + this.player = player; + return this; + }; + + Association = function (par) { + this.itemIdentifiers = []; + this.parnt = par; + this.id = this.getTopicMap()._getConstructId(); + this.getTopicMap()._id2construct.put(this.id, this); + this.roles = []; + this.scope = []; + this.type = null; + this.reifier = null; + }; + + Association.swiss(Typed, 'getType', 'setType'); + Association.swiss(Reifiable, 'getReifier', 'setReifier'); + Association.swiss(Scoped, 'addTheme', 'getScope', 'removeTheme'); + Association.swiss(Construct, 'addItemIdentifier', 'equals', 'getId', + 'getItemIdentifiers', 'getParent', 'getTopicMap', 'hashCode', 'remove', + 'removeItemIdentifier', 'isTopic', 'isAssociation', 'isRole', + 'isOccurrence', 'isName', 'isVariant', 'isTopicMap'); + + Association.prototype.isAssociation = function () { + return true; + }; + + Association.prototype.getTopicMap = function () { + return this.parnt; + }; + + /** + * Creates a new Role representing a role in this association. + * @throws {ModelConstraintException} If type or player is null. + */ + Association.prototype.createRole = function (type, player) { + if (!type) { + throw {name: 'ModelConstraintException', + message: 'type i Role.createPlayer cannot be null'}; + } + if (!player) { + throw {name: 'ModelConstraintException', + message: 'player i Role.createRole cannot be null'}; + } + SameTopicMapHelper.assertBelongsTo(this.parnt, type); + SameTopicMapHelper.assertBelongsTo(this.parnt, player); + var role = new Role(this, type, player); + player.addRolePlayed(role); + this.roles.push(role); + this.parnt.addRoleEvent.fire(role, {type: type, player: player}); + return role; + }; + + Association.prototype._removeRole = function (role) { + for (var i = 0; i < this.roles.length; i += 1) { + if (role.id === this.roles[i].id) { + this.roles.splice(i, 1); + break; + } + } + role.getPlayer().removeRolePlayed(role); + this.getTopicMap()._removeRole(role); + }; + + Association.prototype.remove = function () { + var i; + for (i = 0; i < this.scope.length; i += 1) { + this.parnt.removeThemeEvent.fire(this, {theme: this.scope[i]}); + } + this.parnt.removeAssociationEvent.fire(this); + while (this.roles.length) { + this.roles[0].remove(); + } + this.id = null; + this.roles = null; + this.parnt._removeAssociation(this); + this.getTopicMap()._ii2construct.remove(this.id); + this.item_identifiers = null; + this.scope = null; + this.type = null; + this.reifier = null; + return this.parnt; + }; + + /** + * Returns the roles participating in this association, or, if type + * is given, all roles with the specified type. + * @throws {IllegalArgumentException} If type is null. + */ + Association.prototype.getRoles = function (type) { + if (type === null) { + throw {name: 'IllegalArgumentException', + message: 'Topic.getRoles cannot be called with type null'}; + } + if (!type) { + return this.roles; + } + var ret = [], i; + for (i = 0; i < this.roles.length; i += 1) { + if (this.roles[i].getType().equals(type)) { + ret.push(this.roles[i]); + } + } + return ret; + }; + + /** + * Returns the role types participating in this association. + */ + Association.prototype.getRoleTypes = function () { + // Create a hash with the object ids as keys to avoid duplicates + var types = {}, typearr = [], i, t; + for (i = 0; i < this.roles.length; i += 1) { + types[this.roles[i].getType().getId()] = + this.roles[i].getType(); + } + for (t in types) { + if (types.hasOwnProperty(t)) { + typearr.push(types[t]); + } + } + return typearr; + }; + + // ------ ---------------------------------------------------------------- + /** @class */ + Index = function () { + this.opened = false; + }; + + /** + * Close the index. + */ + Index.prototype.close = function () { + return; + }; + + /** + * Indicates whether the index is updated automatically. + * @returns {boolean} + */ + Index.prototype.isAutoUpdated = function () { + return true; + }; + + /** Indicates if the index is open. + * @returns {boolean} true if index is already opened, false otherwise. + */ + Index.prototype.isOpen = function () { + return this.opened; + }; + + /** + * Opens the index. This method must be invoked before using any other + * method (aside from isOpen()) exported by this interface or derived + * interfaces. + */ + Index.prototype.open = function () { + this.opened = true; + }; + + /** + * Synchronizes the index with data in the topic map. + */ + Index.prototype.reindex = function () { + return; + }; + + /** + * Creates a new instance of TypeInstanceIndex. + * @class Implementation of the TypeInstanceIndex interface. + */ + TypeInstanceIndex = function (tm) { + var eventHandler, that = this; + this.tm = tm; + // we use hash tables of hash tables for our index + this.type2topics = new Hash(); + this.type2associations = new Hash(); + this.type2roles = new Hash(); + this.type2occurrences = new Hash(); + this.type2names = new Hash(); + this.type2variants = new Hash(); + this.opened = false; + + eventHandler = function (eventtype, source, obj) { + var existing, untyped, types, type, i; + switch (eventtype) { + case EventType.ADD_ASSOCIATION: + break; + case EventType.ADD_NAME: + existing = that.type2names.get(obj.type.getId()); + if (typeof existing === 'undefined') { + existing = new Hash(); + } + existing.put(source.getId(), source); + that.type2names.put(obj.type.getId(), existing); + break; + case EventType.ADD_OCCURRENCE: + existing = that.type2occurrences.get(obj.type.getId()); + if (typeof existing === 'undefined') { + existing = new Hash(); + } + existing.put(source.getId(), source); + that.type2occurrences.put(obj.type.getId(), existing); + break; + case EventType.ADD_ROLE: + existing = that.type2roles.get(obj.type.getId()); + if (typeof existing === 'undefined') { + existing = new Hash(); + } + existing.put(source.getId(), source); + that.type2roles.put(obj.type.getId(), existing); + break; + case EventType.ADD_TOPIC: + existing = that.type2topics.get('null'); + if (typeof existing === 'undefined') { + existing = new Hash(); + } + existing.put(source.getId(), source); + that.type2topics.put('null', existing); + break; + case EventType.ADD_TYPE: + // check if source exists with type null, remove it there + untyped = that.type2topics.get('null'); + if (untyped && untyped.get(source.getId())) { + untyped.remove(source.getId()); + that.type2topics.put('null', untyped); + } + + existing = that.type2topics.get(obj.type.getId()); + if (typeof existing === 'undefined') { + existing = new Hash(); + } + existing.put(source.getId(), source); + that.type2topics.put(obj.type.getId(), existing); + break; + case EventType.REMOVE_ASSOCIATION: + type = source.getType(); + if (!type) { + break; + } + existing = that.type2associations.get(type.getId()); + for (i = 0; i < existing.length; i += 1) { + if (existing[i].equals(source)) { + existing.splice(i, 1); + break; + } + } + if (existing.length > 0) { + that.type2associations.put(type.getId(), + existing); + } else { + that.type2associations.remove(type.getId()); + } + break; + case EventType.REMOVE_NAME: + type = source.getType(); + existing = that.type2names.get(type.getId()); + existing.remove(source.getId()); + if (existing.length > 0) { + that.type2names.put(type.getId(), existing); + } else { + that.type2names.remove(type.getId()); + } + break; + case EventType.REMOVE_OCCURRENCE: + type = source.getType(); + existing = that.type2occurrences.get(type.getId()); + existing.remove(source.getId()); + if (existing.length > 0) { + that.type2occurrences.put(type.getId(), existing); + } else { + that.type2occurrences.remove(type.getId()); + } + break; + case EventType.REMOVE_ROLE: + type = source.getType(); + existing = that.type2roles.get(type.getId()); + existing.remove(source.getId()); + if (existing.length > 0) { + that.type2roles.put(type.getId(), existing); + } else { + that.type2roles.remove(type.getId()); + } + break; + case EventType.REMOVE_TOPIC: + // two cases: + // topic has types + types = source.getTypes(); + for (i = 0; i < types.length; i += 1) { + existing = that.type2topics.get(types[i].getId()); + existing.remove(source.getId()); + if (!existing.size()) { + that.type2topics.remove(types[i].getId()); + } + } + // topic used as type + that.type2topics.remove(source.getId()); + that.type2associations.remove(source.getId()); + that.type2roles.remove(source.getId()); + that.type2occurrences.remove(source.getId()); + that.type2variants.remove(source.getId()); + break; + case EventType.REMOVE_TYPE: + existing = that.type2topics.get(obj.type.getId()); + existing.remove(source.getId()); + if (!existing.size()) { + that.type2topics.remove(obj.type.getId()); + } + if (source.getTypes().length === 0) { + untyped = that.type2topics.get('null'); + if (typeof untyped === 'undefined') { + untyped = new Hash(); + } + untyped.put(source.getId(), source); + } + break; + case EventType.SET_TYPE: + if (source.isAssociation()) { + // remove source from type2associations(obj.old.getId()); + if (obj.old) { + existing = that.type2associations.get(obj.old.getId()); + for (i = 0; i < existing.length; i += 1) { + if (existing[i].equals(source)) { + existing.splice(i, 1); + break; + } + } + if (existing.length > 0) { + that.type2associations.put(obj.old.getId(), + existing); + } else { + that.type2associations.remove(obj.old.getId()); + } + } + existing = that.type2associations.get(obj.type.getId()); + if (typeof existing === 'undefined') { + existing = []; + } + existing.push(source); + that.type2associations.put(obj.type.getId(), existing); + } else if (source.isName()) { + existing = that.type2names.get(obj.old.getId()); + if (existing) { + existing.remove(source.getId()); + if (existing.length > 0) { + that.type2names.put(obj.old.getId(), existing); + } else { + that.type2names.remove(obj.old.getId()); + } + } + existing = that.type2names.get(obj.type.getId()); + if (typeof existing === 'undefined') { + existing = new Hash(); + } + existing.put(source.getId(), source); + that.type2names.put(obj.type.getId(), existing); + } else if (source.isOccurrence()) { + existing = that.type2occurrences.get(obj.old.getId()); + if (existing) { + existing.remove(source.getId()); + if (existing.length > 0) { + that.type2occurrences.put(obj.old.getId(), existing); + } else { + that.type2occurrences.remove(obj.old.getId()); + } + } + existing = that.type2occurrences.get(obj.type.getId()); + if (typeof existing === 'undefined') { + existing = new Hash(); + } + existing.put(source.getId(), source); + that.type2occurrences.put(obj.type.getId(), existing); + } else if (source.isRole()) { + existing = that.type2roles.get(obj.old.getId()); + if (existing) { + existing.remove(source.getId()); + if (existing.length > 0) { + that.type2roles.put(obj.old.getId(), existing); + } else { + that.type2roles.remove(obj.old.getId()); + } + } + existing = that.type2roles.get(obj.type.getId()); + if (typeof existing === 'undefined') { + existing = new Hash(); + } + existing.put(source.getId(), source); + that.type2roles.put(obj.type.getId(), existing); + } + break; + } + }; + tm.addAssociationEvent.registerHandler(eventHandler); + tm.addNameEvent.registerHandler(eventHandler); + tm.addOccurrenceEvent.registerHandler(eventHandler); + tm.addRoleEvent.registerHandler(eventHandler); + tm.addTopicEvent.registerHandler(eventHandler); + tm.addTypeEvent.registerHandler(eventHandler); + tm.removeAssociationEvent.registerHandler(eventHandler); + tm.removeNameEvent.registerHandler(eventHandler); + tm.removeOccurrenceEvent.registerHandler(eventHandler); + tm.removeRoleEvent.registerHandler(eventHandler); + tm.removeTopicEvent.registerHandler(eventHandler); + tm.removeTypeEvent.registerHandler(eventHandler); + tm.setTypeEvent.registerHandler(eventHandler); + }; + + TypeInstanceIndex.swiss(Index, 'close', 'isAutoUpdated', + 'isOpen', 'open', 'reindex'); + + /** + * Returns the associations in the topic map whose type property equals type. + * + * @param {Topic} type + * @returns {Array} A list of all associations in the topic map with the given type. + */ + TypeInstanceIndex.prototype.getAssociations = function (type) { + var ret = this.type2associations.get(type.getId()); + if (!ret) { + return []; + } + return ret; + }; + + /** + * Returns the topics in the topic map used in the type property of Associations. + * + * @returns {Array} A list of all topics that are used as an association type. + */ + TypeInstanceIndex.prototype.getAssociationTypes = function () { + var ret = [], keys = this.type2associations.keys(), i; + for (i = 0; i < keys.length; i += 1) { + ret.push(this.tm.getConstructById(keys[i])); + } + return ret; + }; + + /** + * Returns the topic names in the topic map whose type property equals type. + * + * @param {Topic} type + * @returns {Array} + */ + TypeInstanceIndex.prototype.getNames = function (type) { + var ret = this.type2names.get(type.getId()); + if (!ret) { + return []; + } + return ret.values(); + }; + + /** + * Returns the topics in the topic map used in the type property of Names. + * + * @returns {Array} An array of topic types. Note that the array contains + * a reference to the actual topics, not copies of them. + */ + TypeInstanceIndex.prototype.getNameTypes = function () { + var ret = [], keys = this.type2names.keys(), i; + for (i = 0; i < keys.length; i += 1) { + ret.push(this.tm.getConstructById(keys[i])); + } + return ret; + }; + + /** + * Returns the occurrences in the topic map whose type property equals type. + * + * @returns {Array} + */ + TypeInstanceIndex.prototype.getOccurrences = function (type) { + var ret = this.type2occurrences.get(type.getId()); + if (!ret) { + return []; + } + return ret.values(); + }; + + /** + * Returns the topics in the topic map used in the type property of + * Occurrences. + * + * @returns {Array} An array of topic types. Note that the array contains + * a reference to the actual topics, not copies of them. + */ + TypeInstanceIndex.prototype.getOccurrenceTypes = function () { + var ret = [], keys = this.type2occurrences.keys(), i; + for (i = 0; i < keys.length; i += 1) { + ret.push(this.tm.getConstructById(keys[i])); + } + return ret; + }; + + + /** + * Returns the roles in the topic map whose type property equals type. + * + * @returns {Array} + */ + TypeInstanceIndex.prototype.getRoles = function (type) { + var ret = this.type2roles.get(type.getId()); + if (!ret) { + return []; + } + return ret.values(); + }; + + /** + * Returns the topics in the topic map used in the type property of Roles. + * + * @returns {Array} An array of topic types. Note that the array contains + * a reference to the actual topics, not copies of them. + */ + TypeInstanceIndex.prototype.getRoleTypes = function () { + var ret = [], keys = this.type2roles.keys(), i; + for (i = 0; i < keys.length; i += 1) { + ret.push(this.tm.getConstructById(keys[i])); + } + return ret; + }; + + /** + * Returns the topics which are an instance of the specified type. + */ + TypeInstanceIndex.prototype.getTopics = function (type) { + var ret = this.type2topics.get((type ? type.getId() : 'null')); + if (!ret) { + return []; + } + return ret.values(); + }; + + /** + * Returns the topics which are an instance of the specified types. + * If matchall is true only topics that have all of the listed types + * are returned. + * @returns {Array} A list of Topic objects + */ + TypeInstanceIndex.prototype.getTopicsByTypes = function (types, matchall) { + var instances, i, j; + instances = IndexHelper.getForKeys(this.type2topics, types); + if (!matchall) { + return instances; + } + // If matchall is true, we check all values for all types in {types} + // It's a hack, but will do for now + for (i = 0; i < instances.length; i += 1) { + for (j = 0; j < types.length; j += 1) { + if (!ArrayHelper.contains(instances[i].getTypes(), types[j])) { + instances.splice(i, 1); + i -= 1; + break; + } + } + } + return instances; + }; + + /** + * Returns the topics in topic map which are used as type in an + * "type-instance"-relationship. + */ + TypeInstanceIndex.prototype.getTopicTypes = function () { + var ret = [], keys = this.type2topics.keys(), i; + for (i = 0; i < keys.length; i += 1) { + if (keys[i] !== 'null') { + ret.push(this.tm.getConstructById(keys[i])); + } + } + return ret; + }; + + TypeInstanceIndex.prototype.close = function () { + return; + }; + + + /** + * Index for Scoped statements and their scope. This index provides access + * to Associations, Occurrences, Names, and Variants by their scope + * property and to Topics which are used as theme in a scope. + */ + ScopedIndex = function (tm) { + var that = this, eventHandler; + this.tm = tm; + this.theme2associations = new Hash(); + this.theme2names = new Hash(); + this.theme2occurrences = new Hash(); + this.theme2variants = new Hash(); + eventHandler = function (eventtype, source, obj) { + var existing, key, unscoped, remove_from_index, add_to_index; + add_to_index = function (hash, source, obj) { + key = (obj.theme ? obj.theme.getId() : 'null'); + + // check if source exists with theme null, remove it there + // this is the case iff source now has one scoping topic + if (source.getScope().length === 1) { + unscoped = hash.get('null'); + if (unscoped && unscoped.get(source.getId())) { + unscoped.remove(source.getId()); + hash.put('null', unscoped); + } + } + existing = hash.get(key); + if (typeof existing === 'undefined') { + existing = new Hash(); + } + existing.put(source.getId(), source); + hash.put(key, existing); + }; + remove_from_index = function (hash, source, obj) { + key = obj.theme.getId(); + existing = hash.get(key); + if (typeof existing !== 'undefined') { + existing.remove(source.getId()); + if (!existing.size()) { + hash.remove(key); + } + } + }; + switch (eventtype) { + case EventType.ADD_THEME: + if (source.isAssociation()) { + add_to_index(that.theme2associations, source, obj); + } else if (source.isName()) { + add_to_index(that.theme2names, source, obj); + } else if (source.isOccurrence()) { + add_to_index(that.theme2occurrences, source, obj); + } else if (source.isVariant()) { + add_to_index(that.theme2variants, source, obj); + } + break; + case EventType.REMOVE_THEME: + if (source.isAssociation()) { + remove_from_index(that.theme2associations, source, obj); + } else if (source.isName()) { + remove_from_index(that.theme2names, source, obj); + } else if (source.isOccurrence()) { + remove_from_index(that.theme2occurrences, source, obj); + } else if (source.isVariant()) { + remove_from_index(that.theme2variants, source, obj); + } + break; + } + }; + tm.addThemeEvent.registerHandler(eventHandler); + tm.removeThemeEvent.registerHandler(eventHandler); + }; + + ScopedIndex.swiss(Index, 'close', 'isAutoUpdated', + 'isOpen', 'open', 'reindex'); + + ScopedIndex.prototype.close = function () { + return; + }; + + /** + * Returns the Associations in the topic map whose scope property contains + * the specified theme. The return value may be empty but must never be null. + * @param theme can be array or {Topic} + * @param [matchall] boolean + */ + ScopedIndex.prototype.getAssociations = function (theme) { + var ret = this.theme2associations.get((theme ? theme.getId() : 'null')); + if (!ret) { + return []; + } + return ret.values(); + }; + + /** + * Returns the Associations in the topic map whose scope property contains + * the specified theme. The return value may be empty but must never be null. + * @param theme can be array or {Topic} + * @param [matchall] boolean + * @throws {IllegalArgumentException} If themes is null. + */ + ScopedIndex.prototype.getAssociationsByThemes = function (themes, matchall) { + if (themes === null) { + throw {name: 'IllegalArgumentException', + message: 'ScopedIndex.getAssociationsByThemes cannot be called without themes'}; + } + return IndexHelper.getConstructsByThemes(this.theme2associations, + themes, matchall); + }; + + /** + * Returns the topics in the topic map used in the scope property of + * Associations. + */ + ScopedIndex.prototype.getAssociationThemes = function () { + return IndexHelper.getConstructThemes(this.tm, this.theme2associations); + }; + + /** + * Returns the Names in the topic map whose scope property contains the + * specified theme. + */ + ScopedIndex.prototype.getNames = function (theme) { + var ret = this.theme2names.get((theme ? theme.getId() : 'null')); + if (!ret) { + return []; + } + return ret.values(); + }; + + /** + * Returns the Names in the topic map whose scope property equals one of + * those themes at least. + * @throws {IllegalArgumentException} If themes is null. + */ + ScopedIndex.prototype.getNamesByThemes = function (themes, matchall) { + if (themes === null) { + throw {name: 'IllegalArgumentException', + message: 'ScopedIndex.getNamesByThemes cannot be called without themes'}; + } + return IndexHelper.getConstructsByThemes(this.theme2names, + themes, matchall); + }; + + /** + * Returns the topics in the topic map used in the scope property of Names. + */ + ScopedIndex.prototype.getNameThemes = function () { + return IndexHelper.getConstructThemes(this.tm, this.theme2names); + }; + + /** + * Returns the Occurrences in the topic map whose scope property contains the + * specified theme. + */ + ScopedIndex.prototype.getOccurrences = function (theme) { + var ret = this.theme2occurrences.get((theme ? theme.getId() : 'null')); + if (!ret) { + return []; + } + return ret.values(); + }; + + /** + * Returns the Occurrences in the topic map whose scope property equals one + * of those themes at least. + * @throws {IllegalArgumentException} If themes is null. + */ + ScopedIndex.prototype.getOccurrencesByThemes = function (themes, matchall) { + if (themes === null) { + throw {name: 'IllegalArgumentException', + message: 'ScopedIndex.getOccurrencesByThemes cannot be called without themes'}; + } + return IndexHelper.getConstructsByThemes(this.theme2occurrences, + themes, matchall); + }; + + /** + * Returns the topics in the topic map used in the scope property of + * Occurrences. + */ + ScopedIndex.prototype.getOccurrenceThemes = function () { + return IndexHelper.getConstructThemes(this.tm, this.theme2occurrences); + }; + + /** + * Returns the Variants in the topic map whose scope property contains the + * specified theme. The return value may be empty but must never be null. + * @param {Topic} The Topic which must be part of the scope. This must not be + * null. + * @returns {Array} An array of Variants. + * @throws {IllegalArgumentException} If theme is null. + */ + ScopedIndex.prototype.getVariants = function (theme) { + if (theme === null) { + throw {name: 'IllegalArgumentException', + message: 'ScopedIndex.getVariants cannot be called without themes'}; + } + var ret = this.theme2variants.get((theme ? theme.getId() : 'null')); + if (!ret) { + return []; + } + return ret.values(); + }; + + /** + * Returns the Variants in the topic map whose scope property equals one of + * those themes at least. + * @param {Array} themes Scope of the Variants to be returned. + * @param {boolean} If true the scope property of a variant must match all + * themes, if false one theme must be matched at least. + * @returns {Array} An array of variants + * @throws {IllegalArgumentException} If themes is null. + */ + ScopedIndex.prototype.getVariantsByThemes = function (themes, matchall) { + if (themes === null) { + throw {name: 'IllegalArgumentException', + message: 'ScopedIndex.getVariantsByThemes cannot be called without themes'}; + } + return IndexHelper.getConstructsByThemes(this.theme2variants, + themes, matchall); + }; + + /** + * Returns the topics in the topic map used in the scope property of Variants. + * The return value may be empty but must never be null. + * @returns {Array} An array of Topics. + */ + ScopedIndex.prototype.getVariantThemes = function () { + return IndexHelper.getConstructThemes(this.tm, this.theme2variants); + }; + + + + + /** + * @class Helper class that is used to check if constructs belong to + * a given topic map. + */ + SameTopicMapHelper = { + /** + * Checks if topic belongs to the topicmap 'topicmap'. + * topic can be instance of Topic or an Array with topics. + * topic map be null. + * @static + * @throws ModelConstraintException if the topic(s) don't + * belong to the same topic map. + * @returns false if the topic was null or true otherwise. + */ + assertBelongsTo: function (topicmap, topic) { + var i; + if (!topic) { + return false; + } + if (topic && topic instanceof Topic && + !topicmap.equals(topic.getTopicMap())) { + throw {name: 'ModelConstraintException', + message: 'scope topic belongs to different topic map'}; + } + if (topic && topic instanceof Array) { + for (i = 0; i < topic.length; i += 1) { + if (!topicmap.equals(topic[i].getTopicMap())) { + throw {name: 'ModelConstraintException', + message: 'scope topic belong to different topic maps'}; + } + } + } + return true; + } + }; + + /** + * Helper functions for hashes of hashes + * @ignore + */ + IndexHelper = { + getForKeys: function (hash, keys) { + var i, j, tmp = new Hash(), value_hash, value_keys; + for (i = 0; i < keys.length; i += 1) { + value_hash = hash.get(keys[i].getId()); + if (value_hash) { + value_keys = value_hash.keys(); + // we use a hash to store instances to avoid duplicates + for (j = 0; j < value_keys.length; j += 1) { + tmp.put(value_hash.get(value_keys[j]).getId(), + value_hash.get(value_keys[j])); + } + } + } + return tmp.values(); + }, + + getConstructThemes: function (tm, hash) { + var ret = [], keys = hash.keys(), i; + for (i = 0; i < keys.length; i += 1) { + if (keys[i] !== 'null') { + ret.push(tm.getConstructById(keys[i])); + } + } + return ret; + }, + + getConstructsByThemes: function (hash, themes, matchall) { + var constructs, i, j; + constructs = IndexHelper.getForKeys(hash, themes); + if (!matchall) { + return constructs; + } + // If matchall is true, we check all values for all types in {types} + // It's a hack, but will do for now + for (i = 0; i < constructs.length; i += 1) { + for (j = 0; j < themes.length; j += 1) { + if (!ArrayHelper.contains(constructs[i].getScope(), themes[j])) { + constructs.splice(i, 1); + i -= 1; + break; + } + } + } + return constructs; + } + }; + + /** + * Helper functions for arrays. We don't modify the global array + * object to avoid conflicts with other libraries. + * @ignore + */ + ArrayHelper = { + /** Checks if arr contains elem */ + contains: function (arr, elem) { + for (var key in arr) { + if (arr.hasOwnProperty(key)) { + if (arr[key].equals(elem)) { + return true; + } + } + } + return false; + } + }; + + /** + * Internal function to add scope. scope may be Array, Topic or null. + * @ignore + * FIXME: Move to a class + */ + addScope = function (construct, scope) { + var i; + if (scope && typeof scope === 'object') { + if (scope instanceof Array) { + for (i = 0; i < scope.length; i += 1) { + construct.addTheme(scope[i]); + } + } else if (scope instanceof Topic) { + construct.addTheme(scope); + } + } else { + construct.getTopicMap().addThemeEvent.fire(construct, {theme: null}); + } + }; + + /** + * Helper class for generating signatures of Topic Maps constructs. + */ + SignatureGenerator = { + makeNameValueSignature: function (name) { + return name.getValue(); + }, + + makeNameSignature: function (name) { + return SignatureGenerator.makeNameValueSignature(name) + + '#' + SignatureGenerator.makeTypeSignature(name) + + '#' + SignatureGenerator.makeScopeSignature(name); + }, + + makeOccurrenceSignature: function (occ) { + return SignatureGenerator.makeOccurrenceValueSignature(occ) + + '#' + SignatureGenerator.makeTypeSignature(occ) + + '#' + SignatureGenerator.makeScopeSignature(occ); + }, + + makeOccurrenceValueSignature: function (occ) { + return '#' + occ.getValue() + '#' + + (occ.getDatatype() ? occ.getDatatype().getReference() : 'null'); + }, + + makeTypeSignature: function (obj) { + var type = obj.getType(); + if (type) { + return type.getId(); + } else { + return ''; + } + }, + + makeScopeSignature: function (scope) { + var i, arr = []; + for (i = 0; i < scope.length; i += 1) { + arr.push(scope[i].getId()); + } + arr.sort(); + return arr.join('#'); + }, + + makeAssociationSignature: function (ass) { + var roles, i, tmp = []; + roles = ass.getRoles(); + for (i = 0; i < roles.length; i += 1) { + tmp.push(SignatureGenerator.makeRoleSignature(roles[i])); + } + tmp.sort(); + + return '#' + SignatureGenerator.makeTypeSignature(ass) + '#' + tmp.join('#') + + SignatureGenerator.makeScopeSignature(ass); + }, + + makeRoleSignature: function (role) { + return SignatureGenerator.makeTypeSignature(role) + '#' + + role.getPlayer().getId(); + }, + + makeVariantValueSignature: function (variant) { + return '#' + variant.getValue() + '#' + variant.getDatatype().getReference(); + }, + + makeVariantSignature: function (variant) { + return SignatureGenerator.makeVariantValueSignature(variant) + + '#' + SignatureGenerator.makeScopeSignature(variant); + } + }; + + /** + * Utility class that removes duplicates according to the TMDM. + */ + DuplicateRemover = { + removeTopicMapDuplicates: function (tm) { + var i, topics, associations, sig2ass = new Hash(), sig, existing; + topics = tm.getTopics(); + for (i = 0; i < topics.length; i += 1) { + DuplicateRemover.removeOccurrencesDuplicates(topics[i].getOccurrences()); + DuplicateRemover.removeNamesDuplicates(topics[i].getNames()); + } + associations = tm.getAssociations(); + for (i = 0; i < associations.length; i += 1) { + DuplicateRemover.removeAssociationDuplicates(associations[i]); + sig = SignatureGenerator.makeAssociationSignature(associations[i]); + if ((existing = sig2ass.get(sig))) { + MergeHelper.moveConstructCharacteristics(associations[i], existing); + MergeHelper.moveRoleCharacteristics(associations[i], existing); + associations[i].remove(); + } else { + sig2ass.put(sig, associations[i]); + } + } + sig2ass.empty(); + }, + + removeOccurrencesDuplicates: function (occurrences) { + var i, sig2occ = new Hash(), occ, sig, existing; + for (i = 0; i < occurrences.length; i += 1) { + occ = occurrences[i]; + sig = SignatureGenerator.makeOccurrenceSignature(occ); + if ((existing = sig2occ.get(sig))) { + MergeHelper.moveConstructCharacteristics(occ, existing); + occ.remove(); + } else { + sig2occ.put(sig, occ); + } + } + sig2occ.empty(); + }, + + removeNamesDuplicates: function (names) { + var i, sig2names = new Hash(), name, sig, existing; + for (i = 0; i < names.length; i += 1) { + name = names[i]; + DuplicateRemover.removeVariantsDuplicates(name.getVariants()); + sig = SignatureGenerator.makeNameSignature(name); + if ((existing = sig2names.get(sig))) { + MergeHelper.moveConstructCharacteristics(name, existing); + MergeHelper.moveVariants(name, existing); + name.remove(); + } else { + sig2names.put(sig, name); + } + } + sig2names.empty(); + }, + + removeVariantsDuplicates: function (variants) { + var i, sig2variants = new Hash(), variant, sig, existing; + for (i = 0; i < variants.length; i += 1) { + variant = variants[i]; + sig = SignatureGenerator.makeVariantSignature(variant); + if ((existing = sig2variants.get(sig))) { + MergeHelper.moveConstructCharacteristics(variant, existing); + variant.remove(); + } else { + sig2variants.put(sig, variant); + } + } + sig2variants.empty(); + }, + + removeAssociationDuplicates: function (assoc) { + var i, roles = assoc.getRoles(), sig2role = new Hash(), sig, existing; + for (i = 0; i < roles.length; i += 1) { + sig = SignatureGenerator.makeRoleSignature(roles[i]); + if ((existing = sig2role.get(sig))) { + MergeHelper.moveConstructCharacteristics(roles[i], existing); + roles[i].remove(); + } else { + sig2role.put(sig, roles[i]); + } + } + } + }; + + MergeHelper = { + moveTypes: function (arr, target) { + var i; + for (i = 0; i < arr.length; i += 1) { + arr[i].setType(target); + } + }, + + moveThemes: function (arr, source, target) { + for (var i = 0; i < arr.length; i += 1) { + arr[i].removeTheme(source); + arr[i].addTheme(target); + } + }, + + moveItemIdentifiers: function (source, target) { + var iis, ii; + iis = source.getItemIdentifiers(); + while (iis.length) { + ii = iis[iis.length - 1]; + source.removeItemIdentifier(ii); + target.addItemIdentifier(ii); + } + }, + + /** + * Moves variants from the name source to the name target + */ + moveVariants: function (source, target) { + var arr, i, tmp, tmp2, signatures; + arr = target.getVariants(); + signatures = {}; + for (i = 0; i < arr.length; i += 1) { + signatures[SignatureGenerator.makeVariantSignature(arr[i])] = arr[i]; + } + arr = source.getVariants(); + for (i = 0; i < arr.length; i += 1) { + tmp = arr[i]; + if ((tmp2 = signatures[SignatureGenerator.makeVariantSignature(arr[i])])) { + MergeHelper.moveItemIdentifiers(tmp, tmp2); + MergeHelper.moveReifier(tmp, tmp2); + tmp.remove(); + } else { + target.createVariant(tmp.getValue(), tmp.getDatatype(), tmp.getScope()); + } + } + }, + + moveReifier: function (source, target) { + var r1, r2; + if (source.getReifier() === null) { + return; + } else if (target.getReifier() === null) { + target.setReifier(source.getReifier()); + } else { + r1 = source.getReifier(); + r2 = target.getReifier(); + source.setReifier(null); + r1.mergeIn(r2); + } + }, + + moveRoleCharacteristics: function (source, target) { + var i, roles, sigs = new Hash(); + roles = target.getRoles(); + for (i = 0; i < roles.length; i += 1) { + sigs.put(roles[i], SignatureGenerator.makeRoleSignature(roles[i])); + } + roles = source.getRoles(); + for (i = 0; i < roles.length; i += 1) { + MergeHelper.moveItemIdentifiers(roles[i], + sigs.get(SignatureGenerator.makeRoleSignature(roles[i]))); + roles[i].remove(); + } + }, + + moveConstructCharacteristics: function (source, target) { + MergeHelper.moveReifier(source, target); + MergeHelper.moveItemIdentifiers(source, target); + } + }; + + CopyHelper = { + copyAssociations: function (source, target, mergeMap) { + }, + copyItemIdentifiers: function (source, target) { + }, + copyReifier: function (source, target, mergeMap) { + }, + copyScope: function (source, target, mergeMap) { + }, + copyTopicMap: function (source, target) { + }, + copyTopic: function (sourcetm, targettm, mergeMap) { + }, + copyType: function (source, target, mergeMap) { + } + }; + + TypeInstanceHelper = { + convertAssociationsToType: function (tm) { + var typeInstance, type, instance, associations, index, i, ass, roles; + typeInstance = tm.getTopicBySubjectIdentifier( + tm.createLocator(TMDM.TYPE_INSTANCE)); + type = tm.getTopicBySubjectIdentifier( + tm.createLocator(TMDM.TYPE)); + instance = tm.getTopicBySubjectIdentifier( + tm.createLocator(TMDM.INSTANCE)); + if (!typeInstance || !type || !instance) { + return; + } + index = tm.getIndex('TypeInstanceIndex'); + if (!index) { + return; + } + if (!index.isAutoUpdated()) { + index.reindex(); + } + associations = index.getAssociations(typeInstance); + for (i = 0; i < associations.length; i += 1) { + ass = associations[i]; + if (ass.getScope().length > 0 || + ass.getReifier() !== null || + ass.getItemIdentifiers().length > 0) { + continue; + } + roles = ass.getRoles(); + if (roles.length !== 2) { + continue; + } + if (roles[0].getType().equals(type) && roles[1].getType().equals(instance)) { + roles[1].getPlayer().addType(roles[0].getPlayer()); + } else + if (roles[1].getType().equals(type) && roles[0].getType().equals(instance)) { + roles[0].getPlayer().addType(roles[1].getPlayer()); + } else { + continue; + } + ass.remove(); + } + } + }; + + // Export objects into the TM namespace + return { + TopicMapSystemFactory: TopicMapSystemFactory, + XSD: XSD, + TMDM: TMDM, + Hash: Hash, // needed by CXTM export + Version: Version + }; +}()); + +// Pollute the global namespace +TopicMapSystemFactory = TM.TopicMapSystemFactory; + +// Check if we are in a CommonJS environment (e.g. node.js) +if (typeof exports === 'object' && exports !== null) { + exports.TopicMapSystemFactory = TopicMapSystemFactory; + exports.TM = TM; +} + +/*jslint browser: true, devel: true, onevar: true, undef: true, nomen: false, eqeqeq: true, plusplus: true, bitwise: true, + regexp: true, newcap: true, immed: true, indent: 4 */ +/*global TM, window, DOMParser, ActiveXObject*/ + +TM.JTM = (function () { + var ReaderImpl, WriterImpl; + + ReaderImpl = function (tm) { + var that = this; + this.tm = tm; + this.version = null; // Keep the JTM version number + this.prefixes = {}; + this.defaultDatatype = this.tm.createLocator(TM.XSD.string); + + this.curieToLocator = function (loc) { + var curie, prefix, pos; + if (that.version === '1.1' && + loc.substr(0, 1) === '[') { + if (loc.substr(loc.length - 1, 1) !== ']') { + throw {name: 'InvalidFormat', + message: 'Invaild CURIE: missing tailing bracket'}; + } + curie = loc.substr(1, loc.length - 2); + pos = curie.indexOf(':'); + if (pos !== -1) { + // Lookup prefix and replace with URL + prefix = curie.substr(0, pos); + if (that.prefixes[prefix]) { + loc = that.prefixes[prefix] + + curie.substr(pos + 1, curie.length - 1); + return loc; + } else { + throw {name: 'InvalidFormat', + message: 'Missing prefix declaration: ' + prefix}; + } + } else { + throw {name: 'InvalidFormat', + message: 'Invaild CURIE: missing colon'}; + } + } + return loc; + }; + + /** + * Internal function that takes a JTM-identifier string as a parameter + * and returns a topic object - either an existing topic or a new topic + * if the requested topic did not exist + * @param {String} locator JTM-identifier + * @throws {InvalidFormat} If the locator could not be parsed. + */ + this.getTopicByReference = function (locator) { + if (typeof locator === 'undefined' || locator === null) { + return null; + } + switch (locator.substr(0, 3)) { + case 'si:' : + return this.tm.createTopicBySubjectIdentifier( + this.tm.createLocator(this.curieToLocator(locator.substr(3)))); + case 'sl:' : + return this.tm.createTopicBySubjectLocator( + this.tm.createLocator(this.curieToLocator(locator.substr(3)))); + case 'ii:' : + return this.tm.createTopicByItemIdentifier( + this.tm.createLocator(this.curieToLocator(locator.substr(3)))); + } + throw {name: 'InvalidFormat', + message: 'Invaild topic reference '' + locator + '''}; + }; + }; + + /** + * Imports a JTM topic map or JTM fragment from a JSON-string. + * name, variant, occurrence and role fragments need the optional parent + * construct as a parameter. + * TODO: Decide if this should be part of tmjs. Add functions for decoding/ + * encoding JSON if so. + * + * @param {String} str JSON encoded JTM + * @param {Construct} [parent] Parent construct if the JTM fragment contains + * a name, variant, occurrence or role. + */ + ReaderImpl.prototype.fromString = function (str, parent) { + var obj = JSON.parse(str); + return this.fromObject(obj); + }; + + /** + * Imports a JTM topic map or JTM fragment. + * name, variant, occurrence and role fragments need the parent construct + * as a parameter. + * + * @param {object} obj with JTM properties + * @param {Construct} [parent] Parent construct if the JTM fragment contains + * a name, variant, occurrence or role. + */ + ReaderImpl.prototype.fromObject = function (obj, parent) { + var ret; + parent = parent || null; + if (obj.version !== '1.0' && obj.version !== '1.1') { + throw {name: 'InvalidFormat', + message: 'Unknown version of JTM: ' + obj.version}; + } + this.version = obj.version; + if (obj.version === '1.1' && obj.prefixes) { + this.prefixes = obj.prefixes; + // Check if xsd is defined and if it is valid: + if (obj.prefixes && obj.prefixes.xsd && + obj.prefixes.xsd !== 'http://www.w3.org/2001/XMLSchema#') { + throw {name: 'InvalidFormat', + message: 'The XSD prefix MUST have the value "http://www.w3.org/2001/XMLSchema#%22%27%7D; + } + } else if (obj.prefixes) { + throw {name: 'InvalidFormat', + message: 'Prefixes are invalid in JTM 1.0: ' + obj.version}; + } + if (!this.prefixes.xsd) { + this.prefixes.xsd = 'http://www.w3.org/2001/XMLSchema#'; + } + if (!obj.item_type) { + throw {name: 'InvalidFormat', + message: 'Missing item_type'}; + } + switch (obj.item_type.toLowerCase()) { + case "topicmap": + ret = this.parseTopicMap(obj); + break; + case "topic": + ret = this.parseTopic(obj); + break; + case "name": + ret = this.parseName(parent, obj); + break; + case "variant": + ret = this.parseVariant(parent, obj); + break; + case "occurrence": + ret = this.parseOccurrence(parent, obj); + break; + case "association": + ret = this.parseAssociation(obj); + break; + case "role": + ret = this.parseRole(parent, obj); + break; + default: + throw {name: 'InvalidFormat', + message: 'Unknown item_type property'}; + } + return ret; + }; + + /** + * FIXME: Work in progress. We have to specify *how* the information + * item can be created. + * + * Internal function that parses a parent field. From the JTM spec: + * "The value of the parent member is an array of item identifiers, + * each prefixed by "ii:". For occurrences and names the parent array + * may as well contain subject identifiers prefixed by "si:" and + * subject locators prefixed by "sl:". + */ + ReaderImpl.prototype.parseParentAsTopic = function (obj, allowTopic) { + var parent = null, tmp, i; + if (!obj.parent) { + parent = this.tm.createTopic(); + } else if (!(obj.parent instanceof Array) || obj.parent.length === 0) { + throw {name: 'InvalidFormat', + message: 'Missing parent topic reference in occurrence'}; + } + if (obj.parent) { + for (i = 0; i < obj.parent.length; i += 1) { + tmp = this.getTopicByReference(obj.parent[i]); + if (!parent) { + parent = tmp; + } else { + parent.mergeIn(tmp); + } + } + } + return parent; + }; + + ReaderImpl.prototype.parseTopicMap = function (obj) { + var i, len, arr; + this.parseItemIdentifiers(this.tm, obj.item_identifiers); + this.parseReifier(this.tm, obj.reifier); + if (obj.topics && typeof obj.topics === 'object' && obj.topics instanceof Array) { + arr = obj.topics; + len = arr.length; + for (i = 0; i < len; i += 1) { + this.parseTopic(arr[i]); + } + arr = null; + } + if (obj.associations && typeof obj.associations === 'object' && + obj.associations instanceof Array) { + arr = obj.associations; + len = arr.length; + for (i = 0; i < len; i += 1) { + this.parseAssociation(arr[i]); + } + arr = null; + } + this.tm.sanitize(); // remove duplicates and convert type-instance associations to types + return true; + }; + + ReaderImpl.prototype.parseTopic = function (obj) { + var that = this, topic = null, parseIdentifier, arr, i, identifier, type; + parseIdentifier = function (tm, topic, arr, getFunc, createFunc, addFunc) { + var i, len, tmp; + if (arr && typeof arr === 'object' && arr instanceof Array) { + len = arr.length; + for (i = 0; i < len; i += 1) { + identifier = decodeURI(that.curieToLocator(arr[i])); + if (!topic) { + topic = createFunc.apply(tm, [tm.createLocator(identifier)]); + } else { + tmp = getFunc.apply(tm, [tm.createLocator(identifier)]); + if (tmp && tmp.isTopic() && !topic.equals(tmp)) { + topic.mergeIn(tmp); + } else if (!(tmp && tmp.isTopic() && topic.equals(tmp))) { + topic[addFunc](tm.createLocator(identifier)); + } + } + } + } + return topic; + }; + topic = parseIdentifier(this.tm, topic, obj.subject_identifiers, + this.tm.getTopicBySubjectIdentifier, + this.tm.createTopicBySubjectIdentifier, 'addSubjectIdentifier'); + topic = parseIdentifier(this.tm, topic, obj.subject_locators, + this.tm.getTopicBySubjectLocator, + this.tm.createTopicBySubjectLocator, 'addSubjectLocator'); + topic = parseIdentifier(this.tm, topic, obj.item_identifiers, + this.tm.getConstructByItemIdentifier, + this.tm.createTopicByItemIdentifier, 'addItemIdentifier'); + + if ((arr = obj.instance_of) && this.version === '1.1') { + for (i = 0; i < arr.length; i += 1) { + type = this.getTopicByReference(arr[i]); + topic.addType(type); + } + } else if (obj.instance_of && this.version === '1.0') { + throw {name: 'InvalidFormat', + message: 'instance_of is invalid in JTM 1.0'}; + } + + arr = obj.names; + if (arr && typeof arr === 'object' && arr instanceof Array) { + for (i = 0; i < arr.length; i += 1) { + this.parseName(topic, arr[i]); + } + } + arr = obj.occurrences; + if (arr && typeof arr === 'object' && arr instanceof Array) { + for (i = 0; i < arr.length; i += 1) { + this.parseOccurrence(topic, arr[i]); + } + } + }; + + ReaderImpl.prototype.parseName = function (parent, obj) { + var name, type, scope, arr, i; + if (!parent) { + parent = this.parseParentAsTopic(obj); + } + scope = this.parseScope(obj.scope); + type = this.getTopicByReference(obj.type); + name = parent.createName(obj.value, type, scope); + arr = obj.variants; + if (arr && typeof arr === 'object' && arr instanceof Array) { + for (i = 0; i < arr.length; i += 1) { + this.parseVariant(name, arr[i]); + } + } + this.parseItemIdentifiers(name, obj.item_identifiers); + this.parseReifier(name, obj.reifier); + }; + + ReaderImpl.prototype.parseVariant = function (parent, obj) { + var variant, scope; + scope = this.parseScope(obj.scope); + variant = parent.createVariant(obj.value, + obj.datatype ? + this.tm.createLocator(this.curieToLocator(obj.datatype)) : + this.defaultDatatype, scope); + this.parseItemIdentifiers(variant, obj.item_identifiers); + this.parseReifier(variant, obj.reifier); + }; + + ReaderImpl.prototype.parseOccurrence = function (parent, obj) { + var occurrence, type, scope; + if (!parent) { + parent = this.parseParentAsTopic(obj); + } + scope = this.parseScope(obj.scope); + type = this.getTopicByReference(obj.type); + occurrence = parent.createOccurrence(type, obj.value, + obj.datatype ? + this.tm.createLocator(this.curieToLocator(obj.datatype)) : + this.defaultDatatype, scope); + this.parseItemIdentifiers(occurrence, obj.item_identifiers); + this.parseReifier(occurrence, obj.reifier); + }; + + ReaderImpl.prototype.parseAssociation = function (obj) { + var association, type, scope, arr, i; + scope = this.parseScope(obj.scope); + type = this.getTopicByReference(obj.type); + association = this.tm.createAssociation(type, scope); + arr = obj.roles; + if (arr && typeof arr === 'object' && arr instanceof Array) { + if (arr.length === 0) { + throw {name: 'InvalidFormat', + message: 'Association needs roles'}; + } + for (i = 0; i < arr.length; i += 1) { + this.parseRole(association, arr[i]); + } + } else { + throw {name: 'InvalidFormat', + message: 'Association needs roles'}; + } + this.parseItemIdentifiers(association, obj.item_identifiers); + this.parseReifier(association, obj.reifier); + }; + + ReaderImpl.prototype.parseRole = function (parent, obj) { + var role, type, player; + type = this.getTopicByReference(obj.type); + player = this.getTopicByReference(obj.player); + role = parent.createRole(type, player); + this.parseItemIdentifiers(role, obj.item_identifiers); + this.parseReifier(role, obj.reifier); + }; + + ReaderImpl.prototype.parseScope = function (arr) { + var i, scope = []; + if (arr && typeof arr === 'object' && arr instanceof Array) { + for (i = 0; i < arr.length; i += 1) { + scope.push(this.getTopicByReference(arr[i])); + } + } + return scope; + }; + + + ReaderImpl.prototype.parseItemIdentifiers = function (construct, arr) { + var i, tm, identifier; + tm = construct.getTopicMap(); + if (arr && typeof arr === 'object' && arr instanceof Array) { + for (i = 0; i < arr.length; i += 1) { + identifier = this.curieToLocator(arr[i]); + if (!tm.getConstructByItemIdentifier(tm.createLocator(identifier))) { + construct.addItemIdentifier(tm.createLocator(identifier)); + } + } + } + }; + + ReaderImpl.prototype.parseReifier = function (construct, reifier) { + var reifierTopic = this.getTopicByReference(reifier); + if (reifierTopic && reifierTopic.getReified() === null || !reifierTopic) { + construct.setReifier(reifierTopic); + } // else: Ignore the case that reifierTopic reifies another item + }; + + /** + * @class Exports topic maps constructs as JTM 1.0 JavaScript objects. + * See http://www.cerny-online.com/jtm/1.0/ for the JSON Topic Maps specification. + * JSON 1.1 is described at http://www.cerny-online.com/jtm/1.1/ + * @param {String} version Version number of the JTM export. Valid values are '1.0' + * and '1.1'. Version 1.1 produces more compact files. The default + * value is '1.0', but this may change in the future. + */ + WriterImpl = function (version) { + var that = this, referenceToCURIEorURI; + this.defaultDatatype = TM.XSD.string; + this.prefixes = new TM.Hash(); + this.version = version || '1.0'; + + referenceToCURIEorURI = function (reference) { + var key, keys, i, value; + if (that.version === '1.0') { + return reference; + } + // TODO Sort keys after descending value length - longest first + // to find the best prefix + keys = that.prefixes.keys(); + for (i = 0; i < keys.length; i += 1) { + key = keys[i]; + value = that.prefixes.get(key); + if (reference.substring(0, value.length) === value) { + return '[' + key + ':' + + reference.substr(value.length) + ']'; + } + } + return reference; + }; + + /** + * Sets prefixes for JTM 1.1 export. prefixes is an object with the + * prefix as key and its corresponding reference as value. + */ + this.setPrefixes = function (prefixes) { + var key; + for (key in prefixes) { + if (prefixes.hasOwnProperty(key)) { + this.prefixes.put(key, prefixes[key]); + } + } + }; + + /** + * Generates a JTM reference based on the topics subject identifier, + * subject locator or item identifier (whatever is set, tested in this + * order). + * @returns {string} Representing the topic t, e.g. + * "si:http://psi.topicmaps.org/iso13250/model/type + */ + this.getTopicReference = function (t) { + var arr; + arr = t.getSubjectIdentifiers(); + if (arr.length > 0) { + return 'si:' + referenceToCURIEorURI(arr[0].getReference()); + } + arr = t.getSubjectLocators(); + if (arr.length > 0) { + return 'sl:' + referenceToCURIEorURI(arr[0].getReference()); + } + arr = t.getItemIdentifiers(); + if (arr.length > 0) { + return 'ii:' + referenceToCURIEorURI(arr[0].getReference()); + } + // ModelConstraintExeption: TMDM says that t MUST have on of these + }; + + this.exportIdentifiers = function (obj, arr, attr) { + var i, len = arr.length; + if (len > 0) { + obj[attr] = []; + for (i = 0; i < len; i += 1) { + obj[attr].push(referenceToCURIEorURI(arr[i].getReference())); + } + } + + }; + + this.exportScope = function (obj, construct) { + var i, arr = construct.getScope(); + if (arr.length > 0) { + obj.scope = []; + for (i = 0; i < arr.length; i += 1) { + obj.scope.push(that.getTopicReference(arr[i])); + } + } + }; + + this.exportParent = function (obj, construct) { + var parent = construct.getParent(); + that.exportIdentifiers(obj, parent.getItemIdentifiers(), 'parent'); + }; + + this.exportTopicMap = function (m) { + var arr, i, len, obj; + obj = { + topics: [], + associations: [] + }; + arr = m.getTopics(); + len = arr.length; + for (i = 0; i < len; i += 1) { + obj.topics.push(that.exportTopic(arr[i])); + } + arr = m.getAssociations(); + len = arr.length; + for (i = 0; i < len; i += 1) { + obj.associations.push(that.exportAssociation(arr[i])); + } + return obj; + }; + + this.exportTopic = function (t) { + var arr, i, len, obj; + obj = {}; + that.exportIdentifiers(obj, t.getSubjectIdentifiers(), 'subject_identifiers'); + that.exportIdentifiers(obj, t.getSubjectLocators(), 'subject_locators'); + that.exportIdentifiers(obj, t.getItemIdentifiers(), 'item_identifiers'); + arr = t.getNames(); + len = arr.length; + if (len > 0) { + obj.names = []; + for (i = 0; i < len; i += 1) { + obj.names.push(that.exportName(arr[i])); + } + } + arr = t.getOccurrences(); + len = arr.length; + if (len > 0) { + obj.occurrences = []; + for (i = 0; i < len; i += 1) { + obj.occurrences.push(that.exportOccurrence(arr[i])); + } + } + arr = t.getTypes(); + len = arr.length; + if (len > 0) { + obj.instance_of = []; + for (i = 0; i < len; i += 1) { + obj.instance_of.push(that.getTopicReference(arr[i])); + } + } + return obj; + }; + + this.exportName = function (name) { + var arr, i, len, obj, tmp; + obj = { + 'value': name.getValue() + }; + tmp = name.getType(); + if (tmp) { + obj.type = that.getTopicReference(tmp); + } + tmp = name.getReifier(); + if (tmp) { + obj.reifier = that.getTopicReference(tmp); + } + + that.exportIdentifiers(obj, name.getItemIdentifiers(), 'item_identifiers'); + that.exportScope(obj, name); + arr = name.getVariants(); + len = arr.length; + if (len > 0) { + obj.variants = []; + for (i = 0; i < len; i += 1) { + obj.variants.push(that.exportVariant(arr[i])); + } + } + return obj; + }; + + this.exportVariant = function (variant) { + var obj, tmp; + obj = { + 'value': variant.getValue() + }; + tmp = variant.getDatatype(); + if (tmp && tmp !== variant.getTopicMap().createLocator(that.defaultDatatype)) { + obj.datatype = referenceToCURIEorURI(tmp.getReference()); + } + tmp = variant.getReifier(); + if (tmp) { + obj.reifier = that.getTopicReference(tmp); + } + + that.exportIdentifiers(obj, variant.getItemIdentifiers(), 'item_identifiers'); + that.exportScope(obj, variant); + }; + + this.exportOccurrence = function (occ) { + var obj, tmp; + obj = { + value: occ.getValue(), + type: that.getTopicReference(occ.getType()) + }; + tmp = occ.getDatatype(); + if (tmp && tmp !== occ.getTopicMap().createLocator(that.defaultDatatype)) { + obj.datatype = referenceToCURIEorURI(tmp.getReference()); + } + tmp = occ.getReifier(); + if (tmp) { + obj.reifier = that.getTopicReference(tmp); + } + + that.exportIdentifiers(obj, occ.getItemIdentifiers(), 'item_identifiers'); + that.exportScope(obj, occ); + return obj; + }; + + this.exportAssociation = function (association) { + var arr, i, obj, tmp; + obj = { + type: that.getTopicReference(association.getType()), + roles: [] + }; + tmp = association.getReifier(); + if (tmp) { + obj.reifier = that.getTopicReference(tmp); + } + that.exportIdentifiers(obj, association.getItemIdentifiers(), 'item_identifiers'); + that.exportScope(obj, association); + arr = association.getRoles(); + for (i = 0; i < arr.length; i += 1) { + obj.roles.push(that.exportRole(arr[i])); + } + return obj; + }; + + this.exportRole = function (role) { + var obj, tmp; + obj = { + player: that.getTopicReference(role.getPlayer()), + type: that.getTopicReference(role.getType()) + }; + tmp = role.getReifier(); + if (tmp) { + obj.reifier = that.getTopicReference(tmp); + } + that.exportIdentifiers(obj, role.getItemIdentifiers(), 'item_identifiers'); + return obj; + }; + }; + + /** + * Returns a JTM JavaScript object representation of construct. + * @param {Construct} construct The topic map construct to be exported. Can be + * TopicMap, Topic, Occurrence, Name, Variant, Association or Role. + * @param {boolean} [includeParent] If true the optional JTM element 'parent' is + * included. Refers to the parent via its item identifier. If undefined or false, + * the parent element is dropped. + */ + WriterImpl.prototype.toObject = function (construct, includeParent) { + var obj, tm, keys, i; + includeParent = includeParent || false; + tm = construct.getTopicMap(); + + if (construct.isTopicMap()) { + obj = this.exportTopicMap(construct); + obj.item_type = 'topicmap'; + } else if (construct.isRole()) { + obj = this.exportRole(construct); + obj.item_type = 'role'; + } else if (construct.isTopic()) { + obj = this.exportTopic(construct); + obj.item_type = 'topic'; + } else if (construct.isAssociation()) { + obj = this.exportAssociation(construct); + obj.item_type = 'association'; + } else if (construct.isOccurrence()) { + obj = this.exportOccurrence(construct); + obj.item_type = 'occurrence'; + } else if (construct.isName()) { + obj = this.exportName(construct); + obj.item_type = 'name'; + } else if (construct.isVariant()) { + obj = this.exportVariant(construct); + obj.item_type = 'variant'; + } + obj.version = this.version; + if (this.version === '1.1' && this.prefixes) { + if (this.prefixes.size()) { + keys = this.prefixes.keys(); + obj.prefixes = {}; + for (i = 0; i < keys.length; i += 1) { + obj.prefixes[keys[i]] = this.prefixes.get(keys[i]); + } + } + } + if (!construct.isTopic() && construct.getReifier()) { + obj.reifier = this.getTopicReference(construct.getReifier()); + } + if (includeParent && !construct.isTopicMap()) { + this.exportParent(obj, construct); + } + return obj; + }; + + return { + Reader: ReaderImpl, + Writer: WriterImpl + }; +}());
Copied: branches/gdl-frontend/playground/GWT-JSNI/GWT-JSNI-example/war/gwt_jsni_example/external/tm.min.js (from r482, branches/gdl-frontend/playground/GWT-JSNI/GWT-JSNI-example/war/gwt_jsni_example/external/tm.min.js) ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ branches/gdl-frontend/playground/GWT-JSNI/GWT-JSNI-example/war/gwt_jsni_example/external/tm.min.js Wed Jun 15 09:05:52 2011 (r483, copy of r482, branches/gdl-frontend/playground/GWT-JSNI/GWT-JSNI-example/war/gwt_jsni_example/external/tm.min.js) @@ -0,0 +1,116 @@ +// tmjs, version 0.4.0 +// http://github.com/jansc/tmjs +// Copyright (c) 2010 Jan Schreiber jans@ravn.no +// Licensed under the MIT-License. + +var TM,TopicMapSystemFactory; +TM=function(){var n,C,h,g,e,f,i,l,m,o,t,u,p,D,x,A,B,v,y,w,z,O,E,J,H,s,q,P;Function.prototype.swiss=function(a){var b,c;for(b=1;b<arguments.length;b+=1){c=arguments[b];this.prototype[c]=a.prototype[c]}return this};n=function(){this.hash={};this.length=0};n.prototype={get:function(a){return this.hash[a]},contains:function(a){return this.get(a)!==undefined},put:function(a,b){this.hash[a]||(this.length+=1);return this.hash[a]=b},remove:function(a){delete this.hash[a];this.length-=1;return this},keys:function(){var a= +[],b;for(b in this.hash)this.hash.hasOwnProperty(b)&&a.push(b);return a},values:function(){var a=[],b;for(b in this.hash)this.hash.hasOwnProperty(b)&&a.push(this.hash[b]);return a},empty:function(){this.hash={};this.length=0},size:function(){return this.length}};e={};e.ADD_ASSOCIATION=1;e.ADD_NAME=2;e.ADD_OCCURRENCE=3;e.ADD_ROLE=4;e.ADD_THEME=5;e.ADD_TOPIC=6;e.ADD_TYPE=7;e.REMOVE_ASSOCIATION=8;e.REMOVE_NAME=9;e.REMOVE_OCCURRENCE=10;e.REMOVE_ROLE=11;e.REMOVE_THEME=12;e.REMOVE_TOPIC=13;e.REMOVE_TYPE= +14;e.SET_TYPE=15;C={string:"http://www.w3.org/2001/XMLSchema#string%22,integer:%22http://www.w3.org/2001... this.iri}; +g.prototype.equals=function(a){return this.iri===a.getReference()};g.prototype.toExternalForm=function(){throw{name:"NotImplemented",message:"Locator.toExternalForm() not implemented"};};m=function(){};m.prototype.addItemIdentifier=function(a){var b;if(a===null)throw{name:"ModelConstraintException",message:"addItemIdentifier(null) is illegal"};if(b=this.getTopicMap()._ii2construct.get(a.getReference()))throw{name:"IdentityConstraintException",message:"Topic Maps constructs with the same item identifier are not allowed", +reporter:this,existing:b,locator:a};this.itemIdentifiers.push(a);this.getTopicMap()._ii2construct.put(a.getReference(),this);return this};m.prototype.equals=function(a){return this.id===a.id};m.prototype.getId=function(){return this.id};m.prototype.getItemIdentifiers=function(){return this.itemIdentifiers};m.prototype.getParent=function(){return this.parnt};m.prototype.getTopicMap=function(){throw{name:"NotImplemented",message:"getTopicMap() not implemented"};};m.prototype.hashCode=function(){throw{name:"NotImplemented", +message:"hashCode() not implemented"};};m.prototype.remove=function(){throw{name:"NotImplemented",message:"remove() not implemented"};};m.prototype.removeItemIdentifier=function(a){if(a!==null){for(var b=0;b<this.itemIdentifiers.length;b+=1)if(this.itemIdentifiers[b].getReference()===a.getReference()){this.itemIdentifiers.splice(b,1);break}this.getTopicMap()._ii2construct.remove(a.getReference());return this}};m.prototype.isTopicMap=function(){return false};m.prototype.isTopic=function(){return false}; +m.prototype.isAssociation=function(){return false};m.prototype.isRole=function(){return false};m.prototype.isName=function(){return false};m.prototype.isOccurrence=function(){return false};m.prototype.isVariant=function(){return false};o=function(){};o.prototype.getType=function(){return this.type};o.prototype.setType=function(a){if(a===null)throw{name:"ModelConstraintException",message:"Topic.setType cannot be called without type"};z.assertBelongsTo(this.getTopicMap(),a);this.getTopicMap().setTypeEvent.fire(this, +{old:this.type,type:a});this.type=a;return this};l=function(){};l.prototype.addTheme=function(a){if(a===null)throw{name:"ModelConstraintException",message:"addTheme(null) is illegal"};for(var b=0;b<this.scope.length;b+=1)if(this.scope[b]===a)return false;z.assertBelongsTo(this.getTopicMap(),a);this.scope.push(a);this.getTopicMap().addThemeEvent.fire(this,{theme:a});if(this.isName())for(b=0;b<this.variants.length;b+=1)this.getTopicMap().addThemeEvent.fire(this.variants[b],{theme:a});return this};l.prototype.getScope= +function(){if(this.isVariant()){var a,b=new n,c=this.parnt.getScope();for(a=0;a<c.length;a+=1)b.put(c[a].getId(),c[a]);for(a=0;a<this.scope.length;a+=1)b.put(this.scope[a].getId(),this.scope[a]);return b.values()}return this.scope};l.prototype.removeTheme=function(a){var b,c,d,j;for(b=0;b<this.scope.length;b+=1)if(this.scope[b]===a){this.getTopicMap().removeThemeEvent.fire(this,{theme:this.scope[b]});this.scope.splice(b,1);break}if(this.isName())for(b=0;b<this.variants.length;b+=1){d=this.variants[b].scope; +j=false;for(c=0;c<d.length;c+=1)if(a.equals(d[c]))j=true;j||this.getTopicMap().removeThemeEvent.fire(this.variants[b],{theme:a})}return this};t=function(){};t.prototype.getReifier=function(){return this.reifier};t.prototype.setReifier=function(a){if(a&&a.getReified()!==null)throw{name:"ModelConstraintException",message:"Reifies already another construct"};z.assertBelongsTo(this.getTopicMap(),a);this.reifier&&this.reifier._setReified(null);a&&a._setReified(this);this.reifier=a;return this};u=function(){}; +u.prototype.decimalValue=function(){};u.prototype.floatValue=function(){var a=parseFloat(this.value);if(isNaN(a))throw{name:"NumberFormatException",message:'"'+this.value+'" is not a float'};return a};u.prototype.getDatatype=function(){return this.datatype};u.prototype.getValue=function(){if(typeof this.value==="object"&&this.value instanceof g)return this.value.getReference();return this.value.toString()};u.prototype.integerValue=function(){var a=parseInt(this.value,10);if(isNaN(a))throw{name:"NumberFormatException", +message:'"'+this.value+'" is not an integer'};return a};u.prototype.locatorValue=function(){if(!(typeof this.value==="object"&&this.value instanceof g))throw{name:"ModelConstraintException",message:'"'+this.value+'" is not a locator'};return this.value};u.prototype.longValue=function(){};u.prototype.setValue=function(a,b){var c=this.getTopicMap();if(b===null)throw{name:"ModelConstraintException",message:"Invalid datatype"};if(a===null)throw{name:"ModelConstraintException",message:"Invalid value"}; +this.value=a;this.datatype=b||this.getTopicMap().createLocator(C.string);if(b&&b.getReference()===C.anyURI)this.value=c.createLocator(a);if(!b)if(typeof a==="number")this.datatype=c.createLocator(C.integer);if(typeof a==="object"&&a instanceof g)this.datatype=c.createLocator(C.anyURI)};TopicMapSystemFactory=function(){this.properties={};this.features={}};TopicMapSystemFactory.prototype.getFeature=function(){return this.features};TopicMapSystemFactory.prototype.getProperty=function(a){return this.properties[a]}; +TopicMapSystemFactory.prototype.hasFeature=function(){return false};TopicMapSystemFactory.newInstance=function(){return new TopicMapSystemFactory};TopicMapSystemFactory.prototype.newTopicMapSystem=function(){if((this.properties["com.semanticheadache.tmjs.backend"]||"memory")==="memory")return new v};TopicMapSystemFactory.prototype.setFeature=function(a,b){this.features[a]=b};TopicMapSystemFactory.prototype.setProperty=function(a,b){this.properties[a]=b};v=function(){this.topicmaps={}};v.prototype.createTopicMap= +function(a){if(this.topicmaps[a.getReference()])throw{name:"TopicMapExistsException",message:"A topic map under the same IRI already exists"};var b=new p(this,a);return this.topicmaps[a.getReference()]=b};v.prototype.getLocators=function(){var a=[],b;for(b in this.topicmaps)this.topicmaps.hasOwnProperty(b)&&a.push(this.createLocator(b));return a};v.prototype.getTopicMap=function(a){a=a instanceof g?this.topicmaps[a.getReference()]:this.topicmaps[a];if(!a)return null;return a};v.prototype.createLocator= +function(a){return new g(this,a)};v.prototype.getFeature=function(){return false};v.prototype._removeTopicMap=function(a){var b;for(b in this.topicmaps)this.topicmaps.hasOwnProperty(b)&&b===a.locator.getReference()&&delete this.topicmaps[b]};v.prototype.close=function(){this.topicmaps=null};p=function(a,b){this.topicmapsystem=a;this.itemIdentifiers=[];this.locator=b;this.topics=[];this.associations=[];this._constructId=1;this._si2topic=new n;this._sl2topic=new n;this._ii2construct=new n;this._id2construct= +new n;this.id=0;this._id2construct.put(this.id,this);this.reifier=null;this.handlers=[];a=function(c){this.eventtype=c;this.handlers=[]};a.prototype={registerHandler:function(c){this.handlers.push(c)},removeHandler:function(c){for(var d=0;d<this.handlers.length;d+=1)c.toString()===this.handlers[d].toString()&&this.handlers.splice(d,1)},fire:function(c,d){d=d||{};for(var j=0;j<this.handlers.length;j+=1)this.handlers[j](this.eventtype,c,d)}};this.addAssociationEvent=new a(e.ADD_ASSOCIATION);this.addNameEvent= +new a(e.ADD_NAME);this.addOccurrenceEvent=new a(e.ADD_OCCURRENCE);this.addRoleEvent=new a(e.ADD_ROLE);this.addThemeEvent=new a(e.ADD_THEME);this.addTopicEvent=new a(e.ADD_TOPIC);this.addTypeEvent=new a(e.ADD_TYPE);this.removeAssociationEvent=new a(e.REMOVE_ASSOCIATION);this.removeNameEvent=new a(e.REMOVE_NAME);this.removeOccurrenceEvent=new a(e.REMOVE_OCCURRENCE);this.removeRoleEvent=new a(e.REMOVE_ROLE);this.removeThemeEvent=new a(e.REMOVE_THEME);this.removeTopicEvent=new a(e.REMOVE_TOPIC);this.removeTypeEvent= +new a(e.REMOVE_TYPE);this.setTypeEvent=new a(e.SET_TYPE);this.typeInstanceIndex=new y(this);this.scopedIndex=new w(this)};p.prototype.register_event_handler=function(a,b){switch(a){case e.ADD_ASSOCIATION:this.addAssociationEvent.registerHandler(b);break;case e.ADD_NAME:this.addNameEvent.registerHandler(b);break;case e.ADD_OCCURRENCE:this.addOccurrenceEvent.registerHandler(b);break;case e.ADD_ROLE:this.addRoleEvent.registerHandler(b);break;case e.ADD_THEME:this.addThemeEvent.registerHandler(b);break; +case e.ADD_TOPIC:this.addTopicEvent.registerHandler(b);break;case e.ADD_TYPE:this.addTypeEvent.registerHandler(b);break;case e.REMOVE_ASSOCIATION:this.removeAssociationEvent.registerHandler(b);break;case e.REMOVE_NAME:this.removeNameEvent.registerHandler(b);break;case e.REMOVE_OCCURRENCE:this.removeOccurrenceEvent.registerHandler(b);break;case e.REMOVE_ROLE:this.removeRoleEvent.registerHandler(b);break;case e.REMOVE_THEME:this.removeThemeEvent.registerHandler(b);break;case e.REMOVE_TOPIC:this.removeTopicEvent.registerHandler(b); +break;case e.REMOVE_TYPE:this.removeTypeEvent.registerHandler(b);break;case e.SET_TYPE:this.setTypeEvent.registerHandler(b);break}return this};p.swiss(t,"getReifier","setReifier");p.swiss(m,"addItemIdentifier","getItemIdentifiers","removeItemIdentifier","isTopic","isAssociation","isRole","isOccurrence","isName","isVariant","isTopicMap");p.prototype.sanitize=function(){H.removeTopicMapDuplicates(this);P.convertAssociationsToType(this);return this};p.prototype.isTopicMap=function(){return true};p.prototype._getConstructId= +function(){this._constructId+=1;return this._constructId};p.prototype.remove=function(){if(this.topicmapsystem===null)return null;this.topicmapsystem._removeTopicMap(this);return this.typeInstanceIndex=this.id=this.reifier=this._id2construct=this._ii2construct=this._sl2topic=this._si2topic=this.associations=this.topics=this.locator=this.itemIdentifiers=this.topicmapsystem=null};p.prototype.createAssociation=function(a,b){var c;if(a===null)throw{name:"ModelConstraintException",message:"Creating an association with type == null is not allowed"}; +if(b===null)throw{name:"ModelConstraintException",message:"Creating an association with scope == null is not allowed"};z.assertBelongsTo(this,a);z.assertBelongsTo(this,b);c=new i(this);this.associations.push(c);a&&c.setType(a);J(c,b);this.addAssociationEvent.fire(c);return c};p.prototype.createLocator=function(a){return new g(this,a)};p.prototype._createEmptyTopic=function(){var a=new f(this);this.addTopicEvent.fire(a);this.topics.push(a);return a};p.prototype.createTopic=function(){var a=this._createEmptyTopic(); +a.addItemIdentifier(this.createLocator("urn:x-tmjs:"+a.getId()));return a};p.prototype.createTopicByItemIdentifier=function(a){if(!a)throw{name:"ModelConstraintException",message:"createTopicByItemIdentifier() needs an item identifier"};var b=this.getConstructByItemIdentifier(a);if(b){if(!b.isTopic())throw{name:"IdentityConstraintException",message:"Another construct with the specified item identifier exists which is not a Topic."};return b}b=this._createEmptyTopic();b.addItemIdentifier(a);return b}; +p.prototype.createTopicBySubjectIdentifier=function(a){if(!a)throw{name:"ModelConstraintException",message:"createTopicBySubjectIdentifier() needs a subject identifier"};var b=this.getTopicBySubjectIdentifier(a);if(b)return b;b=this._createEmptyTopic();b.addSubjectIdentifier(a);return b};p.prototype.createTopicBySubjectLocator=function(a){if(!a)throw{name:"ModelConstraintException",message:"createTopicBySubjectLocator() needs a subject locator"};var b=this.getTopicBySubjectLocator(a);if(b)return b; +b=this._createEmptyTopic();b.addSubjectLocator(a);return b};p.prototype.getAssociations=function(){return this.associations};p.prototype.getConstructById=function(a){if(a===null)throw{name:"ModelConstraintException",message:"getConstructById(null) is illegal"};a=this._id2construct.get(a);if(!a)return null;return a};p.prototype.getConstructByItemIdentifier=function(a){if(a===null)throw{name:"ModelConstraintException",message:"getConstructByItemIdentifier(null) is illegal"};a=this._ii2construct.get(a.getReference()); +if(!a)return null;return a};p.prototype.getIndex=function(a){if(a==="TypeInstanceIndex")return a=this.typeInstanceIndex;else if(a==="ScopedIndex")return a=new w(this);throw{name:"UnsupportedOperationException",message:"getIndex ist not (yet) supported"};};p.prototype.getParent=function(){return null};p.prototype.getTopicBySubjectIdentifier=function(a){if(a=this._si2topic.get(a.getReference()))return a;return null};p.prototype.getTopicBySubjectLocator=function(a){if(a=this._sl2topic.get(a.getReference()))return a; +return null};p.prototype.getLocator=function(){return this.locator};p.prototype.getTopics=function(){return this.topics};p.prototype.mergeIn=function(){throw{name:"NotImplemented",message:"TopicMap.mergeIn() not implemented"};};p.prototype.equals=function(a){return this.locator.equals(a.locator)};p.prototype.getId=function(){return this.id};p.prototype.getTopicMap=function(){return this};p.prototype._removeConstruct=function(a){var b=a.getItemIdentifiers(),c;for(c=0;c<b.length;c+=1)this._ii2construct.remove(b[c].getReference()); +this._id2construct.remove(a.getId())};p.prototype._removeTopic=function(a){var b,c=a.getSubjectIdentifiers(),d=a.getSubjectLocators();for(b=0;b<c.length;b+=1)this._si2topic.remove(c[b].getReference());for(b=0;b<d.length;b+=1)this._sl2topic.remove(d[b].getReference());this._removeConstruct(a);for(b=0;b<this.topics.length;b+=1)if(a.id===this.topics[b].id){this.topics.splice(b,1);break}};p.prototype._removeAssociation=function(a){var b;for(b=0;b<this.associations.length;b+=1)if(a.id===this.associations[b].id){this.associations.splice(b, +1);break}this._removeConstruct(a);for(b=0;b<this.associations.length;b+=1)if(a.id===this.associations[b].id){this.associations.splice(b,1);break}};p.prototype._removeRole=function(a){this._removeConstruct(a)};p.prototype._removeOccurrence=function(a){this._removeConstruct(a)};p.prototype._removeName=function(a){this._removeConstruct(a)};p.prototype._removeVariant=function(a){this._removeConstruct(a)};f=function(a){this.subjectIdentifiers=[];this.subjectLocators=[];this.itemIdentifiers=[];this.parnt= +a;this.id=a._getConstructId();this.getTopicMap()._id2construct.put(this.id,this);this.types=[];this.rolesPlayed=[];this.occurrences=[];this.names=[];this.reified=null};f.swiss(m,"addItemIdentifier","equals","getId","getItemIdentifiers","getParent","getTopicMap","hashCode","remove","removeItemIdentifier","isTopic","isAssociation","isRole","isOccurrence","isName","isVariant","isTopicMap");f.prototype.isTopic=function(){return true};f.prototype.getTopicMap=function(){return this.parnt};f.prototype.addSubjectIdentifier= +function(a){if(!a)throw{name:"ModelConstraintException",message:"addSubjectIdentifier() needs subject identifier"};for(var b=0;b<this.subjectIdentifiers.length;b+=1)if(this.subjectIdentifiers[b].getReference()===a.getReference())return;this.subjectIdentifiers.push(a);this.parnt._si2topic.put(a.getReference(),this);return this};f.prototype.addSubjectLocator=function(a){if(!a)throw{name:"ModelConstraintException",message:"addSubjectLocator() needs subject locator"};for(var b=0;b<this.subjectLocators.length;b+= +1)if(this.subjectLocators[b].getReference()===a.getReference())return;this.subjectLocators.push(a);this.parnt._sl2topic.put(a.getReference(),this);return this};f.prototype.addType=function(a){if(!a)throw{name:"ModelConstraintException",message:"addType() needs type"};z.assertBelongsTo(this.parnt,a);this.parnt.addTypeEvent.fire(this,{type:a});this.types.push(a);return this};f.prototype.createName=function(a,b,c){b&&z.assertBelongsTo(this.parnt,b);c&&z.assertBelongsTo(this.parnt,c);if(typeof c==="undefined")c= +null;a=new x(this,a,b);J(a,c);this.names.push(a);return a};f.prototype.createOccurrence=function(a,b,c,d){z.assertBelongsTo(this.parnt,a);z.assertBelongsTo(this.parnt,d);c=new B(this,a,b,c);this.parnt.addOccurrenceEvent.fire(c,{type:a,value:b});J(c,d);this.occurrences.push(c);return c};f.prototype.getNames=function(a){var b=[],c;for(c=0;c<this.names.length;c+=1)if(a&&this.names[c].getType().equals(a))b.push(this.names[c]);else a||b.push(this.names[c]);return b};f.prototype.getOccurrences=function(a){var b= +[],c;if(a===null)throw{name:"IllegalArgumentException",message:"Topic.getOccurrences cannot be called without type"};for(c=0;c<this.occurrences.length;c+=1)if(a&&this.occurrences[c].getType().equals(a))b.push(this.occurrences[c]);else a||b.push(this.occurrences[c]);return b};f.prototype._removeOccurrence=function(a){for(var b=0;b<this.occurrences.length;b+=1)if(this.occurrences[b].equals(a)){this.occurrences.splice(b,1);break}this.getTopicMap()._removeOccurrence(a)};f.prototype.getReified=function(){return this.reified}; +f.prototype._setReified=function(a){this.reified=a};f.prototype.getRolesPlayed=function(a,b){if(a===null)throw{name:"IllegalArgumentException",message:"Topic.getRolesPlayed cannot be called without type"};if(b===null)throw{name:"IllegalArgumentException",message:"Topic.getRolesPlayed cannot be called with assocType===null"};var c=[],d;for(d=0;d<this.rolesPlayed.length;d+=1)if(a){if(this.rolesPlayed[d].getType().equals(a))if(b&&this.rolesPlayed[d].getParent().getType().equals(b)||!b)c.push(this.rolesPlayed[d])}else c.push(this.rolesPlayed[d]); +return c};f.prototype.addRolePlayed=function(a){this.rolesPlayed.push(a)};f.prototype.removeRolePlayed=function(a){for(var b=0;b<this.rolesPlayed.length;b+=1)this.rolesPlayed[b].id===a.id&&this.rolesPlayed.splice(b,1)};f.prototype.getSubjectIdentifiers=function(){return this.subjectIdentifiers};f.prototype.getSubjectLocators=function(){return this.subjectLocators};f.prototype.getTypes=function(){return this.types};f.prototype.mergeIn=function(a){var b,c,d,j,k;if(this.equals(a))return true;z.assertBelongsTo(this.getTopicMap(), +a);if(this.getReified()&&a.getReified()&&!this.getReified().equals(a.getReified()))throw{name:"ModelConstraintException",message:"The topics reify different Topic Maps constructs and cannot be merged!"};if(!this.getReified()&&a.getReified()){d=a.getReified();d.setReifier(this)}b=this.parnt.typeInstanceIndex;q.moveTypes(b.getOccurrences(a),this);q.moveTypes(b.getNames(a),this);q.moveTypes(b.getAssociations(a),this);q.moveTypes(b.getRoles(a),this);b=b.getTopics(a);for(c=0;c<b.length;c+=1){b[c].removeType(a); +b[c].addType(this)}b=this.parnt.scopedIndex;q.moveThemes(b.getAssociations(a),a,this);q.moveThemes(b.getOccurrences(a),a,this);q.moveThemes(b.getNames(a),a,this);q.moveThemes(b.getVariants(a),a,this);q.moveItemIdentifiers(a,this);for(b=a.getSubjectLocators();b.length;){d=b[b.length-1];a.removeSubjectLocator(d);this.addSubjectLocator(d)}for(b=a.getSubjectIdentifiers();b.length;){d=b[b.length-1];a.removeSubjectIdentifier(d);this.addSubjectIdentifier(d)}for(b=a.getTypes();b.length;){d=b[b.length-1]; +a.removeType(d);this.addType(d)}b=this.getRolesPlayed();k={};for(c=0;c<b.length;c+=1){j=b[c].getParent();k[s.makeAssociationSignature(j)]=j}b=a.getRolesPlayed();for(c=0;c<b.length;c+=1){d=b[c];d.setPlayer(this);if(j=k[s.makeAssociationSignature(d.getParent())]){q.moveItemIdentifiers(d.getParent(),j);q.moveReifier(d.getParent(),j);d.getParent().remove()}}b=this.getNames();k={};for(c=0;c<b.length;c+=1)k[s.makeNameSignature(b[c])]=b[c];b=a.getNames();for(c=0;c<b.length;c+=1){d=b[c];if(j=k[s.makeNameSignature(b[c])]){q.moveItemIdentifiers(d, +j);q.moveReifier(d,j);q.moveVariants(d,j);d.remove()}else{j=this.createName(d.getValue(),d.getType(),d.getScope());q.moveVariants(d,j)}}b=this.getOccurrences();k={};for(c=0;c<b.length;c+=1)k[s.makeOccurrenceSignature(b[c])]=b[c];b=a.getOccurrences();for(c=0;c<b.length;c+=1){d=b[c];if(j=k[s.makeOccurrenceSignature(b[c])]){q.moveItemIdentifiers(d,j);q.moveReifier(d,j);d.remove()}else{j=this.createOccurrence(d.getType(),d.getValue(),d.getDatatype(),d.getScope());q.moveReifier(d,j)}}a.remove();return this}; +f.prototype.remove=function(){var a=this.parnt.typeInstanceIndex,b=this.parnt.scopedIndex;if(this.getReified()||a.getOccurrences(this).length||a.getNames(this).length||a.getAssociations(this).length||a.getRoles(this).length||a.getTopics(this).length||b.getAssociations(this).length||b.getOccurrences(this).length||b.getNames(this).length||b.getVariants(this).length||this.getRolesPlayed().length)throw{name:"TopicInUseException",message:"",reporter:this};this.parnt._removeTopic(this);this.parnt._id2construct.remove(this.id); +this.parnt.removeTopicEvent.fire(this);this.id=null;return this.parnt};f.prototype.removeSubjectIdentifier=function(a){for(var b=0;b<this.subjectIdentifiers.length;b+=1)if(this.subjectIdentifiers[b].getReference()===a.getReference()){this.subjectIdentifiers.splice(b,1);break}this.parnt._sl2topic.remove(a.getReference());return this};f.prototype.removeSubjectLocator=function(a){for(var b=0;b<this.subjectLocators.length;b+=1)if(this.subjectLocators[b].getReference()===a.getReference()){this.subjectLocators.splice(b, +1);break}this.parnt._sl2topic.remove(a.getReference());return this};f.prototype.removeType=function(a){for(var b=0;b<this.types.length;b+=1)if(this.types[b].equals(a)){this.types.splice(b,1);this.parnt.removeTypeEvent.fire(this,{type:a});break}};f.prototype._removeName=function(a){for(var b=0;b<this.names.length;b+=1)if(this.names[b].equals(a)){this.names.splice(b,1);break}this.getTopicMap()._removeName(a)};B=function(a,b,c,d){this.itemIdentifiers=[];this.parnt=a;this.type=b;this.value=c;this.datatype= +d?d:this.getTopicMap().createLocator(C.string);this.scope=[];this.reifier=null;this.id=this.getTopicMap()._getConstructId();this.getTopicMap()._id2construct.put(this.id,this)};B.swiss(o,"getType","setType");B.swiss(u,"decimalValue","floatValue","getDatatype","getValue","integerValue","locatorValue","longValue","setValue");B.swiss(t,"getReifier","setReifier");B.swiss(l,"addTheme","getScope","removeTheme");B.swiss(m,"addItemIdentifier","equals","getId","getItemIdentifiers","getParent","getTopicMap", +"hashCode","remove","removeItemIdentifier","isTopic","isAssociation","isRole","isOccurrence","isName","isVariant","isTopicMap");B.prototype.isOccurrence=function(){return true};B.prototype.getTopicMap=function(){return this.parnt.getParent()};B.prototype.remove=function(){var a;for(a=0;a<this.scope.length;a+=1)this.parnt.parnt.removeThemeEvent.fire(this,{theme:this.scope[a]});this.parnt.parnt.removeOccurrenceEvent.fire(this);this.parnt._removeOccurrence(this);this.id=null;return this.parnt};x=function(a, +b,c){this.itemIdentifiers=[];this.parnt=a;this.value=b;this.scope=[];this.id=this.getTopicMap()._getConstructId();this.type=c||a.parnt.createTopicBySubjectIdentifier(a.parnt.createLocator("http://psi.topicmaps.org/iso13250/model/topic-name%22));this.reifier=null;th..."); +x.swiss(m,"addItemIdentifier","equals","getId","getItemIdentifiers","getParent","getTopicMap","hashCode","remove","removeItemIdentifier","isTopic","isAssociation","isRole","isOccurrence","isName","isVariant","isTopicMap");x.prototype.isName=function(){return true};x.prototype.getTopicMap=function(){return this.parnt.parnt};x.prototype.createVariant=function(a,b,c){if(typeof c==="undefined"||c===null)throw{name:"ModelConstraintException",message:"Creation of a variant with a null scope is not allowed"}; +a=new A(this,a,b);J(a,c);for(c=0;c<this.scope.length;c+=1)this.getTopicMap().addThemeEvent.fire(a,{theme:this.scope[c]});this.variants.push(a);return a};x.prototype.setValue=function(a){if(!a)throw{name:"ModelConstraintException",message:"Name.setValue(null) is not allowed"};this.value=a;return this};x.prototype.getValue=function(){return this.value};x.prototype.remove=function(){var a;for(a=0;a<this.scope.length;a+=1)this.parnt.parnt.removeThemeEvent.fire(this,{theme:this.scope[a]});this.parnt.parnt.removeNameEvent.fire(this); +this.parnt._removeName(this);this.id=null;return this.parnt};x.prototype._removeVariant=function(a){for(var b=0;b<this.variants.length;b+=1)if(this.variants[b].equals(a)){this.variants.splice(b,1);break}this.getTopicMap()._removeVariant(a)};x.prototype.getVariants=function(){return this.variants};A=function(a,b,c){if(b===null)throw{name:"ModelConstraintException",message:"Creation of a variant with null value is not allowed"};if(c===null)throw{name:"ModelConstraintException",message:"Creation of a variant with datatype == null is not allowed"}; +this.itemIdentifiers=[];this.scope=[];this.parnt=a;this.datatype=typeof b==="object"&&b instanceof g?this.getTopicMap().createLocator("http://www.w3.org/2001/XMLSchema#anyURI%22):this.getTopicMap().createLocator...", +"getParent","getTopicMap","hashCode","remove","removeItemIdentifier","isTopic","isAssociation","isRole","isOccurrence","isName","isVariant","isTopicMap");A.swiss(u,"decimalValue","floatValue","getDatatype","getValue","integerValue","locatorValue","longValue","setValue");A.prototype.isVariant=function(){return true};A.prototype.getTopicMap=function(){return this.getParent().getParent().getParent()};A.prototype.remove=function(){var a;for(a=0;a<this.scope.length;a+=1)this.getTopicMap().removeThemeEvent.fire(this, +{theme:this.scope[a]});this.getParent()._removeVariant(this);this.id=null;return this.parnt};D=function(a,b,c){this.itemIdentifiers=[];this.parnt=a;this.type=b;this.player=c;this.id=this.getTopicMap()._getConstructId();this.reifier=null;this.getTopicMap()._id2construct.put(this.id,this)};D.swiss(o,"getType","setType");D.swiss(t,"getReifier","setReifier");D.swiss(m,"addItemIdentifier","equals","getId","getItemIdentifiers","getParent","getTopicMap","hashCode","remove","removeItemIdentifier","isTopic", +"isAssociation","isRole","isOccurrence","isName","isVariant","isTopicMap");D.prototype.isRole=function(){return true};D.prototype.getTopicMap=function(){return this.getParent().getParent()};D.prototype.remove=function(){var a=this.parnt;this.parnt.parnt.removeRoleEvent.fire(this);this.parnt._removeRole(this);this.id=this.reifier=this.player=this.type=this.parnt=this.itemIdentifiers=null;return a};D.prototype.getPlayer=function(){return this.player};D.prototype.setPlayer=function(a){if(!a)throw{name:"ModelConstraintException", +message:"player i Role.setPlayer cannot be null"};z.assertBelongsTo(this.parnt.parnt,a);if(!this.player.equals(a)){this.player.removeRolePlayed(this);a.addRolePlayed(this);this.player=a;return this}};i=function(a){this.itemIdentifiers=[];this.parnt=a;this.id=this.getTopicMap()._getConstructId();this.getTopicMap()._id2construct.put(this.id,this);this.roles=[];this.scope=[];this.reifier=this.type=null};i.swiss(o,"getType","setType");i.swiss(t,"getReifier","setReifier");i.swiss(l,"addTheme","getScope", +"removeTheme");i.swiss(m,"addItemIdentifier","equals","getId","getItemIdentifiers","getParent","getTopicMap","hashCode","remove","removeItemIdentifier","isTopic","isAssociation","isRole","isOccurrence","isName","isVariant","isTopicMap");i.prototype.isAssociation=function(){return true};i.prototype.getTopicMap=function(){return this.parnt};i.prototype.createRole=function(a,b){if(!a)throw{name:"ModelConstraintException",message:"type i Role.createPlayer cannot be null"};if(!b)throw{name:"ModelConstraintException", +message:"player i Role.createRole cannot be null"};z.assertBelongsTo(this.parnt,a);z.assertBelongsTo(this.parnt,b);var c=new D(this,a,b);b.addRolePlayed(c);this.roles.push(c);this.parnt.addRoleEvent.fire(c,{type:a,player:b});return c};i.prototype._removeRole=function(a){for(var b=0;b<this.roles.length;b+=1)if(a.id===this.roles[b].id){this.roles.splice(b,1);break}a.getPlayer().removeRolePlayed(a);this.getTopicMap()._removeRole(a)};i.prototype.remove=function(){var a;for(a=0;a<this.scope.length;a+= +1)this.parnt.removeThemeEvent.fire(this,{theme:this.scope[a]});for(this.parnt.removeAssociationEvent.fire(this);this.roles.length;)this.roles[0].remove();this.roles=this.id=null;this.parnt._removeAssociation(this);this.getTopicMap()._ii2construct.remove(this.id);this.reifier=this.type=this.scope=this.item_identifiers=null;return this.parnt};i.prototype.getRoles=function(a){if(a===null)throw{name:"IllegalArgumentException",message:"Topic.getRoles cannot be called with type null"};if(!a)return this.roles; +var b=[],c;for(c=0;c<this.roles.length;c+=1)this.roles[c].getType().equals(a)&&b.push(this.roles[c]);return b};i.prototype.getRoleTypes=function(){var a={},b=[],c,d;for(c=0;c<this.roles.length;c+=1)a[this.roles[c].getType().getId()]=this.roles[c].getType();for(d in a)a.hasOwnProperty(d)&&b.push(a[d]);return b};l=function(){this.opened=false};l.prototype.close=function(){};l.prototype.isAutoUpdated=function(){return true};l.prototype.isOpen=function(){return this.opened};l.prototype.open=function(){this.opened= +true};l.prototype.reindex=function(){};y=function(a){var b,c=this;this.tm=a;this.type2topics=new n;this.type2associations=new n;this.type2roles=new n;this.type2occurrences=new n;this.type2names=new n;this.type2variants=new n;this.opened=false;b=function(d,j,k){var r;switch(d){case e.ADD_ASSOCIATION:break;case e.ADD_NAME:d=c.type2names.get(k.type.getId());if(typeof d==="undefined")d=new n;d.put(j.getId(),j);c.type2names.put(k.type.getId(),d);break;case e.ADD_OCCURRENCE:d=c.type2occurrences.get(k.type.getId()); +if(typeof d==="undefined")d=new n;d.put(j.getId(),j);c.type2occurrences.put(k.type.getId(),d);break;case e.ADD_ROLE:d=c.type2roles.get(k.type.getId());if(typeof d==="undefined")d=new n;d.put(j.getId(),j);c.type2roles.put(k.type.getId(),d);break;case e.ADD_TOPIC:d=c.type2topics.get("null");if(typeof d==="undefined")d=new n;d.put(j.getId(),j);c.type2topics.put("null",d);break;case e.ADD_TYPE:if((d=c.type2topics.get("null"))&&d.get(j.getId())){d.remove(j.getId());c.type2topics.put("null",d)}d=c.type2topics.get(k.type.getId()); +if(typeof d==="undefined")d=new n;d.put(j.getId(),j);c.type2topics.put(k.type.getId(),d);break;case e.REMOVE_ASSOCIATION:k=j.getType();if(!k)break;d=c.type2associations.get(k.getId());for(r=0;r<d.length;r+=1)if(d[r].equals(j)){d.splice(r,1);break}d.length>0?c.type2associations.put(k.getId(),d):c.type2associations.remove(k.getId());break;case e.REMOVE_NAME:k=j.getType();d=c.type2names.get(k.getId());d.remove(j.getId());d.length>0?c.type2names.put(k.getId(),d):c.type2names.remove(k.getId());break;case e.REMOVE_OCCURRENCE:k= +j.getType();d=c.type2occurrences.get(k.getId());d.remove(j.getId());d.length>0?c.type2occurrences.put(k.getId(),d):c.type2occurrences.remove(k.getId());break;case e.REMOVE_ROLE:k=j.getType();d=c.type2roles.get(k.getId());d.remove(j.getId());d.length>0?c.type2roles.put(k.getId(),d):c.type2roles.remove(k.getId());break;case e.REMOVE_TOPIC:k=j.getTypes();for(r=0;r<k.length;r+=1){d=c.type2topics.get(k[r].getId());d.remove(j.getId());d.size()||c.type2topics.remove(k[r].getId())}c.type2topics.remove(j.getId()); +c.type2associations.remove(j.getId());c.type2roles.remove(j.getId());c.type2occurrences.remove(j.getId());c.type2variants.remove(j.getId());break;case e.REMOVE_TYPE:d=c.type2topics.get(k.type.getId());d.remove(j.getId());d.size()||c.type2topics.remove(k.type.getId());if(j.getTypes().length===0){d=c.type2topics.get("null");if(typeof d==="undefined")d=new n;d.put(j.getId(),j)}break;case e.SET_TYPE:if(j.isAssociation()){if(k.old){d=c.type2associations.get(k.old.getId());for(r=0;r<d.length;r+=1)if(d[r].equals(j)){d.splice(r, +1);break}d.length>0?c.type2associations.put(k.old.getId(),d):c.type2associations.remove(k.old.getId())}d=c.type2associations.get(k.type.getId());if(typeof d==="undefined")d=[];d.push(j);c.type2associations.put(k.type.getId(),d)}else if(j.isName()){if(d=c.type2names.get(k.old.getId())){d.remove(j.getId());d.length>0?c.type2names.put(k.old.getId(),d):c.type2names.remove(k.old.getId())}d=c.type2names.get(k.type.getId());if(typeof d==="undefined")d=new n;d.put(j.getId(),j);c.type2names.put(k.type.getId(), +d)}else if(j.isOccurrence()){if(d=c.type2occurrences.get(k.old.getId())){d.remove(j.getId());d.length>0?c.type2occurrences.put(k.old.getId(),d):c.type2occurrences.remove(k.old.getId())}d=c.type2occurrences.get(k.type.getId());if(typeof d==="undefined")d=new n;d.put(j.getId(),j);c.type2occurrences.put(k.type.getId(),d)}else if(j.isRole()){if(d=c.type2roles.get(k.old.getId())){d.remove(j.getId());d.length>0?c.type2roles.put(k.old.getId(),d):c.type2roles.remove(k.old.getId())}d=c.type2roles.get(k.type.getId()); +if(typeof d==="undefined")d=new n;d.put(j.getId(),j);c.type2roles.put(k.type.getId(),d)}break}};a.addAssociationEvent.registerHandler(b);a.addNameEvent.registerHandler(b);a.addOccurrenceEvent.registerHandler(b);a.addRoleEvent.registerHandler(b);a.addTopicEvent.registerHandler(b);a.addTypeEvent.registerHandler(b);a.removeAssociationEvent.registerHandler(b);a.removeNameEvent.registerHandler(b);a.removeOccurrenceEvent.registerHandler(b);a.removeRoleEvent.registerHandler(b);a.removeTopicEvent.registerHandler(b); +a.removeTypeEvent.registerHandler(b);a.setTypeEvent.registerHandler(b)};y.swiss(l,"close","isAutoUpdated","isOpen","open","reindex");y.prototype.getAssociations=function(a){a=this.type2associations.get(a.getId());if(!a)return[];return a};y.prototype.getAssociationTypes=function(){var a=[],b=this.type2associations.keys(),c;for(c=0;c<b.length;c+=1)a.push(this.tm.getConstructById(b[c]));return a};y.prototype.getNames=function(a){a=this.type2names.get(a.getId());if(!a)return[];return a.values()};y.prototype.getNameTypes= +function(){var a=[],b=this.type2names.keys(),c;for(c=0;c<b.length;c+=1)a.push(this.tm.getConstructById(b[c]));return a};y.prototype.getOccurrences=function(a){a=this.type2occurrences.get(a.getId());if(!a)return[];return a.values()};y.prototype.getOccurrenceTypes=function(){var a=[],b=this.type2occurrences.keys(),c;for(c=0;c<b.length;c+=1)a.push(this.tm.getConstructById(b[c]));return a};y.prototype.getRoles=function(a){a=this.type2roles.get(a.getId());if(!a)return[];return a.values()};y.prototype.getRoleTypes= +function(){var a=[],b=this.type2roles.keys(),c;for(c=0;c<b.length;c+=1)a.push(this.tm.getConstructById(b[c]));return a};y.prototype.getTopics=function(a){a=this.type2topics.get(a?a.getId():"null");if(!a)return[];return a.values()};y.prototype.getTopicsByTypes=function(a,b){var c,d;c=E.getForKeys(this.type2topics,a);if(!b)return c;for(b=0;b<c.length;b+=1)for(d=0;d<a.length;d+=1)if(!O.contains(c[b].getTypes(),a[d])){c.splice(b,1);b-=1;break}return c};y.prototype.getTopicTypes=function(){var a=[],b= +this.type2topics.keys(),c;for(c=0;c<b.length;c+=1)b[c]!=="null"&&a.push(this.tm.getConstructById(b[c]));return a};y.prototype.close=function(){};w=function(a){var b=this,c;this.tm=a;this.theme2associations=new n;this.theme2names=new n;this.theme2occurrences=new n;this.theme2variants=new n;c=function(d,j,k){var r,I,M,K,L;L=function(F,G,N){I=N.theme?N.theme.getId():"null";if(G.getScope().length===1)if((M=F.get("null"))&&M.get(G.getId())){M.remove(G.getId());F.put("null",M)}r=F.get(I);if(typeof r=== +"undefined")r=new n;r.put(G.getId(),G);F.put(I,r)};K=function(F,G,N){I=N.theme.getId();r=F.get(I);if(typeof r!=="undefined"){r.remove(G.getId());r.size()||F.remove(I)}};switch(d){case e.ADD_THEME:if(j.isAssociation())L(b.theme2associations,j,k);else if(j.isName())L(b.theme2names,j,k);else if(j.isOccurrence())L(b.theme2occurrences,j,k);else j.isVariant()&&L(b.theme2variants,j,k);break;case e.REMOVE_THEME:if(j.isAssociation())K(b.theme2associations,j,k);else if(j.isName())K(b.theme2names,j,k);else if(j.isOccurrence())K(b.theme2occurrences, +j,k);else j.isVariant()&&K(b.theme2variants,j,k);break}};a.addThemeEvent.registerHandler(c);a.removeThemeEvent.registerHandler(c)};w.swiss(l,"close","isAutoUpdated","isOpen","open","reindex");w.prototype.close=function(){};w.prototype.getAssociations=function(a){a=this.theme2associations.get(a?a.getId():"null");if(!a)return[];return a.values()};w.prototype.getAssociationsByThemes=function(a,b){if(a===null)throw{name:"IllegalArgumentException",message:"ScopedIndex.getAssociationsByThemes cannot be called without themes"}; +return E.getConstructsByThemes(this.theme2associations,a,b)};w.prototype.getAssociationThemes=function(){return E.getConstructThemes(this.tm,this.theme2associations)};w.prototype.getNames=function(a){a=this.theme2names.get(a?a.getId():"null");if(!a)return[];return a.values()};w.prototype.getNamesByThemes=function(a,b){if(a===null)throw{name:"IllegalArgumentException",message:"ScopedIndex.getNamesByThemes cannot be called without themes"};return E.getConstructsByThemes(this.theme2names,a,b)};w.prototype.getNameThemes= +function(){return E.getConstructThemes(this.tm,this.theme2names)};w.prototype.getOccurrences=function(a){a=this.theme2occurrences.get(a?a.getId():"null");if(!a)return[];return a.values()};w.prototype.getOccurrencesByThemes=function(a,b){if(a===null)throw{name:"IllegalArgumentException",message:"ScopedIndex.getOccurrencesByThemes cannot be called without themes"};return E.getConstructsByThemes(this.theme2occurrences,a,b)};w.prototype.getOccurrenceThemes=function(){return E.getConstructThemes(this.tm, +this.theme2occurrences)};w.prototype.getVariants=function(a){if(a===null)throw{name:"IllegalArgumentException",message:"ScopedIndex.getVariants cannot be called without themes"};a=this.theme2variants.get(a?a.getId():"null");if(!a)return[];return a.values()};w.prototype.getVariantsByThemes=function(a,b){if(a===null)throw{name:"IllegalArgumentException",message:"ScopedIndex.getVariantsByThemes cannot be called without themes"};return E.getConstructsByThemes(this.theme2variants,a,b)};w.prototype.getVariantThemes= +function(){return E.getConstructThemes(this.tm,this.theme2variants)};z={assertBelongsTo:function(a,b){var c;if(!b)return false;if(b&&b instanceof f&&!a.equals(b.getTopicMap()))throw{name:"ModelConstraintException",message:"scope topic belongs to different topic map"};if(b&&b instanceof Array)for(c=0;c<b.length;c+=1)if(!a.equals(b[c].getTopicMap()))throw{name:"ModelConstraintException",message:"scope topic belong to different topic maps"};return true}};E={getForKeys:function(a,b){var c,d,j=new n,k, +r;for(c=0;c<b.length;c+=1)if(k=a.get(b[c].getId())){r=k.keys();for(d=0;d<r.length;d+=1)j.put(k.get(r[d]).getId(),k.get(r[d]))}return j.values()},getConstructThemes:function(a,b){var c=[];b=b.keys();var d;for(d=0;d<b.length;d+=1)b[d]!=="null"&&c.push(a.getConstructById(b[d]));return c},getConstructsByThemes:function(a,b,c){var d;a=E.getForKeys(a,b);if(!c)return a;for(c=0;c<a.length;c+=1)for(d=0;d<b.length;d+=1)if(!O.contains(a[c].getScope(),b[d])){a.splice(c,1);c-=1;break}return a}};O={contains:function(a, +b){for(var c in a)if(a.hasOwnProperty(c))if(a[c].equals(b))return true;return false}};J=function(a,b){var c;if(b&&typeof b==="object")if(b instanceof Array)for(c=0;c<b.length;c+=1)a.addTheme(b[c]);else b instanceof f&&a.addTheme(b);else a.getTopicMap().addThemeEvent.fire(a,{theme:null})};s={makeNameValueSignature:function(a){return a.getValue()},makeNameSignature:function(a){return s.makeNameValueSignature(a)+"#"+s.makeTypeSignature(a)+"#"+s.makeScopeSignature(a)},makeOccurrenceSignature:function(a){return s.makeOccurrenceValueSignature(a)+ +"#"+s.makeTypeSignature(a)+"#"+s.makeScopeSignature(a)},makeOccurrenceValueSignature:function(a){return"#"+a.getValue()+"#"+(a.getDatatype()?a.getDatatype().getReference():"null")},makeTypeSignature:function(a){return(a=a.getType())?a.getId():""},makeScopeSignature:function(a){var b,c=[];for(b=0;b<a.length;b+=1)c.push(a[b].getId());c.sort();return c.join("#")},makeAssociationSignature:function(a){var b,c,d=[];b=a.getRoles();for(c=0;c<b.length;c+=1)d.push(s.makeRoleSignature(b[c]));d.sort();return"#"+ +s.makeTypeSignature(a)+"#"+d.join("#")+s.makeScopeSignature(a)},makeRoleSignature:function(a){return s.makeTypeSignature(a)+"#"+a.getPlayer().getId()},makeVariantValueSignature:function(a){return"#"+a.getValue()+"#"+a.getDatatype().getReference()},makeVariantSignature:function(a){return s.makeVariantValueSignature(a)+"#"+s.makeScopeSignature(a)}};H={removeTopicMapDuplicates:function(a){var b,c,d=new n,j;c=a.getTopics();for(b=0;b<c.length;b+=1){H.removeOccurrencesDuplicates(c[b].getOccurrences()); +H.removeNamesDuplicates(c[b].getNames())}a=a.getAssociations();for(b=0;b<a.length;b+=1){H.removeAssociationDuplicates(a[b]);c=s.makeAssociationSignature(a[b]);if(j=d.get(c)){q.moveConstructCharacteristics(a[b],j);q.moveRoleCharacteristics(a[b],j);a[b].remove()}else d.put(c,a[b])}d.empty()},removeOccurrencesDuplicates:function(a){var b,c=new n,d,j,k;for(b=0;b<a.length;b+=1){d=a[b];j=s.makeOccurrenceSignature(d);if(k=c.get(j)){q.moveConstructCharacteristics(d,k);d.remove()}else c.put(j,d)}c.empty()}, +removeNamesDuplicates:function(a){var b,c=new n,d,j,k;for(b=0;b<a.length;b+=1){d=a[b];H.removeVariantsDuplicates(d.getVariants());j=s.makeNameSignature(d);if(k=c.get(j)){q.moveConstructCharacteristics(d,k);q.moveVariants(d,k);d.remove()}else c.put(j,d)}c.empty()},removeVariantsDuplicates:function(a){var b,c=new n,d,j,k;for(b=0;b<a.length;b+=1){d=a[b];j=s.makeVariantSignature(d);if(k=c.get(j)){q.moveConstructCharacteristics(d,k);d.remove()}else c.put(j,d)}c.empty()},removeAssociationDuplicates:function(a){var b= +a.getRoles(),c=new n,d,j;for(a=0;a<b.length;a+=1){d=s.makeRoleSignature(b[a]);if(j=c.get(d)){q.moveConstructCharacteristics(b[a],j);b[a].remove()}else c.put(d,b[a])}}};q={moveTypes:function(a,b){var c;for(c=0;c<a.length;c+=1)a[c].setType(b)},moveThemes:function(a,b,c){for(var d=0;d<a.length;d+=1){a[d].removeTheme(b);a[d].addTheme(c)}},moveItemIdentifiers:function(a,b){var c,d;for(c=a.getItemIdentifiers();c.length;){d=c[c.length-1];a.removeItemIdentifier(d);b.addItemIdentifier(d)}},moveVariants:function(a, +b){var c,d,j,k;c=b.getVariants();k={};for(d=0;d<c.length;d+=1)k[s.makeVariantSignature(c[d])]=c[d];c=a.getVariants();for(d=0;d<c.length;d+=1){a=c[d];if(j=k[s.makeVariantSignature(c[d])]){q.moveItemIdentifiers(a,j);q.moveReifier(a,j);a.remove()}else b.createVariant(a.getValue(),a.getDatatype(),a.getScope())}},moveReifier:function(a,b){var c;if(a.getReifier()!==null)if(b.getReifier()===null)b.setReifier(a.getReifier());else{c=a.getReifier();b=b.getReifier();a.setReifier(null);c.mergeIn(b)}},moveRoleCharacteristics:function(a, +b){var c,d=new n;c=b.getRoles();for(b=0;b<c.length;b+=1)d.put(c[b],s.makeRoleSignature(c[b]));c=a.getRoles();for(b=0;b<c.length;b+=1){q.moveItemIdentifiers(c[b],d.get(s.makeRoleSignature(c[b])));c[b].remove()}},moveConstructCharacteristics:function(a,b){q.moveReifier(a,b);q.moveItemIdentifiers(a,b)}};P={convertAssociationsToType:function(a){var b,c,d,j,k;b=a.getTopicBySubjectIdentifier(a.createLocator(h.TYPE_INSTANCE));c=a.getTopicBySubjectIdentifier(a.createLocator(h.TYPE));d=a.getTopicBySubjectIdentifier(a.createLocator(h.INSTANCE)); +if(!(!b||!c||!d))if(a=a.getIndex("TypeInstanceIndex")){a.isAutoUpdated()||a.reindex();b=a.getAssociations(b);for(a=0;a<b.length;a+=1){j=b[a];if(!(j.getScope().length>0||j.getReifier()!==null||j.getItemIdentifiers().length>0)){k=j.getRoles();if(k.length===2){if(k[0].getType().equals(c)&&k[1].getType().equals(d))k[1].getPlayer().addType(k[0].getPlayer());else if(k[1].getType().equals(c)&&k[0].getType().equals(d))k[0].getPlayer().addType(k[1].getPlayer());else continue;j.remove()}}}}}};return{TopicMapSystemFactory:TopicMapSystemFactory, +XSD:C,TMDM:h,Hash:n,Version:"0.4.0"}}();TopicMapSystemFactory=TM.TopicMapSystemFactory;if(typeof exports==="object"&&exports!==null){exports.TopicMapSystemFactory=TopicMapSystemFactory;exports.TM=TM} +TM.JTM=function(){var n,C;n=function(h){var g=this;this.tm=h;this.version=null;this.prefixes={};this.defaultDatatype=this.tm.createLocator(TM.XSD.string);this.curieToLocator=function(e){var f,i;if(g.version==="1.1"&&e.substr(0,1)==="["){if(e.substr(e.length-1,1)!=="]")throw{name:"InvalidFormat",message:"Invaild CURIE: missing tailing bracket"};e=e.substr(1,e.length-2);i=e.indexOf(":");if(i!==-1){f=e.substr(0,i);if(g.prefixes[f])return e=g.prefixes[f]+e.substr(i+1,e.length-1);else throw{name:"InvalidFormat", +message:"Missing prefix declaration: "+f};}else throw{name:"InvalidFormat",message:"Invaild CURIE: missing colon"};}return e};this.getTopicByReference=function(e){if(typeof e==="undefined"||e===null)return null;switch(e.substr(0,3)){case "si:":return this.tm.createTopicBySubjectIdentifier(this.tm.createLocator(this.curieToLocator(e.substr(3))));case "sl:":return this.tm.createTopicBySubjectLocator(this.tm.createLocator(this.curieToLocator(e.substr(3))));case "ii:":return this.tm.createTopicByItemIdentifier(this.tm.createLocator(this.curieToLocator(e.substr(3))))}throw{name:"InvalidFormat", +message:"Invaild topic reference '"+e+"'"};}};n.prototype.fromString=function(h){return this.fromObject(JSON.parse(h))};n.prototype.fromObject=function(h,g){g=g||null;if(h.version!=="1.0"&&h.version!=="1.1")throw{name:"InvalidFormat",message:"Unknown version of JTM: "+h.version};this.version=h.version;if(h.version==="1.1"&&h.prefixes){if((this.prefixes=h.prefixes)&&h.prefixes.xsd&&h.prefixes.xsd!=="http://www.w3.org/2001/XMLSchema#%22)throw%7Bname:%22InvalidFormat%22,messag... XSD prefix MUST have the value "http://www.w3.org/2001/XMLSchema#%22%27%7D; +}else if(h.prefixes)throw{name:"InvalidFormat",message:"Prefixes are invalid in JTM 1.0: "+h.version};if(!this.prefixes.xsd)this.prefixes.xsd="http://www.w3.org/2001/XMLSchema#%22;if(!h.item_type)throw%7Bname:%22Invalid... item_type"};switch(h.item_type.toLowerCase()){case "topicmap":h=this.parseTopicMap(h);break;case "topic":h=this.parseTopic(h);break;case "name":h=this.parseName(g,h);break;case "variant":h=this.parseVariant(g,h);break;case "occurrence":h=this.parseOccurrence(g,h); +break;case "association":h=this.parseAssociation(h);break;case "role":h=this.parseRole(g,h);break;default:throw{name:"InvalidFormat",message:"Unknown item_type property"};}return h};n.prototype.parseParentAsTopic=function(h){var g=null,e,f;if(h.parent){if(!(h.parent instanceof Array)||h.parent.length===0)throw{name:"InvalidFormat",message:"Missing parent topic reference in occurrence"};}else g=this.tm.createTopic();if(h.parent)for(f=0;f<h.parent.length;f+=1){e=this.getTopicByReference(h.parent[f]); +if(g)g.mergeIn(e);else g=e}return g};n.prototype.parseTopicMap=function(h){var g,e,f;this.parseItemIdentifiers(this.tm,h.item_identifiers);this.parseReifier(this.tm,h.reifier);if(h.topics&&typeof h.topics==="object"&&h.topics instanceof Array){f=h.topics;e=f.length;for(g=0;g<e;g+=1)this.parseTopic(f[g])}if(h.associations&&typeof h.associations==="object"&&h.associations instanceof Array){f=h.associations;e=f.length;for(g=0;g<e;g+=1)this.parseAssociation(f[g])}this.tm.sanitize();return true};n.prototype.parseTopic= +function(h){var g=this,e=null,f,i,l,m;f=function(o,t,u,p,D,x){var A,B,v;if(u&&typeof u==="object"&&u instanceof Array){B=u.length;for(A=0;A<B;A+=1){l=decodeURI(g.curieToLocator(u[A]));if(t)if((v=p.apply(o,[o.createLocator(l)]))&&v.isTopic()&&!t.equals(v))t.mergeIn(v);else v&&v.isTopic()&&t.equals(v)||t[x](o.createLocator(l));else t=D.apply(o,[o.createLocator(l)])}}return t};e=f(this.tm,e,h.subject_identifiers,this.tm.getTopicBySubjectIdentifier,this.tm.createTopicBySubjectIdentifier,"addSubjectIdentifier"); +e=f(this.tm,e,h.subject_locators,this.tm.getTopicBySubjectLocator,this.tm.createTopicBySubjectLocator,"addSubjectLocator");e=f(this.tm,e,h.item_identifiers,this.tm.getConstructByItemIdentifier,this.tm.createTopicByItemIdentifier,"addItemIdentifier");if((f=h.instance_of)&&this.version==="1.1")for(i=0;i<f.length;i+=1){m=this.getTopicByReference(f[i]);e.addType(m)}else if(h.instance_of&&this.version==="1.0")throw{name:"InvalidFormat",message:"instance_of is invalid in JTM 1.0"};if((f=h.names)&&typeof f=== +"object"&&f instanceof Array)for(i=0;i<f.length;i+=1)this.parseName(e,f[i]);if((f=h.occurrences)&&typeof f==="object"&&f instanceof Array)for(i=0;i<f.length;i+=1)this.parseOccurrence(e,f[i])};n.prototype.parseName=function(h,g){var e,f;h||(h=this.parseParentAsTopic(g));f=this.parseScope(g.scope);e=this.getTopicByReference(g.type);h=h.createName(g.value,e,f);if((e=g.variants)&&typeof e==="object"&&e instanceof Array)for(f=0;f<e.length;f+=1)this.parseVariant(h,e[f]);this.parseItemIdentifiers(h,g.item_identifiers); +this.parseReifier(h,g.reifier)};n.prototype.parseVariant=function(h,g){var e;e=this.parseScope(g.scope);h=h.createVariant(g.value,g.datatype?this.tm.createLocator(this.curieToLocator(g.datatype)):this.defaultDatatype,e);this.parseItemIdentifiers(h,g.item_identifiers);this.parseReifier(h,g.reifier)};n.prototype.parseOccurrence=function(h,g){var e,f;h||(h=this.parseParentAsTopic(g));f=this.parseScope(g.scope);e=this.getTopicByReference(g.type);h=h.createOccurrence(e,g.value,g.datatype?this.tm.createLocator(this.curieToLocator(g.datatype)): +this.defaultDatatype,f);this.parseItemIdentifiers(h,g.item_identifiers);this.parseReifier(h,g.reifier)};n.prototype.parseAssociation=function(h){var g,e,f;g=this.parseScope(h.scope);g=this.tm.createAssociation(this.getTopicByReference(h.type),g);if((e=h.roles)&&typeof e==="object"&&e instanceof Array){if(e.length===0)throw{name:"InvalidFormat",message:"Association needs roles"};for(f=0;f<e.length;f+=1)this.parseRole(g,e[f])}else throw{name:"InvalidFormat",message:"Association needs roles"};this.parseItemIdentifiers(g, +h.item_identifiers);this.parseReifier(g,h.reifier)};n.prototype.parseRole=function(h,g){var e,f;e=this.getTopicByReference(g.type);f=this.getTopicByReference(g.player);h=h.createRole(e,f);this.parseItemIdentifiers(h,g.item_identifiers);this.parseReifier(h,g.reifier)};n.prototype.parseScope=function(h){var g,e=[];if(h&&typeof h==="object"&&h instanceof Array)for(g=0;g<h.length;g+=1)e.push(this.getTopicByReference(h[g]));return e};n.prototype.parseItemIdentifiers=function(h,g){var e,f,i;f=h.getTopicMap(); +if(g&&typeof g==="object"&&g instanceof Array)for(e=0;e<g.length;e+=1){i=this.curieToLocator(g[e]);f.getConstructByItemIdentifier(f.createLocator(i))||h.addItemIdentifier(f.createLocator(i))}};n.prototype.parseReifier=function(h,g){if((g=this.getTopicByReference(g))&&g.getReified()===null||!g)h.setReifier(g)};C=function(h){var g=this,e;this.defaultDatatype=TM.XSD.string;this.prefixes=new TM.Hash;this.version=h||"1.0";e=function(f){var i,l,m,o;if(g.version==="1.0")return f;l=g.prefixes.keys();for(m= +0;m<l.length;m+=1){i=l[m];o=g.prefixes.get(i);if(f.substring(0,o.length)===o)return"["+i+":"+f.substr(o.length)+"]"}return f};this.setPrefixes=function(f){var i;for(i in f)f.hasOwnProperty(i)&&this.prefixes.put(i,f[i])};this.getTopicReference=function(f){var i;i=f.getSubjectIdentifiers();if(i.length>0)return"si:"+e(i[0].getReference());i=f.getSubjectLocators();if(i.length>0)return"sl:"+e(i[0].getReference());i=f.getItemIdentifiers();if(i.length>0)return"ii:"+e(i[0].getReference())};this.exportIdentifiers= +function(f,i,l){var m,o=i.length;if(o>0){f[l]=[];for(m=0;m<o;m+=1)f[l].push(e(i[m].getReference()))}};this.exportScope=function(f,i){var l=i.getScope();if(l.length>0){f.scope=[];for(i=0;i<l.length;i+=1)f.scope.push(g.getTopicReference(l[i]))}};this.exportParent=function(f,i){i=i.getParent();g.exportIdentifiers(f,i.getItemIdentifiers(),"parent")};this.exportTopicMap=function(f){var i,l,m,o;o={topics:[],associations:[]};i=f.getTopics();m=i.length;for(l=0;l<m;l+=1)o.topics.push(g.exportTopic(i[l])); +i=f.getAssociations();m=i.length;for(l=0;l<m;l+=1)o.associations.push(g.exportAssociation(i[l]));return o};this.exportTopic=function(f){var i,l,m,o;o={};g.exportIdentifiers(o,f.getSubjectIdentifiers(),"subject_identifiers");g.exportIdentifiers(o,f.getSubjectLocators(),"subject_locators");g.exportIdentifiers(o,f.getItemIdentifiers(),"item_identifiers");i=f.getNames();m=i.length;if(m>0){o.names=[];for(l=0;l<m;l+=1)o.names.push(g.exportName(i[l]))}i=f.getOccurrences();m=i.length;if(m>0){o.occurrences= +[];for(l=0;l<m;l+=1)o.occurrences.push(g.exportOccurrence(i[l]))}i=f.getTypes();m=i.length;if(m>0){o.instance_of=[];for(l=0;l<m;l+=1)o.instance_of.push(g.getTopicReference(i[l]))}return o};this.exportName=function(f){var i,l,m;m={value:f.getValue()};if(i=f.getType())m.type=g.getTopicReference(i);if(i=f.getReifier())m.reifier=g.getTopicReference(i);g.exportIdentifiers(m,f.getItemIdentifiers(),"item_identifiers");g.exportScope(m,f);f=f.getVariants();l=f.length;if(l>0){m.variants=[];for(i=0;i<l;i+=1)m.variants.push(g.exportVariant(f[i]))}return m}; +this.exportVariant=function(f){var i,l;i={value:f.getValue()};if((l=f.getDatatype())&&l!==f.getTopicMap().createLocator(g.defaultDatatype))i.datatype=e(l.getReference());if(l=f.getReifier())i.reifier=g.getTopicReference(l);g.exportIdentifiers(i,f.getItemIdentifiers(),"item_identifiers");g.exportScope(i,f)};this.exportOccurrence=function(f){var i,l;i={value:f.getValue(),type:g.getTopicReference(f.getType())};if((l=f.getDatatype())&&l!==f.getTopicMap().createLocator(g.defaultDatatype))i.datatype=e(l.getReference()); +if(l=f.getReifier())i.reifier=g.getTopicReference(l);g.exportIdentifiers(i,f.getItemIdentifiers(),"item_identifiers");g.exportScope(i,f);return i};this.exportAssociation=function(f){var i,l;l={type:g.getTopicReference(f.getType()),roles:[]};if(i=f.getReifier())l.reifier=g.getTopicReference(i);g.exportIdentifiers(l,f.getItemIdentifiers(),"item_identifiers");g.exportScope(l,f);f=f.getRoles();for(i=0;i<f.length;i+=1)l.roles.push(g.exportRole(f[i]));return l};this.exportRole=function(f){var i,l;i={player:g.getTopicReference(f.getPlayer()), +type:g.getTopicReference(f.getType())};if(l=f.getReifier())i.reifier=g.getTopicReference(l);g.exportIdentifiers(i,f.getItemIdentifiers(),"item_identifiers");return i}};C.prototype.toObject=function(h,g){var e,f,i;g=g||false;h.getTopicMap();if(h.isTopicMap()){e=this.exportTopicMap(h);e.item_type="topicmap"}else if(h.isRole()){e=this.exportRole(h);e.item_type="role"}else if(h.isTopic()){e=this.exportTopic(h);e.item_type="topic"}else if(h.isAssociation()){e=this.exportAssociation(h);e.item_type="association"}else if(h.isOccurrence()){e= +this.exportOccurrence(h);e.item_type="occurrence"}else if(h.isName()){e=this.exportName(h);e.item_type="name"}else if(h.isVariant()){e=this.exportVariant(h);e.item_type="variant"}e.version=this.version;if(this.version==="1.1"&&this.prefixes)if(this.prefixes.size()){f=this.prefixes.keys();e.prefixes={};for(i=0;i<f.length;i+=1)e.prefixes[f[i]]=this.prefixes.get(f[i])}if(!h.isTopic()&&h.getReifier())e.reifier=this.getTopicReference(h.getReifier());g&&!h.isTopicMap()&&this.exportParent(e,h);return e}; +return{Reader:n,Writer:C}}();