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

/**
 * Represents a deck of playing cards
 * 
 * @author Sara Sprenkle
 */
public class Deck {

    // define our instance variable as an *interface* variable, List, not the
    // concrete implementation class.

    // Only Card objects can be put into the list or taken
    // out of the list.
    /** a list of Card objects */
    private List<Card> deck;
    
    /**
     * Creates a new, shuffled deck of cards
     */
    public Deck() {
        this(true);	
    }
    
    /**
     * Creates a new deck of cards
     * 
     * @param shuffle
     *            - true if the cards should be shuffled
     */
    public Deck(boolean shuffle) {
        deck = new ArrayList<>();
        refresh(shuffle);
    }
    
    /**
     * Refresh the deck from the beginning -- as in, it contains all the cards again
     * 
     * @param shuffle true if the cards should be shuffled
     */
    public void refresh(boolean shuffle) {
        // removes all the Cards from the deck
        deck.clear();
        
        // Use the enums defined in the Card class
        for (Card.Suit suit : Card.Suit.values()) {
            for (Card.Rank rank : Card.Rank.values()) {
                Card c = new Card(rank, suit);
                deck.add(c);
            }
        }
        
        if (shuffle) {
            shuffle();
        }
    }

    /**
     * Display the contents of the deck.
     */
    public void display() {
        for (Card c : deck) {
            System.out.println(c);
        }
    }

    /**
     * Shuffles the deck of cards
     */
    public void shuffle() {
        Collections.shuffle(deck);
    }
    
    /**
     * Draws the first/"top" card from the deck, removes it from the deck, 
     * and returns the chosen card
     * 
     * @return the top card from the deck, which is removed
     */
    public Card draw() {
        return deck.remove(0);
    }

    /**
     * Returns a list of cards of size numCards that are drawn
     * from the top of the deck.
     * 
     * @param numCards the number of cards to deal
     * @return a list of cards (of the specified size)
     */
    public List<Card> deal(int numCards) {
        /* Note that this method returns a *List*, not an 
        ArrayList.  This adds flexibility to our code.
        We can change the list implementation (maybe a 
        LinkedList would be better?) and the calling code
        is not affected.
        */
        List<Card> hand = new ArrayList<>();
        for (int i = 0; i < numCards; i++) {
            hand.add(draw());
        }
        return hand;
    }
    
    /**
     * Evaluates the strength of a hand in Poker, poorly.
     * Returns an integer representing the strength of the hand.
     * @param pokerHand a poker hand
     * @return the strength of the hand in poker
     */
    public static int calcStrengthOfHand(List<Card> pokerHand) {
        int strength = 0;
        for( Card c : pokerHand ) {
            if( c.getRank() == Card.Rank.ACE ) {
                strength += 5;
            } else {
               strength += 1;
            }
        }
        return strength;
    }        


    /**
     * Demo some functionality of the Deck class.
     *
     * @param args not used in this method
     */
    public static void main(String[] args) {
        Deck d = new Deck();
        d.display();
        d.shuffle();
        
        /* deal returns a List<Card>.  I don't know which List
        implementation is used, and I don't *need* to know.  
        If the Deck's underlying implementation changes, 
        my code doesn't need to change!  Horray!!
        */
        List<Card> myHand = d.deal(5);
        System.out.println("\nMy hand contains:");
        for( Card c : myHand ) {
            System.out.println(c);
        }
        
        System.out.println("\nMy hand's strength in Poker is " + calcStrengthOfHand(myHand));
    }
}
