//!
//! Handles the Run instance request
//!
//! @param[in]  pStub a pointer to the node controller (NC) stub structure
//! @param[in]  pMeta a pointer to the node controller (NC) metadata structure
//! @param[in]  uuid unique user identifier string
//! @param[in]  instanceId the instance identifier string (i-XXXXXXXX)
//! @param[in]  reservationId the reservation identifier string
//! @param[in]  params a pointer to the virtual machine parameters to use
//! @param[in]  imageId the image identifier string
//! @param[in]  imageURL the image URL address tring
//! @param[in]  kernelId the kernel image identifier (eki-XXXXXXXX)
//! @param[in]  kernelURL the kernel image URL address
//! @param[in]  ramdiskId the ramdisk image identifier (eri-XXXXXXXX)
//! @param[in]  ramdiskURL the ramdisk image URL address
//! @param[in]  ownerId the owner identifier string
//! @param[in]  accountId the account identifier string
//! @param[in]  keyName the key name string
//! @param[in]  netparams a pointer to the network parameters string
//! @param[in]  userData the user data string
//! @param[in]  launchIndex the launch index string
//! @param[in]  platform the platform name string
//! @param[in]  expiryTime the reservation expiration time
//! @param[in]  groupNames a list of group name string
//! @param[in]  groupNamesSize the number of group name in the groupNames list
//! @param[out] outInstPtr the list of instances created by this request
//!
//! @return the result of doRunInstance()
//!
//! @see doRunInstance()
//!
int ncRunInstanceStub(ncStub * pStub, ncMetadata * pMeta, char *uuid, char *instanceId, char *reservationId, virtualMachine * params, char *imageId,
                      char *imageURL, char *kernelId, char *kernelURL, char *ramdiskId, char *ramdiskURL, char *ownerId, char *accountId,
                      char *keyName, netConfig * netparams, char *userData, char* credential, char *launchIndex, char *platform, int expiryTime, char **groupNames,
                      int groupNamesSize, ncInstance ** outInstPtr)
{
    return doRunInstance(pMeta, uuid, instanceId, reservationId, params, imageId, imageURL, kernelId, kernelURL, ramdiskId, ramdiskURL, ownerId,
                         accountId, keyName, netparams, userData, credential, launchIndex, platform, expiryTime, groupNames, groupNamesSize, outInstPtr);
}
adb_ncRunInstanceResponse_t* ncRunInstanceMarshal (adb_ncRunInstance_t* ncRunInstance, const axutil_env_t *env)
{
    pthread_mutex_lock(&ncHandlerLock);
    adb_ncRunInstanceType_t * input          = adb_ncRunInstance_get_ncRunInstance(ncRunInstance, env);
    adb_ncRunInstanceResponse_t * response   = adb_ncRunInstanceResponse_create(env);
    adb_ncRunInstanceResponseType_t * output = adb_ncRunInstanceResponseType_create(env);

    // get standard fields from input
    axis2_char_t * correlationId = adb_ncRunInstanceType_get_correlationId(input, env);
    axis2_char_t * userId = adb_ncRunInstanceType_get_userId(input, env);

    // get operation-specific fields from input
    axis2_char_t * instanceId = adb_ncRunInstanceType_get_instanceId(input, env);
    axis2_char_t * reservationId = adb_ncRunInstanceType_get_reservationId(input, env);
    virtualMachine params;
    copy_vm_type_from_adb (&params, adb_ncRunInstanceType_get_instanceType(input, env), env);
    axis2_char_t * imageId = adb_ncRunInstanceType_get_imageId(input, env);
    axis2_char_t * imageURL = adb_ncRunInstanceType_get_imageURL(input, env);
    axis2_char_t * kernelId = adb_ncRunInstanceType_get_kernelId(input, env);
    axis2_char_t * kernelURL = adb_ncRunInstanceType_get_kernelURL(input, env);
    axis2_char_t * ramdiskId = adb_ncRunInstanceType_get_ramdiskId(input, env);
    axis2_char_t * ramdiskURL = adb_ncRunInstanceType_get_ramdiskURL(input, env);
    axis2_char_t * keyName = adb_ncRunInstanceType_get_keyName(input, env);
    adb_netConfigType_t *net_type = adb_ncRunInstanceType_get_netParams(input, env);
    netConfig netparams;
    netparams.vlan = adb_netConfigType_get_vlan(net_type, env);
    netparams.networkIndex = adb_netConfigType_get_networkIndex(net_type, env);
    snprintf(netparams.privateMac, 24, "%s", adb_netConfigType_get_privateMacAddress(net_type, env));
    snprintf(netparams.privateIp, 24, "%s", adb_netConfigType_get_privateIp(net_type, env));
    snprintf(netparams.publicIp, 24, "%s", adb_netConfigType_get_publicIp(net_type, env));
    axis2_char_t * userData = adb_ncRunInstanceType_get_userData(input, env);
    axis2_char_t * launchIndex = adb_ncRunInstanceType_get_launchIndex(input, env);
    int groupNamesSize = adb_ncRunInstanceType_sizeof_groupNames(input, env);
    char ** groupNames = calloc (groupNamesSize, sizeof(char *));
    if (groupNames==NULL) {
        logprintfl (EUCAERROR, "ERROR: out of memory in ncRunInstancesMarshall()\n");
        adb_ncRunInstanceResponseType_set_return(output, env, AXIS2_FALSE);

    } else {
        int i;
        for (i=0; i<groupNamesSize; i++) {
            groupNames[i] = adb_ncRunInstanceType_get_groupNames_at(input, env, i);
        }
    
        { // log event
            char other[256];
            snprintf(other, 256, "begin,%s", reservationId);
            eventlog("NC", userId, correlationId, "RunInstance", other);
        }
        
        { // do it
            ncMetadata meta = { correlationId, userId };
            ncInstance * outInst;
            
            int error = doRunInstance (&meta, instanceId, reservationId, &params, 
                                       imageId, imageURL, 
                                       kernelId, kernelURL, 
                                       ramdiskId, ramdiskURL, 
                                       keyName, 
                                       &netparams, 
                                       userData, launchIndex, groupNames, groupNamesSize,
                                       &outInst);
            
            if (error) {
                logprintfl (EUCAERROR, "ERROR: doRunInstance() failed error=%d\n", error);
                adb_ncRunInstanceResponseType_set_return(output, env, AXIS2_FALSE);
                
            } else {
                ///// set standard fields in output
                adb_ncRunInstanceResponseType_set_return(output, env, AXIS2_TRUE);
                adb_ncRunInstanceResponseType_set_correlationId(output, env, correlationId);
                adb_ncRunInstanceResponseType_set_userId(output, env, userId);
                
                ///// set operation-specific fields in output            
                adb_instanceType_t * instance = adb_instanceType_create(env);
                copy_instance_to_adb (instance, env, outInst); // copy all values outInst->instance
                
                // TODO: should we free_instance(&outInst) here or not? currently you don't have to
                adb_ncRunInstanceResponseType_set_instance(output, env, instance);
            }
            
            if (groupNamesSize)
                free (groupNames);
        }
    }
    
    // set response to output
    adb_ncRunInstanceResponse_set_ncRunInstanceResponse(response, env, output);
    pthread_mutex_unlock(&ncHandlerLock);
    
    eventlog("NC", userId, correlationId, "RunInstance", "end");
    return response;
}