// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html#License
/*
 *******************************************************************************
 * Copyright (C) 2013-2015, International Business Machines Corporation and
 * others. All Rights Reserved.
 *******************************************************************************
 */
package com.ibm.icu.text;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.TreeSet;

import com.ibm.icu.text.PluralRules.FixedDecimal;
import com.ibm.icu.text.PluralRules.KeywordStatus;
import com.ibm.icu.util.Output;

/**
 * @author markdavis
 * Refactor samples as first step to moving into CLDR
 * 
 * @internal
 * @deprecated This API is ICU internal only.
 */
@Deprecated
public class PluralSamples {

    private PluralRules pluralRules;
    private final Map<String, List<Double>> _keySamplesMap;

    /**
     * @internal
     * @deprecated This API is ICU internal only.
     */
    @Deprecated
    public final Map<String, Boolean> _keyLimitedMap;
    private final Map<String, Set<FixedDecimal>> _keyFractionSamplesMap;
    private final Set<FixedDecimal> _fractionSamples;

    /**
     * @internal
     * @deprecated This API is ICU internal only.
     */
    @Deprecated
    public PluralSamples(PluralRules pluralRules) {
        this.pluralRules = pluralRules;
        Set<String> keywords = pluralRules.getKeywords();
        // ensure both _keySamplesMap and _keyLimitedMap are initialized.
        // If this were allowed to vary on a per-call basis, we'd have to recheck and
        // possibly rebuild the samples cache.  Doesn't seem worth it.
        // This 'max samples' value only applies to keywords that are unlimited, for
        // other keywords all the matching values are returned.  This might be a lot.
        final int MAX_SAMPLES = 3;

        Map<String, Boolean> temp = new HashMap<String, Boolean>();
        for (String k : keywords) {
            temp.put(k, pluralRules.isLimited(k));
        }
        _keyLimitedMap = temp;

        Map<String, List<Double>> sampleMap = new HashMap<String, List<Double>>();
        int keywordsRemaining = keywords.size();

        int limit = 128; // Math.max(5, getRepeatLimit() * MAX_SAMPLES) * 2;

        for (int i = 0; keywordsRemaining > 0 && i < limit; ++i) {
            keywordsRemaining = addSimpleSamples(pluralRules, MAX_SAMPLES, sampleMap, keywordsRemaining, i / 2.0);
        }
        // Hack for Celtic
        keywordsRemaining = addSimpleSamples(pluralRules, MAX_SAMPLES, sampleMap, keywordsRemaining, 1000000);


        // collect explicit samples
        Map<String, Set<FixedDecimal>> sampleFractionMap = new HashMap<String, Set<FixedDecimal>>();
        Set<FixedDecimal> mentioned = new TreeSet<FixedDecimal>();
        // make sure that there is at least one 'other' value
        Map<String, Set<FixedDecimal>> foundKeywords = new HashMap<String, Set<FixedDecimal>>();
        for (FixedDecimal s : mentioned) {
            String keyword = pluralRules.select(s);
            addRelation(foundKeywords, keyword, s);
        }
        main:
            if (foundKeywords.size() != keywords.size()) {
                for (int i = 1; i < 1000; ++i) {
                    boolean done = addIfNotPresent(i, mentioned, foundKeywords);
                    if (done) break main;
                }
                // if we are not done, try tenths
                for (int i = 10; i < 1000; ++i) {
                    boolean done = addIfNotPresent(i/10d, mentioned, foundKeywords);
                    if (done) break main;
                }
                System.out.println("Failed to find sample for each keyword: " + foundKeywords + "\n\t" + pluralRules + "\n\t" + mentioned);
            }
        mentioned.add(new FixedDecimal(0)); // always there
        mentioned.add(new FixedDecimal(1)); // always there
        mentioned.add(new FixedDecimal(2)); // always there
        mentioned.add(new FixedDecimal(0.1,1)); // always there
        mentioned.add(new FixedDecimal(1.99,2)); // always there
        mentioned.addAll(fractions(mentioned));
        for (FixedDecimal s : mentioned) {
            String keyword = pluralRules.select(s);
            Set<FixedDecimal> list = sampleFractionMap.get(keyword);
            if (list == null) {
                list = new LinkedHashSet<FixedDecimal>(); // will be sorted because the iteration is
                sampleFractionMap.put(keyword, list);
            }
            list.add(s);
        }

        if (keywordsRemaining > 0) {
            for (String k : keywords) {
                if (!sampleMap.containsKey(k)) {
                    sampleMap.put(k, Collections.<Double>emptyList());
                }
                if (!sampleFractionMap.containsKey(k)) {
                    sampleFractionMap.put(k, Collections.<FixedDecimal>emptySet());
                }
            }
        }

        // Make lists immutable so we can return them directly
        for (Entry<String, List<Double>> entry : sampleMap.entrySet()) {
            sampleMap.put(entry.getKey(), Collections.unmodifiableList(entry.getValue()));
        }
        for (Entry<String, Set<FixedDecimal>> entry : sampleFractionMap.entrySet()) {
            sampleFractionMap.put(entry.getKey(), Collections.unmodifiableSet(entry.getValue()));
        }
        _keySamplesMap = sampleMap;
        _keyFractionSamplesMap = sampleFractionMap;
        _fractionSamples = Collections.unmodifiableSet(mentioned);
    }

