#include <string.h>
#include <ctype.h>
#include "config.h"
#include "saphire_string.h"
#include "saphire_debug.h"

//////////////////////////////////////////////////////////////////////
// 初期化
//////////////////////////////////////////////////////////////////////
#ifdef MDEBUG
string_obj* string_new_debug(char* str, const char* fname, int line, const char* func_name)
{
    string_obj* self;

    const int len = strlen(str);
    
    self = (string_obj*)CheckMemLeak_Malloc(sizeof(string_obj), fname, line
                                                , func_name);
    
    self->mMallocLen = (len < 128) ? 128 : (len + 1) * 2;
    self->mStr = (char*)MALLOC(sizeof(char)*self->mMallocLen);
    xstrncpy(self->mStr, str, self->mMallocLen);
    
    self->mLen = len;

    return self;
}
#else
string_obj* string_new(char* str)
{
    string_obj* self;
    const int len = strlen(str);
    
    self = (string_obj*)MALLOC(sizeof(string_obj));
    
    self->mMallocLen = (len < 128) ? 128 : (len + 1) * 2;
    self->mStr = (char*)MALLOC(sizeof(char)*self->mMallocLen);
    xstrncpy(self->mStr, str, self->mMallocLen);
    
    self->mLen = len;

    return self;
}
#endif

//////////////////////////////////////////////////////////////////////
// 解放
//////////////////////////////////////////////////////////////////////
void string_delete(string_obj* self)
{
    FREE(self->mStr);
    
    FREE(self);
}

//////////////////////////////////////////////////////////////////////
// 文字列をposの位置に追加
//////////////////////////////////////////////////////////////////////
void string_insert(string_obj* obj, int pos, char* str)
{
    char* new_str;
    char* tmp_str;
    const int str_len = strlen(str);

    if(pos <= obj->mLen) {
        if(obj->mLen+str_len+1 > obj->mMallocLen) {
            obj->mMallocLen = (obj->mLen + str_len + 1) * 2;
            new_str = (char*)MALLOC(obj->mMallocLen);

            memcpy(new_str, obj->mStr, pos);
            memcpy(new_str + pos, str, str_len);
            strcpy(new_str + pos + str_len, obj->mStr + pos);

            FREE(obj->mStr);

            obj->mStr = new_str;
            obj->mLen = strlen(new_str);
        }
        else {
            tmp_str = (char*)MALLOC(obj->mMallocLen);

            memcpy(tmp_str, obj->mStr, pos);
            memcpy(tmp_str + pos, str, str_len);
            strcpy(tmp_str + pos + str_len, obj->mStr + pos);

            strcpy(obj->mStr, tmp_str);
    
            FREE(tmp_str);
    
            obj->mLen = strlen(obj->mStr);
        }
    }
}

//////////////////////////////////////////////////////////////////////
// 後ろから文字列を追加
//////////////////////////////////////////////////////////////////////
void string_push_back(string_obj* self, char* str)
{
    char* new_str;
    const int str_len = strlen(str);

    if(self->mLen + str_len < self->mMallocLen) {
        strcat(self->mStr, str);
        self->mLen += str_len;
    }
    else {
        self->mMallocLen = (self->mLen + str_len + 1) * 2;
        new_str = (char*)MALLOC(self->mMallocLen);

        strcpy(new_str, self->mStr);
        strcat(new_str, str);

        FREE(self->mStr);

        self->mStr = new_str;
        self->mLen = self->mLen + str_len;
    }
}

//////////////////////////////////////////////////////////////////////
// 後ろから文字列を追加
//////////////////////////////////////////////////////////////////////
void string_push_back2(string_obj* self, char c)
{
    char* new_str;

    if(self->mLen + 1 < self->mMallocLen) {
        self->mStr[self->mLen] = c;
        self->mStr[self->mLen + 1] = 0;
        self->mLen++;
    }
    else {
        self->mMallocLen = (self->mLen + 1) * 2;
        new_str = (char*)MALLOC(self->mMallocLen);

        strcpy(new_str, self->mStr);
        new_str[self->mLen] = c;
        new_str[self->mLen + 1] = 0;

        FREE(self->mStr);

        self->mStr = new_str;
        self->mLen++;
    }
}

//////////////////////////////////////////////////////////////////////
// 後ろから文字列を追加
//////////////////////////////////////////////////////////////////////
void string_push_back3(string_obj* self, char* str, int n)
{
    char* new_str;
    char* tmp_str;
    const int str_len = strlen(str);

    if(n > str_len) {
        n = str_len;
    }

    if(self->mLen+n+1 > self->mMallocLen) {
        self->mMallocLen = (self->mLen + n + 1) * 2;
        new_str = (char*)MALLOC(self->mMallocLen);

        int len = strlen(self->mStr);

        strcpy(new_str, self->mStr);
        memcpy(new_str + len, str, n);
        new_str[len + n] = 0;

        FREE(self->mStr);

        self->mStr = new_str;
        self->mLen = strlen(new_str);
    }
    else {
        int len = strlen(self->mStr);
        memcpy(self->mStr + len, str, n);
        (self->mStr)[len + n] = 0;

        self->mLen = strlen(self->mStr);
    }
}

