First stub dialog for showing your own GPX traces
[potlatch2.git] / net / systemeD / halcyon / connection / Connection.as
1 package net.systemeD.halcyon.connection {
2
3     import flash.net.*;
4
5     import flash.events.EventDispatcher;
6     import flash.events.Event;
7         import net.systemeD.halcyon.Globals;
8         import net.systemeD.halcyon.connection.actions.*;
9
10         public class Connection extends EventDispatcher {
11
12         private static var connectionInstance:Connection = null;
13
14         protected static var policyURL:String;
15         protected static var apiBaseURL:String;
16         protected static var params:Object;
17
18         public static function getConnection(initparams:Object=null):Connection {
19             if ( connectionInstance == null ) {
20             
21                 params = initparams == null ? new Object() : initparams;
22                 policyURL = getParam("policy", "http://127.0.0.1:3000/api/crossdomain.xml");
23                 apiBaseURL = getParam("api", "http://127.0.0.1:3000/api/0.6/");
24                 var connectType:String = getParam("connection", "XML");
25                 
26                 if ( connectType == "XML" )
27                     connectionInstance = new XMLConnection();
28                 else if ( connectType == "OSM" )
29                     connectionInstance = new OSMConnection();
30                 else
31                     connectionInstance = new AMFConnection();
32             }
33             return connectionInstance;
34         }
35
36         public static function getParam(name:String, defaultValue:String):String {
37             return params[name] == null ? defaultValue : params[name];
38         }
39
40         public function get apiBase():String {
41             return apiBaseURL;
42         }
43
44         public static function get serverName():String {
45             return getParam("serverName", "Localhost");
46         }
47                 
48                 public static function getConnectionInstance():Connection {
49             return connectionInstance;
50                 }
51
52                 public function getEnvironment(responder:Responder):void {}
53
54         // connection events
55         public static var LOAD_STARTED:String = "load_started";
56         public static var LOAD_COMPLETED:String = "load_completed";
57         public static var SAVE_STARTED:String = "save_started";
58         public static var SAVE_COMPLETED:String = "save_completed";
59         public static var DATA_DIRTY:String = "data_dirty";
60         public static var DATA_CLEAN:String = "data_clean";
61         public static var NEW_CHANGESET:String = "new_changeset";
62         public static var NEW_CHANGESET_ERROR:String = "new_changeset_error";
63         public static var NEW_NODE:String = "new_node";
64         public static var NEW_WAY:String = "new_way";
65         public static var NEW_RELATION:String = "new_relation";
66         public static var NEW_POI:String = "new_poi";
67         public static var NODE_RENUMBERED:String = "node_renumbered";
68         public static var WAY_RENUMBERED:String = "way_renumbered";
69         public static var RELATION_RENUMBERED:String = "relation_renumbered";
70         public static var TAG_CHANGED:String = "tag_change";
71         public static var NODE_MOVED:String = "node_moved";
72         public static var WAY_NODE_ADDED:String = "way_node_added";
73         public static var WAY_NODE_REMOVED:String = "way_node_removed";
74         public static var WAY_REORDERED:String = "way_reordered";
75         public static var WAY_DRAGGED:String = "way_dragged";
76                 public static var NODE_DELETED:String = "node_deleted";
77                 public static var WAY_DELETED:String = "way_deleted";
78                 public static var RELATION_DELETED:String = "relation_deleted";
79                 public static var RELATION_MEMBER_ADDED:String = "relation_member_added";
80                 public static var RELATION_MEMBER_REMOVED:String = "relation_member_deleted";
81                 public static var ADDED_TO_RELATION:String = "added_to_relation";
82                 public static var REMOVED_FROM_RELATION:String = "removed_from_relation";
83                 public static var SUSPEND_REDRAW:String = "suspend_redraw";
84                 public static var RESUME_REDRAW:String = "resume_redraw";
85
86         // store the data we download
87         private var negativeID:Number = -1;
88         private var nodes:Object = {};
89         private var ways:Object = {};
90         private var relations:Object = {};
91         private var pois:Array = [];
92         private var changeset:Changeset = null;
93                 private var changesetUpdated:Number;
94                 private var modified:Boolean = false;
95                 public var nodecount:int=0;
96                 public var waycount:int=0;
97                 public var relationcount:int=0;
98         private var traces:Array = [];
99
100         protected function get nextNegative():Number {
101             return negativeID--;
102         }
103
104         protected function setNode(node:Node, queue:Boolean):void {
105                         if (!nodes[node.id]) { nodecount++; }
106             nodes[node.id] = node;
107             if (node.loaded) { sendEvent(new EntityEvent(NEW_NODE, node),queue); }
108         }
109
110         protected function setWay(way:Way, queue:Boolean):void {
111                         if (!ways[way.id]) { waycount++; }
112             ways[way.id] = way;
113             if (way.loaded) { sendEvent(new EntityEvent(NEW_WAY, way),queue); }
114         }
115
116         protected function setRelation(relation:Relation, queue:Boolean):void {
117                         if (!relations[relation.id]) { relationcount++; }
118             relations[relation.id] = relation;
119             if (relation.loaded) { sendEvent(new EntityEvent(NEW_RELATION, relation),queue); }
120         }
121
122         protected function renumberNode(oldID:Number, node:Node, queue:Boolean):void {
123             nodes[node.id] = node;
124             if (node.loaded) { sendEvent(new EntityRenumberedEvent(NODE_RENUMBERED, node, oldID),queue); }
125             delete nodes[oldID];
126         }
127
128         protected function renumberWay(oldID:Number, way:Way, queue:Boolean):void {
129             ways[way.id] = way;
130             if (way.loaded) { sendEvent(new EntityRenumberedEvent(WAY_RENUMBERED, way, oldID),queue); }
131             delete ways[oldID];
132         }
133
134         protected function renumberRelation(oldID:Number, relation:Relation, queue:Boolean):void {
135             relations[relation.id] = relation;
136             if (relation.loaded) { sendEvent(new EntityRenumberedEvent(RELATION_RENUMBERED, relation, oldID),queue); }
137             delete relations[oldID];
138         }
139
140
141                 public function sendEvent(e:*,queue:Boolean):void {
142                         // queue is only used for AMFConnection
143                         dispatchEvent(e);
144                 }
145
146         public function registerPOI(node:Node):void {
147             if ( pois.indexOf(node) < 0 ) {
148                 pois.push(node);
149                 sendEvent(new EntityEvent(NEW_POI, node),false);
150             }
151         }
152
153         public function unregisterPOI(node:Node):void {
154             var index:uint = pois.indexOf(node);
155             if ( index >= 0 ) {
156                 pois.splice(index,1);
157             }
158         }
159
160         public function getNode(id:Number):Node {
161             return nodes[id];
162         }
163
164         public function getWay(id:Number):Way {
165             return ways[id];
166         }
167
168         public function getRelation(id:Number):Relation {
169             return relations[id];
170         }
171
172                 // Remove data from Connection
173                 // These functions are used only internally to stop redundant data hanging around
174                 // (either because it's been deleted on the server, or because we have panned away
175                 //  and need to reduce memory usage)
176
177                 protected function killNode(id:Number):void {
178                         if (!nodes[id]) return;
179             nodes[id].dispatchEvent(new EntityEvent(Connection.NODE_DELETED, nodes[id]));
180                         if (nodes[id].parentRelations.length>0) {
181                                 nodes[id]=new Node(id,0,{},false,0,0);
182                         } else {
183                                 delete nodes[id];
184                         }
185                         nodecount--;
186                 }
187
188                 protected function killWay(id:Number):void {
189                         if (!ways[id]) return;
190             ways[id].dispatchEvent(new EntityEvent(Connection.WAY_DELETED, ways[id]));
191                         if (ways[id].parentRelations.length>0) {
192                                 ways[id]=new Way(id,0,{},false,[]);
193                         } else {
194                                 delete ways[id];
195                         }
196                         waycount--;
197                 }
198
199                 protected function killRelation(id:Number):void {
200                         if (!relations[id]) return;
201             relations[id].dispatchEvent(new EntityEvent(Connection.RELATION_DELETED, relations[id]));
202                         if (relations[id].parentRelations.length>0) {
203                                 relations[id]=new Relation(id,0,{},false,[]);
204                         } else {
205                                 delete relations[id];
206                         }
207                         relationcount--;
208                 }
209
210                 protected function killWayWithNodes(id:Number):void {
211                         var way:Way=ways[id];
212                         var node:Node;
213                         for (var i:uint=0; i<way.length; i++) {
214                                 node=way.getNode(i);
215                                 if (node.isDirty) { continue; }
216                                 if (node.parentWays.length>1) {
217                                         node.removeParent(way);
218                                 } else {
219                                         killNode(node.id);
220                                 }
221                         }
222                         killWay(id);
223                 }
224                 
225
226
227         public function createNode(tags:Object, lat:Number, lon:Number, performCreate:Function):Node {
228             var node:Node = new Node(nextNegative, 0, tags, true, lat, lon);
229             performCreate(new CreateEntityAction(node, setNode));
230                         //markDirty();
231             return node;
232         }
233
234         public function createWay(tags:Object, nodes:Array, performCreate:Function):Way {
235             var way:Way = new Way(nextNegative, 0, tags, true, nodes.concat());
236             performCreate(new CreateEntityAction(way, setWay));
237                         //markDirty();
238             return way;
239         }
240
241         public function createRelation(tags:Object, members:Array, performCreate:Function):Relation {
242             var relation:Relation = new Relation(nextNegative, 0, tags, true, members.concat());
243             performCreate(new CreateEntityAction(relation, setRelation));
244                         //markDirty();
245             return relation;
246         }
247
248         public function getAllNodeIDs():Array {
249             var list:Array = [];
250             for each (var node:Node in nodes)
251                 list.push(node.id);
252             return list;
253         }
254
255         public function getAllWayIDs():Array {
256             var list:Array = [];
257             for each (var way:Way in ways)
258                 list.push(way.id);
259             return list;
260         }
261
262         public function getAllRelationIDs():Array {
263             var list:Array = [];
264             for each (var relation:Relation in relations)
265                 list.push(relation.id);
266             return list;
267         }
268
269         public function getMatchingRelationIDs(match:Object):Array {
270             var list:Array = [];
271                         var ok:Boolean;
272             for each (var relation:Relation in relations) {
273                                 ok=true;
274                                 if (relation.deleted) { ok=false; }
275                                 for (var k:String in match) {
276                                         if (!relation.getTagsHash()[k] || relation.getTagsHash()[k]!=match[k]) { ok=false; }
277                                 }
278                                 if (ok) { list.push(relation.id); }
279                         }
280             return list;
281         }
282
283                 public function getObjectsByBbox(left:Number, right:Number, top:Number, bottom:Number):Object {
284                         var o:Object = { nodesInside: [], nodesOutside: [], waysInside: [], waysOutside: [] };
285                         for each (var way:Way in ways) {
286                                 if (way.within(left,right,top,bottom)) { o.waysInside.push(way); }
287                                                                   else { o.waysOutside.push(way); }
288                         }
289                         for each (var node:Node in nodes) {
290                                 if (node.within(left,right,top,bottom)) { o.nodesInside.push(node); }
291                                                                    else { o.nodesOutside.push(node); }
292                         }
293                         return o;
294                 }
295
296                 public function purgeOutside(left:Number, right:Number, top:Number, bottom:Number):void {
297                         return;
298                         // ** this doesn't work - WayUIs stick around.
299                         // ** should purge POIs and relations too
300                         for each (var way:Way in ways) {
301                                 if (!way.within(left,right,top,bottom) && !way.isDirty) {
302                                         killWayWithNodes(way.id);
303                                 }
304                         }
305                 }
306
307                 public function markDirty():void {
308             if (!modified) { dispatchEvent(new Event(DATA_DIRTY)); }
309                         modified=true;
310                 }
311                 public function markClean():void {
312             if (modified) { dispatchEvent(new Event(DATA_CLEAN)); }
313                         modified=false;
314                 }
315                 public function get isDirty():Boolean {
316                         return modified;
317                 }
318
319                 // Changeset tracking
320
321         protected function setActiveChangeset(changeset:Changeset):void {
322             this.changeset = changeset;
323                         changesetUpdated = new Date().getTime();
324             sendEvent(new EntityEvent(NEW_CHANGESET, changeset),false);
325         }
326
327                 protected function freshenActiveChangeset():void {
328                         changesetUpdated = new Date().getTime();
329                 }
330                 
331                 protected function closeActiveChangeset():void {
332                         changeset = null;
333                 }
334         
335         public function getActiveChangeset():Changeset {
336                         if (changeset && (new Date().getTime()) > (changesetUpdated+58*60*1000)) {
337                                 closeActiveChangeset();
338                         }
339             return changeset;
340         }
341         
342
343         // these are functions that the Connection implementation is expected to
344         // provide. This class has some generic helpers for the implementation.
345                 public function loadBbox(left:Number, right:Number,
346                                                                 top:Number, bottom:Number):void {
347             }
348             
349             public function setAppID(id:Object):void {}
350             public function setAuthToken(id:Object):void {}
351             public function createChangeset(tags:Object):void {}
352                 public function closeChangeset():void {}
353             public function uploadChanges():void {}
354         public function fetchUserTraces():void {}
355     }
356
357 }
358