give Halcyon the ability to load .osm files
[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             trace("Returning param "+name+" as "+(params[name] == null ? defaultValue : params[name]));
38             return params[name] == null ? defaultValue : params[name];
39         }
40
41         public static 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 NEW_CHANGESET:String = "new_changeset";
61         public static var NEW_CHANGESET_ERROR:String = "new_changeset_error";
62         public static var NEW_NODE:String = "new_node";
63         public static var NEW_WAY:String = "new_way";
64         public static var NEW_RELATION:String = "new_relation";
65         public static var NEW_POI:String = "new_poi";
66         public static var NODE_RENUMBERED:String = "node_renumbered";
67         public static var WAY_RENUMBERED:String = "way_renumbered";
68         public static var RELATION_RENUMBERED:String = "relation_renumbered";
69         public static var TAG_CHANGED:String = "tag_change";
70         public static var NODE_MOVED:String = "node_moved";
71         public static var WAY_NODE_ADDED:String = "way_node_added";
72         public static var WAY_NODE_REMOVED:String = "way_node_removed";
73         public static var WAY_REORDERED:String = "way_reordered";
74         public static var WAY_DRAGGED:String = "way_dragged";
75                 public static var NODE_DELETED:String = "node_deleted";
76                 public static var WAY_DELETED:String = "way_deleted";
77                 public static var RELATION_DELETED:String = "relation_deleted";
78                 public static var RELATION_MEMBER_ADDED:String = "relation_member_added";
79                 public static var RELATION_MEMBER_REMOVED:String = "relation_member_deleted";
80                 public static var ADDED_TO_RELATION:String = "added_to_relation";
81                 public static var REMOVED_FROM_RELATION:String = "removed_from_relation";
82                 public static var SUSPEND_REDRAW:String = "suspend_redraw";
83                 public static var RESUME_REDRAW:String = "resume_redraw";
84
85         // store the data we download
86         private var negativeID:Number = -1;
87         private var nodes:Object = {};
88         private var ways:Object = {};
89         private var relations:Object = {};
90         private var pois:Array = [];
91         private var changeset:Changeset = null;
92                 public var nodecount:int=0;
93                 public var waycount:int=0;
94                 public var relationcount:int=0;
95
96         protected function get nextNegative():Number {
97             return negativeID--;
98         }
99
100         protected function setNode(node:Node, queue:Boolean):void {
101                         if (!nodes[node.id]) { nodecount++; }
102             nodes[node.id] = node;
103             if (node.loaded) { sendEvent(new EntityEvent(NEW_NODE, node),queue); }
104         }
105
106         protected function setWay(way:Way, queue:Boolean):void {
107                         if (!ways[way.id]) { waycount++; }
108             ways[way.id] = way;
109             if (way.loaded) { sendEvent(new EntityEvent(NEW_WAY, way),queue); }
110         }
111
112         protected function setRelation(relation:Relation, queue:Boolean):void {
113                         if (!relations[relation.id]) { relationcount++; }
114             relations[relation.id] = relation;
115             if (relation.loaded) { sendEvent(new EntityEvent(NEW_RELATION, relation),queue); }
116         }
117
118         protected function renumberNode(oldID:Number, node:Node, queue:Boolean):void {
119             nodes[node.id] = node;
120             if (node.loaded) { sendEvent(new EntityRenumberedEvent(NODE_RENUMBERED, node, oldID),queue); }
121             delete nodes[oldID];
122         }
123
124         protected function renumberWay(oldID:Number, way:Way, queue:Boolean):void {
125             ways[way.id] = way;
126             if (way.loaded) { sendEvent(new EntityRenumberedEvent(WAY_RENUMBERED, way, oldID),queue); }
127             delete ways[oldID];
128         }
129
130         protected function renumberRelation(oldID:Number, relation:Relation, queue:Boolean):void {
131             relations[relation.id] = relation;
132             if (relation.loaded) { sendEvent(new EntityRenumberedEvent(RELATION_RENUMBERED, relation, oldID),queue); }
133             delete relations[oldID];
134         }
135
136
137                 public function sendEvent(e:*,queue:Boolean):void {
138                         // queue is only used for AMFConnection
139                         dispatchEvent(e);
140                 }
141
142         public function registerPOI(node:Node):void {
143             if ( pois.indexOf(node) < 0 ) {
144                 pois.push(node);
145                 sendEvent(new EntityEvent(NEW_POI, node),false);
146             }
147         }
148
149         public function unregisterPOI(node:Node):void {
150             var index:uint = pois.indexOf(node);
151             if ( index >= 0 ) {
152                 pois.splice(index,1);
153             }
154         }
155
156         protected function setActiveChangeset(changeset:Changeset):void {
157             this.changeset = changeset;
158             sendEvent(new EntityEvent(NEW_CHANGESET, changeset),false);
159         }
160         
161         public function getNode(id:Number):Node {
162             return nodes[id];
163         }
164
165         public function getWay(id:Number):Way {
166             return ways[id];
167         }
168
169         public function getRelation(id:Number):Relation {
170             return relations[id];
171         }
172
173                 // Remove data from Connection
174                 // These functions are used only internally to stop redundant data hanging around
175                 // (either because it's been deleted on the server, or because we have panned away
176                 //  and need to reduce memory usage)
177
178                 protected function killNode(id:Number):void {
179                         if (!nodes[id]) return;
180             nodes[id].dispatchEvent(new EntityEvent(Connection.NODE_DELETED, nodes[id]));
181                         if (nodes[id].parentRelations.length>0) {
182                                 nodes[id]=new Node(id,0,{},false,0,0);
183                         } else {
184                                 delete nodes[id];
185                         }
186                         nodecount--;
187                 }
188
189                 protected function killWay(id:Number):void {
190                         if (!ways[id]) return;
191             ways[id].dispatchEvent(new EntityEvent(Connection.WAY_DELETED, ways[id]));
192                         if (ways[id].parentRelations.length>0) {
193                                 ways[id]=new Way(id,0,{},false,[]);
194                         } else {
195                                 delete ways[id];
196                         }
197                         waycount--;
198                 }
199
200                 protected function killRelation(id:Number):void {
201                         if (!relations[id]) return;
202             relations[id].dispatchEvent(new EntityEvent(Connection.RELATION_DELETED, relations[id]));
203                         if (relations[id].parentRelations.length>0) {
204                                 relations[id]=new Relation(id,0,{},false,[]);
205                         } else {
206                                 delete relations[id];
207                         }
208                         relationcount--;
209                 }
210
211                 protected function killWayWithNodes(id:Number):void {
212                         var way:Way=ways[id];
213                         var node:Node;
214                         for (var i:uint=0; i<way.length; i++) {
215                                 node=way.getNode(i);
216                                 if (node.isDirty) { continue; }
217                                 if (node.parentWays.length>1) {
218                                         node.removeParent(way);
219                                 } else {
220                                         killNode(node.id);
221                                 }
222                         }
223                         killWay(id);
224                 }
225                 
226
227
228         public function createNode(tags:Object, lat:Number, lon:Number, performCreate:Function):Node {
229             var node:Node = new Node(nextNegative, 0, tags, true, lat, lon);
230             performCreate(new CreateEntityAction(node, setNode));
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             return way;
238         }
239
240         public function createRelation(tags:Object, members:Array, performCreate:Function):Relation {
241             var relation:Relation = new Relation(nextNegative, 0, tags, true, members.concat());
242             performCreate(new CreateEntityAction(relation, setRelation));
243             return relation;
244         }
245
246         public function getAllNodeIDs():Array {
247             var list:Array = [];
248             for each (var node:Node in nodes)
249                 list.push(node.id);
250             return list;
251         }
252
253         public function getAllWayIDs():Array {
254             var list:Array = [];
255             for each (var way:Way in ways)
256                 list.push(way.id);
257             return list;
258         }
259
260         public function getAllRelationIDs():Array {
261             var list:Array = [];
262             for each (var relation:Relation in relations)
263                 list.push(relation.id);
264             return list;
265         }
266
267                 public function getObjectsByBbox(left:Number, right:Number, top:Number, bottom:Number):Object {
268                         var o:Object = { poisInside: [], poisOutside: [], waysInside: [], waysOutside: [] };
269                         for each (var way:Way in ways) {
270                                 if (way.within(left,right,top,bottom)) { o.waysInside.push(way); }
271                                                                   else { o.waysOutside.push(way); }
272                         }
273                         for each (var node:Node in nodes) {
274                                 if (!node.hasParentWays) {
275                                         if (node.within(left,right,top,bottom)) { o.poisInside.push(node); }
276                                                                            else { o.poisOutside.push(node); }
277                                 }
278                         }
279                         return o;
280                 }
281
282         public function getActiveChangeset():Changeset {
283             return changeset;
284         }
285         
286                 public function purgeOutside(left:Number, right:Number, top:Number, bottom:Number):void {
287                         for each (var way:Way in ways) {
288                                 if (!way.within(left,right,top,bottom) && !way.isDirty) {
289                                         killWayWithNodes(way.id);
290                                 }
291                         }
292                         // ** should purge POIs and relations too
293                 }
294
295         // these are functions that the Connection implementation is expected to
296         // provide. This class has some generic helpers for the implementation.
297                 public function loadBbox(left:Number, right:Number,
298                                                                 top:Number, bottom:Number):void {
299             }
300             
301             public function setAppID(id:Object):void {}
302             public function setAuthToken(id:Object):void {}
303             public function createChangeset(tags:Object):void {}
304             public function uploadChanges():void {}
305     }
306
307 }
308