

import java.util.ArrayList;

/**
 * Represents a blackjack hand (player's or dealer's)
 */
public class BlackjackHand
{
    public static final int MAX_HAND_VALUE = 21;

    private static final int ADDITIONAL_ACE_VALUE = 10;
    private static final int NUM_CARDS_FOR_BLACKJACK = 2;

    private ArrayList<BlackjackCard> cards;

    /**
     * Constructs a hand containing the specified 2 cards
     * @param card1 the first card
     * @param card2 the second card
     */
    public BlackjackHand(BlackjackCard card1, BlackjackCard card2)
    {
        cards = new ArrayList<BlackjackCard>();
        cards.add(card1);
        cards.add(card2);
    }

    /**
     * Returns the numerical value of this hand
     * according to the rules of blackjack
     * @return the numerical value of this hand
     */
    public int getNumericalValue()
    {
        boolean containsAce = false;
        int value = 0;

        for (BlackjackCard card : cards)
        {
            value += card.getNumericalValue();

            if (card.isAce())
                containsAce = true;
        }

        if (containsAce &&
                value + ADDITIONAL_ACE_VALUE <= MAX_HAND_VALUE)
            value += ADDITIONAL_ACE_VALUE;

        return value;
    }
    
    /**
     * Returns true if it is possible to add a card to this hand,
     * false otherwise
     * @return true if it is possible to add a card to this hand
     */
    public boolean canAddCard()
    {
        return getNumericalValue() < MAX_HAND_VALUE;
    }

    /**
     * Adds the specified card to this hand
     * @param card the card to add
     * @throws IllegalStateException if ! canAddCard()
     */
    public void addCard(BlackjackCard card)
    {
        if( ! canAddCard() )
            throw new IllegalStateException("cannot add card to this hand");

        cards.add(card);
    }
    
    /**
     * Returns the cards in this hand
     * @return the cards in this hand
     */
    public ArrayList<BlackjackCard> getCards()
    {
        return new ArrayList<BlackjackCard>(cards);
    }
    
    /**
     * Returns the number of cards in this hand
     * @return the number of cards in this hand
     */
    public int getNumCards()
    {
        return cards.size();
    }

    /**
     * Returns true if this hand is a blackjack, false otherwise
     * @return true if this hand is a blackjack, false otherwise
     */
    public boolean isBlackjack()
    {
        return cards.size() == NUM_CARDS_FOR_BLACKJACK &&
                getNumericalValue() == MAX_HAND_VALUE;
    }
    
    /**
     * Returns true if this hand is a bust, false otherwise
     * @return true if this hand is a bust, false otherwise
     */
    public boolean isBust()
    {
        return getNumericalValue() > MAX_HAND_VALUE;
    }

    /**
     * Returns a string representation of the cards
     * in this hand followed by this hand's numerical
     * value in parentheses
     * Ex: "JS AH (21)"
     * @returns a string representation of this hand 
     */
    public String toString()
    {
        String result = "";

        for (BlackjackCard card : cards)
            result += card.toString() + " ";

        return result + "(" + getNumericalValue() + ")";
    }
}
