#
# config.tcl --
#

namespace eval NSConfig {

variable Priv

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

proc InitModule {} {

	# Read tk/config, which contains a list of icon configurations
	# and the current icon configuration.
	NSConfig::ReadConfigFile

	# Set the default set of files to pass to SourceOne. These
	# can be overridden by scripts to use common configuration
	# files. See ShareConfigFile() below.
	set prefix [Global config,prefix]
	Global config,alternate $prefix-alternate
	Global config,sprite $prefix-sprite
	Global config,assign $prefix-assign
	Global config,town $prefix-town
}

# NSConfig::ReadConfigFile --
#
#	Reads the tk/config file, which holds a list of configuration
#	prefixes, along with descriptive text for each prefix. Each
#	prefix can be used to read and write certain icon configuration
#	files.
#
# Arguments:
#	arg1					about arg1
#
# Results:
#	What happened.

proc ReadConfigFile {} {

	global Angband
	variable Priv

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

	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(text) $list

		if {$count == 0} continue

		switch -- [lindex $list 0] {
			Config: {
				lappend Priv(config) [lindex $list 1] [lindex $list 2]
			}
			Current: {
				Global config,prefix [lindex $list 1]
			}
		}
	}

	close $fileId

dbwin "ReadConfigFile: config='$Priv(config)' config='[Global config,prefix]'\n"
}

# NSConfig::WriteConfigFile --
#
#	Writes the tk/config file. This is done when the user chooses
#	a different configuration prefix via ChooseConfig().
#
# Arguments:
#	arg1					about arg1
#
# Results:
#	What happened.

proc WriteConfigFile {} {

	global Angband
	variable Priv

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

	foreach line $Priv(text) {
		if {[string length $line]} {
			switch -- [lindex $line 0] {
				Current: {
					set line "Current: [Global config,prefix]"
				}
			}
		}
		puts $fileId $line
	}

	close $fileId
}

# NSConfig::ChooseConfig --
#
#	Puts up a list of defined configuration settings, and allows
#	the user to choose one.
#
# Arguments:
#	arg1					about arg1
#
# Results:
#	What happened.

proc ChooseConfig {} {

	variable Priv

	set win .chooseconfig
	toplevel $win
	wm title $win "Icon Set"
	wm transient $win .

	set frame $win.frameList
	frame $frame \
		-borderwidth 1 -relief sunken
	listbox $frame.list \
		-height 5 -width 35 -background White -borderwidth 0 \
		-yscrollcommand "$frame.yscroll set" -highlightthickness 0
	scrollbar $frame.yscroll \
		-command "$frame.list yview"

	# Double-click selects an item
	bind $win.frameList.list <Double-ButtonPress-1> {
		set NSUtils::UtilsPriv(result) 1
	}

	set frame $win.buttons
	frame $frame \
		-borderwidth 0
	button $frame.buttonOK \
		-text OK -width 9 -command "set NSUtils::UtilsPriv(result) 1" \
		-default active
	button $frame.buttonCancel \
		-text Cancel -width 9 -command "set NSUtils::UtilsPriv(result) 2"

	# Return selects item
	bind $win <KeyPress-Return> "
		tkButtonInvoke $win.buttons.buttonOK
		set NSUtils::UtilsPriv(result) 1
	"

	# Escape cancels
	bind $win <KeyPress-Escape> "
		tkButtonInvoke $win.buttons.buttonCancel
		set NSUtils::UtilsPriv(result) 2
	"

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

	pack $win.buttons \
		-side top -padx 5 -pady 0 -anchor e
	pack $win.buttons.buttonCancel \
		-side right -padx 5 -pady 0
	pack $win.buttons.buttonOK \
		-side right -padx 5 -pady 0

	pack [frame $win.framePad1 -borderwidth 0 -height 10] \
		-side top

	foreach {prefix desc} $Priv(config) {
		$win.frameList.list insert end $desc
		lappend config $prefix
	}

	# <Destroy> handler sets UtilsPriv(result)
	bind $win <Destroy> "set NSUtils::UtilsPriv(result) 2"

	# Position window
	WindowPosition $win 2 3

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

	# Select the current settings
	set row [lsearch -exact $config [Global config,prefix]]
	$win.frameList.list selection set $row
	$win.frameList.list see $row

	# Wait for a button press
	set NSUtils::UtilsPriv(result) ""
	tkwait variable NSUtils::UtilsPriv(result)

	# Release grab and reset focus
	NSUtils::GrabRelease $win
	
	if {[winfo exists $win]} {
		switch $NSUtils::UtilsPriv(result) {
			1 {
				set selection [$win.frameList.list curselection]
				Global config,prefix [lindex $config $selection]
				WriteConfigFile

				# Set the default set of files to pass to SourceOne. These
				# can be overridden by scripts to use common configuration
				# files. See ShareConfigFile() below.
				set prefix [Global config,prefix]
				Global config,alternate $prefix-alternate
				Global config,sprite $prefix-sprite
				Global config,assign $prefix-assign
				Global config,town $prefix-town
			}
			2 {
			}
		}
	}

	# Maybe the window is already destroyed
	catch {
		bind $win <Destroy> {}
		destroy $win
	}
}

