/*
 * @(#)SelectableDataSetSortItem.java    0.2  2001/11/27 Chris Welty
 *
 * Copyright (c) 2001 Chris Welty. All Rights Reserved.
 *
 * Permission to use, copy, modify, and distribute this software
 * and its documentation for NON-COMMERCIAL or COMMERCIAL purposes and
 * without fee is hereby granted. 
 */


/**
 * A simple applet class to demonstrate a sort algorithm.
 * This extends Goslings SortItem class to allow one to select
 * from a set of interesting data sets.
 *
 * @author Chris Welty
 * @version     0.1, 26 Nov 2001
 */
public class SelectableDataSetSortItem extends SortItem {
	/**
     * Cycle through the scrambled patterns
     */
    int scrambled=0;
    
    /**
     * Is the array in the sorted state?
     */
    boolean sortedp=false;
     
    /**
     * Max number of scramble patterns
     */
	int maxScrambled=8; 

    /**
     * Select how to scramble the input - 
     *  ADDING A NEW SCRAMBLE REQUIRES UPPING maxScrambled!
     */
    void scramble() {
        int a[] = new int[size().height / 2];        
        double f = size().width / (double) a.length;
        scrambled++;
        scrambled = scrambled % maxScrambled;
        switch (scrambled) {
        	case 0: randomScramble(a,f); break;
        	case 1: convexScramble(a,f); break;
        	case 2: concaveScramble(a,f); break;
        	case 3: nColorScramble(a,f,3); break;
        	case 4: nColorScramble(a,f,10); break;
        	case 5: backwardScramble(a,f); break;
        	case 6: nearlySortedScramble(a,f,8); break;
        	case 7: forwardScramble(a,f); break;
        	/* adding a new element requires updating maxScrambled */
		}        	
        arr = a;
        sortedp = false;
    }

    /**
     * Fill the array such that the ends are pretty close, but the
     * middle has increasing entropy.
     */
	void stableEndsScramble(int a[], double f) {
        for (int i = 0; i< a.length; i++) {
            a[i] = (int)((i * f) + (int) (Math.random() *  2) - 3);
        }
    }
    /**
     * Fill the array nearly sorted, each elt off by spread.
     */
	void nearlySortedScramble(int a[], double f, int spread) {
        for (int i = 0; i< spread; i++) {
            a[i] = (int)(i * f);
        }
         for (int i = spread; i< a.length-spread; i++) {
            a[i] = (int)((i + (int) (Math.random() * spread * 2) - spread)  * f);
        }
        for (int i = a.length-spread; i< a.length; i++) {
            a[i] = (int)(i * f);
        }
    }

    /**
     * Fill the array sorted.
     */
	void forwardScramble(int a[], double f) {
        for (int i = 0; i< a.length; i++) {
            a[i] = (int)(i * f);
        }
    }

    /**
     * Fill the array reverse sorted  - shoudl be the worst case for most.
     */
	void backwardScramble(int a[], double f) {
        for (int i = 0; i< a.length; i++) {
            a[i] = (int)((a.length - i) * f);
        }
    }

    /**
     * Fill the array making a concave shape.
     */
	void concaveScramble(int a[], double f) {
		int i;
        for (i = 0; i< (a.length / 2); i++) {
            a[i] = (int)((a.length / 2 - i) * f * 2);
        }
        for (; i < a.length; i++) {
        	a[i] = (int)((i - (a.length/2)) * f * 2);
        }
    }

    /**
     * Fill the array making a convex shape.
     */
    void convexScramble(int a[], double f) {
		int i;
        for (i = 0; i< (a.length / 2); i++) {
            a[i] = (int)(i * f * 2);
        }
        for (; i < a.length; i++) {
        	a[i] = (int)((a.length - i) * f * 2);
        }
    }
    
    /**
     * Fill the array with random numbers from 0..n-1.
     */
    void randomScramble(int a[], double f) {
        for (int i = a.length; --i >= 0;) {
            a[i] = (int)(i * f);
        }
        for (int i = a.length; --i >= 0;) {
            int j = (int)(i * Math.random());
            int t = a[i];
            a[i] = a[j];
            a[j] = t;
        }
    }

    /**
     * Fill the array with only n types of values.
     */
    void nColorScramble(int a[], double f, int n) {
		for (int i=0; i<a.length; i++) {
			a[i] = (int) (n * Math.random() + 1) * (int) (a.length / n * f);
		}
    }

    /**
     * For a Thread to actually do the sorting. This routine makes
     * sure we do not simultaneously start several sorts if the user
     * repeatedly clicks on the sort item.  It needs to be
     * synchronoized with the stop() method because they both
     * manipulate the common kicker variable.
     *
     * Extended to handle multiple mouse clicks.
     */
    private synchronized void startSort() {
        if ((kicker == null || !kicker.isAlive()) && !sortedp) {
            kicker = new Thread(this);
            kicker.start();
        }
        else {
            if (kicker != null) kicker.stop();
            scramble();
            repaint();
        }
    }
    
    /*
     * extended to add the setting of sortedp
     */
    public void run() {
        try {
            if (algorithm == null) {
                algorithm = (SortAlgorithm)Class.forName(algName).newInstance();
                algorithm.setParent(this);
            }
            algorithm.init();
            algorithm.sort(arr);
            sortedp = true;
        } catch(Exception e) {
        }
    }
 
    /**
     * The user clicked in the applet. Start the clock!
     * This needed to be redefined here I think because startSort is private
     */
    public boolean mouseUp(java.awt.Event evt, int x, int y) {
        startSort();
        return true;
    }
}

