#!/usr/bin/ruby

require 'rexml/document'
require 'rexml/parsers/streamparser'

class XMLListener
   attr_accessor :pass

   def initialize(min_lat, min_lon, max_lat, max_lon, target_root)
      @min_lat = min_lat
      @min_lon = min_lon
      @max_lat = max_lat
      @max_lon = max_lon
      @target_root = target_root
      @matches = 0
      @processed = 0
      @symbol = "|"
      @matched_node_ids = {}
      @matched_segment_ids = {}
      @in_way = false
      @segments = []
      @current_elements = []
   end

   def tag_start(name, attrs)
      if name == "tag" then
         if @current_elements.last then
            element = REXML::Element.new("tag")
            attrs.each { |name, value| element.attributes[name] = value }
            @current_elements.last.elements << element
            @current_elements.push(element)
         else
            @current_elements.push(nil)
         end
      elsif @in_way then
         if name == "seg" then
            element = REXML::Element.new("seg")
            attrs.each { |name, value| element.attributes[name] = value }
            @segments << element
            @current_elements.push(element)
         else
            @current_elements.push(nil)
         end
      else
         if name == "node" then
            element = REXML::Element.new(name)
            attrs.each { |name, value| element.attributes[name] = value }
            lat = attrs["lat"].to_f
            lon = attrs["lon"].to_f
            if lat > @min_lat and lat < @max_lat and lon > @min_lon and lon < @max_lon then
               @matches = @matches + 1
               @target_root.elements << element
               @matched_node_ids[attrs["id"]] = true
               @current_elements.push(element)
            else
               @current_elements.push(nil)
            end
            @processed = @processed+1
         elsif name == "segment" then
            # if both nodes are good, then keep it
            if @matched_node_ids[attrs["from"]] == true and @matched_node_ids[attrs["to"]] == true then
               element = REXML::Element.new(name)
               attrs.each { |name, value| element.attributes[name] = value }
               @target_root.elements << element
               @matches = @matches + 1
               @matched_segment_ids[attrs["id"]] = true
               @current_elements.push(element)
            else
               @current_elements.push(nil)
            end
            @processed = @processed+1
         elsif name == "way" then
            @in_way = true
            # prep the new element in case we need to use it
            @way_element = REXML::Element.new(name)
            attrs.each { |name, value| @way_element.attributes[name] = value }
            @current_elements.push(@way_element)
         else
            @current_elements.push(nil)
            @processed = @processed+1
         end
      end

      if @symbol == "|" then
         @symbol = "/"
      elsif @symbol == "/" then
         @symbol = "-"
      elsif @symbol == "-" then
         @symbol = "\\"
      elsif @symbol == "\\" then
         @symbol = "|"
      end

      print "\r#{@symbol} Matched #{@matches}/#{@processed} processed entities"
   end
   def text(text)
   end
   def tag_end(name)
      @current_elements.pop
      if name == "way" then
         #check all the segs
         found_segment = false
         @segments.each do |segment|
            if @matched_segment_ids[segment.attributes["id"]] == true
               @way_element.elements << segment
               found_segment = true
            end
         end
         # if the way is complete, add it to the doc
         if found_segment then
            @target_root.elements << @way_element
            @matches = @matches + 1
         end
         @in_way = false
         @segments = []
      end
   end
   def xmldecl(one, two, three)
   end
end

min_lat = ARGV[1].to_f
min_lon = ARGV[2].to_f
max_lat = ARGV[3].to_f
max_lon = ARGV[4].to_f

unless max_lat > min_lat and max_lon > min_lon then
   puts "Invalid range"
   exit
end


file = File.new(ARGV[0])

target = REXML::Document.new
target_root = REXML::Element.new("osm");
target_root.attributes["generator"] = "osm-excerpt-area.rb"
target_root.attributes["version"] = "0.4"
target.elements << target_root

puts "Parsing document..."
xml_listener = XMLListener.new(min_lat, min_lon, max_lat, max_lon, target_root)
REXML::Document.parse_stream(file, xml_listener)
puts
puts "Done parsing, writing file..."

outfile = File.new(ARGV[5], "w")
target.write(outfile, 1)

puts "Output written to #{ARGV[5]}"