#!/usr/local/bin/dptcl -f
#
proc UpdatePersonDisplay {person} {
}

proc Quickie {msg time} {
  puts ">> $msg <<"
}

proc Init {} {
}

proc MainLoop {} {
  global people
  set usage  "commands are: (r)eserve (d)elete (s)how (a)dd (c)hange (h)elp (q)uit"
  while {[True]} {
    puts ""
    foreach line [BreakIntoLines "$people" 70] {
      puts "PEOPLE: $line"
    }
    puts $usage
    puts -nonewline "** enter command> "
    gets stdin cmd
    switch $cmd {
      r	{ReservePerson}
      d	{DeleteReservation}
      s	{Display}
      h	{Help}
      a	{AddPerson}
      c	{Change}
      q {QuitApp {}}
      default	{puts "I don't understand that\n$usage"}
    }
  }
}

proc Dialog {tkname wintitle text bitmap buttonnum args} {
  global dialog_button
  # figure out how many letters are needed
  
  set options [join $args "/"]
  set textlist [BreakIntoLines $text 79]
  for {set i 0} {$i <= [expr [llength $textlist] - 1]} {incr i} {
    puts "[lindex $textlist $i]"
  }
  #puts "[lindex $textlist $i]"
  if {[llength $args] < 2} {return 0}
  puts -nonewline "\[$options\]> "
  while {1} {
    gets stdin ans
    set ans [string tolower $ans]
    set anslen [expr [string length $ans] - 1]
    set count 0
    set matches 0
    foreach foo [string tolower $args] {
      if {$ans == [string range $foo 0 $anslen]} {
        incr matches
        set dialog_button $count
      }
      incr count
    }
    if {$matches == 1} {return $dialog_button}
    if {$matches > 1} {
      puts "%% not enough letters supplied: ambiguous %%"
    }
    puts "must be one of \"$options\""
    puts -nonewline "\nretry> "
  }
}

proc BreakIntoLines {str length} {
  set reststr $str
  set outlist {}
  while {[string length $reststr] > $length} {
    set chunk [string range $reststr 0 [expr $length - 1]]
    set spacemark [string last { } $chunk]
    set reststr [string range $reststr [expr $spacemark + 1] end]
    set subchunk [string range $chunk 0 [expr $spacemark - 1]]
    lappend outlist $subchunk
  }
  if {[string length reststr]} {
    lappend outlist $reststr
  }
  return $outlist
}

proc True {} {
  return 1
}

proc QuitApp {arg} {
  global armed_person server signon

  if {$arg != "force"} {
    if {$armed_person != ""} {
      puts -nonewline "** You have not saved your changes. Are you sure? "
      gets stdin ans
      if {[regexp {[Yy].*} $ans]} {
        RelinquishLock $armed_person
      }
    }
  }
  ExecRPC SignOff $signon
  dp_CloseRPC $server
  exit
}

proc Help {} {
  puts "type 'r' to make a reservation"
  puts "type 'd' to delete a reservation"
  puts "type 's' to show Person stammdaten or reservations"
  puts "type 'a' to add a Person to system"
  puts "type 'c' to change Person Stammdaten"
}

proc Enter {prompt force default} {
  set done 0
  set def_str ""
  if {[string length $default]} {
    set force 0
    set def_str " \[$default\]"
  }
  while {!$done} {
    puts -nonewline "** $prompt${def_str}: "
    gets stdin buf
    if {[regexp {[{}]} $buf]} {
      regsub -all {([{}])} $buf {\\\1} tmp
      set buf "$tmp"
    }
    if {$force} {
      if {[string length $buf] > 0} {set done 1}
    } else {
      set done 1
    }
  }
  if {[string length $buf] == 0} {
    return "$default"
  }
  return "$buf"
}

proc GetHalf {} {
  while {[True]} {
    set tmp [Enter {Enter "(m)orning" or "(a)fternoon"} 1 {}]
    switch $tmp {
      m	{return 0}
      a	{return 1}
      default	{puts "haeh?"}
    }
  }
}

