#include "config.h"
#include "saphire_debug.h"
#include "saphire_kanji.h"
#include "saphire_curses.h"
#include <wctype.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>

char* gKanjiCodeString[5] = {
    "eucjp", "sjis", "utf8", "utf8-mac", "unknown"
};

char* gIconvKanjiCodeName[5] = {
    "eucjp", "sjis", "utf-8", "utf-8-mac", "unknown"
};

//////////////////////////////////////////////////////////////////////
// 初期化
//////////////////////////////////////////////////////////////////////
void kanji_init()
{
}

//////////////////////////////////////////////////////////////////////
// 解放
//////////////////////////////////////////////////////////////////////
void kanji_final()
{
}

//////////////////////////////////////////////////////////////////////
// 引数の文字列が画面で何文字か(範囲指定)
//////////////////////////////////////////////////////////////////////
int str_termlen_range(enum eKanjiCode code, char* mbs, int utfpos1, int utfpos2)
{
    if(code == kUtf8) {
        if(is_utf8_bytes(mbs)) {
            if(utfpos1 < utfpos2) {
                char* putfpos1 = str_kanjipos2pointer(kUtf8, mbs, utfpos1);
                char* putfpos2 = str_kanjipos2pointer(kUtf8, mbs, utfpos2);
                
                char* mbs2 = MALLOC(putfpos2 - putfpos1 + 1);
                memcpy(mbs2, putfpos1, putfpos2 - putfpos1);
                mbs2[putfpos2 - putfpos1] = 0;

                int result = str_termlen(kUtf8, mbs2);
                FREE(mbs2);

                return result;
            }
            else {
                return -1;
            }
        }
        else {
            return strlen(mbs);
        }
    }
    else {
        fprintf(stderr, "not defined kEucjp, kSjis");
        exit(1);
    }
}

//////////////////////////////////////////////////////////////////////
// 文字列がUTF8文字列かどうか
//////////////////////////////////////////////////////////////////////
BOOL is_utf8_bytes(char* mbs)
{
    const int size = (strlen(mbs)+1)*MB_CUR_MAX;
    wchar_t* wcs = (wchar_t*)MALLOC(size);
    char* mbs2 = MALLOC(size);

    if(mbstowcs(wcs, mbs, size) < 0) {
        FREE(wcs);
        FREE(mbs2);
        return FALSE;
    }

    if(wcstombs(mbs2, wcs, size) < 0) {
        FREE(wcs);
        FREE(mbs2);
        return FALSE;
    }

    if(strcmp(mbs, mbs2) == 0) {
        FREE(wcs);
        FREE(mbs2);
        return TRUE;
    }
    else {
        FREE(wcs);
        FREE(mbs2);
        return FALSE;
    }
}

//////////////////////////////////////////////////////////////////////
// mbsを漢字文字列とみたときのpointの場所は何文字目かを返す
//////////////////////////////////////////////////////////////////////
int str_pointer2kanjipos(enum eKanjiCode code, char* mbs, char* point)
{
    if(code == kEucjp || code == kSjis) {
        int result = 0;

        char* p = mbs;
        while(p < point) {
            if(is_kanji(code, *p)) {
                p+=2;
                result++;
            }
            else {
                p++;
                result++;
            }
        }

        return result;
    }
    else {
        char* mbs2;
        int result;

        mbs2 = STRDUP(mbs);
        *(mbs2 + (point-mbs)) = 0;

        result = str_kanjilen(code, mbs2);

        FREE(mbs2);

        return result;
    }
}

//////////////////////////////////////////////////////////////////////
// mbsをsjis,eucjp,UTF文字列と見たときのpos文字目の位置を返す
//////////////////////////////////////////////////////////////////////
char* str_kanjipos2pointer(enum eKanjiCode code, char* mbs, int pos)
{
    if(code == kUtf8) {
        if(pos<0) return mbs;

        char* p = mbs;
        int n = 0;
    
        char* max = mbs + strlen(mbs);
        while(p < max) {
            if(n == pos) {
                return p;
            }
            if(((unsigned char)*p) > 127) {
                int size = ((*p & 0x80) >> 7) + ((*p & 0x40) >> 6) + ((*p & 0x20) >> 5) + ((*p & 0x10) >> 4);
                p+= size;
                n++;
            }
            else {
                p++;
                n++;
            }
/*
            if(gKitutukiSigInt) {
                return NULL;
            }
*/
        }

        return mbs + strlen(mbs);
    }
    else {
        if(pos<0) return mbs;

        char* p = mbs;
        int c = 0;
        char* max = mbs + strlen(mbs);
        while(p < max) {
            if(c==pos) {
                return p;
            }

            if(is_kanji(code, *p)) {
                p+=2;
                c++;
            }
            else {
                p++;
                c++;
            }
        }

        return mbs + strlen(mbs);
    }
}

//////////////////////////////////////////////////////////////////////
// 引数が漢字で何文字か
//////////////////////////////////////////////////////////////////////
int str_kanjilen(enum eKanjiCode code, char* mbs)
{
    if(code == kUtf8) {
        int n = 0;
        char* p = mbs;

        char* max = strlen(mbs) + mbs;
        while(p < max) {
            if(((unsigned char)*p) > 127) {
                int size = ((*p & 0x80) >> 7) + ((*p & 0x40) >> 6) + ((*p & 0x20) >> 5) + ((*p & 0x10) >> 4);
                p+= size;
                n++;
            }
            else {
                p++;
                n++;
            }
/*
if(gKitutukiSigInt) {
    return -1;
}
*/
        }

        return n;
    }
    else {
        int result = 0;
        char* p = mbs;
        while(*p) {
            if(is_kanji(code, *p) && *(p+1) != 0) {
                p+=2;
                result++;
            }
            else {
                p++;
                result++;
            }
        }
        return result;
    }
}

