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