#!/usr/local/bin/wish

# Config info:
#  prefix

set Online  0

set FileName "$env(HOME)/.phone_nums"

proc AddNumber { Nam Num } {
   global ListOfNumbers
   lappend ListOfNumbers "$Nam $Num"
#   puts "$Nam $Num"
   DumpNumList 
}

#
# Read File with user's stored numbers
#
set ListOfNumbers {}

if { [file readable $FileName]} {
   set f [open $FileName r]
   while {[gets $f line] >= 0} {
      if { [string compare "NUMBER" [lindex $line 0]] == 0 } {
         lappend ListOfNumbers [lrange $line 1 end]
      } elseif { [string compare "PREFIX" [lindex $line 0]] == 0 } {
         global prefix
         set prefix [lindex $line 1]
      }
   }
   close $f
}

proc DumpNumList {} {
   global prefix
   global FileName
   global ListOfNumbers
   set f [open $FileName w]
 
   if { [string length $prefix] > 0 } {
      puts $f [concat "PREFIX" $prefix] 
   }
   if { [llength $ListOfNumbers] > 0 } {
      set Rest $ListOfNumbers

      while { 1 } {
         set line [lindex $Rest 0]
         set Rest [lrange $Rest 1 end]

         if { [string length $line] == 0 } { break }

         puts $f [concat "NUMBER" $line]
      }
   }
   close $f
}

proc GetPrefix { w } {
   global prefix
   global GPbtn
   global GPentry
   set GPentry $prefix
   set GPbtn "CANCEL"
   
   toplevel $w -class Dialog
   wm title $w "Selecting a new prefix:"
   wm iconname $w "Selecting a new prefix:"

   frame $w.top -relief raised -bd 1
   pack $w.top -side top -fill both
   frame $w.bot -relief raised -bd 1
   pack $w.bot -side bottom -fill both

   label $w.top.l -text "Type a new prefix:"
   entry $w.top.e -relief sunken -bd 2 -textvariable GPentry
   pack $w.top.l $w.top.e -side top -expand 1 -fill x -padx 3m -pady 2m 

   button $w.bot.ok -text "OK" -command { 
      global GPentry
      global prefix
      set prefix $GPentry
      set GPbtn "OK" 
   }

   button $w.bot.cancel -text "Cancel" -command { set GPbtn "CANCEL" }
   pack $w.bot.ok $w.bot.cancel -side left -expand 1 -padx 3m -pady 2m \
      -in $w.bot

   bind $w <Key-Return> { 
      global GPentry
      global prefix
      set prefix $GPentry
      set GPbtn "OK" 
   }
   bind $w <Key-Escape> { set GPbtn "CANCEL" }

   set oldFocus [focus]
   grab set $w
   focus $w.top.e

   tkwait variable GPbtn
   grab release $w
   focus $oldFocus
}

#
# Create a new number for storing in the list
#
proc AddNewNumber { w Name Num } {
   global ANNbtn
   global ANNassoc
   global ANNumber
   set ANNumber $Num
   set ANNassoc $Name

   toplevel $w -class Dialog
   wm title $w "Adding Number to the Save List"
   wm iconname $w "Adding Number to the Save List"

   frame $w.top -relief raised -bd 1
   pack $w.top -side top -fill both
   frame $w.bot -relief raised -bd 1
   pack $w.bot -side bottom -fill both

   label $w.top.l -text "Type associated name for $ANNumber:"
   entry $w.top.e -relief sunken -bd 2 -textvariable ANNassoc
   pack $w.top.l $w.top.e -side top -expand 1 -fill x -padx 3m -pady 2m 

   button $w.bot.ok -text "Add" -command { 
      if { [string length $ANNassoc] != 0 } {
         global ANNassoc ANNumber
         AddNumber $ANNassoc $ANNumber
         set ANNbtn "OK" 
      }
   }

   button $w.bot.cancel -text "Cancel" -command { set ANNbtn "CANCEL" }
   pack $w.bot.ok $w.bot.cancel -side left -expand 1 -padx 3m -pady 2m \
      -in $w.bot

   bind $w <Key-Return> { 
      if { [string length $ANNassoc] != 0 } {
         global ANNassoc ANNumber
         AddNumber $ANNassoc $ANNumber
         set ANNbtn "OK" 
      }
   }
   bind $w <Key-Escape> { set ANNbtn "CANCEL" }

   set oldFocus [focus]
   grab set $w
   focus $w.top.e

   tkwait variable ANNbtn
   grab release $w
   focus $oldFocus
   return $ANNbtn
}