//////////////////////////////////////////////////////////////////////
// 文字列をposの位置からlenだけ削除
//////////////////////////////////////////////////////////////////////
void string_erase(string_obj* obj, int pos, int len)
{
    if(pos == 0 && len == obj->mLen) {
        string_put(obj, "");
    }
    else if(len > 0 && pos>=0 && pos<obj->mLen && pos+len <= obj->mLen) {
        memmove(obj->mStr + pos, obj->mStr+pos+len, obj->mLen-pos-len+1);

        obj->mLen-=len;
    }
}

//////////////////////////////////////////////////////////////////////
// 文字列を代入
//////////////////////////////////////////////////////////////////////
void string_put(string_obj* self, char* str)
{
    const int len = strlen(str);

    if(len+1 < self->mMallocLen) {
        strcpy(self->mStr, str);
        self->mLen = len;
    }
    else {
        FREE(self->mStr);
        
        self->mMallocLen = (len < 16) ? 16 : (len + 1) * 2;
        self->mStr = (char*)MALLOC(sizeof(char)*self->mMallocLen);
       
        strcpy(self->mStr, str);
        self->mLen = len;
    }
}

//////////////////////////////////////////////////////////////////////
// 文字列を代入
//////////////////////////////////////////////////////////////////////
void string_put2(string_obj* self, char c)
{
    if(self->mMallocLen > 1) {
        self->mStr[0] = c;
        self->mStr[1] = 0;
        self->mLen = 1;
    }
    else {
        FREE(self->mStr);
        
        self->mMallocLen = 16;
        self->mStr = (char*)MALLOC(sizeof(char)*self->mMallocLen);
        
        self->mStr[0] = c;
        self->mStr[1] = 0;
        self->mLen = 1;
    }
}

//////////////////////////////////////////////////////////////////////
// 文字列を短くする
//////////////////////////////////////////////////////////////////////
void string_trunc(string_obj* self, int n)
{
    if(n < strlen(self->mStr)) {
        self->mStr[n] = 0;
        self->mLen = strlen(self->mStr);
    }
}


//////////////////////////////////////////////////////////////////////////
// 部分文字列を得る
//////////////////////////////////////////////////////////////////////////
BOOL string_sub_str(string_obj* self, string_obj* result, int index1, int index2, enum eKanjiCode code)
{
/*
    if(index1 < 0 || index1 >= self->mLen 
            || index2 < 0 || index2 >= self->mLen || index2 < index1) 
    {
        return FALSE;
    }

    if(code == kUtf8) {
        char* pos1 = str_utfpos2pointer(self->mStr, index1);
        char* pos2 = str_utfpos2pointer(self->mStr, index2);
        char* tmp = MALLOC(pos2 - pos1 + 1);
        memcpy(tmp, pos1, pos2-pos1);
        tmp[pos2-pos1] = 0;

        string_put(result, tmp);

        FREE(tmp);

        return TRUE;
    }
    else {
        char* pos1 = str_eucsjispos2pointer(self->mStr, index1);
        char* pos2 = str_eucsjispos2pointer(self->mStr, index1);
        char* tmp = MALLOC(pos2 - pos1 + 1);
        memcpy(tmp, pos1, pos2-pos1);
        tmp[pos2-pos1] = 0;

        string_put(result, tmp);

        FREE(tmp);

        return TRUE;
    }
*/
}


//////////////////////////////////////////////////////////////////////////
// 文字を小文字にする
//////////////////////////////////////////////////////////////////////////
void string_tolower(string_obj* self, enum eKanjiCode code)
{
    if(code == kSjis || code == kEucjp) {
        int i;
        for(i=0; i<self->mLen; i++) {
            if(is_kanji(code, self->mStr[i])) {
                self->mStr[i] = self->mStr[i];
                self->mStr[i+1] = self->mStr[i+1];
                i++;
            }
            else {
                self->mStr[i] = tolower(self->mStr[i]);
            }
        }
    }
    else {
        int i;
        for(i=0; i<self->mLen; i++) {
            self->mStr[i] = tolower(self->mStr[i]);
        }
    }
}

//////////////////////////////////////////////////////////////////////////
// 文字を大文字にする
//////////////////////////////////////////////////////////////////////////
void string_toupper(string_obj* self, enum eKanjiCode code)
{
    if(code == kSjis || code == kEucjp) {
        int i;
        for(i=0; i<self->mLen; i++) {
            if(is_kanji(code, self->mStr[i])) {
                self->mStr[i] = self->mStr[i];
                self->mStr[i+1] = self->mStr[i+1];
                i++;
            }
            else {
                self->mStr[i] = toupper(self->mStr[i]);
            }
        }
    }
    else {
        int i;
        for(i=0; i<self->mLen; i++) {
            self->mStr[i] = toupper(self->mStr[i]);
        }
    }
}