proc YesNo {prompt} {
  while {[True]} {
    puts -nonewline "$prompt \[(y)es/(n)o\] ? "
    gets stdin ans
    set ans [string tolower $ans]
    switch $ans {
      y	-
      ye -
      yes {return 1}
      n	-
      no {return 0}
      default	{puts "haeh?"}
    }
  }
}

proc LockPerson {person} {
  global lock_serial

  incr lock_serial
  dp_after 120000 "LockTimeout $person $lock_serial"
  set ret [ClientRequestLock $person]
  if {$ret} {puts "You now have two minutes to make changes..."}
  return $ret
}

proc RelinquishLock {person} {
  global signon

  ExecRPC ReleaseLock $person $signon
}

proc PromptForDate {prompt} {
  set done 0
  while {!$done} {
    set tmp [Enter "$prompt" 0 {}]
    if {$tmp == ""} {
      return -1
    }
    set half [GetHalf]
    set hc [ConvertFromFileDate "$tmp/$half"]
    if {($hc == "")||($hc == "-1")} {
      puts "error in input, reenter"
    } else {
      return $hc
    }
  }
}
proc ReservePerson {} {
  global username alarm_minutes armed_person resconf_cust lock_serial
  global signon person_reservations

  set person [Enter {Enter Person} 0 {}]
  if {![PersonExist $person]} {
    puts "the Person must exist in system."
    return
  }
  if {![LockPerson $person]} {
    return -1
  }
  set armed_person $person
  UpdateIfChanged $person
  set start_hc [PromptForDate {Enter starting date in form dd/mm/yy}]
  if {$start_hc == -1} {
    RelinquishLock $person; set armed_person ""; return -1
  }
  set end_hc [PromptForDate {Enter ending date in form dd/mm/yy}]
  if {$end_hc == -1} {
    RelinquishLock $person; set armed_person ""; return -1
  }
  set ret [CheckBits $person $start_hc $end_hc]
  if {$ret == -1} {
    puts "You can't reserve that far ahead"
  } elseif {$ret == 0} {
    puts "This would overlap another reservation"
  } else {
    set cust [Enter {Customer} 0 {}]
    set phone [Enter {Phone} 0 {}]
    set sonst [Enter {Sonstiges} 0 {}]
    set busy [YesNo "Busy but present"]
    puts "\n---------------------------------"
    puts "person:	$person"
    puts "from:	[Convert nicedate $start_hc]"
    puts "to:	[Convert nicedate $end_hc]"
    puts "kunde:	$cust"
    puts "phone:	$phone"
    puts "sonst:	$sonst"
    puts "present:	[expr "{$busy} ? {Yes} : {No}"]"
    if {[YesNo "** Confirm the reservation"]} {
      ReserveBits $person $start_hc $end_hc "$cust" "$sonst" "$phone" $busy
      ExecRPC LogIt "{$username reserved person $person}\
          {\tfrom [Convert nicedate $start_hc]}\
          {\tto [Convert nicedate $end_hc]}"
      set resconf_cust $cust
      NotifyQuery confirm $person $start_hc $end_hc
    }
    #WritePersonFile $person nochgrp
    UpdatePersonOnServer $person {} "$person_reservations($person)"
  }
  RelinquishLock $person
  set armed_person ""
  #alarm 0.0
}

proc UpdatePersonOnServer {person pinfo pres} {
  global signon person_reservations

  set ret [ExecRPC ServerUpdatePerson $person "$pinfo" "$pres" $signon]
  if {$ret != "success"} {
    puts "An error occurred while trying to update"
    puts "${person}'s information:"
    if {[lindex $ret 0] == "NOTLOCKED"} {
      puts "-- Your time ran out --"
    } else {
      puts "Error: $ret"
    }
  }
}

proc CheckBits {person start end} {
  global biglist
  if {$end >= [llength $biglist($person)]} {return -1}
  for {set i $start} {$i <= $end} {incr i} {
    if {[lindex $biglist($person) $i] > 0} {
      return 0
    }
  }
}

proc PersonExist {person} {
  global people
  if {[lsearch $people $person] >= 0} {return 1}
  return 0
}