proc GetNumberFromList { w } {
   global GNFLbtn
   global ListOfNumbers
   global GNFSelection
   set GNFSelection {}

   #
   # Retreive a number from the list
   #
   toplevel $w -class Dialog
   wm title $w "Select a number to dial"
   wm iconname $w "Selection List"

   frame $w.top -relief raised -bd 1
   pack $w.top -side top -fill both -expand 1
   frame $w.bot -relief raised -bd 1
   pack $w.bot -side bottom -fill both -expand 1

   label $w.top.l -text "Select Number to Dial:"
   listbox $w.top.lb -relief sunken -bd 2

   if { [llength $ListOfNumbers] != 0 } {
      foreach lbitem [lsort $ListOfNumbers] {
         $w.top.lb insert end $lbitem
      }
   }

   bind $w.top.lb <ButtonRelease-1> {
      global GNFSelection 
      set GNFSelection [selection get]
   }

   bind $w.top.lb <Double-1> {
      set GNFLbtn "ADD" 
   }

   pack $w.top.l $w.top.lb -side top -expand 1 -fill both -padx 3m -pady 2m 

   button $w.bot.ok -text "Use" -command { set GNFLbtn "ADD" }

   global GNFw
   set GNFw $w
   button $w.bot.del -text "Delete" -command { 
      global GNFSelection
      global GNFw
      set rmindex 0
      if { [ string length $GNFSelection ] > 0 } {
         foreach lbitem $ListOfNumbers {
            if { [string compare $lbitem $GNFSelection ] == 0 } {
               break
            }
            incr rmindex
         }
         set GNFSelection {}

         if { $rmindex < [llength $ListOfNumbers] } {
            set ListOfNumbers [lreplace $ListOfNumbers $rmindex $rmindex]
            DumpNumList

            $GNFw.top.lb delete 0 end
            if { [llength $ListOfNumbers] != 0 } {
               foreach lbitem [lsort $ListOfNumbers] {
                  $GNFw.top.lb insert end $lbitem
               }
            }
         }
      }
   }
   button $w.bot.cancel -text "Cancel" -command { 
      global GNFSelection
      set GNFSelection {}
      set GNFLbtn "CANCEL" 
   }

   pack $w.bot.ok $w.bot.del $w.bot.cancel \
      -side left -expand 1 -padx 3m -pady 2m -in $w.bot

   bind $w <Key-Return> { set GNFLbtn "ADD" }
   bind $w <Key-Escape> { set GNFLbtn "CANCEL" }

   set oldFocus [focus]
   grab set $w
   focus $w.top.lb

   tkwait variable GNFLbtn
   grab release $w
   focus $oldFocus
   return $GNFSelection 
}

#
# Write/read info into the user's list of numbers
#
proc StoredNumbers { w Num } {
   global SNNumber
   set SNNumber $Num

   if { [string length $SNNumber] != 0 } {
      AddNewNumber $w {} $SNNumber
      return ""
   } else {
      set retval [GetNumberFromList $w]
      set leng [llength $retval]
      if { $leng >= 1 } {
         set retval [lindex $retval [expr $leng - 1]]
         return $retval
      }
   }
   return ""
}

# 
#  Add a character to the display
#
proc buttonpress { num } {
   global Online
   if { $Online == 0 } {
      global number
      set number ${number}${num}
      if { [string length $number] > 0 } {
         .main.btnlist configure -text "Save"
      }
   } else {
      dial $num
   }
}

