
proc scrib_server_port_default {} { return "6791" }

## Create a socket to a port on the server in the given range. Returns the port
## actually acquired.

proc scrib_server_open_port {server_port_start {server_port_end 49151}} {
    global scrib_server_info
    
    if {("" != [scrib_server_get_datum PORT]) && \
	    ("" != [scrib_server_get_datum SOCKET])} {
	return [scrib_server_get_datum PORT]
    }
    
    if {"" == $server_port_start} {
	set server_port_start [scrib_server_port_default]
    }
    
    for {set port $server_port_start} {$port <= $server_port_end} {incr port} {
	
	if ![catch {socket -server scrib_server_accept_socket $port} sock] {
	    
	    scrib_server_set_datum PORT   $port
	    scrib_server_set_datum SOCKET $sock
	    scrib_server_print_data
	    
	    return $port
	}
    }
    
    puts "Error: could not open server socket between $server_port_start and $server_port_end"
    scrib_server_unset_data
    return ""
}

## 

proc scrib_server_accept_socket {sock addr port} {    
    global scrib_server_info
    
    puts "scrib_server: accepting $sock from $addr port $port"
    set scrib_server_info(socket,$sock) [list $addr $port]    
    fconfigure $sock -buffering line
    fileevent $sock readable [list scrib_server_accept_input $sock]
}

## This proc accepts any of these commands from a client:
##    [FIXME]
## Oherwise an EOF marker will indicate that the socket is being closed from
## the client side and so should be closed by the server.

proc scrib_server_accept_input {sock} {    
    global scrib_server_info
    
    if {[eof $sock] || [catch {gets $sock line}]} {
	#
	# end of file or abnormal connection drop
	#
	close $sock
	puts "scrib_server: closing $sock $scrib_server_info(socket,$sock)"
	unset scrib_server_info(socket,$sock)
	
    } else {
	if {[string compare $line "quit"] == 0} {
	    #
	    # Prevent new connections.
	    # Existing connections stay open.
	    #
	    close $echo(main)
	}
	
	scrib_server_print_data
	
	set command [lindex $line 0]
	set args    [lrange $line 1 end]
	#
	# --> This limits the number of commands we can execute, amounting in
	#     something like a safe-interp
	#
	puts "scrib_server: executing command \"$command\" from peer: [fconfigure $sock -peername]"
	#
	switch -- $command {
	    echo {
		puts $sock "$line"
	    }
	    "which" - default {
		puts $sock [eval exec $command $args]
	    }
	    flush $sock
	}
    }
}

## 

proc scrib_server_get_datum {what} {
    global scrib_server_info
    if [info exists scrib_server_info($what)] {
	return $scrib_server_info($what)
    }
    return ""
}

## 

proc scrib_server_set_datum {what val} {
    global scrib_server_info
    set scrib_server_info($what) $val
}

## 

proc scrib_server_unset_data {} {
    global scrib_server_info
    
    unset scrib_server_info(SOCKET)
    unset scrib_server_info(PORT)
}

## 

proc scrib_server_print_data {} {
    set port [scrib_server_get_datum PORT]
    set sock [scrib_server_get_datum SOCKET]
    if {("" == $port) && ("" == $sock)} {
	puts "scrib_server: no ports are open"
    } else {
	#puts "\nOn server, sock: [fconfigure $sock -sockname]"
	puts "scrib_server: server set up on port \"$port\" with socket \"$sock\""
    }
}

## 

proc scrib_server_close_cleanly {} {
    set port [scrib_server_get_datum PORT]
    set sock [scrib_server_get_datum SOCKET]
    if {"" != $sock} {
	close $sock
	scrib_server_unset_data
	puts "scrib_server: closing port \"$port\" at socket \"$sock\""
    }
}

##

proc help {} {    
    puts "\nScribServer commands:"
    puts "\t[info commands scrib_server_*]"
}

##

proc quit {} {
    puts "scrib_server: cleaning up for exit..."
    # fixme--cleanup--FIXME
    scrib_server_close_cleanly
    puts "scrib_server: ...cleanup finished.\n"
    exit
}
