/*
 * call-seq:
 *   new(...)
 *
 * Parameters:
 * * Since the number of parameters can vary dramatically, all parameters are passed by name in a hash
 * * See QueueManager.new for details on all the parameters
 *
 * Note:
 * * It is not recommended to use this method, rather use QueueManager.connect, since
 *   it will automatically disconnect from the queue manager. It also deals with backing out
 *   the current unit of work in the event of an unhandled exception. E.g. Syntax Error
 * * RuntimeError and ArgumentError exceptions are always thrown regardless of the
 *   value of :exception_on_error
 *
 * Todo:
 * * Support multiple send and receive exits
 */
VALUE QueueManager_initialize(VALUE self, VALUE hash)
{
    VALUE          val;
    VALUE          str;
    size_t         size;
    size_t         length;
    size_t         i;
    PQUEUE_MANAGER pqm;
    char*          pChar;

    Check_Type(hash, T_HASH);

    Data_Get_Struct(self, QUEUE_MANAGER, pqm);

    WMQ_HASH2MQLONG(hash,trace_level, pqm->trace_level)

    /* @name = options[:q_mgr_name] || ''     # QMGR Name optional with Client Connection */
    val = rb_hash_aref(hash, ID2SYM(ID_q_mgr_name));
    if (NIL_P(val))
    {
        rb_iv_set(self, "@name", rb_str_new2(""));
        if(pqm->trace_level > 1) printf("WMQ::QueueManager#initialize() Queue Manager:[Not specified, use Default QMGR]\n");
    }
    else
    {
        rb_iv_set(self, "@name", val);
        if(pqm->trace_level > 1) printf("WMQ::QueueManager#initialize() Queue Manager:%s\n", RSTRING(val)->ptr);
    }

    WMQ_HASH2BOOL(hash,exception_on_error, pqm->exception_on_error)

    /*
     * All Client connection parameters are ignored if connection_name is missing
     */
#ifdef MQCNO_VERSION_2
    if(!NIL_P(rb_hash_aref(hash, ID2SYM(ID_connection_name))))
    {
        PMQCD pmqcd = &pqm->client_conn;              /* Process MQCD */
        pqm->is_client_conn = 1;                      /* Set to Client connection */

        WMQ_HASH2MQCHARS(hash,connection_name,             pmqcd->ConnectionName)
        WMQ_HASH2MQLONG (hash,transport_type,              pmqcd->TransportType)
        WMQ_HASH2MQCHARS(hash,mode_name,                   pmqcd->ModeName)
        WMQ_HASH2MQCHARS(hash,tp_name,                     pmqcd->TpName)
        WMQ_HASH2MQCHARS(hash,security_exit,               pmqcd->SecurityExit)
        WMQ_HASH2MQCHARS(hash,send_exit,                   pmqcd->SendExit)
        WMQ_HASH2MQCHARS(hash,receive_exit,                pmqcd->ReceiveExit)
        WMQ_HASH2MQLONG (hash,max_msg_length,              pmqcd->MaxMsgLength)
        WMQ_HASH2MQCHARS(hash,security_user_data,          pmqcd->SecurityUserData)
        WMQ_HASH2MQCHARS(hash,send_user_data,              pmqcd->SendUserData)
        WMQ_HASH2MQCHARS(hash,receive_user_data,           pmqcd->ReceiveUserData)
        WMQ_HASH2MQCHARS(hash,user_identifier,             pmqcd->UserIdentifier)
        WMQ_HASH2MQCHARS(hash,password,                    pmqcd->Password)

        /* Default channel name to system default */
        val = rb_hash_aref(hash, ID2SYM(ID_channel_name));
        if (NIL_P(val))
        {
            strncpy(pmqcd->ChannelName, "SYSTEM.DEF.SVRCONN", sizeof(pmqcd->ChannelName));
        }
        else
        {
            WMQ_HASH2MQCHARS(hash,channel_name,            pmqcd->ChannelName)
        }

    #ifdef MQCD_VERSION_4
        WMQ_HASH2MQLONG(hash,heartbeat_interval,          pmqcd->HeartbeatInterval)
        /* TODO:
        WMQ_HASH2MQLONG(hash,exit_name_length,            pmqcd->ExitNameLength)
        WMQ_HASH2MQLONG(hash,exit_data_length,            pmqcd->ExitDataLength)
        WMQ_HASH2MQLONG(hash,send_exits_defined,          pmqcd->SendExitsDefined)
        WMQ_HASH2MQLONG(hash,receive_exits_defined,       pmqcd->ReceiveExitsDefined)
        TO_PTR (send_exit_ptr,               pmqcd->SendExitPtr)
        TO_PTR (send_user_data_ptr,          pmqcd->SendUserDataPtr)
        TO_PTR (receive_exit_ptr,            pmqcd->ReceiveExitPtr)
        TO_PTR (receive_user_data_ptr,       pmqcd->ReceiveUserDataPtr)
        */
    #endif
    #ifdef MQCD_VERSION_6
        val = rb_hash_aref(hash, ID2SYM(ID_long_remote_user_id));
        if (!NIL_P(val))
        {
            str = StringValue(val);
            length = RSTRING(str)->len;

            if (length > 0)
            {
                MQPTR pBuffer;
                if(pqm->trace_level > 1)
                    printf("WMQ::QueueManager#initialize() Setting long_remote_user_id:%s\n",
                        RSTRING(str)->ptr);

                /* Include null at end of string */
                pBuffer = ALLOC_N(char, length+1);
                memcpy(pBuffer, RSTRING(str)->ptr, length+1);

                pmqcd->LongRemoteUserIdLength = length;
                pmqcd->LongRemoteUserIdPtr    = pBuffer;
                pqm->long_remote_user_id_ptr  = pBuffer;
            }
        }
        WMQ_HASH2MQBYTES(hash,remote_security_id,          pmqcd->RemoteSecurityId)
        WMQ_HASH2MQCHARS(hash,ssl_cipher_spec,             pmqcd->SSLCipherSpec)
    #endif
    #ifdef MQCD_VERSION_7
        val = rb_hash_aref(hash, ID2SYM(ID_ssl_peer_name));
        if (!NIL_P(val))
        {
            str = StringValue(val);
            length = RSTRING(str)->len;

            if (length > 0)
            {
                MQPTR pBuffer;
                if(pqm->trace_level > 1)
                    printf("WMQ::QueueManager#initialize() Setting ssl_peer_name:%s\n",
                        RSTRING(str)->ptr);

                /* Include null at end of string */
                pBuffer = ALLOC_N(char, length+1);
                memcpy(pBuffer, RSTRING(str)->ptr, length+1);

                pmqcd->SSLPeerNameLength = length;
                pmqcd->SSLPeerNamePtr    = pBuffer;
                pqm->ssl_peer_name_ptr   = pBuffer;
            }
        }
        WMQ_HASH2MQLONG(hash,keep_alive_interval,         pmqcd->KeepAliveInterval)

        /* Only set if SSL options are supplied, otherwise
        * environment variables are ignored: MQSSLKEYR and MQSSLCRYP
        * Any SSL info in the client channel definition tables is also ignored
        */
        if (!NIL_P(rb_hash_aref(hash, ID2SYM(ID_key_repository))) ||
            !NIL_P(rb_hash_aref(hash, ID2SYM(ID_crypto_hardware))))
        {
            /* Process MQSCO */
            WMQ_HASH2MQCHARS(hash,key_repository,              pqm->ssl_config_opts.KeyRepository)
            WMQ_HASH2MQCHARS(hash,crypto_hardware,             pqm->ssl_config_opts.CryptoHardware)

            pqm->connect_options.SSLConfigPtr = &pqm->ssl_config_opts;
        }
    #endif

    }
    else
    {
        pqm->is_client_conn = 0;                       /* Set to Server connection */
    }
#endif

#ifdef MQCNO_VERSION_4
    /* Process MQCNO */
    WMQ_HASH2MQLONG(hash,connect_options,             pqm->connect_options.Options)
#endif

  /* --------------------------------------------------
   * TODO:   MQAIR Structure - LDAP Security
   * --------------------------------------------------*/

    return Qnil;
}