/**
 * The Blackjack class allows a single player to play a game of blackjack.
 * The class tracks the player's bankroll but makes no attempt to prevent
 * a negative bankroll.
 */
public class Blackjack
{
    public static final int LOSS_RESULT = -1,
            PUSH_RESULT = 0,
            WIN_RESULT = 1,
            WIN_BJ_RESULT = 2;
    
    private static final int DECKS = 6, CARDS_PER_DECK = 52;
    private static final double SHOE_PENETRATION = 0.75;
    private static final int DEALER_STAND_VALUE = 17;
    private static final double WIN_BJ_PAYOUT = 2.5, WIN_PAYOUT = 2.0;
    
    private Shoe shoe;
//    private TestShoe shoe;

    private double playersMoney;

    private BlackjackHand playersHand;
    private double playersBet;

    private BlackjackHand dealersHand;

    /**
     * Constructs a blackjack object that is ready to play.
     * @param playersMoney the player's starting bankroll (all values, including 0 and negative values, are permitted)
     */
    public Blackjack(double playersMoney)
    {
        this.shoe = new Shoe(DECKS);
        this.playersMoney = playersMoney;
        playersHand = null;
        playersBet = 0;
        dealersHand = null;
    }

    /**
     * Resets for another round, including resetting shoe if necessary
     */
    private void reset()
    {
        // TODO implement (part 2)
    }

    /**
     * Returns the player's money (can be negative)
     * @return the player's money
     */
    public double getPlayersMoney()
    {
        return playersMoney;
    }

    /**
     * Returns the player's bet
     * @return the player's bet for the hand
     * @throws IllegalStateException if player has not yet bet
     */
    public double getPlayersBet()
    {
        if(playersHand == null)
            throw new IllegalStateException("Player has not yet bet.");
        
        return playersBet;
    }

    /**
     * Places a bet at the start of a round.
     * Deals cards to the player and dealer.
     * @param amount the amount to bet
     */
    public void placeBetAndDealCards(double amount)
    {
        playersMoney -= amount;
        playersBet = amount;

        BlackjackCard first = shoe.dealCard();
        BlackjackCard second = shoe.dealCard();

        playersHand = new BlackjackHand(first, shoe.dealCard());
        dealersHand = new BlackjackHand(second, shoe.dealCard());
      
        // alternate
//        BlackjackCard[] cards = new BlackjackCard[4];
//        for(int i = 0; i < cards.length; i++)
//            cards[i] = shoe.dealCard();
//        
//        playersHand = new BlackjackHand(cards[0], cards[2]);
//        dealersHand = new BlackjackHand(cards[1], cards[3]);
    }

    /**
     * Returns the player's hand
     * @return the player's hand
     * @throws IllegalStateException if player has not yet bet
     */
    public BlackjackHand getPlayersHand()
    {
        if(playersHand == null)
            throw new IllegalStateException("Player has not yet bet.");
        
        return playersHand;
    }

    /**
     * Returns the dealer's hand
     * @return the dealer's hand
     * @throws IllegalStateException if player has not yet bet
     */
    public BlackjackHand getDealersHand()
    {
        if(playersHand == null)
            throw new IllegalStateException("Player has not yet bet.");
        
        return dealersHand;
    }

    /**
     * Returns true if the player can hit, false otherwise
     * @return true if the player can hit, false otherwise
     * @throws IllegalStateException if player has not yet bet
     */
    public boolean canHit()
    {
        if(playersHand == null)
            throw new IllegalStateException("Player has not yet bet.");
        
        return false; // TODO implement (part 2)
    }

    /**
     * Deals another card to the player's hand.
     * @throws IllegalStateException if ! canHit()
     */
    public void hit()
    {
        if( ! canHit() )
            throw new IllegalStateException("canHit() must be true to hit");
        
        // TODO implement (part 2)
    }

    /**
     * Plays the dealer's hand.
     * @throws IllegalStateException if player has not yet bet
     */
    public void playDealersHand()
    {
        if(playersHand == null)
            throw new IllegalStateException("Player has not yet bet.");
        
        // TODO implement (part 2)
    }

    /**
     * Returns true if the round is over, false otherwise
     * @return true if the round is over, false otherwise
     * @throws IllegalStateException if player has not yet bet
     */
    private boolean roundIsOver()
    {
        if(playersHand == null)
            throw new IllegalStateException("Player has not yet bet.");
        
        return playersHand.getNumericalValue() > BlackjackHand.MAX_HAND_VALUE ||
                playersHand.isBlackjack() || 
                dealersHand.getNumericalValue() >= DEALER_STAND_VALUE;
    }

    /**
     * Returns the result of the hand, as described below.
     *  LOSS_RESULT: player loss/dealer win
     *  PUSH_RESULT: push (tie)
     *  WIN_RESULT: player wins without blackjack
     *  WIN_BJ_RESULT: player wins with blackjack 
     * @return the result of the hand, as described
     * @throws IllegalStateException if round is not over
     */
    public int getResult()
    {
        if ( ! roundIsOver() )
            throw new IllegalStateException("Round is not yet over.");
        
        return -2; // TODO implement (part 2)
    }

    /**
     * Resolves the player's bets (updates player's money based on the
     * results of the round) and resets for another round
     * @throws IllegalStateException if round is not over
     */
    public void resolveBetsAndReset()
    {
        if ( ! roundIsOver() )
            throw new IllegalStateException("Round is not yet over.");
        
        // TODO implement (part 2)
    }
}
