/*
 * Document-method: new
 *
 * call-seq:
 *     PGconn.open(connection_hash) -> PGconn
 *     PGconn.open(connection_string) -> PGconn
 *     PGconn.open(host, port, options, tty, dbname, login, password) ->  PGconn
 *
 * * +host+ - server hostname
 * * +hostaddr+ - server address (avoids hostname lookup, overrides +host+)
 * * +port+ - server port number
 * * +dbname+ - connecting database name
 * * +user+ - login user name
 * * +password+ - login password
 * * +connect_timeout+ - maximum time to wait for connection to succeed
 * * +options+ - backend options
 * * +tty+ - (ignored in newer versions of PostgreSQL)
 * * +sslmode+ - (disable|allow|prefer|require)
 * * +krbsrvname+ - kerberos service name
 * * +gsslib+ - GSS library to use for GSSAPI authentication
 * * +service+ - service name to use for additional parameters
 *
 * _connection_hash_ example: +PGconn.connect(:dbname=>'test', :port=>5432)
 * _connection_string_ example: +PGconn.connect("dbname=test port=5432")
 * _connection_hash_ example: +PGconn.connect(nil,5432,nil,nil,'test',nil,nil)
 *  
 *  On failure, it raises a PGError exception.
 */

static VALUE
pgconn_init(argc, argv, self)
    int argc;
    VALUE *argv;
    VALUE self;
{
    VALUE args,arg;
    PGconn *conn = NULL;
        char *conninfo = NULL;
        VALUE conninfo_rstr;
        VALUE error;
        char *host, *port, *opt, *tty, *dbname, *login, *pwd;
        host=port=opt=tty=dbname=login=pwd=NULL;

    rb_scan_args(argc, argv, "0*", &args); 
    if (RARRAY_LEN(args) == 1) { 
                arg = rb_ary_entry(args,0);
                if(TYPE(arg) == T_HASH) {
                        conninfo_rstr = rb_str_new2("");
                        build_key_value_string(arg, conninfo_rstr, "host");
                        build_key_value_string(arg, conninfo_rstr, "hostaddr");
                        build_key_value_string(arg, conninfo_rstr, "port");
                        build_key_value_string(arg, conninfo_rstr, "dbname");
                        build_key_value_string(arg, conninfo_rstr, "user");
                        build_key_value_string(arg, conninfo_rstr, "password");
                        build_key_value_string(arg, conninfo_rstr, "opt");
                        build_key_value_string(arg, conninfo_rstr, "tty");
                        build_key_value_string(arg, conninfo_rstr, "sslmode");
                        build_key_value_string(arg, conninfo_rstr, "krbsrvname");
                        build_key_value_string(arg, conninfo_rstr, "gsslib");
                        build_key_value_string(arg, conninfo_rstr, "service");
                        conninfo = StringValuePtr(conninfo_rstr);
                }
                else if(TYPE(arg) == T_STRING) {
                        conninfo = StringValuePtr(arg);
                }
                else {
                        rb_raise(rb_eArgError, 
                                "Expecting String or Hash as single argument");
                }
                conn = PQconnectdb(conninfo);
    }
        else if (RARRAY_LEN(args) == 7) {
                host = value_as_cstring(rb_ary_entry(args,0));
                port = value_as_cstring(rb_ary_entry(args,1));
                opt = value_as_cstring(rb_ary_entry(args,2));
                tty = value_as_cstring(rb_ary_entry(args,3));
                dbname = value_as_cstring(rb_ary_entry(args,4));
                login = value_as_cstring(rb_ary_entry(args,5));
                pwd = value_as_cstring(rb_ary_entry(args,6));

                conn = PQsetdbLogin(host, port, opt, tty, dbname, login, pwd);
        }
        else {
                rb_raise(rb_eArgError, 
                        "Expected connection info string, hash, or 7 separate arguments.");
        }

    if (PQstatus(conn) == CONNECTION_BAD) {
        error = rb_exc_new2(rb_ePGError, PQerrorMessage(conn));
        rb_iv_set(error, "@connection", self);
        rb_exc_raise(error);
    }

        Check_Type(self, T_DATA);
        DATA_PTR(self) = conn;
        
    if (rb_block_given_p()) {
        return rb_ensure(rb_yield, self, pgconn_finish, self);
    }
    return self;
}