package com.cybozu.labs.langdetect;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;

import com.cybozu.labs.langdetect.util.LangProfile;
import com.rmtheis.langdetect.profile.*;

/**
 * Language Detector Factory Class
 * 
 * This class manages an initialization and constructions of {@link Detector}. 
 * 
 * Before using language detection library, 
 * load profiles with {@link DetectorFactory#loadProfile(String)} method
 * and set initialization parameters.
 * 
 * When the language detection,
 * construct Detector instance via {@link DetectorFactory#create()}.
 * See also {@link Detector}'s sample code.
 * 
 * <ul>
 * <li>4x faster improvement based on Elmer Garduno's code. Thanks!</li>
 * </ul>
 * 
 * @see Detector
 * @author Nakatani Shuyo
 */
public class LinusDetectorFactory {
    public HashMap<String, double[]> wordLangProbMap;
    public ArrayList<String> langlist;
    private static List<LangProfile> profilelist;
    private static boolean isProfileListLoaded = false;
    public Long seed = null;
    
    private LinusDetectorFactory() {
        wordLangProbMap = new HashMap<String, double[]>();        
        langlist = new ArrayList<String>();
        profilelist = Arrays.asList(
                new AR().getLangProfile(),
                new BG().getLangProfile(),
                new CA().getLangProfile(),
                new CS().getLangProfile(),
                new DA().getLangProfile(),
                new DE().getLangProfile(),
                new EN().getLangProfile(),
                new ES().getLangProfile(),
                new ET().getLangProfile(),
                new FI().getLangProfile(),
                new FR().getLangProfile(),
                new HE().getLangProfile(),
                new HR().getLangProfile(),
                new HU().getLangProfile(),
                new ID().getLangProfile(),
                new IT().getLangProfile(),
                new JA().getLangProfile(),
                new KO().getLangProfile(),
                new MK().getLangProfile(),
                new NL().getLangProfile(),
                new NO().getLangProfile(),
                new PA().getLangProfile(),
                new PL().getLangProfile(),
                new PT().getLangProfile(),
                new RO().getLangProfile(),
                new RU().getLangProfile(),
                new SQ().getLangProfile(),
                new SV().getLangProfile(),
                new TL().getLangProfile(),
                new TR().getLangProfile(),
                new UK().getLangProfile(),
                new VI().getLangProfile(),
                new ZHCN().getLangProfile()
        ); 
    }
    static private LinusDetectorFactory instance_ = new LinusDetectorFactory();

    public static void loadProfile(List<LangProfile> profiles) {
      int index = 0;
      int langsize = profiles.size();
      for (LangProfile profile: profiles) {
        addProfile(profile, index, langsize);
        ++index;
      }
    }

    /**
     * @param profile
     * @param langsize 
     * @param index 
     * @throws LangDetectException 
     */
    static /* package scope */ void addProfile(LangProfile profile, int index, int langsize) {
        String lang = profile.name;
        instance_.langlist.add(lang);
        for (String word: profile.freq.keySet()) {
            if (!instance_.wordLangProbMap.containsKey(word)) {
                instance_.wordLangProbMap.put(word, new double[langsize]);
            }
            int length = word.length();
            if (length >= 1 && length <= 3) {
                double prob = profile.freq.get(word).doubleValue() / profile.n_words[length - 1];
                instance_.wordLangProbMap.get(word)[index] = prob;
            }
        }
    }

    /**
     * Clear loaded language profiles (reinitialization to be available)
     */
    static public void clear() {
        instance_.langlist.clear();
        instance_.wordLangProbMap.clear();
    }

    /**
     * Construct Detector instance
     * 
     * @return Detector instance
     * @throws LangDetectException 
     */
    static public LinusDetector create() {
        return createDetector();
    }

    /**
     * Construct Detector instance with smoothing parameter 
     * 
     * @param alpha smoothing parameter (default value = 0.5)
     * @return Detector instance
     * @throws LangDetectException 
     */
    public static LinusDetector create(double alpha) throws LangDetectException {
        LinusDetector detector = createDetector();
        detector.setAlpha(alpha);
        return detector;
    }

    static private LinusDetector createDetector() {
        LinusDetector detector = new LinusDetector(instance_);
        // Check whether probabilities have already been loaded
        if (!isProfileListLoaded) {
            LinusDetectorFactory.loadProfile(profilelist);
            isProfileListLoaded = true;
        }
        return detector;
    }
    
    public static void setSeed(long seed) {
        instance_.seed = seed;
    }
    
    public static final List<String> getLangList() {
        return Collections.unmodifiableList(instance_.langlist);
    }
}
