1// Copyright (c) 2013 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5'use strict';
6
7/**
8 * @fileoverview Provides the ObjectCollection class.
9 */
10base.require('base.utils');
11base.require('base.range');
12base.require('base.sorted_array_utils');
13base.require('tracing.trace_model.object_instance');
14base.require('tracing.trace_model.time_to_object_instance_map');
15
16base.exportTo('tracing.trace_model', function() {
17  var ObjectInstance = tracing.trace_model.ObjectInstance;
18
19  /**
20   * A collection of object instances and their snapshots, accessible by id and
21   * time, or by object name.
22   *
23   * @constructor
24   */
25  function ObjectCollection(parent) {
26    this.parent = parent;
27    this.bounds = new base.Range();
28    this.instanceMapsById_ = {}; // id -> TimeToObjectInstanceMap
29    this.instancesByTypeName_ = {};
30    this.createObjectInstance_ = this.createObjectInstance_.bind(this);
31  }
32
33  ObjectCollection.prototype = {
34    __proto__: Object.prototype,
35
36    createObjectInstance_: function(parent, id, category, name, creationTs) {
37      var constructor = tracing.trace_model.ObjectInstance.getConstructor(name);
38      var instance = new constructor(parent, id, category, name, creationTs);
39      var typeName = instance.typeName;
40      var instancesOfTypeName = this.instancesByTypeName_[typeName];
41      if (!instancesOfTypeName) {
42        instancesOfTypeName = [];
43        this.instancesByTypeName_[typeName] = instancesOfTypeName;
44      }
45      instancesOfTypeName.push(instance);
46      return instance;
47    },
48
49    getOrCreateInstanceMap_: function(id) {
50      var instanceMap = this.instanceMapsById_[id];
51      if (instanceMap)
52        return instanceMap;
53      instanceMap = new tracing.trace_model.TimeToObjectInstanceMap(
54          this.createObjectInstance_, this.parent, id);
55      this.instanceMapsById_[id] = instanceMap;
56      return instanceMap;
57    },
58
59    idWasCreated: function(id, category, name, ts) {
60      var instanceMap = this.getOrCreateInstanceMap_(id);
61      return instanceMap.idWasCreated(category, name, ts);
62    },
63
64    addSnapshot: function(id, category, name, ts, args) {
65      var instanceMap = this.getOrCreateInstanceMap_(id, category, name, ts);
66      var snapshot = instanceMap.addSnapshot(category, name, ts, args);
67      if (snapshot.objectInstance.category != category) {
68        throw new Error('Added snapshot with different category ' +
69                        'than when it was created');
70      }
71      if (snapshot.objectInstance.name != name) {
72        throw new Error('Added snapshot with different name than ' +
73                        'when it was created');
74      }
75      return snapshot;
76    },
77
78    idWasDeleted: function(id, category, name, ts) {
79      var instanceMap = this.getOrCreateInstanceMap_(id, category, name, ts);
80      var deletedInstance = instanceMap.idWasDeleted(category, name, ts);
81      if (!deletedInstance)
82        return;
83      if (deletedInstance.category != category) {
84        throw new Error('Deleting an object with a different category ' +
85                        'than when it was created');
86      }
87      if (deletedInstance.name != name) {
88        throw new Error('Deleting an object with a different name than ' +
89                        'when it was created');
90      }
91    },
92
93    autoDeleteObjects: function(maxTimestamp) {
94      base.iterItems(this.instanceMapsById_, function(id, i2imap) {
95        var lastInstance = i2imap.lastInstance;
96        if (lastInstance.deletionTs != Number.MAX_VALUE)
97          return;
98        i2imap.idWasDeleted(
99            lastInstance.category, lastInstance.name, maxTimestamp);
100        // idWasDeleted will cause lastInstance.deletionTsWasExplicit to be set
101        // to true. Unset it here.
102        lastInstance.deletionTsWasExplicit = false;
103      });
104    },
105
106    getObjectInstanceAt: function(id, ts) {
107      var instanceMap = this.instanceMapsById_[id];
108      if (!instanceMap)
109        return undefined;
110      return instanceMap.getInstanceAt(ts);
111    },
112
113    getSnapshotAt: function(id, ts) {
114      var instance = this.getObjectInstanceAt(id, ts);
115      if (!instance)
116        return undefined;
117      return instance.getSnapshotAt(ts);
118    },
119
120    iterObjectInstances: function(iter, opt_this) {
121      opt_this = opt_this || this;
122      base.iterItems(this.instanceMapsById_, function(id, i2imap) {
123        i2imap.instances.forEach(iter, opt_this);
124      });
125    },
126
127    getAllObjectInstances: function() {
128      var instances = [];
129      this.iterObjectInstances(function(i) { instances.push(i); });
130      return instances;
131    },
132
133    getAllInstancesNamed: function(name) {
134      return this.instancesByTypeName_[name];
135    },
136
137    getAllInstancesByTypeName: function() {
138      return this.instancesByTypeName_;
139    },
140
141    preInitializeAllObjects: function() {
142      this.iterObjectInstances(function(instance) {
143        instance.preInitialize();
144      });
145    },
146
147    initializeAllObjects: function() {
148      this.iterObjectInstances(function(instance) {
149        instance.initialize();
150      });
151    },
152
153    initializeInstances: function() {
154      this.iterObjectInstances(function(instance) {
155        instance.initialize();
156      });
157    },
158
159    updateBounds: function() {
160      this.bounds.reset();
161      this.iterObjectInstances(function(instance) {
162        instance.updateBounds();
163        this.bounds.addRange(instance.bounds);
164      }, this);
165    },
166
167    shiftTimestampsForward: function(amount) {
168      this.iterObjectInstances(function(instance) {
169        instance.shiftTimestampsForward(amount);
170      });
171    },
172
173    addCategoriesToDict: function(categoriesDict) {
174      this.iterObjectInstances(function(instance) {
175        categoriesDict[instance.category] = true;
176      });
177    },
178
179    toJSON: function() {
180      // TODO(nduca): Implement this if we need it.
181      return {};
182    }
183  };
184
185  return {
186    ObjectCollection: ObjectCollection
187  };
188});
189