#
# Clear display
#
proc clearline { } {
   global number
   set number {}
   .main.btnlist configure -text "List"
}

#
# Delete a character from the display
#
proc delchar {} { 
   global number

   set len [string length $number]
   
   if { [string index $number [expr $len - 1]] == "]" } {
      set number [string range $number 0 \
                   [expr [string last "\[" $number ] - 1]]
   } else {
      set number [string range $number 0 [expr $len - 2]] 
   }

   if { [string length $number ] == 0 } {
      .main.btnlist configure -text "List"
   }
}

#
# Dial or hangup the line depending on the state of the modem
#
proc DialHangup {} {
   global Online
   if { $Online == 0 } {
      global Online
      global number
      global prefix
      if { [string length $number] == 0 } {
         dial {}
      } else {
         dial ${prefix}${number}
      }
      .main.btndial configure -text "Hangup" -bg Red 
      set Online 1
   } else {
      global Online
      clearline
      hangup
      .main.btndial configure -text "Dial" -bg Green
      set Online 0
   }
}

proc TerminateApp {} {
   global Online
   if { $Online == 1 } {
      hangup
   }
   exit
}

#
# Create widgets
#
set padsize 1m
wm title . "SuperPhone"

frame .main

frame .main.col1 -bg DarkGray
frame .main.col2 -bg DarkGray -relief raised -borderwidth 2
frame .main.row0 -bg Gray60 -relief raised -borderwidth 3
frame .main.row00 -bg DarkGray
frame .main.row1 -bg DarkGray
frame .main.row2 -bg DarkGray
frame .main.row3 -bg DarkGray
frame .main.row4 -bg DarkGray

