+def readwayquery(id)
+ ActiveRecord::Base.connection.select_all "SELECT n1.latitude AS lat1,n1.longitude AS long1,n1.id AS id1,n1.tags as tags1, "+
+ " n2.latitude AS lat2,n2.longitude AS long2,n2.id AS id2,n2.tags as tags2,segment_id "+
+ " FROM current_way_segments,current_segments,current_nodes AS n1,current_nodes AS n2 "+
+ " WHERE current_way_segments.id=#{id} "+
+ " AND segment_id=current_segments.id "+
+ " AND current_segments.visible=1 "+
+ " AND n1.id=node_a and n2.id=node_b "+
+ " AND n1.visible=1 AND n2.visible=1 "+
+ " ORDER BY sequence_id"
+end
+
+def createuniquesegments(way,uqs_name,seglist)
+ # Finds segments which appear in (previous version of) this way and no other
+ sql=<<-EOF
+ CREATE TEMPORARY TABLE #{uqs_name}
+ SELECT a.segment_id
+ FROM (SELECT DISTINCT segment_id FROM current_way_segments
+ WHERE id = #{way}) a
+ LEFT JOIN current_way_segments b
+ ON b.segment_id = a.segment_id
+ AND b.id != #{way}
+ WHERE b.segment_id IS NULL
+ EOF
+ if (seglist!='') then sql+=" AND a.segment_id NOT IN (#{seglist})" end
+ ActiveRecord::Base.connection.execute(sql)
+end
+
+def createuniquenodes(uqs_name,uqn_name)
+ # Finds nodes which appear in uniquesegments but no other segments
+ sql=<<-EOF
+ CREATE TEMPORARY TABLE #{uqn_name}
+ SELECT DISTINCT node_id
+ FROM (SELECT cn.id AS node_id
+ FROM current_nodes AS cn,
+ current_segments AS cs,
+ #{uqs_name} AS us
+ WHERE cs.id=us.segment_id
+ AND (cn.id=cs.node_a OR cn.id=cs.node_b)) AS n
+ LEFT JOIN current_segments AS cs2 ON node_id=cs2.node_a AND cs2.visible=1
+ LEFT JOIN current_segments AS cs3 ON node_id=cs3.node_b AND cs3.visible=1
+ WHERE cs2.node_a IS NULL
+ AND cs3.node_b IS NULL
+ EOF
+ ActiveRecord::Base.connection.execute(sql)
+end
+
+def sqlescape(a)
+ a.gsub("'","''").gsub(92.chr,92.chr+92.chr)
+end
+
+def tag2array(a)
+ tags={}
+ a.gsub(';;;','#%').split(';').each do |b|
+ b.gsub!('#%',';;;')
+ b.gsub!('===','#%')
+ k,v=b.split('=')
+ if k.nil? then k='' end
+ if v.nil? then v='' end
+ tags[k.gsub('#%','=')]=v.gsub('#%','=')
+ end
+ tags
+end
+
+def array2tag(a)
+ str=''
+ a.each do |k,v|
+ if v=='' then next end
+ if v[0,6]=='(type ' then next end
+ if str!='' then str+=';' end
+ str+=k.gsub(';',';;;').gsub('=','===')+'='+v.gsub(';',';;;').gsub('=','===')
+ end
+ str
+end
+
+def getuserid(token)
+ token=sqlescape(token)
+ if (token=~/^(.+)\+(.+)$/) then
+ return ActiveRecord::Base.connection.select_value("SELECT id FROM users WHERE active=1 AND email='#{$1}' AND pass_crypt=MD5('#{$2}')")
+ else
+ return ActiveRecord::Base.connection.select_value("SELECT id FROM users WHERE active=1 AND token='#{token}'")
+ end
+end
+
+
+
+# ====================================================================
+# AMF read subroutines
+
+# ----- getint return two-byte integer
+# ----- getlong return four-byte long
+# ----- getstring return string with two-byte length
+# ----- getdouble return eight-byte double-precision float
+# ----- getobject return object/hash
+# ----- getarray return numeric array
+
+def getint(s)
+ s.getc*256+s.getc
+end
+
+def getlong(s)
+ ((s.getc*256+s.getc)*256+s.getc)*256+s.getc
+end
+
+def getstring(s)
+ len=s.getc*256+s.getc
+ s.read(len)
+end
+
+def getdouble(s)
+ a=s.read(8).unpack('G') # G big-endian, E little-endian
+ a[0]
+end
+
+def getarray(s)
+ len=getlong(s)
+ arr=[]
+ for i in (0..len-1)
+ arr[i]=getvalue(s)
+ end
+ arr
+end
+
+def getobject(s)
+ arr={}
+ while (key=getstring(s))
+ if (key=='') then break end
+ arr[key]=getvalue(s)
+ end
+ s.getc # skip the 9 'end of object' value
+ arr
+end
+
+# ----- getvalue parse and get value
+
+def getvalue(s)
+ case s.getc
+ when 0; return getdouble(s) # number
+ when 1; return s.getc # boolean
+ when 2; return getstring(s) # string
+ when 3; return getobject(s) # object/hash
+ when 5; return nil # null
+ when 6; return nil # undefined
+ when 8; s.read(4) # mixedArray
+ return getobject(s) # |
+ when 10; return getarray(s) # array
+ else; return nil # error
+ end
+end
+
+# ====================================================================
+# AMF write subroutines
+
+# ----- putdata envelope data into AMF writeable form
+# ----- encodevalue pack variables as AMF
+
+def putdata(index,n)
+ d =encodestring(index+"/onResult")
+ d+=encodestring("null")
+ d+=[-1].pack("N")
+ d+=encodevalue(n)
+end
+
+def encodevalue(n)
+ case n.class.to_s
+ when 'Array'
+ a=10.chr+encodelong(n.length)
+ n.each do |b|
+ a+=encodevalue(b)
+ end
+ a
+ when 'Hash'
+ a=3.chr
+ n.each do |k,v|
+ a+=encodestring(k)+encodevalue(v)
+ end
+ a+0.chr+0.chr+9.chr
+ when 'String'
+ 2.chr+encodestring(n)
+ when 'Bignum','Fixnum','Float'
+ 0.chr+encodedouble(n)
+ when 'NilClass'
+ 5.chr
+ else
+ RAILS_DEFAULT_LOGGER.error("Unexpected Ruby type for AMF conversion: "+n.class.to_s)
+ end
+end
+
+# ----- encodestring encode string with two-byte length
+# ----- encodedouble encode number as eight-byte double precision float
+# ----- encodelong encode number as four-byte long
+
+def encodestring(n)
+ a,b=n.size.divmod(256)
+ a.chr+b.chr+n
+end
+
+def encodedouble(n)
+ [n].pack('G')
+end
+
+def encodelong(n)
+ [n].pack('N')
+end
+
+# ====================================================================
+# Co-ordinate conversion
+
+def lat2coord(a,basey,masterscale)
+ -(lat2y(a)-basey)*masterscale+250
+end
+
+def long2coord(a,baselong,masterscale)
+ (a-baselong)*masterscale+350
+end
+
+def lat2y(a)
+ 180/Math::PI * Math.log(Math.tan(Math::PI/4+a*(Math::PI/180)/2))
+end
+
+def coord2lat(a,masterscale,basey)
+ y2lat((a-250)/-masterscale+basey)
+end
+
+def coord2long(a,masterscale,baselong)
+ (a-350)/masterscale+baselong
+end
+
+def y2lat(a)
+ 180/Math::PI * (2*Math.atan(Math.exp(a*Math::PI/180))-Math::PI/2)
+end