//
//  memory.c
//  AI003
//
//  Created by 西田　耀 on 13/05/20.
//  Copyright (c) 2013年 Hikaru Nishida. All rights reserved.
//

#include <stdio.h>
#include <stdlib.h>
#include "core.h"

int AI_Memory_AddRootWordData(CHNLIB_String *tag)
{
    //WorkingSet.RootWordListに文字列を追加する。
    //重複がある場合は警告を出し、追加しない。
    //戻り値は追加されたまたは重複したタグのIndex.
    
    return CHNLIB_UIPArray_AppendLast_ProtectFromDuplication(&WorkingSet.RootWordList, 0, tag, &AI_Memory_AddRootWordData_IsDuplicated);
}

int AI_Memory_AddRootWordData_IsDuplicated(const void *listtag, const void *newtag)
{
    //CHNLIB_UIPArray_AppendLast_ProtectFromDuplicationに渡す関数ポインタ。
    if(CHNLIB_StructureHeader_GetTypeID(listtag) != CHNLIB_STRUCT_ID_String){
        return False;
    }
    if(CHNLIB_String_CompareString_Strict(listtag, newtag)){
        //CHNLIB_ReportError("Word[%s] has already existed.", CHNLIB_DEBUG_ARGUMENTS, CHNLIB_String_GetReferencePointerOfCString(newtag));
        return True;
    }
    return False;
}

int AI_Memory_AddRootMemoryData(CHNLIB_UIPArray *tag)
{
    //WorkingSet.RootWordListに文字列を追加する。
    //重複がある場合は警告を出し、追加しない。
    //戻り値は追加されたまたは重複したタグのIndex.
    
    return CHNLIB_UIPArray_AppendLast_ProtectFromDuplication(&WorkingSet.RootMemory, 0, tag, &AI_Memory_AddRootMemoryData_IsDuplicated);
}

int AI_Memory_AddRootMemoryData_IsDuplicated(const void *listtag, const void *newtag)
{
    //CHNLIB_UIPArray_AppendLast_ProtectFromDuplicationに渡す関数ポインタ。
    CHNLIB_UIPArray *listtag_strArray, *newtag_strArray;
    int i, i_max;
    
    if(CHNLIB_StructureHeader_GetTypeID(listtag) != CHNLIB_STRUCT_ID_UIPArray){
        return False;
    }
    
    listtag_strArray = CHNLIB_UIPArray_GetPointerByIndex(listtag, 0);
    newtag_strArray = CHNLIB_UIPArray_GetPointerByIndex(newtag, 0);
    
    i_max = CHNLIB_UIPArray_GetNumberOfDatas(listtag_strArray);
    if(i_max == CHNLIB_UIPArray_GetNumberOfDatas(newtag_strArray)){
        //文字列配列の要素数が一致するので、内容も一致する可能性がある
        for(i = 0; i < i_max; i++){
            if(!CHNLIB_String_CompareString_Strict(CHNLIB_UIPArray_GetPointerByIndex(listtag_strArray, i), CHNLIB_UIPArray_GetPointerByIndex(newtag_strArray, i))){
                //一致しないタグがあったので、不一致
                return False;
            }
        }
        //すべて一致したので、重複している
        return True;
    }
    //文字列配列の要素数が一致しないので、不一致
    return False;
}

//記憶ファイルの構成・書式
//-config.txt
//  一行目に単語リストファイル(words.txt)
//  二行目に記憶データファイル(memory.txt)
//  のファイル名を記述する。
//
//-words.txt
//<単語カウント>:<単語文字列>
//
//-memory.txt
//[<文字列単語>+<文字列単語>+...][<属性値1>,<属性値2>,...][<属性値a>,<属性値b>,...]
//
//
void AI_System_LoadMemory(const char configfilename[])
{
    //指定されたファイル名のテキストファイルから設定を読み出す。
    FILE *configfp, *readfp;
    CHNLIB_String *line, *currentfilename;
    uint wordCount;
    char *invchar;
    int tagIndex, i, i_max;
    CHNLIB_UIPArray *separated, *dataArray, *subDataArray;
    
    configfp = fopen(configfilename, "rb");
    
    //単語リストの読み込み
    currentfilename = CHNLIB_ReadLine(configfp);
    readfp = fopen(CHNLIB_String_GetReferencePointerOfCString(currentfilename), "rb");
    release(currentfilename);
    
    for(;;){
        line = CHNLIB_ReadLine(readfp);
        if(line == NULL){
            break;
        }
        wordCount = (uint)strtol(CHNLIB_String_GetReferencePointerOfCString(line), &invchar, 0);
        for(; *invchar != '\0'; invchar++){
            if(*invchar == ':'){
                invchar++;
                break;
            }
        }
        tagIndex = AI_Memory_AddRootWordData(autorelease(CHNLIB_String_Initialize(invchar)));
        CHNLIB_UIPArray_SetData32ByIndex(WorkingSet.RootWordList, tagIndex, CHNLIB_UIPArray_GetData32ByIndex(WorkingSet.RootWordList, tagIndex) + wordCount);
        release(line);
    }
    fclose(readfp);
    
    //記憶データの読み込み
    currentfilename = CHNLIB_ReadLine(configfp);
    readfp = fopen(CHNLIB_String_GetReferencePointerOfCString(currentfilename), "rb");
    release(currentfilename);
    
    for(;;){
        line = CHNLIB_ReadLine(readfp);
        if(line == NULL){
            break;
        }
        separated = CHNLIB_UIPArray_Initialize();
        CHNLIB_UIPArray_GetSeparatedStringByUIPArray(&separated, WorkingSet.SystemWordList0, line);
        
        dataArray = CHNLIB_UIPArray_Initialize();
        subDataArray = CHNLIB_UIPArray_Initialize();
        
        i_max = CHNLIB_UIPArray_GetNumberOfDatas(separated);
        for(i = 0; i < i_max; i++){
            switch (CHNLIB_UIPArray_GetData32ByIndex(separated, i)) {
                case AI_SW_Delimiter_Colon:
                    //:
                    break;
                    
                case AI_SW_Delimiter_Comma:
                    //,
                    break;
                    
                case AI_SW_Delimiter_Plus:
                    //+
                    break;
                    
                case AI_SW_Bracket_Start:
                    //[
                    subDataArray = CHNLIB_UIPArray_Initialize();
                    break;
                    
                case AI_SW_Bracket_End:
                    //]
                    CHNLIB_UIPArray_AppendLast(&dataArray, 0, subDataArray);
                    release(subDataArray);
                    break;
                    
                case 0:
                    //文字列
                    tagIndex = AI_Memory_AddRootWordData(CHNLIB_UIPArray_GetPointerByIndex(separated, i));
                    CHNLIB_UIPArray_AppendLast(&subDataArray, 0, CHNLIB_UIPArray_GetPointerByIndex(WorkingSet.RootWordList, tagIndex));
                    
                    break;
            }
        }
        if(dataArray != NULL){
            AI_Memory_AddRootMemoryData(dataArray);
            release(dataArray);
        }
        release(separated);
        release(line);
    }
    fclose(readfp);
    
    //終了処理
    fclose(configfp);
    
    return;
}

