1 package net.systemeD.halcyon.connection {
3 import flash.events.EventDispatcher;
4 import flash.utils.Dictionary;
6 import net.systemeD.halcyon.connection.actions.*;
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 public var locked:Boolean = false; // lock against purging when off-screen
18 public var deleted:Boolean = false;
19 // public var parentsLoaded:Boolean = true; // are all its parents in memory?
21 public function Entity(id:Number, version:uint, tags:Object, loaded:Boolean, uid:Number, timestamp:String) {
23 this._version = version;
25 this._timestamp = timestamp;
27 this._loaded = loaded;
31 public function get id():Number {
35 public function get version():uint {
39 public function get uid():Number {
43 public function get loaded():Boolean {
47 public function get timestamp():String {
51 public function updateEntityProperties(version:uint, tags:Object, loaded:Boolean, uid:Number, timestamp:String):void {
52 _version=version; this.tags=tags; _loaded=loaded; _uid = uid; _timestamp = timestamp;
56 public function renumber(newID:Number, newVersion:uint):void {
58 this._version = newVersion;
61 // Tag-handling methods
63 public function hasTags():Boolean {
64 for (var key:String in tags)
69 public function hasInterestingTags():Boolean {
70 for (var key:String in tags) {
71 if (key != "attribution" && key != "created_by" && key != "source" && key.indexOf('tiger:') != 0) {
79 public function isUneditedTiger():Boolean {
80 // todo: make this match the rules from the tiger edited map
81 // http://github.com/MapQuest/TIGER-Edited-map/blob/master/inc/layer-tiger.xml.inc
82 if (this is Way && (uid == 7168 || uid == 15169 || uid == 20587)) {//todo fixme etc
88 public function getTag(key:String):String {
92 public function tagIs(key:String,value:String):Boolean {
93 if (!tags[key]) { return false; }
94 return tags[key]==value;
97 public function setTag(key:String, value:String, performAction:Function):void {
98 performAction(new SetTagAction(this, key, value));
101 public function renameTag(oldKey:String, newKey:String, performAction:Function):void {
102 performAction(new SetTagKeyAction(this, oldKey, newKey));
105 public function getTagList():TagList {
106 return new TagList(tags);
109 public function getTagsCopy():Object {
110 var copy:Object = {};
111 for (var key:String in tags )
112 copy[key] = tags[key];
116 public function getTagsHash():Object {
117 // hm, not sure we should be doing this, but for read-only purposes
118 // it's faster than using getTagsCopy
122 public function getTagArray():Array {
124 for (var key:String in tags )
125 copy.push(new Tag(this, key, tags[key]));
129 // Clean/dirty methods
131 public function get isDirty():Boolean {
135 public function markClean():void {
139 internal function markDirty():void {
145 public function remove(performAction:Function):void {
149 public function isDeleted():Boolean {
153 public function setDeletedState(isDeleted:Boolean):void {
156 var n:Node = Node(this);
158 Connection.getConnection().removeDupe(n);
160 Connection.getConnection().addDupe(n);
165 internal function isEmpty():Boolean {
166 return false; // to be overridden
169 public function nullify():void {
170 // this retains a dummy entity in memory, for entities that we no longer need
171 // but which are part of a still-in-memory relation
175 protected function nullifyEntity():void {
176 // this is the common nullify behaviour for all entity types (we'd call this by super() if ActionScript let us)
183 public function within(left:Number,right:Number,top:Number,bottom:Number):Boolean {
184 return true; // to be overridden
187 public function removeFromParents(performAction:Function):void {
188 for (var o:Object in parents) {
189 if (o is Relation) { Relation(o).removeMember(this, performAction); }
190 else if (o is Way) { Way(o).removeNode(Node(this), performAction); }
191 if (o.isEmpty()) { o.remove(performAction); }
197 public function addParent(parent:Entity):void {
198 parents[parent]=true;
200 if ( parent is Relation )
201 dispatchEvent(new RelationMemberEvent(Connection.ADDED_TO_RELATION, this, parent as Relation, -1));
204 public function removeParent(parent:Entity):void {
205 delete parents[parent];
207 if ( parent is Relation )
208 dispatchEvent(new RelationMemberEvent(Connection.REMOVED_FROM_RELATION, this, parent as Relation, -1));
211 public function get parentWays():Array {
213 for (var o:Object in parents) {
214 if (o is Way) { a.push(o); }
219 public function get hasParents():Boolean {
220 for (var o:Object in parents) { return true; }
224 public function get hasParentWays():Boolean {
225 for (var o:Object in parents) {
226 if (o is Way) { return true; }
231 public function get numParentWays():uint {
233 for (var o:Object in parents) {
234 if (o is Way) { i++; }
239 public function get parentRelations():Array {
241 for (var o:Object in parents) {
242 if (o is Relation) { a.push(o); }
247 public function findParentRelationsOfType(type:String, role:String=null):Array {
249 for (var o:Object in parents) {
250 if (o is Relation && Relation(o).tagIs('type',type) && (role==null || Relation(o).hasMemberInRole(this,role))) {
257 public function countParentObjects(within:Object):uint {
259 for (var o:Object in parents) {
260 if (o.getType()==within.entity && o.getTag(within.k)) {
261 if (within.v && within.v!=o.getTag(within.k)) { break; }
262 if (within.role && !Relation(o).hasMemberInRole(this,within.role)) { break; }
269 public function get parentObjects():Array {
271 for (var o:Object in parents) { a.push(o); }
275 public function hasParent(entity:Entity):Boolean {
276 return parents[entity] == true;
279 public function get memberships():Array {
281 for (var o:Object in parents) {
283 for (var i:uint=0; i<o.length; i++) {
284 if (o.getMember(i).entity==this) {
285 list.push( { relation:o, position:i, role: o.getMember(i).role } );
290 // it's useful to return in a sorted order, even if the relations are interleaved
291 // e.g. [{r0 p1},{r1 p1},{r0 p4}]
292 return list.sortOn("position");
295 // Resume/suspend redraw
297 public function suspend():void {
298 dispatchEvent(new EntityEvent(Connection.SUSPEND_REDRAW, this));
301 public function resume():void {
302 dispatchEvent(new EntityEvent(Connection.RESUME_REDRAW, this));
307 public function getDescription():String {
308 var basic:String=this.getType()+" "+_id;
309 if (tags['ref'] && tags['name']) { return tags['ref']+' '+tags['name']+' ('+basic+')'; }
310 if (tags['ref']) { return tags['ref']+' ('+basic+')'; }
311 if (tags['name']) { return tags['name']+' ('+basic+')'; }
315 public function getType():String {