package kevin.lawrence.bowling;

import static org.hamcrest.Matchers.*;
import static org.hamcrest.MatcherAssert.*;

import java.util.Iterator;

import static org.junit.Assert.*;
import org.junit.Before;
import org.junit.Test;

public class FrameTest {  
  private Frame frame;

  @Before
  public void createFrame() {
    frame = new Frame(null, false);
  }

  @Test
  public void firstBallShouldBeRecorded() {
    frame.addBall(3);    
    assertThat(frame.getFirstBall(), is("3"));
  }

  @Test
  public void secondBallShouldBeRecorded() {
    frame.addBall(3);    
    frame.addBall(4);    
    assertThat(frame.getSecondBall(), is("4"));
  }

  @Test
  public void frameShouldNeedMoreThanOneBall() {
    frame.addBall(3);    
    assertThat(frame.needsMoreBalls(), is(true));
  }

  @Test
  public void frameShouldNotNeedMoreThanTwoBalls() {
    frame.addBall(3);    
    frame.addBall(4);    
    assertThat(frame.needsMoreBalls(), is(false));
  }

  @Test
  public void gutterBallShouldBeDash() {
    frame.addBall(0);    
    assertThat(frame.getFirstBall(), is("-"));
  }

  @Test
  public void shouldShowTheScoreForCompletedFrame() {
    frame.addBall(4);    
    frame.addBall(5);    
    assertThat(frame.getScore(), is("9"));
  }

  @Test
  public void shouldNotShowTheScoreForIncompleteFrame() {
    frame.addBall(4);    
    assertThat(frame.getScore(), is(""));
  }

  @Test
  public void shouldAccumulateTheScoreFromPreviousFrame() {
    Frame nextFrame = new Frame(frame, false);

    frame.addBall(3);    
    frame.addBall(4);
    nextFrame.addBall(3);
    nextFrame.addBall(4);
    
    assertThat(nextFrame.getScore(), is("14"));
  }
  
  @Test 
  public void totalForTwoBallsShouldNotExceed10() {
    Frame frame = new Frame(null, false);
    frame.addBall(1);
    try {
      frame.addBall(10);
      fail();
    }
    catch(IllegalArgumentException e){
      assertThat(frame.getCumulativeScore(), is(1));
    }
  }

  @Test
  public void aStrikeIsTenPinsDownWithFirstBall(){
    frame.addBall(10);
    assertThat(frame.isStrike(), is(true));
  }

  @Test
  public void aStrikeIsMarkedByX(){
    frame.addBall(10);
    assertThat(frame.getFirstBall(), is("X"));
  }
  
  @Test
  public void strikeShouldScoreTenPlusNextTwoDeliveries() {
    frame.addBall(10);
    frame.addBall(4);
    frame.addBall(5);
    
    assertThat(frame.getCumulativeScore(), is(19));
  }
  
  @Test
  public void aFrameIsCompleteIfItHasTwoBalls(){
    frame.addBall(4);
    frame.addBall(5);
    
    assertThat(frame.isComplete(), is(true));
  }

  @Test
  public void aFrameIsIncompleteUntilTheSecondBall(){
    frame.addBall(4);
    
    assertThat(frame.isComplete(), is(false));
  }

  @Test
  public void aStrikeFrameIsComplete(){
    frame.addBall(10);
    assertThat(frame.isComplete(), is(true));
  }

  @Test
  public void aStrikeFrameNeedsThreeBalls(){
    frame.addBall(10);
    frame.addBall(5);
    assertThat(frame.needsMoreBalls(), is(true));
  }

  @Test
  public void aStrikeFrameDoesNotNeedFourBalls(){
    frame.addBall(10);
    frame.addBall(5);
    frame.addBall(4);
    assertThat(frame.needsMoreBalls(), is(false));
  }

  @Test
  public void shouldNotShowExtraBallsInStrikeFrame(){
    frame.addBall(10);
    frame.addBall(4);

    assertThat(frame.getFirstBall(), is("X"));
    assertThat(frame.getSecondBall(), is(""));
  }
  
  @Test
  public void allPinsDownWithSecondBallIsSpare(){
    frame.addBall(6);
    frame.addBall(4);

    assertThat(frame.isSpare(), is(true));
  }
  
  @Test
  public void ninePinsDownIsNotASpare(){
    frame.addBall(6);
    frame.addBall(3);

    assertThat(frame.isSpare(), is(false));
  }
  
  @Test
  public void aStrikeIsNotASpare(){
    frame.addBall(10);
    frame.addBall(0);

    assertThat(frame.isSpare(), is(false));
  }
  
  @Test
  public void aSpareIsMarkedBySlash(){
    frame.addBall(9);
    frame.addBall(1);

    assertThat(frame.getFirstBall(), is("9"));
    assertThat(frame.getSecondBall(), is("/"));
  }
  
  @Test
  public void aSpareNeedsOneBonusBall(){
    frame.addBall(9);
    frame.addBall(1);

    assertThat(frame.needsMoreBalls(), is(true));
  }
  
  @Test
  public void spareShouldScoreTenPlusNextDelivery() {
    frame.addBall(6);
    frame.addBall(4);
    frame.addBall(5);
    
    assertThat(frame.getCumulativeScore(), is(15));
  }

}

