/*
 * oclh_h_ws_base_log.c
 *      Author: havock
 */
#include <time.h>
#include <string.h>
#include <oclh_h_settings.h>
#include <oclh_h_base_clapi_strings.h>
#include <oclh_h_ws_base_log.h>
#include <oclh_hd_std_types.clh>
#include <oclh_h_internals.h>

int32_t __ghf_logWS_MsgIgnoringLock(const _GHT_WRKSET wSet,
                                    const char* const pcLogMsg) {
    time_t timeRaw;
    struct tm* stTime;
    time(&timeRaw);
    stTime=localtime(&timeRaw);
    fprintf(wSet.Log.pfOut,"%04d-%02d-%02d %02d:%02d:%02d ws_0x%04lx %s\n",
            stTime->tm_year+1900,stTime->tm_mon+1,stTime->tm_mday,
            stTime->tm_hour,stTime->tm_min,stTime->tm_sec,
            __GHM_U64STRIPTO2B(wSet.pwSetAddr),pcLogMsg);
#ifdef _GHM_FLUSH_LOGS
    fflush(wSet.Log.pfOut);
#endif /* _GHM_FLUSH_LOGS */
    return(_GHM_OK);
}

int32_t _ghf_logWS_Msg(const _GHT_WRKSET wSet, const char* const pcLogMsg) {
    if(_ghf_isLog_Valid(wSet.Log)) {
        pthread_mutex_lock(wSet.Log.pMtx);
            __ghf_logWS_MsgIgnoringLock(wSet, pcLogMsg);
        pthread_mutex_unlock(wSet.Log.pMtx);
        return(_GHM_OK);
    }
    return(_GHM_NULL_POINTER_RECEIVED_ERROR);
}

int32_t _ghf_logWS_Hdr(const _GHT_WRKSET wSet,const char* const pcLogHdr) {
    char pcLogHdrTop[_GHM_MAXLEN_OF_LOGMSG];
    char pcLogHdrBottom[_GHM_MAXLEN_OF_LOGMSG];
    const size_t len=strlen(pcLogHdr);
    size_t i=0ul;
    for(i=0ul;i<len && i<_GHM_MAXLEN_OF_LOGMSG-2ul;i++) {
        pcLogHdrTop[i]='_'; pcLogHdrBottom[i]='~';
    }
    pcLogHdrTop[i]=pcLogHdrBottom[i]='\0';
    pthread_mutex_lock(wSet.Log.pMtx);
        __ghf_logWS_MsgIgnoringLock(wSet,pcLogHdrTop);
        __ghf_logWS_MsgIgnoringLock(wSet,pcLogHdr);
        __ghf_logWS_MsgIgnoringLock(wSet,pcLogHdrBottom);
    pthread_mutex_unlock(wSet.Log.pMtx);
    return(_GHM_OK);
}

