#!/bin/tclsh
#Version 1.4
#param 0 = Breitengrad (nördlich)
#param 1 = Längengrad (östlich)
#param 2 = künstlicher Horizont
#param 3 = PLZ

source /www/addons/lcd_msg/daemonize.tcl

load tclrega.so

proc showTime x {
  clock format $x -format "%H:%M:%S"
}

proc log x {
  puts "[showTime [clock seconds]]: $x"  
}

log "args: $argv"

set latitude [lindex $argv 0]
set longitude [lindex $argv 1]
set indoor_horizon [lindex $argv 2]
set plz [lindex $argv 3]
set timezone [expr {([clock scan "0 UTC"] - [clock scan "0"]) / 3600.0}]
#get the day of the year as numeric value
set dayofyear [string trimleft [clock format [clock seconds] -format "%j"] "0"]
#add the fractional part to the next leap-year to the current day of the year
set dayofyear [expr {$dayofyear + ([clock format [clock seconds] -format "%Y"]%4)/4.0 + ($dayofyear)/365.0/4.0}]
log "timezone: $timezone, day of year: $dayofyear"


#define constants for the list access to make review easier
set NIGHT 0
set SR_ASTRONOMICAL 1
set SR_NAUTICAL 2
set SR_CIVIL 3
set SR_SUNRISE 4
set SR_INDOOR 5
set SR_WEATHER 6
set SS_WEATHER 7
set SS_INDOOR 8
set SS_SUNRISE 9
set SS_CIVIL 10
set SS_NAUTICAL 11
set SS_ASTRONOMICAL 12


proc calcTwilightTimes {latitude longitude timezone dayofyear horizon sunrisevar sunsetvar} {
  upvar $sunrisevar sunrise
  upvar $sunsetvar sunset
 
  set timediff [expr {-0.171*sin(0.0337 * $dayofyear + 0.465) - 0.1299*sin(0.01787 * $dayofyear - 0.168)}]
  set declination [expr {0.4095 * sin(0.016906 * ($dayofyear - 80.086) ) }]
  set suntime [expr {12*acos((sin($horizon/57.29578) - sin($latitude/57.29578)*sin($declination)) / (cos($latitude/57.29578)*cos($declination)))/3.141592}]
  set sunrise [expr {[clock scan "0"] + round((12 - $timediff - $suntime - $longitude/15.0 + $timezone)*3600)}]
  set sunset  [expr {[clock scan "0"] + round((12 - $timediff + $suntime - $longitude/15.0 + $timezone)*3600)}]
}

proc getTwilightHorizon {plz base_horizon} {
  set url http://www.google.com/ig/api?weather=$plz-Germany&hl=de
  set twilightHorizon 5.0
  catch {
    exec /usr/bin/wget -q -O /tmp/twilightweather.xml $url
    set f [open "/tmp/twilightweather.xml"]
    set a [read $f]
    close $f
    regexp "<current_conditions>(.*)</current_conditions>" $a dummy current
    foreach tag [split $current >] {
      regexp {<([^=>]*) data="([^=>"]*)"/} $tag dummy key value
        #" for editor
      set aCurrent($key) "$value"
    }
    log "current condition is \"$aCurrent(condition)\""
    file delete /tmp/twilightweather.xml
    switch $aCurrent(condition) {
      "Klar"              {set twilightHorizon [expr {$base_horizon + 0.2}]}
      "Meist sonnig"      {set twilightHorizon [expr {$base_horizon + 1.5}]}
      "Teils sonnig"      {set twilightHorizon [expr {$base_horizon + 3.0}]}
    }
  }
  log "twilight horizon set to $twilightHorizon"
  return $twilightHorizon
}

proc waitToTime destTime {
  set waittime [expr {1000*($destTime - [clock seconds])}]
  if {$waittime > 0} then {
    log "waiting [expr $waittime/1000] s until [clock format $destTime]"
    after $waittime
  } else { 
    log "not waiting [expr $waittime/1000] s" 
  } 
}