# NSConfig::Load --
#
#	Processes the set of files for the "current" configuration set.
#
# Arguments:
#	arg1					about arg1
#
# Results:
#	What happened.

proc Load {} {

	# Get the current configuration prefix
	set prefix [Global config,prefix]

	# Try "prefix.cfg"
	SourceOne $prefix.cfg

	# These next files are automatically generated at shutdown
	SourceOne [Global config,alternate]
	SourceOne [Global config,sprite]
	SourceOne [Global config,assign]

	# Try "prefix-town", custom town layout and appearance
	ReadTownFile [Global config,town]
}

# NSConfig::ShareConfigFile --
#
#	.
#
# Arguments:
#	arg1					about arg1
#
# Results:
#	What happened.

proc ShareConfigFile {which file} {

	switch -- $which {
		alternate -
		sprite -
		assign -
		town {
			Global config,$which $file
		}

		default {
			error "unknown config file \"$which\""
		}
	}
}

# NSConfig::SourceOne --
#
#	Looks for the given file in the tk/config directory. If it
#	exists, it is sourced at the global level. This command is
#	usually called from a icon configuration file, type ".cfg".
#
# Arguments:
#	arg1					about arg1
#
# Results:
#	What happened.

proc SourceOne fileName {

	global Angband

	set fileName [file tail $fileName]
	set fileName [file join $Angband(dirTK) config $fileName]
	if {[file exists $fileName]} {
dbwin "NSConfig::SourceOne $fileName\n"
		uplevel #0 source $fileName
	}
}

# NSConfig::FileLibData --
#
#	Takes the "tail" of the given file name, and appends it to the
#	complete pathname of the lib/data directory.
#
# Arguments:
#	arg1					about arg1
#
# Results:
#	What happened.

proc FileLibData file {

	global Angband

	set file [file tail $file]
	return [file join $Angband(dir) lib data $file]
}

# NSConfig::CheckIconData --
#
#	Creates an icon data file in the lib/data directory if it does
#	not already exist. If it exists but is older than the given
#	image file, it is overwritten.
#
# Arguments:
#	arg1					about arg1
#
# Results:
#	What happened.

proc CheckIconData {imageFile iconFile} {

	global Angband

dbwin "check_icon_data $imageFile $iconFile\n"

	# The image file is required
	set imageFile [file join $Angband(dirTK) image $imageFile]
	if {![file exists $imageFile]} {
		error "icon image file \"$imageFile\" was not found"
	}

	# The icon file may or may not exist
	set iconFile [FileLibData $iconFile]
	if {[file exists $iconFile]} {

		set mtime [file mtime $imageFile]
		set mtime2 [file mtime $iconFile]
		if {$mtime < $mtime2} return
	}

dbwin "makeicon \"$imageFile\" \"$iconFile\"\n"

	angband_load prompt "Writing icon file \"[file tail $iconFile]...\""

	# People using Windows NT sometimes get the Tcl error
	#     "couldn't duplicate input handle: bad file number"
	# The fix seems to be renaming "AngbandTk-283r1" to "AngbandTk",
	# so perhaps the "-" is the culprit?
	
	if {$::tcl_platform(os) == "Windows NT"} {
		set wd [pwd]
		cd [file join $Angband(dirTK) bin]
		if {[catch {
			exec makeicon.exe [icon size] $imageFile $iconFile
			cd $wd
		} result]} {
			cd $wd
			error $result
		}
	} else {
		set makeicon [file join $Angband(dirTK) bin makeicon.exe]
		exec $makeicon [icon size] $imageFile $iconFile
	}
}