void AI_System_SaveMemory_RootWordList(const char wordlistfilename[])
{
    //指定されたファイル名へ単語リストを出力する。
    FILE *writefp;
    CHNLIB_UIPArray *sorted;
    int i, i_max;
    
    writefp = fopen(wordlistfilename, "wb");
    if(writefp == NULL){
        puts("File open error.");
    } else{
        sorted = CHNLIB_UIPArray_GetSortedInDescendingOrderByData32(WorkingSet.RootWordList);
        i_max = CHNLIB_UIPArray_GetNumberOfDatas(sorted);
        for(i = 0; i < i_max; i++){
            fprintf(writefp, "%10d:%s\n", CHNLIB_UIPArray_GetData32ByIndex(sorted, i), CHNLIB_String_GetReferencePointerOfCString(CHNLIB_UIPArray_GetPointerByIndex(sorted, i)));
        }
        fclose(writefp);
        writefp = NULL;
        release(sorted);
        puts("Save RootWordList done.");
    }
    
    return;
}

void AI_System_SaveMemory_RootMemory(const char memlistfilename[])
{
    //指定されたファイル名へ記憶データを出力する。
    FILE *writefp;
    CHNLIB_UIPArray *subArray;
    int i, i_max;
    int j, j_max;
    int k, k_max;
    
    writefp = fopen(memlistfilename, "wb");
    if(writefp == NULL){
        puts("File open error.");
    } else{
        i_max = CHNLIB_UIPArray_GetNumberOfDatas(WorkingSet.RootMemory);
        for(i = 0; i < i_max; i++){
            subArray = CHNLIB_UIPArray_GetPointerByIndex(CHNLIB_UIPArray_GetPointerByIndex(WorkingSet.RootMemory, i), 0);
            j_max = CHNLIB_UIPArray_GetNumberOfDatas(subArray);
            fputc('[', writefp);
            for(j = 0; j < j_max - 1; j++){
                fprintf(writefp, "%s+", CHNLIB_String_GetReferencePointerOfCString(CHNLIB_UIPArray_GetPointerByIndex(subArray, j)));
            }
            fprintf(writefp, "%s]", CHNLIB_String_GetReferencePointerOfCString(CHNLIB_UIPArray_GetPointerByIndex(subArray, j)));
            
            k_max = CHNLIB_UIPArray_GetNumberOfDatas(CHNLIB_UIPArray_GetPointerByIndex(WorkingSet.RootMemory, i));
            for(k = 1; k < k_max; k++){
                subArray = CHNLIB_UIPArray_GetPointerByIndex(CHNLIB_UIPArray_GetPointerByIndex(WorkingSet.RootMemory, i), k);
                j_max = CHNLIB_UIPArray_GetNumberOfDatas(subArray);
                fputc('[', writefp);
                for(j = 0; j < j_max - 1; j++){
                    fprintf(writefp, "%s,", CHNLIB_String_GetReferencePointerOfCString(CHNLIB_UIPArray_GetPointerByIndex(subArray, j)));
                }
                fprintf(writefp, "%s]", CHNLIB_String_GetReferencePointerOfCString(CHNLIB_UIPArray_GetPointerByIndex(subArray, j)));
            }
            fputc('\n', writefp);
        }
        fclose(writefp);
        writefp = NULL;
        puts("Save RootMemory done.");
    }
    
    return;
}