    private int addSimpleSamples(PluralRules pluralRules, final int MAX_SAMPLES, Map<String, List<Double>> sampleMap,
            int keywordsRemaining, double val) {
        String keyword = pluralRules.select(val);
        boolean keyIsLimited = _keyLimitedMap.get(keyword);

        List<Double> list = sampleMap.get(keyword);
        if (list == null) {
            list = new ArrayList<Double>(MAX_SAMPLES);
            sampleMap.put(keyword, list);
        } else if (!keyIsLimited && list.size() == MAX_SAMPLES) {
            return keywordsRemaining;
        }
        list.add(Double.valueOf(val));

        if (!keyIsLimited && list.size() == MAX_SAMPLES) {
            --keywordsRemaining;
        }
        return keywordsRemaining;
    }

    private void addRelation(Map<String, Set<FixedDecimal>> foundKeywords, String keyword, FixedDecimal s) {
        Set<FixedDecimal> set = foundKeywords.get(keyword);
        if (set == null) {
            foundKeywords.put(keyword, set = new HashSet<FixedDecimal>());
        }
        set.add(s);
    }

    private boolean addIfNotPresent(double d, Set<FixedDecimal> mentioned, Map<String, Set<FixedDecimal>> foundKeywords) {
        FixedDecimal numberInfo = new FixedDecimal(d);
        String keyword = pluralRules.select(numberInfo);
        if (!foundKeywords.containsKey(keyword) || keyword.equals("other")) {
            addRelation(foundKeywords, keyword, numberInfo);
            mentioned.add(numberInfo);
            if (keyword.equals("other")) {
                if (foundKeywords.get("other").size() > 1) {
                    return true;
                }
            }
        }
        return false;
    }

    private static final int[] TENS = {1, 10, 100, 1000, 10000, 100000, 1000000};

    private static final int LIMIT_FRACTION_SAMPLES = 3;


    private Set<FixedDecimal> fractions(Set<FixedDecimal> original) {
        Set<FixedDecimal> toAddTo = new HashSet<FixedDecimal>();

        Set<Integer> result = new HashSet<Integer>();
        for (FixedDecimal base1 : original) {
            result.add((int)base1.integerValue);
        }
        List<Integer> ints = new ArrayList<Integer>(result);
        Set<String> keywords = new HashSet<String>();

        for (int j = 0; j < ints.size(); ++j) {
            Integer base = ints.get(j);
            String keyword = pluralRules.select(base);
            if (keywords.contains(keyword)) {
                continue;
            }
            keywords.add(keyword);
            toAddTo.add(new FixedDecimal(base,1)); // add .0
            toAddTo.add(new FixedDecimal(base,2)); // add .00
            Integer fract = getDifferentCategory(ints, keyword);
            if (fract >= TENS[LIMIT_FRACTION_SAMPLES-1]) { // make sure that we always get the value
                toAddTo.add(new FixedDecimal(base + "." + fract));
            } else {
                for (int visibleFractions = 1; visibleFractions < LIMIT_FRACTION_SAMPLES; ++visibleFractions) {
                    for (int i = 1; i <= visibleFractions; ++i) {
                        // with visible fractions = 3, and fract = 1, then we should get x.10, 0.01
                        // with visible fractions = 3, and fract = 15, then we should get x.15, x.15
                        if (fract >= TENS[i]) {
                            continue;
                        }
                        toAddTo.add(new FixedDecimal(base + fract/(double)TENS[i], visibleFractions));
                    }
                }
            }
        }
        return toAddTo;
    }

