#
# Steps
# 
# 1. finish the reqwidth and reqheight algorithm handling
# 2. add tests
# 


set dir [file dirname [info script]]
load [file join $dir structure.so]

proc _grid.insert.widget {grid_var w c r} {
 upvar $grid_var grid

 if {[llength $grid] <= ($r + 1)} {
  #
  # The grid row doesn't exist, so insert it.
  #
  for {set i [expr {[llength $grid] - 1}]} {$i < $r} {incr i} {
   lappend grid [list]
  }
 } 

 set row [lindex $grid $r]
 
 if {[llength $row] <= ($c + 1)} {
  #
  # The grid column doesn't exist in the row, so insert it.
  #
  for {set i [expr {[llength $row] - 1}]} {$i < $c} {incr i} {
   lappend row {}
  }
 }
 
 lset row $c $w
 lset grid $r $row
}

proc _grid.dump grid {
 set i 0
 foreach row $grid {
  puts "$i -> $row"
  incr i
 }
}

proc _grid.dump.sizes grid {
 foreach row $grid {
  foreach w $row {
   if {"" eq $w} \
    continue

   puts -nonewline "$w is [$w width] x [$w height] \[[$w -slot]\]\t"
  }
  puts ""
 }
}

proc _grid.rm.col.list {list w} {
 set c [lindex [$w -slot] 0]

 for {set i 0} {$i < [$w -columnspan]} {incr i} {
  set e [lsearch -exact $list [expr {$c + $i}]]

  if {$e < 0} \
   continue
  set list [lreplace $list $e $e]
 }
 return $list
}

proc _grid.sticky? {w arg} {
 expr {[lsearch -exact [$w -sticky] $arg] >= 0}
}

proc _grid.layout {parent w} {
 set m [$parent _manager]

 set grid [$m grid]

 set pwidth [$parent width]
 set pheight [$parent height]

 set visiblecolumns [list]
 set visiblerows [list]

 #
 # Find the number of visible columns.
 #
 set r 0
 foreach row $grid {
  set c 0
  foreach w $row {
   if {"" eq $w} {
    incr c
    continue
   }

   for {set i 0} {$i < [$w -columnspan]} {incr i} {
    lappend visiblecolumns [expr {$c + $i}]
   }

   for {set i 0} {$i < [$w -rowspan]} {incr i} {
    lappend visiblerows [expr {$r + $i}]
   }

   incr c
  }
  incr r
 }

 set totalcolumns [llength $visiblecolumns]
 # the number of visible columns
 set numcolumns [llength [lsort -unique $visiblecolumns]]
 puts NUMCOL:$numcolumns

 # The remaining width and height:
 set remwidth $pwidth
 set remheight $pheight
 #
 # Set the initial sizes of the widgets based on the requests.
 #
 foreach row $grid {
  foreach w $row {
   if {"" eq $w} \
    continue

   if {![_grid.sticky? $w width]} {
    $w width [$w reqwidth]
    set remwidth [expr {$remwidth - [$w width]}]
    set visiblecolumns [_grid.rm.col.list $visiblecolumns $w]
   }

   if {![_grid.sticky? $w height]} {
    $w height [$w reqheight]
    set remheight [expr {$remheight - [$w height]}]
   }
  }
 }

 set numcolumns [llength [lsort -unique $visiblecolumns]]
 
 #
 # Set the sizes of the remaining sticky widgets, if there are any.
 #
 foreach row $grid {
  foreach w $row {
   if {"" eq $w} \
    continue

   if {[_grid.sticky? $w width]} {
    $w width [expr {$remwidth * [$w -columnspan] / $numcolumns}]
    #set remwidth [expr {$remwidth - [$w width]}]    
    #set numcolumns [expr {$numcolumns - [$w -columnspan]}]
   }
  }
 }
}

proc grid {w args} {

 unlock.structure.creation $w
 $w \
   -sticky [list width height] \
   -columnspan 1 \
   -rowspan 1 \
   -slot [list 0 0]


 lock.structure.creation $w

 #XXX we should relayout even if the {expand} and eval fail.
 $w {expand}$args

 # 
 # Get the grid prior to insertion.
 #
 set grid [[[$w _parent] _manager] grid]

 lassign [$w -slot] c r

 _grid.insert.widget grid $w $c $r

 #
 # Set the new grid list.
 #
 [[$w _parent] _manager] grid $grid

 _grid.layout [$w _parent] $w

 # _grid.dump $grid
 _grid.dump.sizes $grid
}

proc window w {
 structure $w

 $w _parent . ;#XXX hardcoded
 $w _manager "" width 0 height 0

 lock.structure.creation $w

 return $w
}

proc main {} {
 window .
 . _parent ""
 set m [structure]
 $m grid [list] 
 . _manager $m width 340 height 60


 foreach w [list .w1 .w2 .w3 .w4 .w5] {
  window $w
 }

 grid .w1 -slot [list 0 0]
 grid .w2 -slot [list 0 1] -columnspan 3
 grid .w3 -slot [list 3 0] -rowspan 2
 grid .w4 -slot [list 5 1] -columnspan 2
 puts -----
 grid .w5 -slot [list 3 3] 
}
main