proc ListPersonReservations {dotag person} {
  # person assumed to be valid
  global person_reservations

  puts "PERSON=$person"
  set dashes "-------------------------------------------------------------------------------"
  puts "$dashes"
  puts "[FormatShowLine $dotag Tag From To Cust/Desc Telephone]"
  puts "[FormatShowLine $dotag ____ ________________________\
    ______________________ ____________________ ___________________]"
  foreach ent $person_reservations($person) {
    set tag [lindex $ent 0]
    set start [lindex $ent 1]
    set end [lindex $ent 2]
    set cust [lindex $ent 3]
    set sonst [lindex $ent 4]
    set fone [lindex $ent 5]
    puts "[FormatShowLine $dotag $tag [Convert nicedate $start]\
      [Convert nicedate $end] $cust $fone]"
  }
  puts "$dashes"
}

proc FormatShowLine {dotag tag start end cust phone} {
  set start_str [string range $start 0 22]
  set end_str [string range $end 0 22]
  set cust_str [string range $cust 0 13]
  if {$dotag == "tag"} {
    set phone_str [string range $phone 0 9]
    set tag "[format "%-5s" $tag]"
    set pl 12
  } else {
    set phone_str [string range $phone 0 14]
    set tag {}
    set pl 16
  }
  return [format "%s%-24s%-24s%-15s%-${pl}s" $tag $start_str $end_str\
    $cust_str $phone_str]
}

proc DeleteReservation {} {
  global person_reservations armed_person username resconf_cust signon

  set person [Enter {Enter person} 0 {}]
  if {![PersonExist $person]} {
    puts "you must specify an existing person"
    return
  }
  if {![LockPerson $person]} {
    return -1
  }
  set armed_person $person
  UpdateIfChanged $person
  ListPersonReservations tag $person
  set found 0
  set index 0
  while {!$found} {
    puts -nonewline "** type the tag of the entry to delete (<CR> to quit): "
    gets stdin ans
    if {[string length $ans] < 1} {
      RelinquishLock $person
      set armed_person ""
      return
    }
    foreach ent $person_reservations($person) {
      set tag [lindex $ent 0]
      if {$tag == $ans} {
        set found 1
        set start [lindex $ent 1]
        set end [lindex $ent 2]
        set cust [lindex $ent 3]
        set sonst [lindex $ent 4]
        set phone [lindex $ent 5]
        break
      }
      incr index
    }
  }
  puts "\n---------------------------------"
  puts "person:	$person"
  puts "from:	[Convert nicedate $start]"
  puts "to:	[Convert nicedate $end]"
  puts "kunde:	$cust"
  puts "phone:	$phone"
  puts "sonst:	$sonst"
  set doit 0
  if {[YesNo "** Confirm delete"]} {
    set doit 1
    if {$username != $person} {
      puts "You did not make this reservation. (a mail will be sent to $person)"
      if {![YesNo "** Really delete"]} {
        Mail $person "$username deleted your reservation for person\
          $person from [Convert nicedate $start] to [Convert nicedate $end]"
        set doit 0
      }
    }
  }  
  if {$doit} {
    puts "index=$index, start=$start, end=$end"
    set newlist [lreplace $person_reservations($person) $index $index]
    set person_reservations($person) $newlist
    #ZeroPersonBits $person $start $end
    set resconf_cust $cust
    NotifyQuery delete $person $start $end
    UpdatePersonOnServer $person {} "$person_reservations($person)"
    ExecRPC LogIt\
        "{$username deleted reservation for $person}\
         {\tfrom [Convert nicedate $start]}\
         {\tto [Convert nicedate $end]}\
         {\tcustomer : $resconf_cust}\
         {\ttelephone: $phone}\
         {\tsonstiges: $sonst}"
  }
  RelinquishLock $person
  set armed_person ""
}

proc Display {} {
  global people
  puts "PEOPLE: $people"
  puts -nonewline "** Show (r)eservation or (s)tammdaten? "
  gets stdin ans
  switch $ans {
    r	{DisplayReservation}
    s	{DisplayStammdaten}
    default	{puts "haeh?"; return}
  }
}

