# -*- coding: utf-8 -*-
#
# xml_art15_checker.rb
# (c) ENDA, 2016
# 
# by mlt
#
# Rel-0-0-1
# 2016-06-24, mlt

class Art15_XML_Checker
  attr :glade

  def initialize(glade, art15_xml_datei)
    @glade = glade
    @art15_xml_datei = art15_xml_datei
    @file_num_lines = 0
    @bar = @glade['progressbar1']
    self.pulse
    @odoc = nil
    @oroot = nil
    @dbh = nil
    # Einziger Method-Call von außen: export, s.u.
  end

  def pulse
    @bar.pulse
    Gtk.main_iteration
  end

  # check_dp2tp_links
  #   → valdoc    : Ein XML-Dokument als gnome-libxml2-Objekt
  #   ← alles_gut : Boolean true, wenn alle TPs vorhanden, sonst false
  #
  #   Sammelt alle Einleitstellen und deren Links auf die Kläranlage
  #   und prüft, ob eine solche Kläranlage im Dokument vorhanden ist
  #   und erzeugt dabei Konsolausgaben (✔ Treffer bzw. ✘ FEHLT!).
  #
  def check_dp2tp_links(valdoc)
    # Erstmal die DPs finden
    # Dann über die iterieren
      # In jedem DP den Zeiger auf die TP finden
      # Prüfen, ob das Dokument diese TP enthält
      # Dabei schöne Meldungen herausgeben
    alles_gut = true
    # Erstmal die DPs finden
    root = valdoc.root
    if dps = root.find_first('/UWWTD_Data/UWWTD_Report/DischargePoints')
      # Dann über die iterieren
      dps.each_element do |dp|
        # In jedem DP den Zeiger auf die TP finden
        dcp_code = dp.find_first("dd823:dcpCode")
        uww_code = dp.find_first("dd823:uwwCode")
        print "Link von <#{dcp_code.content}> auf <#{uww_code.content}>: "
        # Prüfen, ob das Dokument diese TP enthält
        xpath = "/UWWTD_Data/UWWTD_Report/UWWTPs/UWWTP[dd821:uwwCode=\"#{uww_code.content}\"]"
        # Dabei schöne Meldungen herausgeben
        if tps = root.find_first(xpath)
          puts "✔ Treffer"
        else
          puts "✘ FEHLT!"
          alles_gut = false
        end
      end
    end
    return alles_gut
  end

  def check_dp2tp_links_with_schema
    @bar.pulse_step = 0.07
    @bar.fraction = 0.0
    @bar.text="checking dp2tp links..."
    puts "Start am/um #{Stnd.now}"
    self.pulse
    valdoc = XML::Document.file(@art15_xml_datei)
    # result_schema_check = check_against_schema(valdoc)
    result_dp2tp_links_check = check_dp2tp_links(valdoc)
    @bar.text="done"
    @bar.fraction = 1.0
    puts "Ende am/um #{Stnd.now}"
  end

  def check_against_schema(valdoc)
    schema_document = XML::Document.file('../schemata/UWWTD_Art15.xsd')
    schema = XML::Schema.document(schema_document)
    STDOUT.flush
    STDERR.flush
    begin
      result = valdoc.validate_schema(schema) do |message, is_error|
        # Das kann man sich getrost in die Haare reiben, denn validate_schema schmeißt eine Exception...
        if is_error
          puts "ERROR!"
        else
          puts "WARNING!"
        end
        puts "Anfang der Meldung:"
        puts message
        puts "Ende der Meldung."
      end
    rescue Exception => wumm
      pulse
      puts "Exception <#{wumm}>."
      # print wumm.backtrace.join("\n")
      puts
    end
    if result
      puts "Das Dokument ist bzgl. des Schemas perfekt"
    else
      puts "Das Dokument kann noch besser werden"
    end
    pulse
    return result
  end


  def fill_dp(dp_node, dp_row)
    dp_node << state = XML::Node.new('dd823:dcpState')
    active = true
    active_text = "aktiv und berichtet"
    active_flag = 1
    if dp_row['dp_state_active'] == 0
      active = false
      active_text = "aktiv und berichtet"
      active_flag = 0
    elsif dp_row['dp_to_be_reported'] == 0
      active = false
      active_text = "aktiv und berichtet"
      active_flag = 2
    end
    state << active_flag
    
    dp_node << rep_code = XML::Node.new('dd823:repCode')
    rep_code << REP_CODE
    
    fill_node( dp_node, dp_row, 'pl_eu_key', 'dd823:uwwCode')
    if !dp_row['pl_eu_key']
      puts "FEHLER: DP #{dp_row['dp_eu_key']} aus Land #{dp_row['federal_state_id']} hat keinen pl_eu_key!!!!!!!!!!!!!"
    end
    
    fill_node( dp_node, dp_row, 'dp_eu_key', 'dd823:dcpCode')
    fill_node( dp_node, dp_row, 'dp_name', 'dd823:dcpName')
    fill_node( dp_node, dp_row, 'nuts', 'dd823:dcpNUTS')

    if dp_row['dp_eu_lat']
      dp_node << latitude = XML::Node.new('dd823:dcpLatitude')
      latitude << sprintf("%.6e", dp_row['dp_eu_lat']).to_f.to_s
    end
    if dp_row['dp_eu_long']
      dp_node << longitude = XML::Node.new('dd823:dcpLongitude')
      longitude << sprintf("%.6e", dp_row['dp_eu_long']).to_f.to_s
    end
    
    # dcpWaterBodyType:
    if dp_row['dp_surface_sp_id']
      # dp.dp_surface_sp_id <--> l_waters.id
      # l_waters hält leider nicht die EU-Schlüssel, daher müssen wir low-level auf der id arbeiten
      wbt_key = case dp_row['dp_surface_sp_id']
                when 1 then 'LF' # Land
                when 2 then 'FW' # Süßwasser
                when 3 then 'ES' # Ästuar
                when 4 then 'CW' # Küste
                else raise Exception.new, "ERROR: xml_art15_exporter.rb, fill_dp, case dp_surface_sp_id: else reached"
                end
      poke(dp_node, wbt_key, 'dd823:dcpWaterBodyType')
      # dcpIrrigation:
      if dp_row['dp_surface_sp_id'] == 1
        if dp_row['dp_surface_land_id']
          irrigation_key = case dp_row['surface_land_key']
                           when 'BEWAESSERUNG' then 'IR' # Irrigation
                           when 'INFILTRATION' then 'IN' # Infiltration
                           when 'SONSTIGE' then 'OT' # Other
                           else raise Exception.new, "ERROR: xml_art15_exporter.rb, fill_dp, case surface_land_key: else reached"
                           end
          poke(dp_node, irrigation_key, 'dd823:dcpIrrigation')
        else
          puts "FEHLER: Land #{dp_row['federal_state_id']}, dp #{dp_row['dp_name']} (#{dp_row['dp_key']}) hat keine dp_surface_land_id, obwohl die Einleitung in Land erfolgt (Versickerung)"
        end
      end
    else
      puts "FEHLER: Land #{dp_row['federal_state_id']}, dp #{dp_row['dp_name']} (#{dp_row['dp_key']}), active = #{active ? "1" : "0"}, hat keine dp_surface_sp_id. dcpWaterBodyType kann nicht gefüllt werden!"
    end
    
    poke(dp_node, 'A54', 'dd823:dcpTypeOfReceivingArea')
    # Evtl. hier Ziffernkombi statt DE
    poke(dp_node, 'DE', 'dd823:rcaCode') # Das ist die ID, die oben für die Receiving Area Deutschland hartcodiert vergeben wurde
    fill_node_10(dp_node, dp_row, 'dp_surface', 'dd823:dcpSurfaceWaters')
    fill_node(dp_node, dp_row, 'water_body_eu_key', 'dd823:dcpWaterbodyID')
    
    # Nur bei Versickerung:
    if dp_row['dp_surface_sp_id'] && dp_row['dp_surface_sp_id'] == 1
      if dp_row['dp_gwbody_id'] && dp_row['groundwater_body_eu_key']
        fill_node(dp_node, dp_row, 'groundwater_body_eu_key', 'dd823:dcpGroundWater')
      else
        if active then
          puts "FEHLER: Land #{dp_row['federal_state_id']}, dp #{dp_row['dp_name']} (#{active_text}, #{dp_row['dp_key']}) hat keine dp_gwbody_id oder referenziert keinen derzeit gültigen Grundwasserkörper, obwohl die Einleitung in Land erfolgt (Versickerung)"
        end
      end
    end

    # dcpReceivingWater : rw_wise_key fehlt

    if dp_row['wrrl_sub_unit_description']
      wrrl_sub_unit_key = /^[0-9_]+/u.match(dp_row['wrrl_sub_unit_description'])
      poke(dp_node, wrrl_sub_unit_key, 'dd823:dcpWFDSubUnit')
    end

    fill_node(dp_node, dp_row, 'river_basin_district_eu_key', 'dd823:dcpWFDRBD')
    fill_node(dp_node, dp_row, 'dp_remark', 'dd823:dcpRemarks')
  end
  

  def create_discharge_points
    @bar.text="discharge points..."
    dps = XML::Node.new('DischargePoints')
    stmt = "select dp.*, p.pl_eu_key, lrc.key as nuts, lus.key as surface_land_key,
        lwb.eu_key as water_body_eu_key, lgwb.eu_key as groundwater_body_eu_key,
        lsu.description as wrrl_sub_unit_description, lrbd.river_basin_district_eu_key
      from discharge_points dp
        left join plants p
          on dp.plant_id = p.id
        left join l_region_code lrc
          on dp.dp_nuts_id = lrc.id
          and lrc.state = 0
        left join l_usage lus
          on dp.dp_surface_land_id = lus.id
          and lus.state = 0
        left join l_water_body_code lwb
          on dp.dp_waterbody_id = lwb.id
        left join l_groundwater_body lgwb
          on dp.dp_gwbody_id = lgwb.id
        left join l_wrrl_sub_units lsu
          on dp.dp_su_id = lsu.id
        left join l_river_basin_districts lrbd
          on dp.rb_rbd_id = lrbd.id
      where dp.state = 0
        and dp.date_from = #{DATE_FROM}
        and dp.federal_state_id < 17
      order by dp.federal_state_id, dp.dp_eu_key"
    print "SQL-Statement läuft ... #{Stnd.now}\n"
    sth = dbh.execute(stmt)
    pulse
    print "SQL-Statement fertig    #{Stnd.now}\n"
    counter = 0
    sth.fetch do |row|
      counter += 1
      dps << dp = XML::Node.new('DischargePoint')
      fill_dp(dp, row)
      if counter % 100 == 0
        pulse
        print "."
        STDOUT.flush
      end
      break if $testrun && counter >= 25
    end
    print "\n"
    puts "\n#{counter} Discharge Points geschrieben\n"
    return dps
  end

end
