import processing.core.*; 
import processing.data.*; 
import processing.event.*; 
import processing.opengl.*; 

import ddf.minim.spi.*; 
import ddf.minim.signals.*; 
import ddf.minim.*; 
import ddf.minim.analysis.*; 
import ddf.minim.ugens.*; 
import ddf.minim.effects.*; 
import de.looksgood.ani.*; 
import de.looksgood.ani.easing.*; 
import processing.serial.*; 
import cc.arduino.*; 

import java.util.HashMap; 
import java.util.ArrayList; 
import java.io.File; 
import java.io.BufferedReader; 
import java.io.PrintWriter; 
import java.io.InputStream; 
import java.io.OutputStream; 
import java.io.IOException; 

public class freeskee extends PApplet {














Arduino arduino;

PFont font;
PImage backgroundImage;

PShape scoreText; // Declare variable "a" of type PImage
PShape gameOn; // Declare variable "a" of type PImage
PShape comboImages1[] = new PShape[5];// Declare variable "a" of type PImage
PShape comboImages2[] = new PShape[5];// Declare variable "a" of type PImage
PShape ballsText; // Declare variable "a" of type PImage
PShape streakText; // Declare variable "a" of type PImage


int off = color(4, 79, 111);          //colors for button status boxes
int on = color(84, 145, 158);
int  holePin[] = {2,3,4,5,6,7,8};    // the pins that the switches are attached to 
int  holeValue[] = {10,20,30,40,50,100,100};
int  streakValue[] = {0,10,15,25,35,80,80};
int  combo[] = {0,0,0,0,0,0,0};

int combo_image1_1;
int combo_image1_2;
int combo_image1_3;
int combo_image1_4;
int combo_image1_5;
int combo_image1_6;
int combo_image1_7;
int combo_image1_8;

//target of pieces of combo1 image. x,y coords of uper left corner
int combo1_target[] = {100,100};

int combo_image2_1;
int combo_image2_2;
int combo_image2_3;
int combo_image2_4;
int combo_image2_5;
int combo_image2_6;
int combo_image2_7;
int combo_image2_8;

//target of pieces of combo2 image. x,y coords of uper left corner
int combo2_target[] = {50, 100};


int ballCount=0;                             //balls left to play
int newScore=0;                              //game score
int score=0;                                 //game score
int scoreJump = 100;      //jump in score on hitting target
int streak=1;                                //number of times current hole has been hit in a row
int lastHole=0;                              //last hole hit
int lastTime;                                //timer for target switches to reset
int introTime;                               //timer for "Game On!" message
int comboTimer[] = {0,-10000,-10000};                   //timer for combo messages
int introFade;
int introSlide;
int combo1;
int combo2;
float easing=.05f;
float xGameOn;                               //x location of "Game On!" message
final int DELAY_TIME = 1000;                 //Time for switch reset
final int GAME_INTRO = 2500;                 //Time for "Game On!" message
final int COMBO_TIMER[] = {0,5000,5000};                 //Time for combo1 message


public void setup() {
  size(1280, 720);
  smooth();
  arduino = new Arduino(this, Arduino.list()[4], 57600);
  font = loadFont("BlackoakStd-48.vlw");
  textFont(font);
  ballCount=0;
  for (int i = 2; i <= 9; i++)
    arduino.pinMode(i, Arduino.INPUT);
  lastTime = millis();
  backgroundImage = loadImage("back2.gif");
  
    // Loading up all the number images, 0-9, into image array
  for (int i=0; i<10; i++){
    String imageLoad = "carnival_numbers_" + i + ".svg";
    img[i] = loadShape(imageLoad);  // Load the image into the program  
  }

      // Loading up combo2 images
  for (int i=1; i<5; i++){
    String imageLoad = "combo1_" + i + ".svg";
    comboImages1[i] = loadShape(imageLoad);  // Load the image into the program  
  }
  
  
      // Loading up combo2 images
  for (int i=1; i<5; i++){
    String imageLoad = "combo2_" + i + ".svg";
    comboImages2[i] = loadShape(imageLoad);  // Load the image into the program  
  }
  
  scoreText = loadShape("carnival_score.svg"); 
  gameOn = loadShape("gameon_big.svg"); 
  ballsText = loadShape("message_balls.svg"); 
  streakText = loadShape("message_streak.svg"); 

  //Setting up scoreImage with all null images
  for (int i=0; i<3; i++){
    scoreImages[i] = loadShape("carnival_numbers_null.svg");  // Load the image into the program  
  }
  scoreImages[3] = loadShape("carnival_numbers_0.svg");
 
  scoreCenterY = scoreLocationY + numHeight/2;    //setting up center of score, doesn't change
  
  Ani.init(this);

}

public void draw() {
  background(120);
  stroke(on);
  image(backgroundImage,0,0);
/*
  switchBoxes();
*/
  //Start button function, resets all variables
  if (arduino.digitalRead(9) == Arduino.LOW && ballCount==0) {
   startTheGame();  
    }

  //target function, checking for hits and adding to score
  for (int i = 2; i <= 8; i++) {
    if (arduino.digitalRead(i) == Arduino.LOW && ballCount>0 && millis() - lastTime >= DELAY_TIME) {
        {
        scoreJump = holeValue[i-2];
        ballCount--;
        lastTime=millis();
        combo[i-2]++;
        //streak check
        if (holeValue[i-2]==lastHole && lastHole!=10){
          scoreJump += streak*streakValue[i-2];
          streak++;
          }
        else {
          streak=1;
          lastHole=holeValue[i-2];
          }
          
        //checks for Around the World combo and Up the Line
        if (combo[0]>0 && combo[1]>0 && combo[2]>0 && combo[3]>0 && combo[4]>0 && combo[5]>0 && combo[6]>0 && combo1==0 && combo2==0){
          combo3();
          }
        //checks for Around the World combo (all targets)
        if (combo[0]>0 && combo[1]>0 && combo[2]>0 && combo[3]>0 && combo[4]>0 && combo1==0){
          combo1();
          }
        //checks for Around the World combo (all targets)
        if (combo[0]>0 && combo[1]>0 && combo[2]>0 && combo[3]>0 && combo[4]>0 && combo[5]>0 && combo[6]>0 && combo2==0){
          combo2();
          }
          newScore += scoreJump;
        }
     }
  }
  
  //status updates for balls and streak

  shape(scoreText,40,138,500,125); 
  shape(ballsText,40,550,80,80); 
  shape(img[ballCount],430,530,110,130);

  //streak indicator
  if (streak>1){
      shape(streakText,630,550,80,80); 
      shape(img[streak],1110,530,110,130);
  }

  scoreIncrement();
  scoreImage (score);
  

//this makes the score "bounce" when it jumps. The bigger the jump in score the bigger the bounce
  if (angle<3.1f){
    float scalar = 1+(sin(angle))*scoreJump/400;
    //shifting so score scales from center, not origin
    pushMatrix();
    translate(scoreCenterX*(1-scalar),scoreCenterY*(1-scalar));
    scale(scalar);
    scoreDisplay();
    popMatrix();
    angle+=speed;
  }
  else
  scoreDisplay();
  
      //"Game On!" message display
  if (millis() - introTime <= GAME_INTRO){
    textSize(72);
    float targetX = 100;        //end x location for message
    xGameOn += (targetX - xGameOn) * easing;
    shape(gameOn,xGameOn,30,100,100);
   }
  
  //combo images
  fill(255);
  
  //combo1 pieces display
 if (millis() - comboTimer[1] <= COMBO_TIMER[1]){  
  //combo1 pieces display
  shape(comboImages1[4],combo_image1_7,combo_image1_8,1100,1100);
  shape(comboImages1[1],combo_image1_1,combo_image1_2,1100,1100);
  shape(comboImages1[2],combo_image1_3,combo_image1_4,1100,1100);
  shape(comboImages1[3],combo_image1_5,combo_image1_6,1100,1100);
 }

 if (millis() - comboTimer[2] <= COMBO_TIMER[2]){  
  //combo2 pieces display
  shape(comboImages2[1],combo_image2_1,combo_image2_2,100,100);
  shape(comboImages2[2],combo_image2_3,combo_image2_4,100,100);
  shape(comboImages2[3],combo_image2_5,combo_image2_6,100,100);
  shape(comboImages2[4],combo_image2_7,combo_image2_8,100,100);
 }
}

public void startTheGame(){
      score=0;
      newScore=0;
      streak=1;
      lastHole=0;
      ballCount=9;           //setting ball count
      combo1=0;              //resetting combo1 - Up the Line
      combo2=0;              //resetting combo 2 - Around the World
      
      /*not a loop since the ANI function didn't accept array names. These are the starting locations 
      /for all of the pieces of the combo images. Some are farther away so they take slightly longer 
      to get to the target coordinates. */
      combo_image1_1=100;
      combo_image1_2=2000;
      combo_image1_3=300;
      combo_image1_4=3000;
      combo_image1_5=500;
      combo_image1_6=4000;
      combo_image1_7=300;
      combo_image1_8=6000;
      
      combo_image2_1=100;
      combo_image2_2=2000;
      combo_image2_3=300;
      combo_image2_4=3000;
      combo_image2_5=500;
      combo_image2_6=4000;
      combo_image2_7=300;
      combo_image2_8=6000;
      
      introTime=millis();
      
      for (int i=0; i<=6; i++){
        combo[i]=0;      //resets combo marker for new game
      }
      xGameOn=-200;      //start position of "Game On!" message
}

public void switchBoxes(){
      //displays status of buttons for pins 2-9
  for (int i = 2; i <= 9; i++) {
    if (arduino.digitalRead(i) == Arduino.HIGH)
      fill(on);
    else
      fill(off);
      
    rect(20 + i * 40, 30, 20, 20);
  }  
}


public void scoreIncrement(){
    if (score<newScore-10){
    score += 10;
  }
  else if (score==newScore-10){
    score += 10;
    angle=0.0f;
  }
  else if (score==newScore-5){
    score+=5;
    angle=0.0f;
  }
}

public void combo1(){
            combo1=1;
          scoreJump+=500;
            comboTimer[1]= millis();

          //this loop calls the animation functions for the 4 pieces of combo1
          for (int j=1; j<9; j++){
            String shiftThis = "combo_image1_"+j;
            if ((j % 2) == 0){
              Ani.to(this, 2.0f, shiftThis, combo1_target[1], Ani.EXPO_OUT);
            }
            else{
              Ani.to(this, 2.0f, shiftThis, combo1_target[0], Ani.EXPO_OUT);
            }


          }
}

public void combo2(){
            combo2=1;
          scoreJump+=1000;
            comboTimer[2]= millis();

                    //this loop calls the animation functions for the 4 pieces of combo2
          for (int j=1; j<9; j++){
            String shiftThis = "combo_image2_"+j;
            if ((j % 2) == 0){
            Ani.to(this, 2.0f, shiftThis, combo2_target[1], Ani.EXPO_OUT);
            }
            else{
              Ani.to(this, 2.0f, shiftThis, combo2_target[0], Ani.EXPO_OUT);
            }
          }
}


public void combo3(){
            combo2=1;
            combo1=1;
          scoreJump+=1500;
            comboTimer[2]= millis() + 2000;
            comboTimer[1]= millis();

          //this loop calls the animation functions for the 4 pieces of combo1
          for (int j=1; j<9; j++){
            String shiftThis = "combo_image1_"+j;
            if ((j % 2) == 0){
              Ani.to(this, 2.0f, shiftThis, combo1_target[1], Ani.EXPO_OUT);
            }
            else{
              Ani.to(this, 2.0f, shiftThis, combo1_target[0], Ani.EXPO_OUT);
            }

          }

                    //this loop calls the animation functions for the 4 pieces of combo2
          for (int j=1; j<9; j++){
            String shiftThis = "combo_image2_"+j;
            if ((j % 2) == 0){
              Ani.to(this, 6.0f, shiftThis, combo2_target[1], Ani.EXPO_OUT);
            }
            else{
              Ani.to(this, 6.0f, shiftThis, combo2_target[0], Ani.EXPO_OUT);
            }
          }
}
/**
 * Load and Display 
 * 
 * Images can be loaded and displayed to the screen at their actual size
 * or any other size. 
 */
 
// The next line is needed if running in JavaScript Mode with Processing.js
/* @pjs preload="moonwalk.jpg"; */ 

PShape img[] = new PShape[10];  // Declare variable "a" of type PImage
PShape scoreImages[] = new PShape[4];
float angle=3.14f;          //used for score size bounce
float speed=0.10f;          //speed of score bounce
float scoreCenterX = 0;    //center of score image
float scoreCenterY = 0;    
int numWidth = 200;        //width of digits
int numHeight = 200;       //height of digits
int spacing = 150;         //spacing between digits
int scoreLocationX = 530;
int scoreLocationY = 100;

//shows the score
public void scoreDisplay(){
  for (int i=0; i<4 ; i++) {
    shape(scoreImages[i], scoreLocationX+spacing*i, scoreLocationY,numWidth,numHeight);
  }
}

//assigns number images to scoreImage array
public void scoreImage(int a){
  if (a==0){
     for (int i=0; i<3; i++){
      scoreImages[i] = loadShape("carnival_numbers_null.svg");  // Load the image into the program  
      }
      scoreImages[3] = loadShape("carnival_numbers_0.svg");
  }
  else if (a<100){
    scoreImages[2]=img[floor(a/10)];
    scoreImages[3]=img[a % 10];
    scoreCenterX = scoreLocationX + 3*spacing;

  }

    else if (a<1000){
    scoreImages[1]=img[floor(a/100)];
    scoreImages[2]=img[(floor(a/10)) % 10];
    scoreImages[3]=img[a % 10];
    scoreCenterX = scoreLocationX + 2.5f*spacing;

  }
  else {
    scoreImages[0]=img[floor(a/1000)];
    scoreImages[1]=img[(floor(a/100)) % 10];
    scoreImages[2]=img[(floor(a/10)) % 10];
    scoreImages[3]=img[a % 10];
    scoreCenterX = scoreLocationX + 2*spacing;
  }
  
}
  static public void main(String[] passedArgs) {
    String[] appletArgs = new String[] { "--full-screen", "--bgcolor=#666666", "--stop-color=#cccccc", "freeskee" };
    if (passedArgs != null) {
      PApplet.main(concat(appletArgs, passedArgs));
    } else {
      PApplet.main(appletArgs);
    }
  }
}
