//Deck.java

/**
 * Models a deck of playing cards.  This is essentially a stack of cards.
 * <p>
 * Though some of the constructors will pre-load the new deck with cards,
 * an empy deck could be created and used with other classes of Objects.  
 * This would the same as a Stack with a shuffle capability.
 * <p>
 * Note that decks, using Stack's toString(), print from the bottom up
 * (rather than the probably more intuitive top-down).
 *
 * @see PlayingCard
 * @see java.util.Stack
 */
public class Deck extends java.util.Stack{

  //Constructors --------

  /**
  * Creates an empty deck.
  */
  public Deck(){
    super();
  }

  /**
  * Creates a new deck of 52 cards (no jokers).
  *
  * @param Whether to shuffle this deck upon creation.
  */
  public Deck(boolean shuffle) {
    this(0, shuffle);
  }

  /**
  * Creates a new deck of cards.
  *
  * @param jokers  Number of jokers to include.  Options are 0, 1, or 2.
  *                All other values treated as 0.
  * @param shuffle Whether to shuffle this deck after creating it.
  *                Unshuffled decks are ordered A-K, 
  *                Club-Diamond-Heart-Spade, with Ac on the top.
  *                Any jokers are on the bottom (highest value).
  */
  public Deck(int jokers, boolean shuffle) {
    /*
     * Think of the deck face down.  Highest values are on the bottom,
     * lowest on the top.
     */

    super(); //in case there's any setup Stack needs to do

    //put any jokers on the bottom of the deck
    if (jokers == 2) {
      this.push(new PlayingCard(PlayingCard.JOKER, PlayingCard.JOKER));
      this.push(new PlayingCard(PlayingCard.JOKER, PlayingCard.JOKER));         
    }else if (jokers == 1) {
      this.push(new PlayingCard(PlayingCard.JOKER, PlayingCard.JOKER));
    } // otherwise, no jokers

    for (int suit = 4; suit > 0; suit--) {
      //put spades on first, then other suits
      for (int value = PlayingCard.KING;  value > 0; value--) {
        this.push(new PlayingCard(value, suit));
      }
    }

    if (shuffle) {
      this.shuffle();
    }
  }

  //Methods -----------

  /**
  * Shuffles this deck, reordering all the elements 
  * to a random configuration.
  */
  public void shuffle() {
    /*
     * Uses the Fisher_Yates shuffle algorithm
     */
    Object temp;
    int tempIndex;
    for (int i = this.size() - 1; i >= 0; i--){ 
      tempIndex = ((int) (i * Math.random())); 
      if (tempIndex != i){ //swap if different elements
        temp = this.get(i);
        this.set(i, this.get(tempIndex));
        this.set(tempIndex, temp);
      }
    }
  }



  /**
   * Tests Deck by creating a deck of cards, shuffling it, 
   * and sorting it.  Prints results to the screen.
   */
  public static void main(String[] args) {
    Deck deck = new Deck(1, false);
    System.out.println("A new deck with one joker: ");
    System.out.println(deck);

    deck.shuffle();
    System.out.println("\nThe same deck after shuffling: ");
    System.out.println(deck);

    Object[] array = deck.toArray();
    java.util.Arrays.sort(array);
    System.out.println("\nA sorted version (using compareTo) " +
                       "of the shuffled deck:");
    System.out.println(java.util.Arrays.asList(array));

    array = deck.toArray();
    java.util.Arrays.sort(array, new PlayingCard.ComparatorIgnoreSuit());
    System.out.println("\nA sorted version (using CompartorIgnoreSuit) " +
                       "of the shuffled deck:");
    System.out.println(java.util.Arrays.asList(array));

    array = deck.toArray();
    java.util.Arrays.sort(array, new PlayingCard.ComparatorAceHigh());
    System.out.println("\nA sorted version (using CompartorAceHigh) " +
                       "of the shuffled deck:");
    System.out.println(java.util.Arrays.asList(array));

  }


}//end class Deck
