this'll keep the Germans happy
[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, timestamp:String) {
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, timestamp:String):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             // todo: make this match the rules from the tiger edited map
70             // http://github.com/MapQuest/TIGER-Edited-map/blob/master/inc/layer-tiger.xml.inc
71             if (this is Way && (uid == 7168 || uid == 15169 || uid == 20587)) {//todo fixme etc
72               return true;
73             }
74             return false;
75         }
76
77         public function getTag(key:String):String {
78             return tags[key];
79         }
80
81                 public function tagIs(key:String,value:String):Boolean {
82                         if (!tags[key]) { return false; }
83                         return tags[key]==value;
84                 }
85         
86         public function setTag(key:String, value:String, performAction:Function):void {
87             performAction(new SetTagAction(this, key, value));
88         }
89
90         public function renameTag(oldKey:String, newKey:String, performAction:Function):void {
91             performAction(new SetTagKeyAction(this, oldKey, newKey));
92         }
93
94         public function getTagList():TagList {
95             return new TagList(tags);
96         }
97
98         public function getTagsCopy():Object {
99             var copy:Object = {};
100             for (var key:String in tags )
101                 copy[key] = tags[key];
102             return copy;
103         }
104
105                 public function getTagsHash():Object {
106                         // hm, not sure we should be doing this, but for read-only purposes
107                         // it's faster than using getTagsCopy
108                         return tags;
109                 }
110
111         public function getTagArray():Array {
112             var copy:Array = [];
113             for (var key:String in tags )
114                 copy.push(new Tag(this, key, tags[key]));
115             return copy;
116         }
117
118                 // Clean/dirty methods
119
120         public function get isDirty():Boolean {
121             return modified;
122         }
123
124         public function markClean(newID:Number, newVersion:uint):void {
125             this._id = newID;
126             this._version = newVersion;
127             modified = false;
128         }
129
130         internal function markDirty():void {
131             modified = true;
132         }
133
134                 // Delete entity
135                 
136                 public function remove(performAction:Function):void {
137                         // to be overridden
138                 }
139                 
140                 public function isDeleted():Boolean {
141                     return deleted;
142                 }
143                 
144                 public function setDeletedState(isDeleted:Boolean):void {
145                     deleted = isDeleted;
146                 }
147                 
148                 internal function isEmpty():Boolean {
149                         return false;   // to be overridden
150                 }
151                 
152                 public function within(left:Number,right:Number,top:Number,bottom:Number):Boolean {
153                         return true;    // to be overridden
154                 }
155
156                 public function removeFromParents(performAction:Function):void {
157                         for (var o:Object in parents) {
158                                 if (o is Relation) { Relation(o).removeMember(this, performAction); }
159                                 else if (o is Way) { Way(o).removeNode(Node(this), performAction); }
160                                 if (o.isEmpty()) { o.remove(performAction); }
161                         }
162                 }
163
164                 // Parent handling
165                 
166                 public function addParent(parent:Entity):void {
167                         parents[parent]=true;
168                         
169                         if ( parent is Relation )
170                             dispatchEvent(new RelationMemberEvent(Connection.ADDED_TO_RELATION, this, parent as Relation, -1));
171                 }
172
173                 public function removeParent(parent:Entity):void {
174                         delete parents[parent];
175
176                         if ( parent is Relation )
177                             dispatchEvent(new RelationMemberEvent(Connection.REMOVED_FROM_RELATION, this, parent as Relation, -1));
178                 }
179                 
180                 public function get parentWays():Array {
181                         var a:Array=[];
182                         for (var o:Object in parents) {
183                                 if (o is Way) { a.push(o); }
184                         }
185                         return a;
186                 }
187
188                 public function get hasParents():Boolean {
189                         for (var o:Object in parents) { return true; }
190                         return false;
191                 }
192                 
193                 public function get hasParentWays():Boolean {
194                         for (var o:Object in parents) {
195                                 if (o is Way) { return true; }
196                         }
197                         return false;
198                 }
199                 
200                 public function get numParentWays():uint {
201                         var i:uint=0;
202                         for (var o:Object in parents) {
203                                 if (o is Way) { i++; }
204                         }
205                         return i;
206                 }
207                 
208                 public function get parentRelations():Array {
209                         var a:Array=[];
210                         for (var o:Object in parents) {
211                                 if (o is Relation) { a.push(o); }
212                         }
213                         return a;
214                 }
215                 
216                 public function findParentRelationsOfType(type:String, role:String=null):Array {
217                         var a:Array=[];
218                         for (var o:Object in parents) {
219                                 if (o is Relation && Relation(o).tagIs('type',type) && (role==null || Relation(o).hasMemberInRole(this,role))) { 
220                                         a.push(o);
221                                 }
222                         }
223                         return a;
224                 }
225                 
226                 public function countParentObjects(within:Object):uint {
227                         var count:uint=0;
228                         for (var o:Object in parents) {
229                                 if (o.getType()==within.entity && o.getTag(within.k)) {
230                                         if (within.v && within.v!=o.getTag(within.k)) { break; }
231                                         if (within.role && !Relation(o).hasMemberInRole(this,within.role)) { break; }
232                                         count++;
233                                 }
234                         }
235                         return count;
236                 }
237                 
238                 public function get parentObjects():Array {
239                         var a:Array=[];
240                         for (var o:Object in parents) { a.push(o); }
241                         return a;
242                 }
243                 
244                 public function hasParent(entity:Entity):Boolean {
245             return parents[entity] == true;
246         }
247
248                 public function get memberships():Array {
249                         var list:Array=[];
250                         for (var o:Object in parents) {
251                                 if (o is Relation) {
252                                         for (var i:uint=0; i<o.length; i++) {
253                                                 if (o.getMember(i).entity==this) {
254                                                         list.push( { relation:o, position:i, role: o.getMember(i).role } );
255                                                 }
256                                         }
257                                 }
258                         }
259             // it's useful to return in a sorted order, even if the relations are interleaved
260             // e.g. [{r0 p1},{r1 p1},{r0 p4}]
261                         return list.sortOn("position"); 
262                 }
263
264                 // Resume/suspend redraw
265                 
266                 public function suspend():void {
267                         dispatchEvent(new EntityEvent(Connection.SUSPEND_REDRAW, this));
268                 }
269                 
270                 public function resume():void {
271                         dispatchEvent(new EntityEvent(Connection.RESUME_REDRAW, this));
272                 }
273
274                 // To be overridden
275
276                 public function getDescription():String {
277                         var basic:String=this.getType()+" "+_id;
278                         if (tags['ref'] && tags['name']) { return tags['ref']+' '+tags['name']+' ('+basic+')'; }
279                         if (tags['ref']) { return tags['ref']+' ('+basic+')'; }
280                         if (tags['name']) { return tags['name']+' ('+basic+')'; }
281                         return basic;
282                 }
283
284         public function getType():String {
285             return '';
286         }
287
288     }
289
290 }
291