blob: e23db935fe3c7793cb6b1d55e53b9346dd54d389 [file] [log] [blame]
<!DOCTYPE html>
<!--
Copyright (c) 2013 The Chromium Authors. All rights reserved.
Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
<link rel="import" href="/model/event_container.html">
<link rel="import" href="/model/object_instance.html">
<link rel="import" href="/model/time_to_object_instance_map.html">
<link rel="import" href="/base/utils.html">
<link rel="import" href="/base/range.html">
<link rel="import" href="/base/sorted_array_utils.html">
<script>
'use strict';
/**
* @fileoverview Provides the ObjectCollection class.
*/
tr.exportTo('tr.model', function() {
var ObjectInstance = tr.model.ObjectInstance;
var ObjectSnapshot = tr.model.ObjectSnapshot;
/**
* A collection of object instances and their snapshots, accessible by id and
* time, or by object name.
*
* @constructor
*/
function ObjectCollection(parent) {
tr.model.EventContainer.call(this);
this.parent = parent;
this.instanceMapsById_ = {}; // id -> TimeToObjectInstanceMap
this.instancesByTypeName_ = {};
this.createObjectInstance_ = this.createObjectInstance_.bind(this);
}
ObjectCollection.prototype = {
__proto__: tr.model.EventContainer.prototype,
iterateAllChildEventContainers: function(callback, opt_this) {
},
iterateAllEventsInThisContainer: function(eventTypePredicate,
callback, opt_this) {
var bI = !!eventTypePredicate.call(opt_this, ObjectInstance);
var bS = !!eventTypePredicate.call(opt_this, ObjectSnapshot);
if (bI === false && bS === false)
return;
this.iterObjectInstances(function(instance) {
if (bI)
callback.call(opt_this, instance);
if (bS)
instance.snapshots.forEach(callback, opt_this);
}, opt_this);
},
createObjectInstance_: function(
parent, id, category, name, creationTs, opt_baseTypeName) {
var constructor = tr.model.ObjectInstance.getConstructor(
category, name);
var instance = new constructor(
parent, id, category, name, creationTs, opt_baseTypeName);
var typeName = instance.typeName;
var instancesOfTypeName = this.instancesByTypeName_[typeName];
if (!instancesOfTypeName) {
instancesOfTypeName = [];
this.instancesByTypeName_[typeName] = instancesOfTypeName;
}
instancesOfTypeName.push(instance);
return instance;
},
getOrCreateInstanceMap_: function(id) {
var instanceMap = this.instanceMapsById_[id];
if (instanceMap)
return instanceMap;
instanceMap = new tr.model.TimeToObjectInstanceMap(
this.createObjectInstance_, this.parent, id);
this.instanceMapsById_[id] = instanceMap;
return instanceMap;
},
idWasCreated: function(id, category, name, ts) {
var instanceMap = this.getOrCreateInstanceMap_(id);
return instanceMap.idWasCreated(category, name, ts);
},
addSnapshot: function(id, category, name, ts, args, opt_baseTypeName) {
var instanceMap = this.getOrCreateInstanceMap_(id);
var snapshot = instanceMap.addSnapshot(
category, name, ts, args, opt_baseTypeName);
if (snapshot.objectInstance.category != category) {
var msg = 'Added snapshot name=' + name + ' with cat=' + category +
' impossible. It instance was created/snapshotted with cat=' +
snapshot.objectInstance.category + ' name=' +
snapshot.objectInstance.name;
throw new Error(msg);
}
if (opt_baseTypeName &&
snapshot.objectInstance.baseTypeName != opt_baseTypeName) {
throw new Error('Could not add snapshot with baseTypeName=' +
opt_baseTypeName + '. It ' +
'was previously created with name=' +
snapshot.objectInstance.baseTypeName);
}
if (snapshot.objectInstance.name != name) {
throw new Error('Could not add snapshot with name=' + name + '. It ' +
'was previously created with name=' +
snapshot.objectInstance.name);
}
return snapshot;
},
idWasDeleted: function(id, category, name, ts) {
var instanceMap = this.getOrCreateInstanceMap_(id);
var deletedInstance = instanceMap.idWasDeleted(category, name, ts);
if (!deletedInstance)
return;
if (deletedInstance.category != category) {
var msg = 'Deleting object ' + deletedInstance.name +
' with a different category ' +
'than when it was created. It previous had cat=' +
deletedInstance.category + ' but the delete command ' +
'had cat=' + category;
throw new Error(msg);
}
if (deletedInstance.baseTypeName != name) {
throw new Error('Deletion requested for name=' +
name + ' could not proceed: ' +
'An existing object with baseTypeName=' +
deletedInstance.baseTypeName + ' existed.');
}
},
autoDeleteObjects: function(maxTimestamp) {
tr.b.iterItems(this.instanceMapsById_, function(id, i2imap) {
var lastInstance = i2imap.lastInstance;
if (lastInstance.deletionTs != Number.MAX_VALUE)
return;
i2imap.idWasDeleted(
lastInstance.category, lastInstance.name, maxTimestamp);
// idWasDeleted will cause lastInstance.deletionTsWasExplicit to be set
// to true. Unset it here.
lastInstance.deletionTsWasExplicit = false;
});
},
getObjectInstanceAt: function(id, ts) {
var instanceMap = this.instanceMapsById_[id];
if (!instanceMap)
return undefined;
return instanceMap.getInstanceAt(ts);
},
getSnapshotAt: function(id, ts) {
var instance = this.getObjectInstanceAt(id, ts);
if (!instance)
return undefined;
return instance.getSnapshotAt(ts);
},
iterObjectInstances: function(iter, opt_this) {
opt_this = opt_this || this;
tr.b.iterItems(this.instanceMapsById_, function(id, i2imap) {
i2imap.instances.forEach(iter, opt_this);
});
},
getAllObjectInstances: function() {
var instances = [];
this.iterObjectInstances(function(i) { instances.push(i); });
return instances;
},
getAllInstancesNamed: function(name) {
return this.instancesByTypeName_[name];
},
getAllInstancesByTypeName: function() {
return this.instancesByTypeName_;
},
preInitializeAllObjects: function() {
this.iterObjectInstances(function(instance) {
instance.preInitialize();
});
},
initializeAllObjects: function() {
this.iterObjectInstances(function(instance) {
instance.initialize();
});
},
initializeInstances: function() {
this.iterObjectInstances(function(instance) {
instance.initialize();
});
},
updateBounds: function() {
this.bounds.reset();
this.iterObjectInstances(function(instance) {
instance.updateBounds();
this.bounds.addRange(instance.bounds);
}, this);
},
shiftTimestampsForward: function(amount) {
this.iterObjectInstances(function(instance) {
instance.shiftTimestampsForward(amount);
});
},
addCategoriesToDict: function(categoriesDict) {
this.iterObjectInstances(function(instance) {
categoriesDict[instance.category] = true;
});
}
};
return {
ObjectCollection: ObjectCollection
};
});
</script>