/*
 * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
 *
 * This software is dual-licensed to you under the MIT License (MIT) and
 * the Universal Permissive License (UPL). See the LICENSE file in the root
 * directory for license terms. You may choose either license, or both.
 */

#include "util.h"

#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <stdio.h>
#include <ctype.h>
#include <limits.h>

#include "iotcs.h"
#include "iotcs/iotcs_private.h"
#include <math.h>
#include "util/util_memory.h"

#include "log/log.h"
#define IOTCSP_MODULE_LOG_CHANNEL LOG_CHANNEL_UTIL
#include "log/log_template.h"

int util_size_t_to_int(size_t val) {
    return (val <= INT_MAX) ? (int) val : -1;
}

int util_urlencode(const char *src, char *dest, int dest_sz) {
    int size = dest_sz;
    while (*src) {
        if (isalnum((int) *src)) {
            if (dest_sz < 2) { /* print 1 char plus possible '\0' */
                return 0;
            }
            *(dest++) = *src;
            --dest_sz;
        } else {
            if (dest_sz < 4) { /* print 3 char plus possible '\0' */
                return 0;
            }
            if (0 > util_safe_snprintf(dest, dest_sz, "%%%02X", *src)) {
                return 0;
            }
            dest += 3;
            dest_sz -= 3;
        }
        ++src;
    }
    *dest = '\0';
    return size - dest_sz;
}

int util_safe_vsnprintf(char* buf, int buf_length, const char* format, va_list ap) {
    int n;

    n = vsnprintf(buf, buf_length, format, ap);

    if (n < 0) {
        return -1;
    }

    if (n < buf_length) {
        return n;
    }

    return -1;
}

int util_safe_snprintf(char* buf, int buf_length, const char* format, ...) {
    int n;
    va_list ap;

    va_start(ap, format);
    n = vsnprintf(buf, buf_length, format, ap);
    va_end(ap);

    if (n < 0) {
        return -1;
    }

    if (n < buf_length) {
        return n;
    }

    return -1;
}

void util_digest_to_hex(char* hex_buffer, unsigned char* digest, int digest_length) {
    char const hex_chars[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
    int i;

    for (i = 0; i < digest_length; ++i) {
        unsigned char const byte = digest[i];
        hex_buffer[2 * i] = (char) hex_chars[ (byte & 0xF0) >> 4 ];
        hex_buffer[2 * i + 1] = (char) hex_chars[ (byte & 0x0F) >> 0 ];
    }

    hex_buffer[digest_length * 2] = '\0';
}

char* util_get_next_token(char** next, char separator) {
    char* current_ptr = NULL;
    char* prev_ptr = NULL;

    if (!next || separator == '\0' || !*next) {
        return NULL;
    }

    prev_ptr = *next;

    if (NULL == (current_ptr = strchr(prev_ptr, separator))) {
        *next = NULL;
        return prev_ptr;
    }

    *current_ptr++ = '\0';
    *next = current_ptr;

    return prev_ptr;
}

char* util_remove_symbol_from_str(char** str, char separator, int* entry_count) {
    char* current_ptr = NULL;
    char* prev_ptr = NULL;
    int count = 0;

    if (!str || separator == '\0' || !*str) {
        return NULL;
    }

    prev_ptr = *str;

    while (NULL != (current_ptr = strchr(prev_ptr, separator))) {
        memmove(current_ptr, current_ptr + 1, strlen(current_ptr));
        count++;
    }

    *entry_count = count;

    return *str;
}

int util_is_valid_number(float value) {
    if (value != value) {
        LOG_ERRS("Number is NaN");
        return 0;
    }

	//C99
	if (isinf(value) || isinf(-value)) {
	    LOG_ERRS("Number is INFINITY");
	    return 0;
    }

    return 1;
}

char* util_safe_strcpy(const char* source) {
    char* copy = NULL;
    if (!source) {
        return NULL;
    }
    int len = strnlen(source, CL_MAX_STRING_LENGTH);
    copy = (char*) util_malloc(sizeof (char) * (len + 1));
    if (!copy) {
        return NULL;
    } else {
        strncpy(copy, source, len);
        copy[len] = '\0';
        return copy;
    }
}

char* util_safe_strncpy(const char* source, int len) {
    char* copy = NULL;
    if (!source) {
        return NULL;
    }
    copy = (char*) util_malloc(sizeof (char) * (len + 1));
    if (!copy) {
        return NULL;
    } else {
        strncpy(copy, source, len);
        copy[len] = '\0';
        return copy;
    }
}

const char* util_str_null(const char* str) {
    return (!str) ? "" : str;
}