# NSConfig::CreateIconType --
#
#	Creates a new kind of icon from the given icon-image file
#	and optional mask-image file.
#
# Arguments:
#	arg1					about arg1
#
# Results:
#	What happened.

proc CreateIconType {iconType iconFile maskFile} {

	global Angband

	# dragon.gif --> dragon.icd
	set iconFile [file tail $iconFile]
	set iconData [file rootname $iconFile].icd
	CheckIconData $iconFile $iconData
	set iconData [FileLibData $iconData]
	
	# Masked
	if {[string length $maskFile]} {

		# dragon_mask.gif --> dragon.msk
		set maskData [file rootname $iconFile].msk
		CheckIconData $maskFile $maskData
		set maskData [FileLibData $maskData]

		# Now create the icon type
		icon createtype $iconType -file $iconData -maskfile $maskData

	# Unmasked
	} else {

		# Now create the icon type
		icon createtype $iconType -file $iconData
	}
}

# NSConfig::ReadTownFile --
#
#	Looks for the given file in the tk/config directory. If it
#	exists, it is parsed line by line.
#
# Arguments:
#	arg1					about arg1
#
# Results:
#	What happened.

proc ReadTownFile fileName {

	global Angband

	set fileName [file tail $fileName]
	set fileName [file join $Angband(dirTK) config $fileName]

	# No problem if the file doesn't exist
	if {![file exists $fileName]} return

	# Hack -- Startup progress
	angband_load prompt "Reading town file..."

	if {[catch {open $fileName} fileId]} {
		set msg "The following error occurred while attempting to open "
		append msg "the \"town\" file for reading:\n\n$fileId"
		tk_messageBox -title Oops -message $msg
		return
	}

	set hasTown 0
	set symbol ""
	while {![eof $fileId]} {
		set count [gets $fileId lineBuf]
		if {$count == -1} break

		if !$hasTown {
			if !$count {
				set hasTown 1
				continue
			}
			lappend town $lineBuf
			continue
		}

		if {![string compare $symbol ""]} {
			set symbol [lindex $lineBuf 1]
			set feature ""
			set curBlock ""
			set blockFeature ""
			continue
		}
		if {![string compare $feature ""]} {
			set feature [lindex $lineBuf 1]
			continue
		}
		if !$count {
			set block(icon,$symbol) $curBlock
			set block(feature,$symbol) $blockFeature
			set symbol ""
			continue
		}
		set rowIcon ""
		set rowFeature ""
		foreach index [split $lineBuf] {
			if {[string index $index 0] == "0"} {
				set index [string index $index 1]
			}
			if {$index != -1} {
				lappend rowIcon [list town $index]
				lappend rowFeature $feature
			} else {
				lappend rowIcon [list town 81]
				lappend rowFeature 0x01
			}
		}
		lappend curBlock $rowIcon
		lappend blockFeature $rowFeature
	}

	close $fileId

	# Get the height and width
	set height [llength $town]
	set width [string length [lindex $town 0]]

	# Create a vault to hold the town
	set vaultId [vault create $height $width]

	# Scan each grid in the town
	set icon [set feature ""]
	for {set y 0} {$y < $height} {incr y} {
		set rowIcon ""
		set rowFeature ""
		for {set x 0} {$x < $width} {incr x} {
			lappend rowIcon [list town 81]
			lappend rowFeature 0x01
		}
		lappend icon $rowIcon
		lappend feature $rowFeature
	}

	# Fill town with type dirt icon and floor feature
	vault put $vaultId icon 0 0 $icon
	vault put $vaultId feature 0 0 $feature

	set y 0
	foreach row $town {
		for {set x 0} {$x < $width} {incr x} {
			set char [string index $row $x]
			if {[info exists block(icon,$char)]} {
				vault put $vaultId icon $y $x $block(icon,$char)
				vault put $vaultId feature $y $x $block(feature,$char)
				continue
			}

			# Store doors
			set index [string first $char "123456789"]
			if {$index != -1} {
				vault put $vaultId feature $y $x [list [expr $index + 0x4A]]
				vault put $vaultId icon $y $x [list [list [list none 0]]]
			}
		}
		incr y
	}
}

# namespace eval NSConfig
}
