################################################################
# proc distance {x1 y1 x2 y2}--
#    Return the distance between two points using Pythagorean
# Hypotenuse calculation.
# Arguments
#   x1 y1	X and Y coordinates of a point
#   x2 y2	X and Y coordinates of a point
# 
# Results
#   No side effects.

proc distance {x1 y1 x2 y2} {
  set dx [expr {$x1 - $x2}]
  set dy [expr {$y1 - $y2}]
  return [expr {sqrt(($dx*$dx) + ($dy * $dy))}]
}

# Define the X and Y locations of the switches and servers.
# Could also be done as:
# set switch(switch1) {100 100}
# with different code in the loops.
# This organization (separate indices for .x and .y) allows for potential
#  expansion of the array (perhaps info about capacity, age, etc.)

array set switch {
  switch1.x 100
  switch1.y 100
  switch2.x 300
  switch2.y 300
}

array set server {
  server1.x 50
  server1.y 50
  server2.x 250
  server2.y 300
  server3.x 150
  server3.y 100
  server4.x 50
  server4.y 200
}


foreach nmsvr [lsort [array names server *.x]] {
  lassign [split $nmsvr .] serverName x
  set serverX $server($serverName.x)
  set serverY $server($serverName.y)

  set id [lindex [array names switch *.x] 0]
  lassign [split $id .] switchName x
  set switchX $switch($switchName.x)
  set switchY $switch($switchName.y)
  set min [distance $serverX $serverY $switchX $switchY]
  set switchToUse $switchName

  foreach nmswtch [array names switch *.x] {
    lassign [split $nmswtch .] switchName x
    set switchX $switch($switchName.x)
    set switchY $switch($switchName.y)
    set dist [distance $serverX $serverY $switchX $switchY]
    if {$dist < $min} {
      set min $dist
      set switchToUse $switchName
    }
  }
  # To print out report sorted by server name
#  puts "Connect $serverName ($server($serverName.x),$server($serverName.y)) \
#to $switchToUse ($switch($switchToUse.x), $switch($switchToUse.y)) \
#with $min feet of wire"
  # To collect data and then print out sorted by wire length.
  set results($serverName) [list $switchToUse $min]
}

################################################################
# proc compare {arrayName index1 index2}--
#    Compares the second element of the list referenced by 
#    two indices into an array.
#   Array contents are expected to be: 
#     name - unused for sorting
#     number - A numeric value used for the sort
#  Used for special purpose lsort.
# Arguments
#   arrayName	The array that has index1 and index2
#   index1	An index into the array
#   index2	An index into the array
# 
# Results
#   No side effects.
# 
proc compare {arrayName index1 index2} {
  upvar $arrayName arr
  lassign $arr($index1) name length1
  lassign $arr($index2) name length2
  return [expr {$length1 < $length2}]
}

set orderedNames [lsort -command "compare results" [array names results]]

foreach nm $orderedNames {
  lassign $results($nm) name length
  puts "Connect $nm to $name with $length feet of wire"
}
