#============================================================
#
#            Connections Namespace
#
#============================================================
#
namespace eval Connections {

    variable Conn
    variable Msg

    set Conn(last_id) 0

}; # end Connections namepace eval

#------------------------------------------------------------
# ::Connections::getIds --
#
#    Retrieves the known connection ids
#
# Arguments:
#    none
#
# Results
#    list of the attributes requested
#------------------------------------------------------------
#
proc ::Connections::getIds {{host_ *} {db_ *}} {

    variable Conn

    if {[string match "sockets" $host_]} {set host_ ""}

    set res [list]
    foreach {k v} [array get Conn dbname,*] {
	foreach {t i} [split $k ,] {break}

        if {[string match "$host_" $Conn(host,$i)] && [string match "$db_" $Conn(dbname,$i)]} {
            lappend res $i
	}
    }

    if {[llength $res] != 1} {
        return $res
    } else {
        return [lindex $res 0]
    }

}; # end proc ::Connections::getIds

#------------------------------------------------------------
# ::Connections::getNextId --
#
#    Gets the next id in the id list
#
# Arguments:
#    none
#
# Results
#    The next available id
#------------------------------------------------------------
#
proc ::Connections::getNextId {} {

    variable Conn

    return [incr Conn(last_id)]

}; # end proc ::Connections::getNextId

#------------------------------------------------------------
# ::Connections::getDbs --
#
#    Retrieves the known connection dbnames
#
# Arguments:
#    none
#
# Results
#    list of the attributes requested
#------------------------------------------------------------
#
proc ::Connections::getDbs {{host_ "*"}} {

    variable Conn

    if {[string match "sockets" $host_]} {set host_ ""}

    set res [list]
    foreach i [getIds] {
        if {[string match "$host_" $Conn(host,$i)]} {
	    if {[lsearch $res $Conn(dbname,$i)] < 0} {

                lappend res $Conn(dbname,$i)
            }
        }
    }

    if {[llength $res] != 1} {
        return $res
    } else {
        return [lindex $res 0]
    }

}; # end proc ::Connections::getDbs

#------------------------------------------------------------
# ::Connections::getHosts --
#
#    Retrieves the known connection hosts
#
# Arguments:
#    none
#
# Results
#    list of hosts
#------------------------------------------------------------
#
proc ::Connections::getHosts {} {

    variable Conn

    set res [list]
    foreach i [getIds] {
        if {[lsearch $res $Conn(host,$i)] < 0} {
            lappend res $Conn(host,$i)
        }
    }

    if {[llength $res] != 1} {
        return $res
    } else {
        if {[string length [lindex $res 0]]==0} {
            return "sockets"
        } else {
            return [lindex $res 0]
        }
    }

}; # end proc ::Connections::getHosts


#------------------------------------------------------------
# ::Connections::getUsers --
#
#    Retrieves the known connection users
#
# Arguments:
#    none
#
# Results
#    list of the users
#------------------------------------------------------------
#
proc ::Connections::getUsers {{host_ "*"} {db_ *}} {

    variable Conn

    if {[string match "sockets" $host_]} {set host_ ""}

    set res [list]
    foreach i [getIds] {
        if {([string match "$host_" $Conn(host,$i)]) && ([string match "$db_" $Conn(dbname,$i)])} {
            if {[lsearch $res $Conn(username,$i)] < 0} {
                lappend res $Conn(username,$i)
            }
        }
    }

    if {[llength $res] != 1} {
        return $res
    } else {
        return [lindex $res 0]
    }

}; # end proc ::Connections::getUsers

#------------------------------------------------------------
# ::Connections::getHandles --
#
#    Retrieves the known db handles
#
# Arguments:
#    none
#
# Results
#    list of the handles
#------------------------------------------------------------
#
proc ::Connections::getHandles {{host_ "*"} {db_ *}} {

    variable Conn

    if {[string match "sockets" $host_]} {set host_ ""}

    set res [list]
    foreach i [getIds] {
        if {([string match "$host_" $Conn(host,$i)]) && ([string match "$db_" $Conn(dbname,$i)])} {
            if {![info exists Conn(handle,$i)]} {
                continue
            }

            if {[lsearch $res $Conn(handle,$i)] < 0} {
                lappend res $Conn(handle,$i)
            }
        }
    }

    if {[llength $res] != 1} {
        return $res
    } else {
        return [lindex $res 0]
    }

}; # end proc ::Connections::getHandles


