/* UtilLib - Copyright (c) 2014 Vincent Calame - Exemole
 * Logiciel libre donné sous triple licence :
 * 1) selon les termes de la CeCILL V2
 * 2) selon les termes de l’EUPL V.1.1
 * 3) selon les termes de la GNU GPLv3
 * Voir le fichier licences.txt
 */


package net.mapeadores.util.localisation;

import java.io.Serializable;
import java.text.ParseException;
import java.util.HashMap;
import java.util.Map;


/**
 * Suivant l'iso15924 qui décrit les écritures possibles, codées sur quatre
 * lettres. Voir http://www.unicode.org/iso15924/iso15924-codes.html
 *
 * @author Vincent Calame
 */
public final class LangScript implements Serializable, Comparable<LangScript> {

    private static final long serialVersionUID = 1L;
    private final static Map<String, LangScript> langScriptMap = new HashMap<String, LangScript>();

    private final String code;

    private LangScript(String code) {
        this.code = code;
    }

    @Override
    public int hashCode() {
        return code.hashCode();
    }

    @Override
    public boolean equals(Object other) {
        if (other == null) {
            return false;
        }
        if (other == this) {
            return true;
        }
        if (other.getClass() != this.getClass()) {
            return false;
        }
        LangScript otherLangScript = (LangScript) other;
        return otherLangScript.code.equals(this.code);
    }

    @Override
    public String toString() {
        return code;
    }

    @Override
    public int compareTo(LangScript otherLangScript) {
        return this.code.compareTo(otherLangScript.code);
    }

    public boolean isRTLScript() {
        if (code.equals("Arab")) {
            return true;
        } else if (code.equals("Aran")) {
            return true;
        } else if (code.equals("Hebr")) {
            return true;
        } else {
            return false;
        }
    }

    public static LangScript build(String langScriptCode) {
        try {
            return parse(langScriptCode);
        } catch (ParseException pe) {
            throw new IllegalArgumentException(pe.getMessage());
        }
    }

    public static LangScript parse(String langScriptCode) throws ParseException {
        if (langScriptCode == null) {
            throw new ParseException("null", 0);
        }
        LangScript langScript = langScriptMap.get(langScriptCode);
        if (langScript != null) {
            return langScript;
        }
        synchronized (langScriptMap) {
            int length = langScriptCode.length();
            if (length == 4) {
                langScriptCode = normalize(langScriptCode);
                langScript = langScriptMap.get(langScriptCode);
                if (langScript != null) {
                    return langScript;
                }
                if (!testUpperCase(langScriptCode.charAt(0))) {
                    throw new ParseException("wrong char: " + langScriptCode.charAt(0), 0);
                }
                if (!testLowerCase(langScriptCode.charAt(1))) {
                    throw new ParseException("wrong char: " + langScriptCode.charAt(1), 1);
                }
                if (!testLowerCase(langScriptCode.charAt(2))) {
                    throw new ParseException("wrong char: " + langScriptCode.charAt(2), 2);
                }
                if (!testLowerCase(langScriptCode.charAt(3))) {
                    throw new ParseException("wrong char: " + langScriptCode.charAt(3), 3);
                }
                langScript = new LangScript(langScriptCode);
                langScriptMap.put(langScriptCode, langScript);
                return langScript;
            } else if (length == 0) {
                throw new ParseException("empty", 0);
            } else if (length < 4) {
                throw new ParseException("length < 4", 0);
            } else {
                throw new ParseException("length > 2", 2);
            }
        }
    }

    private static String normalize(String langScriptCode) {
        StringBuilder buf = new StringBuilder();
        buf.append(Character.toUpperCase(langScriptCode.charAt(0)));
        for (int i = 1; i < 4; i++) {
            buf.append(Character.toLowerCase(langScriptCode.charAt(i)));
        }
        return buf.toString();
    }

    private static boolean testUpperCase(char carac) {
        return ((carac >= 'A') && (carac <= 'Z'));
    }

    private static boolean testLowerCase(char carac) {
        return ((carac >= 'a') && (carac <= 'z'));
    }
}
