//
//  chnlib02.c
//  AI003
//
//  Created by 西田　耀 on 13/02/09.
//  Copyright (c) 2013年 Hikaru Nishida. All rights reserved.
//

//複数の種類の関数に依存する関数群

//
//Include headers
//

#include <stdio.h>
#include "chnlib.h"

//
//Functions
//

int CHNLIB_String_Search_UIPArrayStringLocation(const CHNLIB_String *s, int s_start, const CHNLIB_UIPArray *list, int *location)
{
    //文字列&s[s_start]に含まれている中で最も左側にある、Array内のStringタグの文字列のArrayにおける添字と、その文字列が開始する、文字列&s[s_start]中の添字を返す。
    //locaton!=NULLの時、*locationに、発見された文字列の最初のバイトの&s[s_start]における添字が代入される。
    //Arrayの文字列がすべて見つからなかった場合、AI_ARRAY_INDEX_NOTFOUNDを返す。そのときの*locatonには0が代入される。
    int i, i_max, j, j_max;
    CHNLIB_String *tag;
    const char *cstr_s;
    
    if(s == NULL || list == NULL){
        if(location != NULL){
            *location = 0;
        }
        return CHNLIB_UIPArray_INDEX_NOTFOUND;
    }
    cstr_s = CHNLIB_String_GetReferencePointerOfCString(s);
    i_max = CHNLIB_CString_GetByteLength(cstr_s);
    
    j_max = CHNLIB_UIPArray_GetNumberOfDatas(list);
    for(i = s_start; i < i_max; i++){
        for(j = 0; j < j_max; j++){
            tag = (CHNLIB_String *)CHNLIB_UIPArray_GetPointerByIndex(list, j);
            if(CHNLIB_StructureHeader_GetTypeID(tag) == CHNLIB_STRUCT_ID_String){
                if(CHNLIB_CString_CompareString(&cstr_s[i], CHNLIB_String_GetReferencePointerOfCString(tag))){
                    if(location != NULL){
                        *location = i - s_start;
                    }
                    return j;
                }
            }
        }
    }
    
    if(location != NULL){
        *location = 0;
    }
    return CHNLIB_UIPArray_INDEX_NOTFOUND;
}

int CHNLIB_UIPArray_GetSeparatedStringByUIPArray(CHNLIB_UIPArray **separated, const CHNLIB_UIPArray *list, const CHNLIB_String *s)
{
    //listにある文字列でsを分割し、その結果をseparatedに追加する。
    //listに存在する文字列は新しくメモリを確保せず、リスト中のStringタグへのポインタをseparatedに記録する。
    ////従ってseparatedを解放する際は、listのdata32をすべてTrueにした上で、CHNLIB_UIPArray_FreeSelectedAllを利用するべきである。
    //referenceCountは、list中の文字列は2以上になり、listにない文字列は1となる。
    //従って、separatedをreleaseすれば、安全に解放できる。
    //listにない文字列はdata32==False(0)
    //listにある文字列はdata32==tag->data32
    int index, end, end_end, location;
    
    if(s == NULL){
        return 1;
    }
   
    end = 0;
    end_end = CHNLIB_String_GetLength(s);
    for(;;){
        index = CHNLIB_String_Search_UIPArrayStringLocation(s, end, list, &location);
        if(index == CHNLIB_UIPArray_INDEX_NOTFOUND){
            //もうリストの文字列はない
            if(end != end_end){
                //でもまだ文字列は残っている
                CHNLIB_UIPArray_AppendLast(separated, False, autorelease(CHNLIB_String_ExtractByLength(s, end, CHNLIB_MAX_STRING_LENGTH)));
            }
            break;
        }
        //リストの文字列が見つかった
        if(location != 0){
            //リストの文字列の前に、リストにない文字列がある
            CHNLIB_UIPArray_AppendLast(separated, False, autorelease(CHNLIB_String_ExtractByLength(s, end, location)));
            end += location;
        }
        CHNLIB_UIPArray_AppendLast(separated, CHNLIB_UIPArray_GetData32ByIndex(list, index), CHNLIB_UIPArray_GetPointerByIndex(list, index));
        end += CHNLIB_String_GetLength(CHNLIB_UIPArray_GetPointerByIndex(list, index));
    }
    return 0;
}

int CHNLIB_UIPArray_GetSeparatedUTF8Character(CHNLIB_UIPArray **separated, const CHNLIB_String *s)
{
    //[UTF-8]
    //文字列sを、UTF-8の一文字ごとに分割し、その文字のUnicodeをdata32、その一文字に該当するStringをpointerに格納し、separatedに追加する形で返す。
    //不完全なUTF-8文字列は無視される。
    const char *p, *q, *p_base;
    uint u;
    
    if(separated == NULL || CHNLIB_StructureHeader_GetTypeID(s) != CHNLIB_STRUCT_ID_String){
        return 1;
    }
    
    p_base = CHNLIB_String_GetReferencePointerOfCString(s);;
    p = p_base;
    
    for(;;){
        u = CHNLIB_UTF8_GetNextUnicodeOfCharacter(p, &q);
        if(u == 0){
            //終端文字
            break;
        }
        CHNLIB_UIPArray_AppendLast(separated, u, autorelease(CHNLIB_String_ExtractByLength(s, (int)(p - p_base), (int)(q - p))));
        p = q;
    }
    
    return 0;
}

CHNLIB_String *CHNLIB_ReadLine(FILE *fp)
{
    //改行文字を削除して、読み込んだ文字列一行を返す。
    char s[CHNLIB_MAX_STRING_LENGTH];
    
    if(fgets(s, sizeof(s), fp) == NULL){
        return NULL;
    }
    
    CHNLIB_CString_DeleteLastCRLF(s);
    
    return CHNLIB_String_Initialize(s);
}

CHNLIB_UUID *CHNLIB_GenerateUUIDVersion4WithRandomGeneratorMT(CHNLIB_RandomGeneratorMT *mt)
{
    //mtが有効でない場合、NullUUIDを返す。
    CHNLIB_UUID *uuid;
    
    uuid = CHNLIB_UUID_Initialise();
    
    if(CHNLIB_StructureHeader_GetTypeID(mt) != CHNLIB_STRUCT_ID_RandomGeneratorMT){
        return uuid;
    }
    
    CHNLIB_UUID_SetValueAsUUIDVersion4CompatibleWithRFC4122(uuid, CHNLIB_RandomGeneratorMT_GetRandomUnsignedInteger32(mt), CHNLIB_RandomGeneratorMT_GetRandomUnsignedInteger32(mt), CHNLIB_RandomGeneratorMT_GetRandomUnsignedInteger32(mt), CHNLIB_RandomGeneratorMT_GetRandomUnsignedInteger32(mt));
    
    return uuid;
}

