/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package kanjiflash;

import java.io.*;
import java.nio.charset.Charset;
import java.util.*;

/**
 *
 * @author Alan
 */
public class KanjiLoader {
    ArrayList<Kanji> KanjiTable;
    int size;
    // ASCII character hex equivalents used to decode Kanjidic file
    final int LBRACE = 0x7b;
    final int RBRACE = 0x7d;
    final int U_C =    0x55;
    final int G_C =    0x47;
    final int Q_C =    0x51;
    final int T_C =    0x54;
    final int Y_C =    0x59;
    final int W_C =    0x57;
    final int SPACE =  0x20;
    final int NEW_LINE=0xa;
    final int DASH = 0x2d;
    final int DOT = 0x2e;
    // ASCII numbers to hex equivalent
    final int n0 = 0x30;
    final int n1 = 0x31;
    final int n2 = 0x32;
    final int n3 = 0x33;
    final int n4 = 0x34;
    final int n5 = 0x35;
    final int n6 = 0x36;
    final int n7 = 0x37;
    final int n8 = 0x38;
    final int n9 = 0x39;
    final int nA = 0x41;
    final int nB = 0x42;
    final int nC = 0x43;
    final int nD = 0x44;
    final int nE = 0x45;
    final int nF = 0x46;

    public KanjiLoader(){
        KanjiTable = new ArrayList<Kanji>();
    }
    public ArrayList<Kanji> getKanji(){
        Kanji kj = new Kanji();
        size = 0;
        int UNI;
        String JISCode = "";
        byte[] JISBytes = new byte[2];
        UNI = -1;
        boolean YSet = false; // Chinese reading
        boolean nanoriSet = false; // Proper names
        int newLineStart = 0;
        BufferedInputStream bf = null;
        byte[] data = new byte[1];
        try {
            bf = new BufferedInputStream(   
                    new FileInputStream("C:\\Documents and Settings\\Alan\\My Documents\\NetBeansProjects\\PlayProjects\\KanjiFlash\\src\\kanjiflash\\kanjidic.txt"));
        } catch (FileNotFoundException ef){
            throw new RuntimeException("Input file not found");
//            System.out.println("File not found");
        }
        if (bf != null){
            try {
                data = new byte[bf.available()];
                bf.read(data);
                bf.close();
            } catch (IOException io){
                throw new RuntimeException("Error in format of input file");
//                System.out.println("IOException occurred at 115");
            }    
        } 

        int lineStart = 0;
        for (int i = 0; i < data.length; i++){
            if (data[i] == NEW_LINE){  // End of header line
                lineStart = i+1;
                break;
            }
        }
        int i = lineStart;
        newLineStart = lineStart;
        while (true){
            if (i >= data.length) // end of data
                break;
            if ((data[i] == NEW_LINE) || (i == lineStart)){
                if (i != lineStart){
//                        System.out.print(kj.toString());
                    KanjiTable.add(kj); 
                    newLineStart = i+1;                        
                }
                kj = new Kanji();
                kj.gradeLevel = 13; // Default if no other field found
                YSet = false;  
                nanoriSet = false;
            }  
            if (i == (newLineStart+3)){ // JIS Code for the Kanji bytes 3 - 6
                JISBytes[0] = (byte)((ASCIItoHEX(data[i])<<4) | ASCIItoHEX(data[i+1]));
                JISBytes[1] = (byte)((ASCIItoHEX(data[i+2])<<4) | ASCIItoHEX(data[i+3]));
                JISCode = new String(JISBytes, 0, 2, Charset.forName("x-JIS0208"));
                if (JISCode != null)
                    kj.JISChar = JISCode;
                i += 4;
            }
            if ((data[i] == U_C) && (data[i-1] == SPACE)) { // Unicode field
                int j = i+1;
                UNI = 0;
                UNI = ASCIItoHEX(data[j++])<<12;
                UNI |= ASCIItoHEX(data[j++])<<8;
                UNI |= ASCIItoHEX(data[j++])<<4;
                UNI |= ASCIItoHEX(data[j]);
//                    System.out.println("Unicode field =" + String.format("%x", UNI));
                kj.unicode = UNI;
                i += 4;
            }
            if (((data[i] == Y_C) || (data[i] == W_C) || (data[i] == Q_C)) && (data[i-1] == SPACE))
                YSet = true;
            if ((data[i] == T_C) && (data[i-1] == SPACE))
                nanoriSet = true;               
            if ((data[i] == G_C) && (data[i-1] == SPACE)) { // Grade level
                int grade = (int)ASCIItoHEX(data[i+1]);
                i++;
                if (data[i+1] != SPACE){
                    grade = grade*10 + (int)ASCIItoHEX(data[i+1]);
                    i++;
                }
                kj.gradeLevel = grade;
                i++;
            }
            if ((data[i] == LBRACE) && (data[i-1] == SPACE)){ // English definition
                int j = i+1;
                int charCnt = 0;
                while (true){
                    if (data[j++] == RBRACE)
                        break;
                    else
                        charCnt++;
                } 
                if (charCnt > 0){
                    byte[] engChars = new byte[charCnt];
                    for (int k = 1; k <= charCnt; k++){
                        engChars[k-1] = data[i+k];
                    }
                    String engD = new String(engChars);
                    kj.englishDef.add(engD);
                    i += (charCnt + 1);
                }     
            }
            if (((data[i] & (byte)0x80) == (byte)0x80) /*&& YSet*/ && (data[i-1] == SPACE) /*&& !nanoriSet*/){ // On, Kun readings
                int charCnt = 0;
                int ascCnt = 0;
                int jchrCnt = 0;
                int j = i;
                while (true){
                    if (data[j] == SPACE)
                        break;
                    else {
                        if ((data[j] & (byte)0x80) == (byte)0x80)
                            jchrCnt++;
                        else
                            ascCnt++;
                    }
                    j++;
                }
                charCnt = jchrCnt + ascCnt; 
                int reading = (data[i] & (byte)0x7F)<<8 | (data[i+1] & (byte)0x7F); 
                byte[] JByte = new byte[jchrCnt + ascCnt*2];
                int byteCnt = 0;
                for (int p = i; p < (i+charCnt); p++){
                    if ((data[p] & (byte)0x80) != (byte)0x80){ // special character
                        if (data[p] == DOT){
                            JByte[byteCnt++] = 0x21; // Katakana dot
                            JByte[byteCnt++] = 0x26;
                        }     
                        if (data[p] == DASH){
                            JByte[byteCnt++] = 0x21; // Katakana dash
                            JByte[byteCnt++] = 0x3c;
                        }                                
                    }
                    else {
                        JByte[byteCnt++] = (byte)(data[p] & (byte)0x7F);
                    }     
                }    
                String readStr = new String(JByte, 0, JByte.length, Charset.forName("x-JIS0208"));
                if (nanoriSet)
                    readStr += " (Proper Name)";
//                System.out.println(readStr);
                if ((reading >= 0x2520)){ // katakana
                    kj.onVal.add(readStr);
                }
                else { // Hiragana    
                    kj.kunVal.add(readStr);
                }
                i += charCnt;
            }
            if ((data[i] == DASH) && ((data[i+1] & (byte)0x80) == (byte)0x80) /*&& YSet*/ && (data[i-1] == SPACE) /*&& !nanoriSet*/){ // On, Kun readings
                int charCnt = 0;  // This part covers the case where the reading starts with a dash instead of a Japanese character
                int ascCnt = 0;
                int jchrCnt = 0;
                int j = i;
                while (true){
                    if (data[j] == SPACE)
                        break;
                    else {
                        if ((data[j] & (byte)0x80) == (byte)0x80)
                            jchrCnt++;
                        else
                            ascCnt++;
                    }
                    j++;
                }
                charCnt  = jchrCnt + ascCnt;  
                int reading = ((data[i+1] & (byte)0x7F)<<8) | (data[i+2] & (byte)0x7F); // new stuff
                byte[] JByte = new byte[jchrCnt + ascCnt*2];
                int byteCnt = 0;
                for (int p = i; p < (i+charCnt); p++){
                    if ((data[p] & (byte)0x80) != (byte)0x80){ // special character
                        if (data[p] == DOT){
                            JByte[byteCnt++] = 0x21; // Katakana dot
                            JByte[byteCnt++] = 0x26;
                        }     
                        if (data[p] == DASH){
                            JByte[byteCnt++] = 0x21; // Katakana dash
                            JByte[byteCnt++] = 0x3c;
                        }                                
                    }
                    else {
                        JByte[byteCnt++] = (byte)(data[p] & (byte)0x7F);
                    } 
                }    
                String readStr = new String(JByte, 0, JByte.length, Charset.forName("x-JIS0208"));
                if (nanoriSet)
                    readStr += " (Proper Name)";
                if ((reading >= 0x2520)){ // katakana
                    kj.onVal.add(readStr);
                }
                else { // Hiragana    
                    kj.kunVal.add(readStr);
                }                   
                i += charCnt;
            }               
            i++;
        } 
 
        return KanjiTable;
    }
    public byte ASCIItoHEX(byte ASC){
        if ((ASC >= 0x30) && (ASC <= 0x39))
            return (byte)(ASC - 0x30);
        if ((ASC >= 0x41) && (ASC <= 0x46))
            return (byte)(ASC - 0x37);
        if ((ASC >= 0x61) && (ASC <= 0x66))
            return (byte)(ASC - 0x57);
        return (byte)0;
    }

}