#------------------------------------------------------------
# ::Connections::load --
#
#    Loads the connection information from the connections
#    resource file, and calls open_data for each one
#
# Arguments:
#    none
#
# Results:
#    none returned
#------------------------------------------------------------
#
proc ::Connections::load {} {

    global PgAcVar

    variable Conn

	set file [file join $::env(HOME) .pgaccess connections]
###	set retval [catch {set fid [open "$file" r]} errmsg]
###
###	if {! $retval} {
###		array set Conn [read $fid [file size $file]]
###		close $fid
###	}

        if {[catch {set fid [open "$file" r]} errmsg]} {
             set Conn(last_id) 0
             return
        }

        array set Conn [read $fid [file size $file]]
        close $fid

        ##
	##  Get the last id number
	##
	set num 0
	foreach {k v} [array get Conn dbname,*] {

	   set i [lindex [split $k ,] 1]

           ##
           ##   We get rid of any entries
           ##   that don't have a dbname
           ##   also
           ##
           if {[string match "" $v]} {
             foreach {k v} [array get Conn *,$i] {
                unset Conn($k)
             }
           }

	   if {$i > $num} {set num $i}
	}
	set Conn(last_id) $num

    return

}; # end proc ::Connections::load


#------------------------------------------------------------
# ::Connections::save --
#
#    Saves the connection info to the file
#
# Arguments:
#    none
#
# Results:
#    none returned
#------------------------------------------------------------
#
proc ::Connections::save {} {

    global PgAcVar

    variable Conn

	set file [file join $::env(HOME) .pgaccess connections]
	set retval [catch {set fid [open "$file" w]} errmsg]

	if {! $retval} {
            # dont save passwords if we are not told to do so
            if {![info exists PgAcVar(pref,savepasswords)]} {
                set PgAcVar(pref,savepasswords) 0
            }

            foreach id [getIds] {
                if {![info exists Conn(savepasswords,$id)]} {
                    set Conn(savepasswords,$id) $PgAcVar(pref,savepasswords)
                }

                if {$Conn(savepasswords,$id) == 0} {
                    set Conn(password,$id) ""
                }
            }

	    puts $fid [array get Conn]
	    close $fid
	}

	return
    
}; # end proc ::Connections::save

#------------------------------------------------------------
# ::Connections::check --
#
#    Checks the open/current db info to see if there
#    is an entry in the Conn array. This is for backwards
#    compatibility
#
# Arguments:
#    none
#
# Results:
#    none returned
#------------------------------------------------------------
#
proc ::Connections::check {} {

    global PgAcVar CurrentDB
    variable Conn

    set create 0
    if {[lsearch [getDbs $PgAcVar(opendb,host)] $PgAcVar(opendb,dbname)] < 0} {
	   set id [getNextId]
	   set Conn(dbname,$id) $PgAcVar(opendb,dbname)
	   set Conn(host,$id) $PgAcVar(opendb,host)
	   set Conn(username,$id) $PgAcVar(opendb,username)
	   set Conn(password,$id) $PgAcVar(opendb,password)
	   set Conn(pgport,$id) $PgAcVar(opendb,pgport)
	   set Conn(handle,$id) $CurrentDB
    }

	return
}; # end proc ::Connections::check


#------------------------------------------------------------
# ::Connections::deleteInfo --
#
#    Deletes info about a connection, indexed by the id
#
# Arguments:
#    id_    the id for that connection
#
# Results:
#    none returned
#------------------------------------------------------------
#
proc ::Connections::deleteInfo {id_} {

    variable Conn

    foreach {k v} [array get Conn *,${id_}] {
	    unset Conn($k)
    }

    return
}; # end proc ::Connections::deleteInfo

