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