proc DisplayReservation {} {
  set person [Enter {Enter person} 0 {}]
  if {![PersonExist $person]} {
    puts "you must specify an existing person"
    return
  }
  #ReadPersonFile $person
  UpdateIfChanged $person
  ListPersonReservations notag $person
}

proc DisplayStammdaten {} {
  global person_info
  set person [Enter {Enter person} 0 {}]
  if {![PersonExist $person]} {
    puts "you must specify an existing person"
    return
  }
  set entry $person_info($person)
  ShowPersonInfo $entry
}

proc ShowPersonInfo {list} {
  set address [lindex $list 2]
  puts "\n-----------------------------"
  puts "person:		[lindex $list 0]"
  puts "phone:		[lindex $list 1]"
  puts "address:	$address"
  puts "-----------------------------\n"
}
  
proc AddPerson {} {
  global people person_info
  set person [Enter {Enter person} 0 {}]
  if {$person == ""} {return}
  set phone [Enter {Telephone} 1 {}]
  set address [Enter {Address} 1 {}]
  ShowPersonInfo "{$person} {$phone} {$address}"
  if {[YesNo "** Confirm"]} {
    lappend people $person
    set person_info($person) "{$person} {$hardware} {$memory} {$disks} {$remarks}"
    #WritePersonFile $person chgrp
    ExecRPC ServerAddPerson "$person_info($person)"
    ExecRPC LogIt "{$username added new person $person}"
  }
}

proc Change {} {
  global person_info alarm_minutes armed_person lock_serial signon
  global person_reservations

  set person [Enter {Enter person} 0 {}]
  if {![PersonExist $person]} {
    puts "you must specify an existing person"
    return
  }
  if {![LockPerson $person]} {
    return -1
  }
  set armed_person $person
  #alarm [expr $alarm_minutes * 60]
  #dp_after 120000 "LockTimeout $person $lock_serial"
  #puts "You now have two minutes to make changes..."
  #ReadPersonFile $person
  UpdateIfChanged $person
  ShowPersonInfo "$person_info($person)"
  set phone [lindex "$person_info($person)" 1]
  set address [lindex "$person_info($person)" 2]
  set phone [Enter {Phone} 0 "$phone"]
  set address [Enter {Address} 0 "$address"]
  ShowPersonInfo "{$person} {$phone} {$address}"
  if {[YesNo "** Confirm Changes"]} {
    set person_info($person) "{$person} {$phone} {$address}"
  }
  #WritePersonFile $person chgrp
  UpdatePersonOnServer $person "$person_info($person)"\
    "$person_reservations($person)"
  RelinquishLock $person
  set armed_person ""
  #alarm 0.0
}

proc LockTimeout {person serial} {
  global armed_person username lock_serial top_win signon

  set msg "."
  if {($armed_person == "") || ($lock_serial != $serial)} {return}
  # consistency check...
  if {$armed_person != $person} {
    puts "whoah! there's something wierd going on here..."
    QuitApp force
  }
  #DisarmPerson $armed_person
  ExecRPC ReleaseLock $person $signon
  Dialog .dialog {timeout} "Your time ran out. Your changes to person\
    $person were saved$msg" warning -1 OK
}

proc Connect {} {
  global server username rpc_port server_name

  if {[catch {set server [dp_MakeRPCClient $server_name $rpc_port]}]} {
    return 0
  }
  return 1
}

##############################################################################
# end of procedure definitions
##############################################################################
set debug 1
set thishost [exec /bin/hostname]

######## *EDIT* ########
set lib_dir /usr/local/lib/abwesenheit
source $lib_dir/config.tcl

if {![Connect]} {
  puts "error: no server running"
  exit
}
source $lib_dir/utils.tcl
set signon [dp_RPC $server SignOn $username]
set num_cells 120
set lock_serial 1
SetDateVars
LoadHolidays
LoadMessen
CellBind
InitVirginBiglist
#FindPeople
set people [ExecRPC set people]
ReadAllPeople
UpdateLists
MainLoop
