# choose-game.tcl --
#
#

namespace eval NSChooseGame {

variable Priv

# NSChooseGame::InitModule --
#
#	One-time-only-ever initialization.
#
# Arguments:
#	arg1					about arg1
#
# Results:
#	What happened.

proc InitModule {} {

	variable Priv

	set Priv(recent,text) [list "MRU: \"xxx\""]
	set Priv(recent,path) ""

	ReadRecentFile
	NSObject::New NSChooseGame
}

# NSChooseGame::NSChooseGame --
#
#	Object constructor called by NSObject::New().
#
# Arguments:
#	arg1					about arg1
#
# Results:
#	What happened.

proc NSChooseGame oop {
	
	InitWindow $oop

	# Create a progress window
	set progId [NSObject::New NSProgressWindow]
	Info $oop progId $progId

	# Configure with the progress window
	set win [NSProgressWindow::Info $progId win]
	wm title $win "Scanning Saved Games..."
	wm transient $win .

	# Position and display the progress window
	WindowPosition $win 2 3
	focus [NSProgressWindow::Info $progId win]
	update

	# Let the user choose a saved game
	ModalLoop $oop
}

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

proc Info {oop info args} {

	global NSChooseGame

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

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

# NSChooseGame::InitWindow --
#
#	Description.
#
# Arguments:
#	arg1					about arg1
#
# Results:
#	What happened.

proc InitWindow oop {

	set win .choosegame$oop
	toplevel $win
	wm title $win "Choose Game"
	
	# Do stuff when window closes
	wm protocol $win WM_DELETE_WINDOW "bell"

	wm transient $win .
	wm resizable $win no no

	wm withdraw $win

	Info $oop win $win

	set frame $win.frameList
	frame $frame \
		-borderwidth 1 -relief sunken
	set canvistId [NSObject::New NSCanvist $frame 20 400 [expr 20 * 8] \
		"NSChooseGame::NewItemCmd $oop" "NSChooseGame::HighlightItemCmd $oop"]
	set canvas [NSCanvist::Info $canvistId canvas]
	$canvas configure -yscrollcommand "$frame.yscroll set"
	scrollbar $frame.yscroll \
		-command "$canvas yview"

	NSCanvist::Info $canvistId selectionCmd \
		"NSChooseGame::SelectionChanged $oop"

	bind $canvas <Double-ButtonPress-1> \
		"tkButtonInvoke $win.frameButton.open"

	Info $oop canvistId $canvistId

	pack $win.frameList \
		-side top -padx 10 -pady 10
	pack $canvas \
		-side left -fill both
	pack $win.frameList.yscroll \
		-side right -fill y

	set frame $win.frameButton
	frame $frame \
		-borderwidth 0
	button $frame.open \
		-text Open -command "NSChooseGame::Info $oop result open" -width 9 \
		-default active -underline 0
	button $frame.browse \
		-text Browse... -command "NSChooseGame::Browse $oop" -width 9 \
		-underline 0
	button $frame.cancel \
		-text Cancel -command "NSChooseGame::Info $oop result cancel" -width 9
	pack $frame.open \
		-side left -padx 5
	pack $frame.browse \
		-side left -padx 5
	pack $frame.cancel \
		-side left -padx 5

	label $win.fileName \
		-anchor w -justify left

	grid rowconfigure $win 0 -weight 1
	grid rowconfigure $win 1 -weight 0
	grid columnconfigure $win 0 -weight 1
	grid columnconfigure $win 0 -weight 1

	grid $win.frameList \
		-row 0 -column 0 -rowspan 1 -columnspan 2 -padx 10 -pady 5 -sticky news
	grid $win.fileName \
		-row 1 -column 0 -rowspan 1 -columnspan 1 -padx 20 -sticky ew
	grid $win.frameButton \
		-row 1 -column 1 -rowspan 1 -columnspan 1 -padx 10 -pady 5

	bind $win <KeyPress-o> \
		"tkButtonInvoke $win.frameButton.open"
	bind $win <KeyPress-b> \
		"tkButtonInvoke $win.frameButton.browse"
	bind $win <KeyPress-Return> \
		"tkButtonInvoke $win.frameButton.open"
	bind $win <KeyPress-Escape> \
		"tkButtonInvoke $win.frameButton.cancel"
}

# NSChooseGame::Close --
#
#	Do something when closing the window.
#
# Arguments:
#	arg1					about arg1
#
# Results:
#	What happened.

proc Close oop {

	destroy [Info $oop win]
	NSObject::Delete NSChooseGame $oop

	namespace delete ::NSChooseGame
}

# NSAlternate::SelectionChanged --
#
#	Description.
#
# Arguments:
#	arg1					about arg1
#
# Results:
#	What happened.

proc SelectionChanged {oop canvistId select deselect} {

	set win [Info $oop win]

	if {![llength $select]} {
		$win.fileName configure -text ""
		$win.frameButton.open configure -state disabled
		Info $oop current -1
		return
	}

	set row [lindex $select 0]
	set path [lindex [Info $oop pathList] $row]
	$win.fileName configure -text "Selected file:\n    \"[file tail $path]\""

	Info $oop current $row
	$win.frameButton.open configure -state normal
}

# NSChooseGame::ModalLoop --
#
#	Present the dialog, interact, then withdraw.
#
# Arguments:
#	arg1					about arg1
#
# Results:
#	What happened.

proc ModalLoop oop {

	global Angband
	global NSChooseGame
	variable Priv

	set win [Info $oop win]
	set canvistId [Info $oop canvistId]
	set canvas [NSCanvist::Info $canvistId canvas]
	set progId [Info $oop progId]

	set elemList {}

	set wd [pwd]
	cd [file join $Angband(dir) lib save]
	set fileList [glob -nocomplain *]
	set count [llength $fileList]
	set i 0
	foreach file $fileList {
		if {[file extension $file] == ""} {
			set path [file join $Angband(dir) lib save $file]
			catch {
				set attrib(name) ""
				angband game savefile_info $path attrib
				if {![string length $attrib(name)]} {
					lappend elemList [list $file $path $attrib(version) "" 0]
				} else {
					lappend elemList [list $attrib(name) $path $attrib(version) \
						"Level $attrib(lev) $attrib(race) $attrib(class),\
						Depth $attrib(depth)/$attrib(max_depth)" $attrib(is_dead)]
				}
			}
		}
		incr i
		NSProgressWindow::Info $progId prompt "Scanning \"$file\"..."
		NSProgressWindow::Info $progId ratio [expr $i / $count.0]
		update idletasks
	}
	cd $wd

	NSProgressWindow::Info $progId prompt "Displaying..."
	update idletasks

	# Assume the list will be empty
	$win.frameButton.open configure -state disabled

	# Are there any files?
	if {[llength $elemList]} {

		# Hack -- Caculate maximum needed display size
		set Priv(width,name) 0
		set Priv(width,version) 0
		set Priv(width,other) 0
		set font "{MS Sans Serif} 8"
		foreach elem $elemList {
			set name [lindex $elem 0]
			set version [lindex $elem 2]
			set other [lindex $elem 3]
			set width [font measure "$font bold" $name]
			if {$width > $Priv(width,name)} {set Priv(width,name) $width}
		
			set width [font measure $font $version]
			if {$width > $Priv(width,version)} {set Priv(width,version) $width}
		
			set width [font measure $font $other]
			if {$width > $Priv(width,other)} {set Priv(width,other) $width}
		}
	
		# Resize the canvas, if necessary
		set width [expr $Priv(width,name) + 32 + $Priv(width,version) + 16 + \
			$Priv(width,other) + 8]
		if {$width > [winfo reqwidth $canvas]} {
			$canvas configure -width $width
		}
	
		set recent -1
		set row 0
		set pathList {}
		set elemList [lsort -dictionary -index 0 $elemList]
		foreach elem $elemList {
			set name [lindex $elem 0]
			if {[catch {
				set path [cxrl_getLongPathName [lindex $elem 1]]
			}]} {
				set path [lindex $elem 1]
			}
			lappend pathList $path
			set version [lindex $elem 2]
			set other [lindex $elem 3]
			if {[lindex $elem 4]} {
				set style normal
			} else {
				set style bold
			}
			NSCanvist::Insert $canvistId end $name $version $other $style
	
			if {![string compare $Priv(recent,path) $path]} {
				set recent $row
			}
			incr row
		}
	
		# Pass list to SelectionChanged()
		Info $oop pathList $pathList
	
		set bbox [$canvas bbox all]
		$canvas configure \
			-scrollregion [list 0 0 [lindex $bbox 2] [lindex $bbox 3]]

		# Select the initial file
		if {$recent != -1} {
			NSToplevel::NaturalSize $win ""
			NSCanvist::UpdateSelection $canvistId $recent {}
			NSCanvist::See $canvistId $recent
		}
	}

	NSProgressWindow::Close $progId

	# Position window
	WindowPosition $win 2 3

	# Weird. The yscrollcommand gets called 3 times,
	# but still the scrollbar stays at the top...
	update
	eval $win.frameList.yscroll set [$canvas yview]

	# Set up a grab and claim focus too
	NSUtils::GrabSave $win
	focus $canvas

	# Wait
	Info $oop result ""
	tkwait variable NSChooseGame($oop,result)

	# Release grab and reset focus
	NSUtils::GrabRelease $win

	# Hack -- Update the button
	update

	switch -- [Info $oop result] {
		open {
			set index [Info $oop current]
			set path [lindex $pathList $index]
			set Priv(recent,path) $path
			WriteRecentFile
			Close $oop
			uplevel #0 angband game open [list $path]
		}
		cancel {
			Close $oop
		}
	}
}

# NSChooseGame::OpenGame --
#
#	Choose a savefile and play a game.
#
# Arguments:
#	arg1					about arg1
#
# Results:
#	What happened.

proc Browse oop {

	global Angband
	variable Priv

	set win [Info $oop win]

	set types {
		{{Save Files} "" SAVE}
	}
	set fileName [tk_getOpenFile -filetypes $types -parent $win \
		-initialdir [file join $Angband(dir) lib save]]
	if {[string length $fileName]} {
		if {[catch {
			set path [cxrl_getLongPathName $fileName]
		}]} {
			set path $fileName
		}
		set Priv(recent,path) $path
		WriteRecentFile
		NSUtils::GrabRelease $win
		Close $oop
		uplevel #0 angband game open [list $path]
	}
}

# NSProjectList::NewItemCmd --
#
#	Called by NSCanvist::InsertItem() to create a list row.
#
# Arguments:
#	arg1					about arg1
#
# Results:
#	What happened.

proc NewItemCmd {oop canvistId y name version info style} {

	variable Priv

	set c [NSCanvist::Info $canvistId canvas]
	set lineHeight [NSCanvist::Info $canvistId rowHgt]

	set font "{MS Sans Serif} 8"

	set fw [font measure "$font bold" $name]
	set fh [font metrics $font -linespace]
	set diff [expr int([expr ($lineHeight - $fh) / 2])]

	# Background under name
	lappend itemIdList [$c create rectangle 0 [expr $y + 1] \
		[winfo reqwidth $c] [expr $y + $lineHeight - 1] -fill #dedede \
		-outline {} -tags sel]

	# Selection rectangle around text
#	lappend itemIdList [$c create rectangle 1 [expr $y + $diff] \
#		[expr [winfo reqwidth $c] - 2] [expr $y + $diff + $fh] -fill {} -outline {} \
#		-tags {enabled sel}]

	# Name
	lappend itemIdList [$c create text 2 [expr $y + $diff] \
		-text $name -anchor nw -font "$font $style" -tags {enabled text}]

	# Version
	set left [expr $Priv(width,name) + 32]
	lappend itemIdList [$c create text $left [expr $y + $diff] \
		-text $version -anchor nw -font $font -tags {enabled text}]

	# Other
	incr left [expr $Priv(width,version) + 16]
	lappend itemIdList [$c create text $left [expr $y + $diff] \
		-text $info -anchor nw -font $font -tags {enabled text}]

	return $itemIdList
}

# NSProjectList::HighlightItemCmd --
#
#	Called by NSCanvist::Select() to highlight a row.
#
# Arguments:
#	oop					OOP ID. See above.
#	canvistId					OOP ID of NSCanvist object.
#	state					1 or 0 highlight state.
#	args					List of canvas item ids
#
# Results:
#	What happened.

proc HighlightItemCmd {oop canvistId state args} {

	global NSCanvist

	set canvas [NSCanvist::Info $canvistId canvas]
	set itemIdList $args

	set idRect [FindItemByTag $canvas $itemIdList sel]
	set idText [FindItemByTag $canvas $itemIdList text]

	if $state {

		$canvas itemconfigure $idRect -fill SystemHighlight -outline SystemHighlight
		foreach id $idText {
			$canvas itemconfigure $id -fill SystemHighlightText
		}

	} else {

		$canvas itemconfigure $idRect -fill #dedede -outline #dedede
		foreach id $idText {
			$canvas itemconfigure $id -fill Black
		}
	}
}

# NSChooseGame::ReadRecentFile --
#
#	Reads the tk/recent file, which holds the most-recently opened file.
#
# Arguments:
#	arg1					about arg1
#
# Results:
#	What happened.

proc ReadRecentFile {} {

	global Angband
	variable Priv

	if {[catch {open [file join $Angband(dirTK) config recent]} fileId]} {

		# Ingore missing file
		return
	}

	set Priv(recent,text) ""

	while {![eof $fileId]} {

		# Read a line
		set count [gets $fileId list]
		if {$count == -1} break

		# Save the text, so it can be written out later
		lappend Priv(recent,text) $list

		if {$count == 0} continue

		switch -- [lindex $list 0] {
			MRU: {
				set path [lindex $list 1]
				if {[file exists $path]} {
					set Priv(recent,path) [cxrl_getLongPathName $path]
				}
			}
		}
	}

	close $fileId
}

# NSChooseGame::WriteRecentFile --
#
#	Writes the tk/recent file.
#
# Arguments:
#	arg1					about arg1
#
# Results:
#	What happened.

proc WriteRecentFile {} {

	global Angband
	variable Priv

	if {[catch {open [file join $Angband(dirTK) config recent] \
		[list CREAT WRONLY TRUNC]} fileId]} {
		set msg "The following error occurred while attempting to open "
		append msg "the \"recent\" file for writing:\n\n$fileId"
		tk_messageBox -title Oops -message $msg
		return
	}

	foreach line $Priv(recent,text) {
		regsub "^MRU: \"(.*)\"" $line "MRU: \"$Priv(recent,path)\"" line
		puts $fileId $line
	}

	close $fileId
}

# namespace eval NSChooseGame
}