//////////////////////////////////////////////////////////////////////
// 半角文字一文字目かどうか
//////////////////////////////////////////////////////////////////////
int is_hankaku(enum eKanjiCode code, unsigned char c)
{
    if(code == kEucjp)
        return c == 0x8e;
    else
        return 0;
}

//////////////////////////////////////////////////////////////////////
// 漢字一文字目かどうか
//////////////////////////////////////////////////////////////////////
int is_kanji(enum eKanjiCode code, unsigned char c)
{
    if(code == kEucjp) {
        return c >= 0xA1 && c <= 0xFE || c == 0x8e;
//        return c >= 161 && c <= 254;
    }
    else if(code == kSjis) {
        return c >= 0x81 && c <= 0x9f || c >= 0xE0;
    }
    else if(code == kUtf8) {
        return c > 127;
    }

    return 0;
}

//////////////////////////////////////////////////////////////////////
// FALSE:漢字まじり TRUE:全部英数字
//////////////////////////////////////////////////////////////////////
int is_all_ascii(char* buf)
{
    char* p = buf;
    while(*p) {
        if(((unsigned char)*p) > 127) {
            return FALSE;
        }
        p++;
    }

    return TRUE;
}

//////////////////////////////////////////////////////////////////////
// 引数の文字列が画面で何文字か
//////////////////////////////////////////////////////////////////////
int str_termlen(enum eKanjiCode code, char* mbs)
{
    if(code == kUtf8) {
        int result;
        wchar_t* wcs;

        wcs = (wchar_t*)MALLOC(sizeof(wchar_t)*((strlen(mbs)+1)*MB_CUR_MAX));
        if(mbstowcs(wcs, mbs, (strlen(mbs)+1)*MB_CUR_MAX) < 0) {
            FREE(wcs);
            return -1;
        }
        result = wcswidth(wcs, wcslen(wcs));
        FREE(wcs);
        if(result < 0) {
            return strlen(mbs);
        }

        return result;
    }
    else {
        return strlen(mbs);
    }
}

//////////////////////////////////////////////////////////////////////
// 漢字でpos文字目までの端末で何文字か
//////////////////////////////////////////////////////////////////////
int str_termlen2(enum eKanjiCode code, char* mbs, int pos)
{
    if(code == kUtf8) {
        char* mbs2;
        int result;
        char* point;

        mbs2 = STRDUP(mbs);
        point = str_kanjipos2pointer(kUtf8, mbs2, pos);
        if(point == NULL) {
            if(pos < 0) 
                result = -1;
            else
                result = str_termlen(code, mbs2);
        }
        else {
            *(mbs2 + (point-mbs2)) = 0;
            result = str_termlen(code, mbs2);
        }

        FREE(mbs2);

        return result;
    }
    else {
        return pos*2;
    }
}

//////////////////////////////////////////////////////////////////////
// 漢字エンコードの変換。iconvのラッパー
//////////////////////////////////////////////////////////////////////
#if defined(HAVE_ICONV_H)
#include <iconv.h>

#if !defined(__FREEBSD__) && !defined(__SUNOS__)
extern size_t iconv (iconv_t cd, char* * inbuf, size_t *inbytesleft, char* * outbuf, size_t *outbytesleft);
#endif

int kanji_convert(char* input_buf, char* output_buf, size_t output_buf_size, enum eKanjiCode input_kanji_encode_type, enum eKanjiCode output_kanji_encode_type)
{
    iconv_t ic;
    char* ptr_in;
    char* ptr_out;
    const int len = strlen(input_buf);
    size_t result;
    size_t bufsz_in;
    size_t bufsz_out;

    if(strlen(input_buf) == 0) {
        xstrncpy(output_buf, input_buf, output_buf_size);
    }
    else {
        if(is_all_ascii(input_buf)
            || input_kanji_encode_type == output_kanji_encode_type
            || input_kanji_encode_type < 0
            || input_kanji_encode_type >= kUnknown 
            || output_kanji_encode_type < 0
            || output_kanji_encode_type >= kUnknown)
        {
            xstrncpy(output_buf, input_buf, output_buf_size);
            return 0;
        }
        
        ptr_in = input_buf;
        ptr_out = output_buf;
        bufsz_in = (size_t) len;
        bufsz_out = (size_t) output_buf_size;

        ic = iconv_open(gIconvKanjiCodeName[output_kanji_encode_type]
                        , gIconvKanjiCodeName[input_kanji_encode_type]);

#if defined(__FREEBSD__) || defined(__SUNOS__)
        if(iconv(ic, (const char**)&ptr_in, &bufsz_in, &ptr_out, &bufsz_out) < 0
#else
        if(iconv(ic, &ptr_in, &bufsz_in, &ptr_out, &bufsz_out) < 0
#endif
                || len-(int)bufsz_in < len) 
        {
            iconv_close(ic);

            return -1;
        }
        output_buf[output_buf_size - bufsz_out] = 0;

        iconv_close(ic);
    }

    return 0;
}


#endif