#------------------------------------------------------------
# ::Connections::getInfoFromHandle --
#
#    This retrieves the connection id based on the
#    db handle, which should be unique
#
# Arguments:
#    dbh_    The db handle for the connection info. Defaults
#            to $CurrentDB if empty
#
# Results:
#    returns the id of the db handle
#------------------------------------------------------------
#
proc ::Connections::getIdFromHandle {{dbh_ ""}} {

    global CurrentDB
	variable Conn

    if {[string match "" $dbh_]} {
	    if {[string match "" $CurrentDB]} {
		    return ""
		} else {
		    set dbh_ $CurrentDB
		}
	}

    foreach {k v} [array get Conn handle,*] {
       if {[string match "$v" "$dbh_"]} {
	       return [lindex [split $k ,] 1]
	   }
	}
   
    return ""

}; # end proc ::Connections::getIdFromHandle

#------------------------------------------------------------
# ::Connections::openConn --
#
#   Opens an existing db connection stored in the
#   connections file
#
# Arguments:
#   id_     The id of the connection
#   win_    optional, if 1 then show DB conn window
# Results:
#   opens database
#------------------------------------------------------------
#
proc ::Connections::openConn {{id_ 0} {win_ 0}} {

    global PgAcVar CurrentDB
    variable Msg
    variable Conn

    # if id_ is 0, its a new connection
    if {$id_==0} {
        set id_ [::Connections::getNextId]
        set Conn(host,$id_) ""
        set Conn(pgport,$id_) 5432
        set Conn(dbname,$id_) ""
        set Conn(username,$id_) ""
        set Conn(password,$id_) ""
    }

    # show window and wait for it to close
    if {$win_} {
        Window show .pgaw:OpenDB
        tkwait visibility .pgaw:OpenDB
        set PgAcVar(opendb,host) $Conn(host,$id_)
        set PgAcVar(opendb,pgport) $Conn(pgport,$id_)
        set PgAcVar(opendb,dbname) $Conn(dbname,$id_)
        set PgAcVar(opendb,username) $Conn(username,$id_)
        set PgAcVar(opendb,password) $Conn(password,$id_)
        if {[string match "sockets" $PgAcVar(opendb,host)]} {
            set PgAcVar(opendb,host) ""
        }
        focus .pgaw:OpenDB.f1.e5
        wm transient .pgaw:OpenDB
        .pgaw:OpenDB.f1.e5 selection range 0 end
        tkwait window .pgaw:OpenDB
        set Conn(host,$id_) $PgAcVar(opendb,host)
        set Conn(pgport,$id_) $PgAcVar(opendb,pgport)
        set Conn(dbname,$id_) $PgAcVar(opendb,dbname)
        set Conn(username,$id_) $PgAcVar(opendb,username)
        set Conn(password,$id_) $PgAcVar(opendb,password)
    }

    setCursor CLOCK

    set Msg($id_) ""

    ##
    ##  If no dbname, then clear that connection, and 
    ##  return 0
    ##
    if {(![info exists Conn(dbname,$id_)]) || ([string match "" $Conn(dbname,$id_)])} {

        deleteInfo $id_
        set Msg($id_) "DB name is empty"
        return 0
    }

    set connstr "dbname=$Conn(dbname,$id_) \
                user=$Conn(username,$id_) \
                password=$Conn(password,$id_)"

    if {$Conn(username,$id_)!=""} {
        if {$Conn(host,$id_)!=""} {
            set connres [catch {set newdbc [pg_connect \
            -conninfo "host=$Conn(host,$id_) port=$Conn(pgport,$id_) $connstr"]} msg]

        } else {
            set connres [catch {set newdbc [pg_connect \
            -conninfo "$connstr"]} msg]
        }

    } else {
        set connres [catch {set newdbc [pg_connect $Conn(dbname,$id_) \
        -host $Conn(host,$id_) \
        -port $Conn(pgport,$id_)]} msg]
    }


    ##
    ##  If connres, then something went wrong...
    ##
    if {$connres} {

        setCursor DEFAULT
        set m [intlmsg "Error trying to connect to database '$Conn(dbname,$id_)' \n\
            on host $Conn(host,$id_) \n\nPostgreSQL error message: $msg"]

        showError $m open_database

        set Msg($id_) "$m"
#        deleteInfo $id_

        return 0
    }

    $::Mainlib::Win(statuslabel) configure \
        -text "Loading $Conn(dbname,$id_) ..."
    set Conn(handle,$id_) $newdbc

    setCursor DEFAULT

    ##
    ##  This is to satisfy any autoexec scripts
    ##  that rely on these vars
    ##
    set CurrentDB $newdbc
    set PgAcVar(currentdb,host) $Conn(host,$id_)
    set PgAcVar(currentdb,dbname) $Conn(dbname,$id_)
    set PgAcVar(currentdb,pgport) $Conn(pgport,$id_)
    set PgAcVar(currentdb,username) $Conn(username,$id_)
    set PgAcVar(currentdb,password) $Conn(password,$id_)

    ##
    ##  Look for autoexec script
    ##
    set sql "SELECT * 
               FROM Pga_scripts
              WHERE scriptname ~* '^autoexec$'"

    wpg_select $newdbc "$sql" recd {
        eval $recd(scriptsource)
    }

    ::Connections::save

    $::Mainlib::Win(statuslabel) configure \
        -text ""

    return 1

}; # end ::Connections::openConn