int32_t _ghf_logWS_Delim(const _GHT_WRKSET wSet) {
    pthread_mutex_lock(wSet.Log.pMtx);
        __ghf_logWS_MsgIgnoringLock(wSet,
             "__________________________________________________");
        __ghf_logWS_MsgIgnoringLock(wSet,
             "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
    pthread_mutex_unlock(wSet.Log.pMtx);
    return(_GHM_OK);
}

int32_t _ghf_logWS_Raw(const _GHT_WRKSET wSet, const char* const pcLogMessage) {
    pthread_mutex_lock(wSet.Log.pMtx);
        fprintf(wSet.Log.pfOut,"%s\n",pcLogMessage);
#ifdef _GHM_FLUSH_LOGS
        fflush(wSet.Log.pfOut);
#endif /* _GHM_FLUSH_LOGS */
    pthread_mutex_unlock(wSet.Log.pMtx);
    return(_GHM_OK);
}

int32_t _ghf_logWS_APIErr(const _GHT_WRKSET wSet, const char* const pcAPICall) {
    char pcLogMsg[_GHM_MAXLEN_OF_LOGMSG];
    snprintf(pcLogMsg,_GHM_MAXLEN_OF_LOGMSG,
             "oclerr: %s returned error %d - %s",
             pcAPICall,wSet.APIErr, _ghf_CLAPIErrString(wSet.APIErr));
    _ghf_logWS_Msg(wSet,pcLogMsg);
    return(_GHM_OK);
}

int32_t _ghf_logWS_UsedMem(const _GHT_WRKSET wSet) {
    if(wSet.pszMemBytes) {
        char pcLogMsg[_GHM_MAXLEN_OF_LOGMSG];
        snprintf(pcLogMsg,_GHM_MAXLEN_OF_LOGMSG,
                 "Mem used: %lu B/%.2f KB/%.2f MB/%.2f GB",
                 (*wSet.pszMemBytes),
                 ((flt32_t) *wSet.pszMemBytes)/1024e0f,
                 ((flt32_t) *wSet.pszMemBytes)/1024e0f/1024e0f,
                 ((flt32_t) *wSet.pszMemBytes)/1024e0f/1024e0f/1024e0f);
        _ghf_logWS_Msg(wSet,pcLogMsg);
    }
    return(_GHM_OK);
}

int32_t _ghf_logWS_DevInf_bool(      _GHT_WRKSET    wSet,
                               const cl_device_id   clDev,
                               const cl_device_info InfoVal,
                               const char*    const pcPrefix,
                               const char*    const pcName,
                               const char*    const pcTrue,
                               const char*    const pcFalse) {
    char pcLogMsg[_GHM_MAXLEN_OF_LOGMSG];
    size_t szRes=0ul;
    cl_bool clbInf=0u;
    wSet.APIErr=clGetDeviceInfo(clDev,InfoVal,sizeof(size_t),&clbInf,&szRes);
    if(wSet.APIErr)
        snprintf(pcLogMsg,_GHM_MAXLEN_OF_LOGMSG,
                 "%s %s Undefined! clGetDeviceInfo returned oclerr %s(%d)",
                 pcPrefix?pcPrefix:"",pcName,
                 _ghf_CLAPIErrString(wSet.APIErr),wSet.APIErr);
    else snprintf(pcLogMsg,_GHM_MAXLEN_OF_LOGMSG,
                  "%s %s %s",pcPrefix?pcPrefix:"",pcName,
                  clbInf?pcTrue:pcFalse);
    _ghf_logWS_Msg(wSet,pcLogMsg);
    return(_GHM_OK);
}

int32_t _ghf_logWS_DevInf_charptr(      _GHT_WRKSET    wSet,
                                  const cl_device_id   clDev,
                                  const cl_device_info InfoVal,
                                  const char*    const pcPrefix,
                                  const char*    const pcName,
                                  const char*    const pcPostfix) {
    char pcLogMsg[_GHM_MAXLEN_OF_LOGMSG], *pcInf=NULL;
    size_t szRes=0ul;
    wSet.APIErr=clGetDeviceInfo(clDev, InfoVal, 0ul, NULL, &szRes);
    if(wSet.APIErr) {
        snprintf(pcLogMsg, _GHM_MAXLEN_OF_LOGMSG,
                 "%s %s Undefined! clGetDeviceInfo returned oclerr %s(%d)",
                 pcPrefix?pcPrefix:"", pcName,
                 _ghf_CLAPIErrString(wSet.APIErr), wSet.APIErr);
    } else {
        if(!szRes) {
            if(pcPrefix) snprintf(pcLogMsg, _GHM_MAXLEN_OF_LOGMSG,
                                  "%s %s empty value", pcPrefix, pcName);
            else snprintf(pcLogMsg, _GHM_MAXLEN_OF_LOGMSG,
                          "%s empty value", pcName);
            return(_GHM_OK);
        }
        pcInf=malloc(szRes);
        if(pcInf) {
            wSet.APIErr=clGetDeviceInfo(clDev, InfoVal, szRes, pcInf, NULL);
            if(wSet.APIErr)
                snprintf(pcLogMsg, _GHM_MAXLEN_OF_LOGMSG,
                         "%s %s Undefined! "
                         "clGetDeviceInfo returned oclerr %s(%d)",
                         pcPrefix?pcPrefix:"", pcName,
                         _ghf_CLAPIErrString(wSet.APIErr), wSet.APIErr);
            else {
                pcInf[szRes-1]='\0';
                __ghf_removePreNPostSpacesFromCharPtr(pcInf);
                if(pcPrefix)
                    snprintf(pcLogMsg, _GHM_MAXLEN_OF_LOGMSG, "%s %s %s %s",
                             pcPrefix, pcName, pcInf, pcPostfix?pcPostfix:"" );
                else snprintf(pcLogMsg, _GHM_MAXLEN_OF_LOGMSG,
                              "%s %s", pcName, pcInf);
            }
            if(pcInf) { free(pcInf); pcInf=NULL; }
        } else snprintf(pcLogMsg, _GHM_MAXLEN_OF_LOGMSG,
                        "%s %s Undefined! Host memory allocation failed",
                        pcPrefix?pcPrefix:"", pcName);
    }
    _ghf_logWS_Msg(wSet, pcLogMsg);
    return(_GHM_OK);
}

int32_t _ghf_logWS_DevInf_cluint(      _GHT_WRKSET    wSet,
                                 const cl_device_id   clDev,
                                 const cl_device_info InfoVal,
                                 const char*    const pcPrefix,
                                 const char*    const pcName,
                                 const char*    const pcPostfix) {
    char pcLogMsg[_GHM_MAXLEN_OF_LOGMSG];
    size_t szRes=0ul;
    cl_uint cluInf=0u;
    wSet.APIErr=clGetDeviceInfo(clDev,InfoVal,sizeof(cl_uint),&cluInf,&szRes);
    if(wSet.APIErr)
        snprintf(pcLogMsg ,_GHM_MAXLEN_OF_LOGMSG,
                 "%s %s Undefined! clGetDeviceInfo returned oclerr %s(%d)",
                 pcPrefix?pcPrefix:"", pcName,
                 _ghf_CLAPIErrString(wSet.APIErr), wSet.APIErr);
    else {
        if(!strncmp("bytes",pcPostfix?pcPostfix:"",_GHM_MAXLEN_OF_LOGMSG)) {
            if(pcPrefix)
                snprintf(pcLogMsg,_GHM_MAXLEN_OF_LOGMSG,
                         "%s %s %.2f GiB/%.2f MiB/%.2f KiB/%u bytes",
                         pcPrefix,pcName,
                         ((float)cluInf)/1024e0f/1024e0f/1024e0f,
                         ((float)cluInf)/1024e0f/1024e0f,
                         ((float)cluInf)/1024e0f,cluInf);
            else snprintf(pcLogMsg,_GHM_MAXLEN_OF_LOGMSG,
                         "%s %.2f GiB/%.2f MiB/%.2f KiB/%u bytes",
                         pcName,((float)cluInf)/1024e0f/1024e0f/1024e0f,
                         ((float)cluInf)/1024e0f/1024e0f,
                         ((float)cluInf)/1024e0f,cluInf);
        } else {
            if(pcPrefix)
                snprintf(pcLogMsg, _GHM_MAXLEN_OF_LOGMSG,
                         "%s %s %u %s", pcPrefix, pcName, cluInf,
                         pcPostfix?pcPostfix:"");
            else snprintf(pcLogMsg, _GHM_MAXLEN_OF_LOGMSG,
                          "%s %u %s", pcName, cluInf, pcPostfix?pcPostfix:"");
        }
    }
    _ghf_logWS_Msg(wSet, pcLogMsg);
    return(_GHM_OK);
}

int32_t _ghf_logWS_DevInf_clulong(      _GHT_WRKSET    wSet,
                                  const cl_device_id   clDev,
                                  const cl_device_info InfoVal,
                                  const char*    const pcPrefix,
                                  const char*    const pcName,
                                  const char*    const pcPostfix) {
    char pcLogMsg[_GHM_MAXLEN_OF_LOGMSG];
    size_t szResSize=0ul;
    cl_ulong clulInf=0ul;
    wSet.APIErr=
        clGetDeviceInfo(clDev, InfoVal, sizeof(cl_ulong), &clulInf, &szResSize);
    if(wSet.APIErr)
        snprintf(pcLogMsg, _GHM_MAXLEN_OF_LOGMSG,
                 "%s %s Undefined! clGetDeviceInfo returned oclerr %s(%d)",
                 pcPrefix?pcPrefix:"", pcName,
                 _ghf_CLAPIErrString(wSet.APIErr), wSet.APIErr);
    else {
        if(!strncmp("bytes",pcPostfix?pcPostfix:"",_GHM_MAXLEN_OF_LOGMSG)) {
            if(pcPrefix)
                snprintf(pcLogMsg, _GHM_MAXLEN_OF_LOGMSG,
                         "%s %s %.2f GiB/%.2f MiB/%.2f KiB/%lu bytes",
                         pcPrefix, pcName,
                         ((float) clulInf)/1024e0f/1024e0f/1024e0f,
                         ((float) clulInf)/1024e0f/1024e0f,
                         ((float) clulInf)/1024e0f,clulInf);
            else snprintf(pcLogMsg, _GHM_MAXLEN_OF_LOGMSG,
                          "%s %.2f GiB/%.2f MiB/%.2f KiB/%lu bytes",
                          pcName, ((float) clulInf)/1024e0f/1024e0f/1024e0f,
                          ((float) clulInf)/1024e0f/1024e0f,
                          ((float) clulInf)/1024e0f,clulInf);
        } else {
            if(pcPrefix)
                snprintf(pcLogMsg, _GHM_MAXLEN_OF_LOGMSG,
                         "%s %s %lu %s", pcPrefix, pcName, clulInf,
                         pcPostfix?pcPostfix:"");
            else snprintf(pcLogMsg, _GHM_MAXLEN_OF_LOGMSG,
                          "%s %lu %s", pcName, clulInf, pcPostfix?pcPostfix:"");
        }
    }
    _ghf_logWS_Msg(wSet, pcLogMsg);
    return(_GHM_OK);
}

int32_t _ghf_logWS_DevInf_clulong_as_hex(      _GHT_WRKSET    wSet,
                                         const cl_device_id   clDev,
                                         const cl_device_info InfoVal,
                                         const char*    const pcPrefix,
                                         const char*    const pcName,
                                         const char*    const pcPostfix) {
    char pcLogMsg[_GHM_MAXLEN_OF_LOGMSG];
    size_t szResSize=0ul;
    cl_ulong clulInf=0ul;
    wSet.APIErr=
        clGetDeviceInfo(clDev, InfoVal, sizeof(cl_ulong), &clulInf, &szResSize);
    if(wSet.APIErr)
        snprintf(pcLogMsg, _GHM_MAXLEN_OF_LOGMSG,
                 "%s %s Undefined! clGetDeviceInfo returned oclerr %s(%d)",
                 pcPrefix?pcPrefix:"", pcName,
                 _ghf_CLAPIErrString(wSet.APIErr), wSet.APIErr);
    else {
        if(pcPrefix)
            snprintf(pcLogMsg, _GHM_MAXLEN_OF_LOGMSG,
                         "%s %s 0x%lx %s", pcPrefix, pcName, clulInf,
                         pcPostfix?pcPostfix:"");
            else snprintf(pcLogMsg, _GHM_MAXLEN_OF_LOGMSG,
                          "%s 0x%lx %s", pcName, clulInf,
                          pcPostfix?pcPostfix:"");
    }
    _ghf_logWS_Msg(wSet,pcLogMsg);
    return(_GHM_OK);
}

int32_t _ghf_logWS_DevInf_size(      _GHT_WRKSET    wSet,
                               const cl_device_id   clDev,
                               const cl_device_info InfoVal,
                               const char*    const pcPrefix,
                               const char*    const pcName,
                               const char*    const pcPostfix) {
    char pcLogMsg[_GHM_MAXLEN_OF_LOGMSG];
    size_t szRes=0ul, szInf=0ul;
    wSet.APIErr=clGetDeviceInfo(clDev, InfoVal, sizeof(size_t), &szInf, &szRes);
    if(wSet.APIErr)
        snprintf(pcLogMsg, _GHM_MAXLEN_OF_LOGMSG,
                 "%s %s Undefined! clGetDeviceInfo returned oclerr %s(%d)",
                 pcPrefix?pcPrefix:"", pcName,
                 _ghf_CLAPIErrString(wSet.APIErr), wSet.APIErr);
    else {
        if(!strncmp("bytes",pcPostfix?pcPostfix:"",_GHM_MAXLEN_OF_LOGMSG)) {
            if(pcPrefix)
                snprintf(pcLogMsg, _GHM_MAXLEN_OF_LOGMSG,
                         "%s %s %.2f GiB/%.2f MiB/%.2f KiB/%lu bytes",
                         pcPrefix, pcName,
                         ((float) szInf)/1024e0f/1024e0f/1024e0f,
                         ((float) szInf)/1024e0f/1024e0f,
                         ((float) szInf)/1024e0f,szInf);
            else snprintf(pcLogMsg, _GHM_MAXLEN_OF_LOGMSG,
                          "%s %.2f GiB/%.2f MiB/%.2f KiB/%lu bytes",
                          pcName, ((float) szInf)/1024e0f/1024e0f/1024e0f,
                          ((float) szInf)/1024e0f/1024e0f,
                          ((float) szInf)/1024e0f,szInf);
        } else {
            if(pcPrefix)
                snprintf(pcLogMsg, _GHM_MAXLEN_OF_LOGMSG,
                         "%s %s %lu %s", pcPrefix, pcName, szInf,
                         pcPostfix?pcPostfix:"");
            else snprintf(pcLogMsg, _GHM_MAXLEN_OF_LOGMSG,
                          "%s %lu %s", pcName, szInf, pcPostfix?pcPostfix:"");
        }
    }
    _ghf_logWS_Msg(wSet,pcLogMsg);
    return(_GHM_OK);
}
