//
// anyRemote
// a wi-fi or bluetooth remote for your PC.
//
// Copyright (C) 2006-2016 Mikhail Fedotov <anyremote@mail.ru>
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 3 of the License, or
// (at your option) any later version.
//
// This program 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 for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
//

//
// On OpenWRT size of GLIB package is more than 700kb, what is nearly unacceptable
// for embedded systems. For such systems use custom made wrappers.
//

#include <stdlib.h>
#include <string.h>

#include "str.h"

#ifndef USE_GLIB

////////////////////////////////////////////////////////////////////////////////
//
// Strings
//
////////////////////////////////////////////////////////////////////////////////

#define SZ_MAXSIZE ((size_t) -1)

static inline size_t nearestPower(size_t base, size_t num)
{
    if (num > SZ_MAXSIZE / 2) {
        return SZ_MAXSIZE;
    } else {
        size_t n = base;
        while (n < num) {
            n <<= 1;
        }
        return n;
    }
}

static void stringMaybeExpand (string_t* string, size_t len) 
{
    if (string->len + len >= string->allocated_len) {
        string->allocated_len = nearestPower(1, string->len + len + 1);
        string->str = realloc(string->str, string->allocated_len);
    }
}

string_t* stringAppendLen(string_t *string, const char *val, size_t len)    
{
    stringMaybeExpand(string, len);
    
    strncpy(string->str + string->len, val, len); 
    string->len += len;
    string->str[string->len] = '\0'; 
       
    return string;
}

string_t* stringSizedNew(size_t dfl_size)    
{
    string_t *string = malloc(sizeof(string_t));

    string->allocated_len = 0;
    string->len = 0;
    string->str = NULL;

    stringMaybeExpand(string, MAX_VALUE(dfl_size, 2));
    string->str[0] = '\0';

    return string;
}

string_t* stringNew (const char *init)
{
    string_t *string;

    if (init == NULL || *init == '\0') {
        string = stringSizedNew(2);
    } else {
        size_t len = strlen(init);
        string = stringSizedNew(len + 2);
        stringAppendLen(string, init, len);
    }

    return string;
}

string_t* stringTruncate(string_t *string, size_t len)    
{
    string->len = MIN_VALUE(len, string->len);
    string->str[string->len] = '\0';
    return string;
}

string_t* stringAppend(string_t *string, const char *val)    
{
    if (val == NULL || *val == '\0') {
        return string;
    }
    return stringAppendLen(string, val, strlen(val));
}

string_t* stringAssign(string_t *string, const char *rval)
{
    if (string->str != rval) {
        // Assigning from substring should be ok since stringTruncate does not realloc
        stringTruncate(string, 0);
        stringAppend(string, rval);
    }
    return string;
}

char* stringFree(string_t *string, boolean_t free_segment)
{
    char* tmp = NULL;
    if (free_segment && string) { 
        free(string->str);
    } else {
        tmp = string->str;
    }
    free(string);
    
    return tmp; 
}

boolean_t stringHasPrefix(const char* str, const char* prefix)
{
    int pl = strlen(prefix);

    if (strlen(str) < pl) return BOOL_NO;

    return (strncmp(str, prefix, pl) == 0 ? BOOL_YES : BOOL_NO);
}

#endif
