/*
 * Copyright (c) 2003, 2007, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

//#define USE_ERROR
//#define USE_TRACE

#include "PLATFORM_API_LinuxOS_ALSA_CommonUtils.h"

static void alsaDebugOutput(const char *file, int line, const char *function, int err, const char *fmt, ...) {
#ifdef USE_ERROR
    va_list args;
    va_start(args, fmt);
    printf("%s:%d function %s: error %d: %s\n", file, line, function, err, snd_strerror(err));
    if (strlen(fmt) > 0) {
        vprintf(fmt, args);
    }
    va_end(args);
#endif
}

static int alsa_inited = 0;
static int alsa_enumerate_pcm_subdevices = FALSE; // default: no
static int alsa_enumerate_midi_subdevices = FALSE; // default: no

void initAlsaSupport() {
    char* enumerate;
    if (!alsa_inited) {
        alsa_inited = TRUE;
        snd_lib_error_set_handler(&alsaDebugOutput);

        enumerate = getenv(ENV_ENUMERATE_PCM_SUBDEVICES);
        if (enumerate != NULL && strlen(enumerate) > 0
            && (enumerate[0] != 'f')   // false
            && (enumerate[0] != 'F')   // False
            && (enumerate[0] != 'n')   // no
            && (enumerate[0] != 'N')) { // NO
            alsa_enumerate_pcm_subdevices = TRUE;
        }
#ifdef ALSA_MIDI_ENUMERATE_SUBDEVICES
        alsa_enumerate_midi_subdevices = TRUE;
#endif
    }
}


/* if true (non-zero), ALSA sub devices should be listed as separate devices
 */
int needEnumerateSubdevices(int isMidi) {
    initAlsaSupport();
    return isMidi ? alsa_enumerate_midi_subdevices
                  : alsa_enumerate_pcm_subdevices;
}


/*
 * deviceID contains packed card, device and subdevice numbers
 * each number takes 10 bits
 * "default" device has id == ALSA_DEFAULT_DEVICE_ID
 */
UINT32 encodeDeviceID(int card, int device, int subdevice) {
    return (((card & 0x3FF) << 20) | ((device & 0x3FF) << 10)
           | (subdevice & 0x3FF)) + 1;
}


void decodeDeviceID(UINT32 deviceID, int* card, int* device, int* subdevice,
                    int isMidi) {
    deviceID--;
    *card = (deviceID >> 20) & 0x3FF;
    *device = (deviceID >> 10) & 0x3FF;
    if (needEnumerateSubdevices(isMidi)) {
        *subdevice = deviceID  & 0x3FF;
    } else {
        *subdevice = -1; // ALSA will choose any subdevices
    }
}


void getDeviceString(char* buffer, int card, int device, int subdevice,
                     int usePlugHw, int isMidi) {
    if (needEnumerateSubdevices(isMidi)) {
        sprintf(buffer, "%s:%d,%d,%d",
                        usePlugHw ? ALSA_PLUGHARDWARE : ALSA_HARDWARE,
                        card, device, subdevice);
    } else {
        sprintf(buffer, "%s:%d,%d",
                        usePlugHw ? ALSA_PLUGHARDWARE : ALSA_HARDWARE,
                        card, device);
    }
}


void getDeviceStringFromDeviceID(char* buffer, UINT32 deviceID,
                                 int usePlugHw, int isMidi) {
    int card, device, subdevice;

    if (deviceID == ALSA_DEFAULT_DEVICE_ID) {
        strcpy(buffer, ALSA_DEFAULT_DEVICE_NAME);
    } else {
        decodeDeviceID(deviceID, &card, &device, &subdevice, isMidi);
        getDeviceString(buffer, card, device, subdevice, usePlugHw, isMidi);
    }
}


static int hasGottenALSAVersion = FALSE;
#define ALSAVersionString_LENGTH 200
static char ALSAVersionString[ALSAVersionString_LENGTH];

void getALSAVersion(char* buffer, int len) {
    if (!hasGottenALSAVersion) {
        // get alsa version from proc interface
        FILE* file;
        int curr, len, totalLen, inVersionString;
        file = fopen(ALSA_VERSION_PROC_FILE, "r");
        ALSAVersionString[0] = 0;
        if (file) {
            fgets(ALSAVersionString, ALSAVersionString_LENGTH, file);
            // parse for version number
            totalLen = strlen(ALSAVersionString);
            inVersionString = FALSE;
            len = 0;
            curr = 0;
            while (curr < totalLen) {
                if (!inVersionString) {
                    // is this char the beginning of a version string ?
                    if (ALSAVersionString[curr] >= '0'
                        && ALSAVersionString[curr] <= '9') {
                        inVersionString = TRUE;
                    }
                }
                if (inVersionString) {
                    // the version string ends with white space
                    if (ALSAVersionString[curr] <= 32) {
                        break;
                    }
                    if (curr != len) {
                        // copy this char to the beginning of the string
                        ALSAVersionString[len] = ALSAVersionString[curr];
                    }
                    len++;
                }
                curr++;
            }
            // remove trailing dots
            while ((len > 0) && (ALSAVersionString[len - 1] == '.')) {
                len--;
            }
            // null terminate
            ALSAVersionString[len] = 0;
        }
        hasGottenALSAVersion = TRUE;
    }
    strncpy(buffer, ALSAVersionString, len);
}


/* end */