#------------------------------------------------------------
# ::Connections::consistCheck --
#
#    This checks the Conn array, and makes sure the
#    data is consistant. If not, then it removes
#    it from the array
#
# Arguments:
#    none
#
# Results:
#    0    if there were errors
#    1    if there were no errors
#------------------------------------------------------------
#
proc ::Connections::consistCheck {} {
}; # end proc ::Connections::consistCheck


#------------------------------------------------------------
# vTclWindow.pgaw:OpenDB --
#
#    Window that prompts to open a database connection
#
# Arguments:
#    base     the base window
#
# Results:
#    none returned
#------------------------------------------------------------
#
proc vTclWindow.pgaw:OpenDB {base} {
	if {$base == ""} {
		set base .pgaw:OpenDB
	}
	if {[winfo exists $base]} {
		wm deiconify $base; return
	}
	toplevel $base -class Toplevel
	wm focusmodel $base passive
	wm geometry $base 283x172+119+210
	wm maxsize $base 1280 1024
	wm minsize $base 1 1
	wm overrideredirect $base 0
	wm resizable $base 0 0
	wm deiconify $base
	wm title $base [intlmsg "Open database"]

	frame $base.f1 \
		-borderwidth 2 \
		-height 75 \
		-width 125 

	label $base.f1.l1 \
		-borderwidth 0 \
		-relief raised \
		-text [intlmsg Host]

	#entry $base.f1.e1 \
		#-background #fefefe -borderwidth 1 -textvariable PgAcVar(opendb,host) -width 200 

    set Win(hostname) [ComboBox $base.f1.e1 \
	    -background #fefefe \
		-borderwidth 1 \
		-width 200]

    $Win(hostname) configure \
	    -textvariable PgAcVar(opendb,host) \
	    -values [::Connections::getHosts]

    $base.f1.e1 bind <Key-KP_Enter> {focus .pgaw:OpenDB.f1.e2}
    $base.f1.e1 bind <Key-Return> {focus .pgaw:OpenDB.f1.e2}

	#bind $base.f1.e1 <Key-KP_Enter> {
		#focus .pgaw:OpenDB.f1.e2
	#}
	#bind $base.f1.e1 <Key-Return> {
		#focus .pgaw:OpenDB.f1.e2
	#}

	label $base.f1.l2 \
		-borderwidth 0 -relief raised -text [intlmsg Port]
	#entry $base.f1.e2 \
		#-background #fefefe -borderwidth 1 -textvariable PgAcVar(opendb,pgport) -width 200 

	SpinBox $base.f1.e2 \
	    -background #fefefe \
		-borderwidth 1 \
		-textvariable PgAcVar(opendb,pgport) \
		-range [list 0 10000 1] \
		-width 200

    $base.f1.e2 bind <Key-Return> {focus .pgaw:OpenDB.f1.e3}

	#bind $base.f1.e2 <Key-Return> {
		#focus .pgaw:OpenDB.f1.e3
	#}

	label $base.f1.l3 \
		-borderwidth 0 -relief raised -text [intlmsg Database]
	entry $base.f1.e3 \
		-background #fefefe -borderwidth 1 -textvariable PgAcVar(opendb,dbname) -width 200 
	bind $base.f1.e3 <Key-Return> {
		focus .pgaw:OpenDB.f1.e4
	}
	label $base.f1.l4 \
		-borderwidth 0 -relief raised -text [intlmsg Username]
	entry $base.f1.e4 \
		-background #fefefe -borderwidth 1 -textvariable PgAcVar(opendb,username) \
		-width 200 
	bind $base.f1.e4 <Key-Return> {
		focus .pgaw:OpenDB.f1.e5
	}
	label $base.f1.ls2 \
		-borderwidth 0 -relief raised -text { } 
	label $base.f1.l5 \
		-borderwidth 0 -relief raised -text [intlmsg Password]
	entry $base.f1.e5 \
		-background #fefefe -borderwidth 1 -show * -textvariable PgAcVar(opendb,password) \
                -font $::PgAcVar(pref,font_normal) \
		-width 200 
	bind $base.f1.e5 <Key-Return> {
		focus .pgaw:OpenDB.fb.btnopen
	}
	frame $base.fb \
		-height 75 -relief groove -width 125 
	button $base.fb.btnopen \
		-borderwidth 1 -command Mainlib::open_database -padx 9 \
		-pady 3 -text [intlmsg Open]
	button $base.fb.btnhelp \
		-borderwidth 1 -command {Help::load open_database} \
		-padx 9 -pady 3 -text [intlmsg Help]
	button $base.fb.btncancel \
		-borderwidth 1 -command {Window hide .pgaw:OpenDB} \
		-padx 9 -pady 3 -text [intlmsg Cancel]
	place $base.f1 \
		-x 9 -y 5 -width 265 -height 126 -anchor nw -bordermode ignore 
	grid columnconf $base.f1 2 -weight 1
	grid $base.f1.l1 \
		-in .pgaw:OpenDB.f1 -column 0 -row 0 -columnspan 1 -rowspan 1 -sticky w 
	grid $base.f1.e1 \
		-in .pgaw:OpenDB.f1 -column 2 -row 0 -columnspan 1 -rowspan 1 -pady 2 
	grid $base.f1.l2 \
		-in .pgaw:OpenDB.f1 -column 0 -row 2 -columnspan 1 -rowspan 1 -sticky w 
	grid $base.f1.e2 \
		-in .pgaw:OpenDB.f1 -column 2 -row 2 -columnspan 1 -rowspan 1 -pady 2 
	grid $base.f1.l3 \
		-in .pgaw:OpenDB.f1 -column 0 -row 4 -columnspan 1 -rowspan 1 -sticky w 
	grid $base.f1.e3 \
		-in .pgaw:OpenDB.f1 -column 2 -row 4 -columnspan 1 -rowspan 1 -pady 2 
	grid $base.f1.l4 \
		-in .pgaw:OpenDB.f1 -column 0 -row 6 -columnspan 1 -rowspan 1 -sticky w 
	grid $base.f1.e4 \
		-in .pgaw:OpenDB.f1 -column 2 -row 6 -columnspan 1 -rowspan 1 -pady 2 
	grid $base.f1.ls2 \
		-in .pgaw:OpenDB.f1 -column 1 -row 0 -columnspan 1 -rowspan 1 
	grid $base.f1.l5 \
		-in .pgaw:OpenDB.f1 -column 0 -row 7 -columnspan 1 -rowspan 1 -sticky w 
	grid $base.f1.e5 \
		-in .pgaw:OpenDB.f1 -column 2 -row 7 -columnspan 1 -rowspan 1 -pady 2 
	place $base.fb \
		-x 0 -y 135 -width 283 -height 40 -anchor nw -bordermode ignore 
	grid $base.fb.btnopen \
		-in .pgaw:OpenDB.fb -column 0 -row 0 -columnspan 1 -rowspan 1 -padx 5 
	grid $base.fb.btnhelp \
		-in .pgaw:OpenDB.fb -column 1 -row 0 -columnspan 1 -rowspan 1 -padx 5 
	grid $base.fb.btncancel \
		-in .pgaw:OpenDB.fb -column 2 -row 0 -columnspan 1 -rowspan 1 -padx 5 
}
