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