Add some documenation notes, and remove some traces
[potlatch2.git] / net / systemeD / halcyon / connection / EntityCollection.as
1 package net.systemeD.halcyon.connection {
2
3         import flash.events.TimerEvent;
4         import flash.utils.Timer;
5     
6         import net.systemeD.halcyon.connection.*;
7     import net.systemeD.halcyon.connection.actions.*;
8
9         // ** FIXME:
10         // - Can we rework the ControllerStates so they work with this (rather than just a raw Array)?
11         // - It may be possible to generalise the event timer code into a tidier "event grouping" class of some sort
12
13     public class EntityCollection extends Entity {
14                 private var _entities:Array;
15                 private var tagChangedTimer:Timer;
16                 private var addedToRelationTimer:Timer;
17                 private var removedFromRelationTimer:Timer;
18                 private var delayedEvents:Array = [];
19
20         public function EntityCollection(entities:Array) {
21                         super(-1, 0, {}, true, NaN, null, null);
22             _entities = entities;
23                         
24                         //To avoid firing on every contained entity, we wait some short time before firing the events
25                         tagChangedTimer         = new Timer(50, 1); tagChangedTimer.addEventListener(TimerEvent.TIMER, onTimerFinished, false, 0, true);
26                         addedToRelationTimer    = new Timer(50, 1); addedToRelationTimer.addEventListener(TimerEvent.TIMER, onTimerFinished, false, 0, true);
27                         removedFromRelationTimer= new Timer(50, 1); removedFromRelationTimer.addEventListener(TimerEvent.TIMER, onTimerFinished, false, 0, true);
28                         for each(var entity:Entity in _entities) {
29                                 entity.addEventListener(Connection.TAG_CHANGED, onTagChanged, false, 0, true);
30                                 entity.addEventListener(Connection.ADDED_TO_RELATION, onAddedToRelation, false, 0, true);
31                                 entity.addEventListener(Connection.REMOVED_FROM_RELATION, onRemovedFromRelation, false, 0, true);
32                         }
33         }
34                 
35                 public override function get entities():Array {
36                         return _entities;
37                 }
38                 
39                 private function onTagChanged(event:TagEvent):void {
40                         if(tagChangedTimer.running) return;
41                         delayedEvents.push(new TagEvent(Connection.TAG_CHANGED, this, event.key, event.key, event.oldValue, event.newValue));
42                         tagChangedTimer.start();
43                 }
44                 
45                 private function onAddedToRelation(event:RelationMemberEvent):void {
46                         if(addedToRelationTimer.running) return;
47                         delayedEvents.push(new RelationMemberEvent(Connection.ADDED_TO_RELATION, this, event.relation, event.index));
48                         addedToRelationTimer.start();
49                 }
50                 
51                 private function onRemovedFromRelation(event:RelationMemberEvent):void {
52                         if(removedFromRelationTimer.running) return;
53                         delayedEvents.push(new RelationMemberEvent(Connection.REMOVED_FROM_RELATION, this, event.relation, event.index));
54                         removedFromRelationTimer.start();
55                 }
56                 
57                 private function onTimerFinished(event:TimerEvent):void { 
58                         dispatchEvent(delayedEvents.shift());
59                 }
60                 
61                 
62                 // Tag-handling methods
63                 
64                 private function getMergedTags():Object {
65                         //Builds an object with tags of all entities in this collection. If the value of a tag differs or is not set in all entities, value is marked
66                         var differentMarker:String = "<different>";
67                         var mergedTags:Object = _entities[0].getTagsCopy();
68                         for each(var entity:Entity in _entities) {
69                                 var entityTags:Object = entity.getTagsHash();
70                                 for(var key:String in entityTags) {
71                                         var value:String = entityTags[key];
72                                         if(mergedTags[key] == null || mergedTags[key] != value) {
73                                                 mergedTags[key] = differentMarker;
74                                         }
75                                 }
76                                 for(var mergedKey:String in mergedTags) {
77                                         var mergedValue:String = mergedTags[mergedKey];
78                                         if(entityTags[mergedKey] == null || entityTags[mergedKey] != mergedValue) {
79                                                 mergedTags[mergedKey] = differentMarker;
80                                         }
81                                 }
82                         }
83                         return mergedTags;
84                 }
85
86         public override function hasTags():Boolean {
87                         for (var key:String in getMergedTags())
88                 return true;
89             return false;
90         }
91
92         public override function hasInterestingTags():Boolean {
93                         for (var key:String in getMergedTags()) {
94               if (key != "attribution" && key != "created_by" && key != "source" && key.indexOf('tiger:') != 0) {
95                 return true;
96               }
97             }
98             return false;
99         }
100
101         public override function isUneditedTiger():Boolean {
102             return false;
103         }
104
105         public override function getTag(key:String):String {
106                         return getMergedTags()[key];
107         }
108
109                 public override function tagIs(key:String,value:String):Boolean {
110                         if (!getMergedTags[key]) { return false; }
111                         return getMergedTags[key]==value;
112                 }
113                 
114                 public override function setTag(key:String, value:String, performAction:Function):void {
115                         var oldValue:String = getMergedTags()[key];     
116                         var undoAction:CompositeUndoableAction = new CompositeUndoableAction("set_tag_entity_collection");
117                         for each (var entity:Entity in _entities) {
118                                 undoAction.push(new SetTagAction(entity, key, value));
119                         }
120             performAction(undoAction);
121         }
122
123         public override function renameTag(oldKey:String, newKey:String, performAction:Function):void {
124                         var undoAction:CompositeUndoableAction = new CompositeUndoableAction("rename_tag_entity_collection");
125                         for each (var entity:Entity in _entities) {
126                                 undoAction.push(new SetTagKeyAction(entity, oldKey, newKey));
127                         }
128             performAction(undoAction);
129         }
130
131         public override function getTagList():TagList {
132             return new TagList(getMergedTags());
133         }
134
135         public override function getTagsCopy():Object {
136                         return getMergedTags();
137         }
138
139                 public override function getTagsHash():Object {
140                         return getMergedTags();
141                 }
142
143         public override function getTagArray():Array {
144             var copy:Array = [];
145                         var mergedTags:Object = getMergedTags();
146             for (var key:String in mergedTags) {
147                 copy.push(new Tag(this, key, mergedTags[key]));
148                         }
149             return copy;
150         }
151
152                 public override function get parentRelations():Array {
153                         var relations:Array = [];
154                         for each (var entity:Entity in _entities) {
155                                 for each (var relation:Relation in entity.parentRelations) {
156                                         if (relations.indexOf(relation)==-1) relations.push(relation);
157                                 }
158                         }
159                         return relations;
160                 }
161
162                 public override function getRelationMemberships():Array {
163                         var relations:Object = {};
164                         for each (var entity:Entity in _entities) {
165                                 for each (var rel:Relation in entity.parentRelations) {
166                                         for each(var memberIndex:int in rel.findEntityMemberIndexes(entity)) {
167                                                 var role:String=rel.getMember(memberIndex).role;
168                                                 if (!relations[rel.id]) {
169                                                         relations[rel.id]= { role: role, relation: rel, distinctCount: 0};
170                                                 } else if (relations[rel.id].role!=role) {
171                                                         relations[rel.id].role="<different>";
172                                                 }
173                                         }
174                                         relations[rel.id].distinctCount++;
175                                 }
176                         }
177                         var memberships:Array = [];
178                         for (var id:String in relations) {
179                                 memberships.push({
180                                         relation: relations[id].relation,
181                                         id: Number(id),
182                                         role: relations[id].role,
183                                         description: relations[id].relation.getDescription(),
184                                         universal: relations[id].distinctCount==_entities.length,
185                                         id_idx: id });
186                         }
187                         return memberships;
188                         // ** FIXME: .universal should be shown in the tag panel
189                 }
190
191                 // Clean/dirty methods
192
193         public override function get isDirty():Boolean {
194             for each (var entity:Entity in _entities) {
195                                 if(entity.isDirty) return true;
196                         }
197                         return false;
198         }
199
200         public override function markClean():void {
201              for each (var entity:Entity in _entities) {
202                                 entity.markClean();
203                         }
204         }
205
206         internal override function markDirty():void {
207             for each (var entity:Entity in _entities) {
208                                 entity.markDirty();
209                         }
210         }
211         
212         
213                 // Others
214         
215                 public override function getDescription():String {
216                         var basic:String=this.getType();
217                         var mergedTags:Object = getMergedTags();
218                         if (mergedTags['ref'] && mergedTags['name']) { return mergedTags['ref']+' '+mergedTags['name']+' ('+basic+')'; }
219                         if (mergedTags['ref']) { return mergedTags['ref']+' ('+basic+')'; }
220                         if (mergedTags['name']) { return mergedTags['name']+' ('+basic+')'; }
221                         return basic;
222                 }
223
224         public override function getType():String {
225                         var entityType:String = '';
226                          for each (var entity:Entity in _entities) {
227                                 if(entityType == '') entityType = entity.getType();
228                                 else if(entityType != entity.getType()) {
229                                         entityType = '';
230                                         break;
231                                 }
232                         }
233             return entityType;
234         }
235
236     }
237
238 }
239