    private Integer getDifferentCategory(List<Integer> ints, String keyword) {
        for (int i = ints.size() - 1; i >= 0; --i) {
            Integer other = ints.get(i);
            String keywordOther = pluralRules.select(other);
            if (!keywordOther.equals(keyword)) {
                return other;
            }
        }
        return 37;
    }

    /**
     * @internal
     * @deprecated This API is ICU internal only.
     */
    @Deprecated
    public KeywordStatus getStatus(String keyword, int offset, Set<Double> explicits, Output<Double> uniqueValue) {
        if (uniqueValue != null) {
            uniqueValue.value = null;
        }

        if (!pluralRules.getKeywords().contains(keyword)) {
            return KeywordStatus.INVALID;
        }
        Collection<Double> values = pluralRules.getAllKeywordValues(keyword);
        if (values == null) {
            return KeywordStatus.UNBOUNDED;
        }
        int originalSize = values.size();

        if (explicits == null) {
            explicits = Collections.emptySet();
        }

        // Quick check on whether there are multiple elements

        if (originalSize > explicits.size()) {
            if (originalSize == 1) {
                if (uniqueValue != null) {
                    uniqueValue.value = values.iterator().next();
                }
                return KeywordStatus.UNIQUE;
            }
            return KeywordStatus.BOUNDED;
        }

        // Compute if the quick test is insufficient.

        HashSet<Double> subtractedSet = new HashSet<Double>(values);
        for (Double explicit : explicits) {
            subtractedSet.remove(explicit - offset);
        }
        if (subtractedSet.size() == 0) {
            return KeywordStatus.SUPPRESSED;
        }

        if (uniqueValue != null && subtractedSet.size() == 1) {
            uniqueValue.value = subtractedSet.iterator().next();
        }

        return originalSize == 1 ? KeywordStatus.UNIQUE : KeywordStatus.BOUNDED;
    }

    Map<String, List<Double>> getKeySamplesMap() {
        return _keySamplesMap;
    }

    Map<String, Set<FixedDecimal>> getKeyFractionSamplesMap() {
        return _keyFractionSamplesMap;
    }

    Set<FixedDecimal> getFractionSamples() {
        return _fractionSamples;
    }

    /**
     * Returns all the values that trigger this keyword, or null if the number of such
     * values is unlimited.
     *
     * @param keyword the keyword
     * @return the values that trigger this keyword, or null.  The returned collection
     * is immutable. It will be empty if the keyword is not defined.
     * @stable ICU 4.8
     */

    Collection<Double> getAllKeywordValues(String keyword) {
        // HACK for now
        if (!pluralRules.getKeywords().contains(keyword)) {
            return Collections.<Double>emptyList();
        }
        Collection<Double> result = getKeySamplesMap().get(keyword);

        // We depend on MAX_SAMPLES here.  It's possible for a conjunction
        // of unlimited rules that 'looks' unlimited to return a limited
        // number of values.  There's no bounds to this limited number, in
        // general, because you can construct arbitrarily complex rules.  Since
        // we always generate 3 samples if a rule is really unlimited, that's
        // where we put the cutoff.
        if (result.size() > 2 && !_keyLimitedMap.get(keyword)) {
            return null;
        }
        return result;
    }
}
