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 private var locked:Boolean = false;
18 public var deleted:Boolean = false;
20 public function Entity(id:Number, version:uint, tags:Object, loaded:Boolean, uid:Number, timestamp:String) {
22 this._version = version;
24 this._timestamp = timestamp;
26 this._loaded = loaded;
30 public function get id():Number {
34 public function get version():uint {
38 public function get uid():Number {
42 public function get loaded():Boolean {
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;
50 public function renumber(newID:Number, newVersion:uint):void {
52 this._version = newVersion;
55 // Tag-handling methods
57 public function hasTags():Boolean {
58 for (var key:String in tags)
63 public function hasInterestingTags():Boolean {
64 for (var key:String in tags) {
65 if (key != "attribution" && key != "created_by" && key != "source" && key.indexOf('tiger:') != 0) {
73 public function isUneditedTiger():Boolean {
74 // todo: make this match the rules from the tiger edited map
75 // http://github.com/MapQuest/TIGER-Edited-map/blob/master/inc/layer-tiger.xml.inc
76 if (this is Way && (uid == 7168 || uid == 15169 || uid == 20587)) {//todo fixme etc
82 public function getTag(key:String):String {
86 public function tagIs(key:String,value:String):Boolean {
87 if (!tags[key]) { return false; }
88 return tags[key]==value;
91 public function setTag(key:String, value:String, performAction:Function):void {
92 performAction(new SetTagAction(this, key, value));
95 public function renameTag(oldKey:String, newKey:String, performAction:Function):void {
96 performAction(new SetTagKeyAction(this, oldKey, newKey));
99 public function getTagList():TagList {
100 return new TagList(tags);
103 public function getTagsCopy():Object {
104 var copy:Object = {};
105 for (var key:String in tags )
106 copy[key] = tags[key];
110 public function getTagsHash():Object {
111 // hm, not sure we should be doing this, but for read-only purposes
112 // it's faster than using getTagsCopy
116 public function getTagArray():Array {
118 for (var key:String in tags )
119 copy.push(new Tag(this, key, tags[key]));
123 // Clean/dirty methods
125 public function get isDirty():Boolean {
129 public function markClean():void {
133 internal function markDirty():void {
139 public function remove(performAction:Function):void {
143 public function isDeleted():Boolean {
147 public function setDeletedState(isDeleted:Boolean):void {
150 var n:Node = Node(this);
152 Connection.getConnection().removeDupe(n);
154 Connection.getConnection().addDupe(n);
159 internal function isEmpty():Boolean {
160 return false; // to be overridden
163 public function nullify():void {
164 // this retains a dummy entity in memory, for entities that we no longer need
165 // but which are part of a still-in-memory relation
169 protected function nullifyEntity():void {
170 // this is the common nullify behaviour for all entity types (we'd call this by super() if ActionScript let us)
177 public function within(left:Number,right:Number,top:Number,bottom:Number):Boolean {
178 return true; // to be overridden
181 public function removeFromParents(performAction:Function):void {
182 for (var o:Object in parents) {
183 if (o is Relation) { Relation(o).removeMember(this, performAction); }
184 else if (o is Way) { Way(o).removeNode(Node(this), performAction); }
185 if (o.isEmpty()) { o.remove(performAction); }
191 public function addParent(parent:Entity):void {
192 parents[parent]=true;
194 if ( parent is Relation )
195 dispatchEvent(new RelationMemberEvent(Connection.ADDED_TO_RELATION, this, parent as Relation, -1));
198 public function removeParent(parent:Entity):void {
199 delete parents[parent];
201 if ( parent is Relation )
202 dispatchEvent(new RelationMemberEvent(Connection.REMOVED_FROM_RELATION, this, parent as Relation, -1));
205 public function get parentWays():Array {
207 for (var o:Object in parents) {
208 if (o is Way) { a.push(o); }
213 public function get hasParents():Boolean {
214 for (var o:Object in parents) { return true; }
218 public function get hasParentWays():Boolean {
219 for (var o:Object in parents) {
220 if (o is Way) { return true; }
225 public function get numParentWays():uint {
227 for (var o:Object in parents) {
228 if (o is Way) { i++; }
233 public function get parentRelations():Array {
235 for (var o:Object in parents) {
236 if (o is Relation) { a.push(o); }
241 public function findParentRelationsOfType(type:String, role:String=null):Array {
243 for (var o:Object in parents) {
244 if (o is Relation && Relation(o).tagIs('type',type) && (role==null || Relation(o).hasMemberInRole(this,role))) {
251 public function countParentObjects(within:Object):uint {
253 for (var o:Object in parents) {
254 if (o.getType()==within.entity && o.getTag(within.k)) {
255 if (within.v && within.v!=o.getTag(within.k)) { break; }
256 if (within.role && !Relation(o).hasMemberInRole(this,within.role)) { break; }
263 public function get parentObjects():Array {
265 for (var o:Object in parents) { a.push(o); }
269 public function hasParent(entity:Entity):Boolean {
270 return parents[entity] == true;
273 public function get memberships():Array {
275 for (var o:Object in parents) {
277 for (var i:uint=0; i<o.length; i++) {
278 if (o.getMember(i).entity==this) {
279 list.push( { relation:o, position:i, role: o.getMember(i).role } );
284 // it's useful to return in a sorted order, even if the relations are interleaved
285 // e.g. [{r0 p1},{r1 p1},{r0 p4}]
286 return list.sortOn("position");
289 // Resume/suspend redraw
291 public function suspend():void {
292 dispatchEvent(new EntityEvent(Connection.SUSPEND_REDRAW, this));
295 public function resume():void {
296 dispatchEvent(new EntityEvent(Connection.RESUME_REDRAW, this));
301 public function getDescription():String {
302 var basic:String=this.getType()+" "+_id;
303 if (tags['ref'] && tags['name']) { return tags['ref']+' '+tags['name']+' ('+basic+')'; }
304 if (tags['ref']) { return tags['ref']+' ('+basic+')'; }
305 if (tags['name']) { return tags['name']+' ('+basic+')'; }
309 public function getType():String {