/*
 * Top10.java
 *
 * Created on 22. říjen 2000, 16:01
 * Documented 9. 7. 2001
 */

package timetable.solver.strategy;

/** Třída zpravující skupinu n nejlepších prvků (prvků s nejmenší hodnotou). 
 *
 * @author Tomáš Müller
 * @version 1.0
 */
public class Top10 extends java.lang.Object {
    /** Počet nejlepších hodnot */
    protected int maximum = 10;
    /** Pole nejlepších prvků */
    protected int top[] = null;
    /** Počet prvků v poli*/
    protected int count=0;
    /** Pole příslušných hodnot prvků*/
    protected Object value[] = null;

    /** Konstruktor
     * @param maximum počet prvků v poli
     */
    public Top10(int maximum) {
        this.maximum=maximum;
        top = new int [ maximum ];
        value = new Object [ maximum ];
        reset();
    }
        
    /** Konstruktor. Počet prvků ve skupině bude 10.
     */
    public Top10() {
        this(10);
    }
    
    /** Vrátí počet prvků ve skupině */
    public int size() { return count; }

    /** Vymaže všechny prvky z pole. */
    public void reset() {
        for (int i=0;i<maximum;i++) {
            top[i]=-1;
            value[i]=null;
        };
        count=0;
    }
    
    /** Bude prvek s danou hodnotou přidán do skupiny.
     * @param top hodnota
     * @return true, pokud bude (t.j. počet prvků ve skupině je menší než je kapacita pole nebo hodnota posledního prvku v pole je vyšší než vstupní hodnota
     */
    public boolean willBeAdded(int top) {
        return (this.top[maximum-1]==-1 || this.top[maximum-1]>top);
    }
    
    /** Přidání prvku do skupiny. Prvek bude přidán pouze tehdy, pokud splňuje podmínky:
     * <ul><li>počet prvků ve skupině je menší, než je kapacita skupiny</li>
     * <li>poslední prvek má vyšší hodnotu</li></ul>
     *  Prvek bude zařazen na příslušnou pozici dle hodnoty ( první s nejmenší hodnotou, dále vzestupně)
     * @param top hodnota prvku
     * @param value prvek
     */
    public void add(int top, Object value) {
        if (this.top[maximum-1]!=-1 && this.top[maximum-1]<=top) return;
        int pos = 0;
        while (pos<maximum && this.top[pos]!=-1 && this.top[pos]<top) pos++;
        for (int i=maximum-2;i>=pos;i--) {
            this.top[i+1]=this.top[i];
            this.value[i+1]=this.value[i];
        };
        this.top[pos]=top;
        this.value[pos]=value;
        if (count<maximum) count++;
    }

    /** Přidání prvku do skupiny. Prvek bude přidán pouze tehdy, pokud splňuje podmínky:
     * <ul><li>počet prvků ve skupině je menší, než je kapacita skupiny</li>
     * <li>poslední prvek má nižší hodnotu</li></ul>
     *  Prvek bude zařazen na příslušnou pozici dle hodnoty ( první s největší hodnotou, dále vzestupně)
     * <i>Poznámka: funkce add a addMax nelze kombinovat !!!</i>
     * @param top hodnota prvku
     * @param value prvek
     */
    public void addMax(int top, Object value) {
        if (this.top[maximum-1]!=-1 && this.top[maximum-1]>top) return;
        int pos = 0;
        while (pos<maximum && this.top[pos]!=-1 && this.top[pos]>top) pos++;
        for (int i=maximum-2;i>=pos;i--) {
            this.top[i+1]=this.top[i];
            this.value[i+1]=this.value[i];
        };
        this.top[pos]=top;
        this.value[pos]=value;
        if (count<maximum) count++;
    }
    
    /** Vrátí daný prvek ze skupiny.
     * @param i pozice prvku ve skupině
     * @return požadovaný prvek
     */
    public Object get(int i) {
        return value[i];
    }
    
    /** Vrátí hodnotu daného prvku.
     * @param i pozive prvku ve skupině
     * @return hodnota prvku
     */
    public int top(int i) {
        return this.top[i];
    }
    
    /** Vygeneruje náhodné číslo 0<= x < limit.
     * @param limit limit
     * @return náhodné číslo
     */
    public static int random(int limit) {
        return (int)(java.lang.Math.random()*limit);
    }
    
    /** Počet zajímavých hodnot v seznamu. Tj. počet takových prvků, kde hodnota nejhoršího prvku není větší než dvojnásobek hodnoty nejlepšího prvku.
     * @return počet zajímavých hodnot
     */
    public int countInteresting() {
        for (int i=1;i<count;i++) {
            if (top(i)>2*top(0)) return i-1;
        }
        return count;
    }
    
}