button .main.btn1 -width 7 -height 2 -text "1\n       " -command {
   buttonpress 1 
}
button .main.btn2 -width 7 -height 2 -text "2\n A B C " -command {
   buttonpress 2 
}
button .main.btn3 -width 7 -height 2 -text "3\n D E F " -command {
   buttonpress 3 
}
button .main.btn4 -width 7 -height 2 -text "4\n G H I " -command {
   buttonpress 4 
}
button .main.btn5 -width 7 -height 2 -text "5\n J K L " -command {
   buttonpress 5 
}
button .main.btn6 -width 7 -height 2 -text "6\n M N O " -command {
   buttonpress 6 
}
button .main.btn7 -width 7 -height 2 -text "7\nP Q R S" -command {
   buttonpress 7 
}
button .main.btn8 -width 7 -height 2 -text "8\n T U V " -command {
   buttonpress 8 
}
button .main.btn9 -width 7 -height 2 -text "9\nW X Y Z" -command {
   buttonpress 9 
}
button .main.btn0 -width 7 -height 2 -text "0" -command {buttonpress 0 }
button .main.btnstar -width 7 -height 2 -text "*" -command {buttonpress "*" }
button .main.btnpound -width 7 -height 2 -text "#" -command {buttonpress # }
button .main.btnexit -text "Exit" -command TerminateApp 
button .main.btnclear -text "Clear" -command clearline
button .main.btnflash -text "Flash" -command { buttonpress "\[FLASH\]" }
button .main.btnpause -text "Pause" -command { buttonpress "\[PAUSE\]" }
button .main.btnmsgs -text "Messages" -command TerminateApp 
button .main.btndial -width 7 -height 2 -bg Green -text "Dial" -command DialHangup 
button .main.btnlist -text "List" -command { 
   buttonpress [ StoredNumbers .s $number ] 
   destroy .s
}

entry .main.entry -relief sunken -bd 2 -textvariable number
entry .main.prefix -relief sunken -bd 2 -width 2 -textvariable prefix

#
# Assign key accelerators
#
foreach evnt {  { 0 } { 1 }
               { 2 a b c A B C } 
               { 3 d e f D E F }
               { 4 g h i G H I }
               { 5 j k l J K L }
               { 6 m n o M N O }
               { 7 p q r s P Q R S }
               { 8 t u v T U V }
               { 9 w x y z W X Y Z }
             } {
   set btn [ lindex $evnt 0 ]
   foreach bnd $evnt {
      set scrpt [ concat \{ buttonpress [expr $btn] \}]
      bind . <Key-$bnd> [ expr $scrpt]
   }
}

bind . <KP_Insert>    {buttonpress "0"}
bind . <KP_End>       {buttonpress "1"}
bind . <KP_Down>      {buttonpress "2"}
bind . <KP_Next>      {buttonpress "3"}
bind . <KP_Left>      {buttonpress "4"}
bind . <KP_Begin>     {buttonpress "5"}
bind . <KP_Right>     {buttonpress "6"}
bind . <KP_Home>      {buttonpress "7"}
bind . <KP_Up>        {buttonpress "8"}
bind . <KP_Prior>     {buttonpress "9"}
bind . <KP_Multiply>  {buttonpress "*"}
bind . <KP_Add>       {buttonpress "#"}
bind . <KP_Enter>     {DialHangup }
bind . <KP_Delete>    {buttonpress "\[FLASH\]"}
bind . <KP_Subtract> {buttonpress "\[PAUSE\]"}
bind . <Key-exclam>   {buttonpress "\[FLASH\]"}
bind . <Key-comma>   {buttonpress "\[PAUSE\]"}
bind . <Key-at>   {buttonpress "\[DIALTONE\]"}
bind . <Key-period>   {buttonpress "\[SILENCE\]"}
bind . <Key-asterisk> { buttonpress * }
bind . <Key-plus> { buttonpress * }
bind . <Key-numbersign> { buttonpress # }
bind . <Key-Return> { DialHangup }
bind . <Key-Escape> { clearline }
bind . <Key-BackSpace> { delchar }
bind . <Key-Delete> { delchar }
#bind . <Any-KeyPress> { buttonpress %K }
bind all <Control-c> { TerminateApp }

bind .main.prefix <ButtonRelease-1> { 
   GetPrefix .s
   destroy .s
   focus .main.btndial
   DumpNumList 
}
bind .main.entry <ButtonRelease-1> { focus .main.btndial }

# 
# Finally display all the stuff in the window
#
pack .main -side left -fill both -expand 1
pack .main.row0 .main.row00 -side top -fill both -in .main
pack .main.col1 .main.col2 -side left -fill both -expand 1 -in .main.row00
pack .main.btnexit .main.btnclear .main.btnflash .main.btnpause .main.btnmsgs \
      -side top -padx $padsize -pady $padsize -fill x -in .main.col2
pack .main.btndial -side bottom -padx $padsize -pady $padsize -fill x \
      -in .main.col2
#pack .main.row0 -side top -fill both -in .main.col1
pack .main.row4 .main.row3 .main.row2 .main.row1 -side bottom -fill both \
      -in .main.col1 -expand 1
pack .main.btnlist -side right -padx $padsize -pady $padsize -in .main.row0
pack .main.prefix -side left -fill both -padx $padsize \
      -pady $padsize -in .main.row0
pack .main.entry -side left -fill both -padx $padsize \
      -pady $padsize -expand 1 -in .main.row0
pack .main.btn1 .main.btn2 .main.btn3 -in .main.row1 -side left \
      -fill both -padx $padsize -pady $padsize -expand 1
pack .main.btn4 .main.btn5 .main.btn6 -in .main.row2 -side left \
      -fill both -padx $padsize -pady $padsize -expand 1
pack .main.btn7 .main.btn8 .main.btn9 -in .main.row3 -side left \
      -fill both -padx $padsize -pady $padsize -expand 1
pack .main.btnstar .main.btn0 .main.btnpound -in .main.row4 -side left \
      -fill both -padx $padsize -pady $padsize -expand 1