proc displayValues {} {
  uplevel {
    set display "siehe folgende Tabelle</div><br/>\n<table border=\"1\" bordercolor=\"#000000\" style=\"background-color:#5d6373\" width=\"100%\">"
    append display "<tr><td><b>Dämmerung</b></td><td><b>Morgens</b></td><td><b>Abends</b></td></tr>"
    for {set i 0} {$i < 6} {incr i} {
      
      set insert "[lindex $twilight_types $i]:"
      if {$i == $current_tt-1 || $i == 11-$current_tt} then {set insert "<b>$insert</b>"}
      append display "<tr><td>$insert</td>"
      
      set insert "[showTime [lindex $twilight_times [expr $i+1]]]"
      if {$i == $current_tt-1} then {set insert "<b>$insert</b>"}
      if {$i == 5 && !$srw_set} then {set insert "<i>$insert</i>"}
      append display "<td>$insert</td>"
      
      set insert "[showTime [lindex $twilight_times [expr 12-$i]]]"
      if {$i == 12-$current_tt} then {set insert "<b>$insert</b>"}
      if {$i == 5 && !$ssw_set} then {set insert "<i>$insert</i>"}
      append display "<td>$insert</td>"
      
      log "updating twilight time table: [showTime [lindex $twilight_times [expr $i+1]]] [showTime [lindex $twilight_times [expr 12-$i]]] [string map {: { }} [lindex $twilight_types $i]]"
    }
    append display "</table>\n</td>"
    rega_script "dom.GetObject('Dämmerungszeiten').State('$display');"
  }
}

#
# Main execution
#

calcTwilightTimes $latitude $longitude $timezone $dayofyear [expr {$indoor_horizon + 5.1}] sunrise_weather sunset_weather
calcTwilightTimes $latitude $longitude $timezone $dayofyear $indoor_horizon sunrise_indoor sunset_indoor
calcTwilightTimes $latitude $longitude $timezone $dayofyear -0.83333333 sunrise sunset
calcTwilightTimes $latitude $longitude $timezone $dayofyear -6 sunrise_civil sunset_civil
calcTwilightTimes $latitude $longitude $timezone $dayofyear -12 sunrise_nautical sunset_nautical
calcTwilightTimes $latitude $longitude $timezone $dayofyear -18 sunrise_astronomical sunset_astronomical

set twilight_times "0 $sunrise_astronomical $sunrise_nautical $sunrise_civil $sunrise $sunrise_indoor $sunrise_weather $sunset_weather $sunset_indoor $sunset $sunset_civil $sunset_nautical $sunset_astronomical"
set twilight_types "Astronom. Nautisch Bürgerlich Standard Indoor Wetterabh."
set srw_set 0
set ssw_set 0
set current_tt $NIGHT
displayValues

for {} {$current_tt < $SS_ASTRONOMICAL} {incr current_tt} {
  set waitfor_tt [expr $current_tt+1]
  set next_time [lindex $twilight_times $waitfor_tt]
  if {$current_tt == $SR_INDOOR && [clock seconds] < $next_time} then {
    #read sunrise weather at indoor twilight (only if time not past worst-case sunrise weather twilight time)
    log "retrieving weather condition for sunrise"
    calcTwilightTimes $latitude $longitude $timezone $dayofyear [getTwilightHorizon $plz $indoor_horizon] sunrise_weather dummy
    set next_time $sunrise_weather
    set srw_set 1
    set twilight_times [lreplace $twilight_times $SR_WEATHER $SR_WEATHER $sunrise_weather]
    displayValues
    log "weather sunrise at [showTime $next_time]"
  }
  if {$current_tt == $SR_WEATHER && [clock seconds] < [lindex $twilight_times $SS_INDOOR]} then {
    log "current twilight state $current_tt ([lindex $twilight_types [expr {6-abs($current_tt-7)}]]), sunlight state [expr {6-abs($current_tt-6)}], waiting to retrieve weather data"
    waitToTime $next_time
    #read sunset weather after sunset weather index has been reached
    log "retrieving weather condition for sunset"
    calcTwilightTimes $latitude $longitude $timezone $dayofyear [getTwilightHorizon $plz $indoor_horizon] dummy sunset_weather
    set next_time $sunset_weather
    set ssw_set 1
    set twilight_times [lreplace $twilight_times $SS_WEATHER $SS_WEATHER $sunset_weather]
    displayValues
    log "weather sunset at [showTime $next_time]"
  }
  if {[clock seconds] < $next_time} then {
    log "current twilight state $current_tt ([lindex $twilight_types [expr {6-abs($current_tt-7)}]]), sunlight state [expr {6-abs($current_tt-6)}], next at [showTime $next_time]"
    rega_script "dom.GetObject('Dämmerung').State('$current_tt');"
    rega_script "dom.GetObject('Tageslicht').State('[expr {6-abs($current_tt-6)}]');"
    displayValues 
    waitToTime $next_time
  }
}
rega_script "dom.GetObject('Dämmerung').State('12');"
rega_script "dom.GetObject('Tageslicht').State('0');"
displayValues 12 $srw_set $ssw_set $twilight_times
    
if {[file exists /tmp/twilight.pid]} then {
  catch {
    set f [open /tmp/twilight.pid]
    set filepid [read $f]
    close $f
    if {[pid] == $filepid} then {file delete /tmp/twilight.pid}
  }
}
