# map.tcl --
#
#	A NSMap object has a Widget plus two scrollbars.
#

namespace eval NSMap {

# NSMap::InitModule --
#
#	One-time-only-ever initialization.
#
# Arguments:
#	oop					OOP ID. See above.
#
# Results:
#	.

proc InitModule {} {

	lappend symbols MIDDLE UNKNOWN CHARACTER
	lappend symbols UPSTAIR DOWNSTAIR DOOR
	lappend symbols FLOOR BRIGHT_FLOOR YELLOW_FLOOR
	lappend symbols WALL BRIGHT_WALL YELLOW_WALL
	lappend symbols MONSTER OBJECT

	foreach symbol $symbols {
		angband mapcolor $symbol [Value map$symbol]
		NSValueManager::AddClient map$symbol "
			angband mapcolor $symbol \[Value map$symbol]
		"
	}
}

# NSMap::NSMap --
#
#	Object constructor called by NSObject::New().
#
# Arguments:
#	oop					OOP ID. See above.
#
# Results:
#	.

proc NSMap {oop parent width height gwidth gheight} {

	global NSMap
	variable MapPriv

	set frame $parent.map$oop

	# Frame + widget + scrollbars
	frame $frame \
		-borderwidth 0

	# I create a frame of the given dimensions, then place the
	# widget inside it, centered, so it will stay centered when
	# changing scale, and without affecting the size of the
	# parent.
	frame $frame.frameWidget \
		-borderwidth 0 -background Black
#		-borderwidth 0 -background Black -width $width -height $height

	# Resize the widget when the parent changes size
	bind $frame.frameWidget <Configure> \
		"NSMap::Configure $oop %w %h"

	scrollbar $frame.xscroll \
		-orient horizontal -command "NSMap::xview $oop"  \
		-highlightthickness 0

	scrollbar $frame.yscroll \
		-orient vertical -command "NSMap::yview $oop" \
		-highlightthickness 0

	set columns [expr $width / $gwidth]
	set rows [expr $height / $gheight]

	set widgetId [NSObject::New NSWidget $frame.frameWidget $columns $rows \
		$gwidth $gheight]
	set widget [NSWidget::Info $widgetId widget]

	NSWidget::Info $widgetId scaleCmd "NSMap::ScaleCmd $oop"

	grid rowconfig $frame 0 -weight 1 -minsize 0
	grid rowconfig $frame 1 -weight 0 -minsize 0
	grid columnconfig $frame 0 -weight 1 -minsize 0
	grid columnconfig $frame 1 -weight 0 -minsize 0

	grid $frame.frameWidget \
		-row 0 -column 0 -rowspan 1 -columnspan 1 -sticky news
	grid $frame.xscroll \
		-row 1 -column 0 -rowspan 1 -columnspan 1 -sticky ew
	grid $frame.yscroll \
		-row 0 -column 1 -rowspan 1 -columnspan 1 -sticky ns

	place $widget -relx 0.5 -rely 0.5 -anchor center

	# Set instance variables
	Info $oop frame $frame
	Info $oop widgetId $widgetId
	Info $oop widget $widget
	Info $oop scaleCmd ""

	# KeyPress bindings
	bind $widget <KeyPress-Left> \
		"NSMap::xview $oop scroll -10 units"
	bind $widget <KeyPress-Right> \
		"NSMap::xview $oop scroll 10 units"
	bind $widget <KeyPress-Up> \
		"NSMap::yview $oop scroll -10 units"
	bind $widget <KeyPress-Down> \
		"NSMap::yview $oop scroll 10 units"
	bind $widget <Control-KeyPress-Left> \
		"NSMap::xview $oop moveto 0"
	bind $widget <Control-KeyPress-Right> \
		"NSMap::xview $oop moveto 1"
	bind $widget <Control-KeyPress-Up> \
		"NSMap::yview $oop moveto 0"
	bind $widget <Control-KeyPress-Down> \
		"NSMap::yview $oop moveto 1"
	
	#
	# Synch the scrollbars when window is shown.
	#

	bind $frame <Map> "NSMap::synch $oop"
}

# NSMap::Configure --
#
#	Called when the frameWidget changes size.
#
# Arguments:
#	oop					OOP ID of NSMainWindow object.
#
# Results:
#	What happened.

proc Configure {oop width height} {

	set widgetId [Info $oop widgetId]
	set widget [Info $oop widget]
	set cols [expr $width / [$widget cget -gwidth]]
	set rows [expr $height / [$widget cget -gheight]]
	set cols [expr int($cols)]
	set rows [expr int($rows)]
	if {$cols < 8} {set cols 8}
	if {$rows < 8} {set rows 8}
	if {[NSWidget::Resize $widgetId $cols $rows]} {
	}
}

# NSMap::Info --
#
#	Query and modify info.
#
# Arguments:
#	arg1					about arg1
#
# Results:
#	What happened.

proc Info {oop info args} {

	global NSMap

	# Set info
	if {[llength $args]} {
		switch -- $info {
			default {
				set NSMap($oop,$info) [lindex $args 0]
			}
		}

	# Get info
	} else {
		switch -- $info {
			default {
				return $NSMap($oop,$info)
			}
		}
	}
}

# NSMap::ScaleCmd --
#
#	Called as the scaleCmd of our NSWidget. 
#
# Arguments:
#	oop					OOP ID. See above.
#
# Results:
#	.

proc ScaleCmd oop {

	set widget [Info $oop widget]
	eval SetView $oop [$widget center]

	set command [Info $oop scaleCmd]
	if {[string length $command]} {
		uplevel #0 eval $command
	}
}

# NSMap::SetView --
#
#	Center the view on the character's position. If this means the map
#	is scrolled "too far", then adjust accordingly. 
#
# Arguments:
#	oop					OOP ID. See above.
#
# Results:
#	.

proc SetView {oop y x} {

	set widget [Info $oop widget]
	
	set ny [ConstrainCenter $y [angband cave height] [$widget cget -height]]
	set nx [ConstrainCenter $x [angband cave width] [$widget cget -width]]

	#
	# Set center
	#

	$widget center $ny $nx

	#
	# Synch scrollbars
	#

	synch $oop
}

proc yview {oop cmd args} {

	set widget [Info $oop widget]
	scan [$widget center] "%d %d" oy ox
	set height [$widget cget -height]
	set dunHgt [expr [angband cave height] + 2]

	switch $cmd {

		moveto {

			set fraction [lindex $args 0]
			set top [expr int($fraction * $dunHgt.0)]
			if {$top < 0} {set top 0}
			# Fiddle
			incr top -1
			set ny [expr $top + $height / 2]
		}

		scroll {

			set number [lindex $args 0]
			set what [lindex $args 1]

			switch $what {

				units {
					set ny [expr $oy + $number]
				}

				pages {
					set pageSize [expr $height - 10]
					set ny [expr $oy + $number * $pageSize]
				}
			}
		}
	}

	set ny [ConstrainCenter $ny [angband cave height] [$widget cget -height]]

	$widget center $ny $ox

	synch $oop
}

proc xview {oop cmd args} {

	set widget [Info $oop widget]
	scan [$widget center] "%d %d" oy ox
	set width [$widget cget -width]
	set dunWid [expr [angband cave width] + 2]

	switch $cmd {

		moveto {

			set fraction [lindex $args 0]
			set left [expr int($fraction * $dunWid.0)]
			if {$left < 0} {set left 0}
			# Fiddle
			incr left -1
			set nx [expr $left + $width / 2]
		}

		scroll {

			set number [lindex $args 0]
			set what [lindex $args 1]

			switch $what {

				units {
					set nx [expr $ox + $number]
				}

				pages {
					set pageSize [expr $width - 10]
					set nx [expr $ox + $number * $pageSize]
				}
			}
		}
	}
	
	set nx [ConstrainCenter $nx [angband cave width] [$widget cget -width]]

	$widget center $oy $nx

	synch $oop
}

proc synch oop {

	set frame [Info $oop frame]
	set widget [Info $oop widget]

	scan [$widget center] "%d %d" py px

	set dunHgt [angband cave height]
	set height [$widget cget -height]
	
	if {$dunHgt != $height} {
		incr dunHgt 2
	}
	
	# Fiddle
	incr py 1
	set top [expr $py - $height / 2]
	if {$top < 0} {set top 0}
	set bottom [expr $top + $height]
	if {$bottom > $dunHgt} {set bottom $dunHgt}
	$frame.yscroll set [expr $top / $dunHgt.0] [expr $bottom / $dunHgt.0]

	set dunWid [angband cave width]
	set width [$widget cget -width]

	if {$dunWid != $width} {
		incr dunWid 2
	}

	# Fiddle
	incr px 1
	set left [expr $px - $width / 2]
	if {$left < 0} {set left 0}
	set right [expr $left + $width]
	if {$right > $dunWid} {set right $dunWid}
	$frame.xscroll set [expr $left / $dunWid.0] [expr $right / $dunWid.0]
}

# namespace eval NSMap
}
