First cut at styling TIGER data via an option. Needs lots of propagation of uid and...
[potlatch2.git] / net / systemeD / halcyon / connection / Entity.as
1 package net.systemeD.halcyon.connection {
2
3     import flash.events.EventDispatcher;
4     import flash.utils.Dictionary;
5     
6     import net.systemeD.halcyon.connection.actions.*;
7
8     public class Entity extends EventDispatcher {
9         private var _id:Number;
10         private var _version:uint;
11         private var _uid:Number;
12         private var _timestamp:String;
13         private var tags:Object = {};
14         private var modified:Boolean = false;
15                 private var _loaded:Boolean = true;
16                 private var parents:Dictionary = new Dictionary();
17                 private var locked:Boolean = false;
18                 public var deleted:Boolean = false;
19
20         public function Entity(id:Number, version:uint, tags:Object, loaded:Boolean, uid:Number = NaN, timestamp:String = null) {
21             this._id = id;
22             this._version = version;
23             this._uid = uid;
24             this._timestamp = timestamp;
25             this.tags = tags;
26                         this._loaded = loaded;
27             modified = id < 0;
28         }
29
30         public function get id():Number {
31             return _id;
32         }
33
34         public function get version():uint {
35             return _version;
36         }
37
38         public function get uid():Number {
39             return _uid;
40         }
41
42         public function get loaded():Boolean {
43             return _loaded;
44         }
45
46                 public function updateEntityProperties(version:uint, tags:Object, loaded:Boolean, uid:Number = NaN, timestamp:String = null):void {
47                         _version=version; this.tags=tags; _loaded=loaded; _uid = uid; _timestamp = timestamp;
48                 }
49
50                 // Tag-handling methods
51
52         public function hasTags():Boolean {
53             for (var key:String in tags)
54                 return true;
55             return false;
56         }
57
58         public function hasInterestingTags():Boolean {
59             for (var key:String in tags) {
60               if (key != "attribution" && key != "created_by" && key != "source" && key.indexOf('tiger:') != 0) {
61                 //trace(key);
62                 return true;
63               }
64             }
65             return false;
66         }
67
68         public function isUneditedTiger():Boolean {
69             if (this is Way && (uid == 110 || uid == 17)) {//todo fixme etc
70               return true;
71             }
72             return false;
73         }
74
75         public function getTag(key:String):String {
76             return tags[key];
77         }
78
79                 public function tagIs(key:String,value:String):Boolean {
80                         if (!tags[key]) { return false; }
81                         return tags[key]==value;
82                 }
83         
84         public function setTag(key:String, value:String, performAction:Function):void {
85             performAction(new SetTagAction(this, key, value));
86         }
87
88         public function renameTag(oldKey:String, newKey:String, performAction:Function):void {
89             performAction(new SetTagKeyAction(this, oldKey, newKey));
90         }
91
92         public function getTagList():TagList {
93             return new TagList(tags);
94         }
95
96         public function getTagsCopy():Object {
97             var copy:Object = {};
98             for (var key:String in tags )
99                 copy[key] = tags[key];
100             return copy;
101         }
102
103                 public function getTagsHash():Object {
104                         // hm, not sure we should be doing this, but for read-only purposes
105                         // it's faster than using getTagsCopy
106                         return tags;
107                 }
108
109         public function getTagArray():Array {
110             var copy:Array = [];
111             for (var key:String in tags )
112                 copy.push(new Tag(this, key, tags[key]));
113             return copy;
114         }
115
116                 // Clean/dirty methods
117
118         public function get isDirty():Boolean {
119             return modified;
120         }
121
122         public function markClean(newID:Number, newVersion:uint):void {
123             this._id = newID;
124             this._version = newVersion;
125             modified = false;
126         }
127
128         internal function markDirty():void {
129             modified = true;
130         }
131
132                 // Delete entity
133                 
134                 public function remove(performAction:Function):void {
135                         // to be overridden
136                 }
137                 
138                 public function isDeleted():Boolean {
139                     return deleted;
140                 }
141                 
142                 public function setDeletedState(isDeleted:Boolean):void {
143                     deleted = isDeleted;
144                 }
145                 
146                 internal function isEmpty():Boolean {
147                         return false;   // to be overridden
148                 }
149                 
150                 public function within(left:Number,right:Number,top:Number,bottom:Number):Boolean {
151                         return true;    // to be overridden
152                 }
153
154                 public function removeFromParents(performAction:Function):void {
155                         for (var o:Object in parents) {
156                                 if (o is Relation) { Relation(o).removeMember(this, performAction); }
157                                 else if (o is Way) { Way(o).removeNode(Node(this), performAction); }
158                                 if (o.isEmpty()) { o.remove(performAction); }
159                         }
160                 }
161
162                 // Parent handling
163                 
164                 public function addParent(parent:Entity):void {
165                         parents[parent]=true;
166                         
167                         if ( parent is Relation )
168                             dispatchEvent(new RelationMemberEvent(Connection.ADDED_TO_RELATION, this, parent as Relation, -1));
169                 }
170
171                 public function removeParent(parent:Entity):void {
172                         delete parents[parent];
173
174                         if ( parent is Relation )
175                             dispatchEvent(new RelationMemberEvent(Connection.REMOVED_FROM_RELATION, this, parent as Relation, -1));
176                 }
177                 
178                 public function get parentWays():Array {
179                         var a:Array=[];
180                         for (var o:Object in parents) {
181                                 if (o is Way) { a.push(o); }
182                         }
183                         return a;
184                 }
185
186                 public function get hasParents():Boolean {
187                         for (var o:Object in parents) { return true; }
188                         return false;
189                 }
190                 
191                 public function get hasParentWays():Boolean {
192                         for (var o:Object in parents) {
193                                 if (o is Way) { return true; }
194                         }
195                         return false;
196                 }
197                 
198                 public function get numParentWays():uint {
199                         var i:uint=0;
200                         for (var o:Object in parents) {
201                                 if (o is Way) { i++; }
202                         }
203                         return i;
204                 }
205                 
206                 public function get parentRelations():Array {
207                         var a:Array=[];
208                         for (var o:Object in parents) {
209                                 if (o is Relation) { a.push(o); }
210                         }
211                         return a;
212                 }
213                 
214                 public function findParentRelationsOfType(type:String, role:String=""):Array {
215                         var a:Array=[];
216                         for (var o:Object in parents) {
217                                 if (o is Relation && Relation(o).tagIs('type',type) && Relation(o).hasMemberInRole(this,role)) { 
218                                         a.push(o);
219                                 }
220                         }
221                         return a;
222                 }
223                 
224                 public function countParentObjects(within:Object):uint {
225                         var count:uint=0;
226                         for (var o:Object in parents) {
227                                 if (o.getType()==within.entity && o.getTag(within.k)) {
228                                         if (within.v && within.v!=o.getTag(within.k)) { break; }
229                                         if (within.role && !Relation(o).hasMemberInRole(this,within.role)) { break; }
230                                         count++;
231                                 }
232                         }
233                         return count;
234                 }
235                 
236                 public function get parentObjects():Array {
237                         var a:Array=[];
238                         for (var o:Object in parents) { a.push(o); }
239                         return a;
240                 }
241                 
242                 public function hasParent(entity:Entity):Boolean {
243             return parents[entity] == true;
244         }
245
246                 public function get memberships():Array {
247                         var list:Array=[];
248                         for (var o:Object in parents) {
249                                 if (o is Relation) {
250                                         for (var i:uint=0; i<o.length; i++) {
251                                                 if (o.getMember(i).entity==this) {
252                                                         list.push( { relation:o, position:i, role: o.getMember(i).role } );
253                                                 }
254                                         }
255                                 }
256                         }
257             // it's useful to return in a sorted order, even if the relations are interleaved
258             // e.g. [{r0 p1},{r1 p1},{r0 p4}]
259                         return list.sortOn("position"); 
260                 }
261
262                 // Resume/suspend redraw
263                 
264                 public function suspend():void {
265                         dispatchEvent(new EntityEvent(Connection.SUSPEND_REDRAW, this));
266                 }
267                 
268                 public function resume():void {
269                         dispatchEvent(new EntityEvent(Connection.RESUME_REDRAW, this));
270                 }
271
272                 // To be overridden
273
274                 public function getDescription():String {
275                         var basic:String=this.getType()+" "+_id;
276                         if (tags['ref'] && tags['name']) { return tags['ref']+' '+tags['name']+' ('+basic+')'; }
277                         if (tags['ref']) { return tags['ref']+' ('+basic+')'; }
278                         if (tags['name']) { return tags['name']+' ('+basic+')'; }
279                         return basic;
280                 }
281
282         public function getType():String {
283             return '';
284         }
285
286     }
287
288 }
289