String greeting = "a holiday mission:";
String msg = "Hey, Happy Holidays! Merry Everything! It's a great time to be with the folks you care about and be grateful for the times we have here on Earth";


String lines[] = new String [30];
int linecount;
import ddf.minim.*;
PImage sig;
plum m;
gift boxes[];

boolean gameover = false;
long wintime;

long timestart;


AudioPlayer music;


movesprat star;
int BOXCOUNT = 30;
void setup(){
  frameRate(30);
  size(400,400);

  try{
    frame.setTitle("the sugardum fairy");
  } catch(Exception e){
    
  }

  textFont(loadFont("AlbaSuper-48.vlw"),24);
  ellipseMode(CENTER);

  sig = loadImage("sig.gif");

  Minim.start(this);
  music = Minim.loadFile("grymg.mp3");



  String[] words = msg.split(" ");
 for(int i = 0; i < words.length;i++){
    words[i] += " ";
 }
 int lineptr = 0;
 lines[lineptr] = "";
 for(int i = 0; i < words.length;i++){
    String tryit = lines[lineptr] + words[i];
    if(textWidth(tryit) > 380){
       lineptr++;
       lines[lineptr] = words[i]; 
    } else {
       lines[lineptr] += words[i]; 
    }
 }
linecount = lineptr + 1;


  startgame();
}
void stop()
{
  music.close();
  super.stop();
}


void startgame(){
    timestart = millis();  
   //movesprat(int px,int py, String imgname, float pmass, float pfriction, float prebound){
  star = new movesprat(int(random(300)),200,"star.gif",10.0,.99,.5);

  String[] plumlook = {"plum.gif","plumleft.gif","plumright.gif"};
  m = new plum(220,230,plumlook,10,.99,.5);
  boxes = new gift[BOXCOUNT];
  for(int i = 0; i < BOXCOUNT; i++){

    boxes[i] = new gift((int)random(width),(int)random(height),(int)random(20)+20,(int)random(20)+20,10,.80,.5);
  }
 
}

int c;

HashSet currentKeys = new HashSet();

void 	keyPressed(KeyEvent e){
  currentKeys.add(new Integer(e.getKeyCode()));

  //println(e.getKeyCode());

  if(e.getKeyCode() == 83){
     if(!gameover){
        gameover = true;
                music.play();
      music.loop();

     } 
  }

  if(e.getKeyCode() == 32){
    if(gameover){
        noLoop();
       gameover = false; 
       startgame();
       loop();
    }
    
    m.jump();

    
  }

}
void 	keyReleased(KeyEvent e){
  currentKeys.remove(new Integer(e.getKeyCode()));
}
boolean isKeyDown(int c){
  return currentKeys.contains(new Integer(c));
}
gift heldBox = null;
float heldXoff,heldYoff;
void mousePressed(){
  for(int i = 0; i < BOXCOUNT; i++){
    gift thisbox = boxes[i];
    if(thisbox.x <= mouseX && mouseX <= thisbox.x + thisbox.w){
      if(thisbox.y <= mouseY && mouseY <= thisbox.y + thisbox.h){
        heldBox = thisbox;
        heldXoff = thisbox.x - mouseX;
        heldYoff = thisbox.y - mouseY;
        return;
      }
    }
  }
}
int showjump;

void mouseReleased(){
  heldBox = null;
}
void mouseDragged(){
  if(heldBox != null){
    float newx =  heldXoff + mouseX; 
    float newy = heldBox.y = heldYoff + mouseY;        
    heldBox.xs = 2*(newx - heldBox.x);
    heldBox.ys = 2*(newy - heldBox.y);
    heldBox.x = newx;
    heldBox.y = newy;

  }

}

boolean mGoLeft = false;


void draw(){
  
  

  if(random(10)< 1){
    m.jump(); 

  }
  if(random(100)< 1){
    mGoLeft = !mGoLeft;
    m.xs *= -1;
  }




  if(mGoLeft){
    m.xs -= .3; 

  } 
  else {
    m.xs += .3; 
 
  }

if(m.xs < 0){
  m.changeframe(1);  
} else {
      m.changeframe(2); 
}


  //gravity  
  m.ys += .2;
  for(int i = 0; i < BOXCOUNT; i++){
    boxes[i].ys += 1;
  }

  m.move();
  for(int i = 0; i < BOXCOUNT; i++){
    boxes[i].move();
  }  
  m.bounds();
  for(int i = 0; i < BOXCOUNT; i++){
    boxes[i].bounds(true);
  }  

  c++;
  if(c % 50 == 0){
    //      m.changeframe(m.currentframe==0?1:0); 
  }

  for(int i = 0; i < BOXCOUNT; i++){

    if(m.overlap(boxes[i],true)){

      m.collide(boxes[i]);
    }
  }
  //round robin collisions... 
  for(int i = 0; i < BOXCOUNT; i++){
    for(int j = i+1; j < BOXCOUNT; j++){
      if(boxes[i].overlap(boxes[j],true)){
        boxes[i].collide(boxes[j]);
      }
    }  
  }


  for(int i = 0; i < BOXCOUNT; i++){
    boxes[i].bounds(true);
  }  

  if(m.ys < -5){
     // m.changeframe(0);
  }

  background(128);

  for(int i = 0; i < BOXCOUNT; i++){
    boxes[i].draw();
  }
  m.draw();

  for(int i = 0; i < BOXCOUNT; i++){
    boxes[i].drawBow();
  }
  star.draw();

  if(star.overlap(m) && ! gameover){
      gameover = true;
        music.play();
      music.loop();
      wintime = ((millis()-timestart)/1000);
  }
  if(! gameover){
    fill(0);
    fill(128,0,0);
    text(greeting,10,30);
    fill(0,128,0);
    text("help the sugardum fairy",10,60);
    fill(128,0,0);
    text("get to the star",30,90);
    fill(0,128,0);
    text("by mouse moving gifts!",30,120);
    fill(128,0,0);
    text("(or cheat and press 's' to skip)",30,150);
    fill(0,128,0);
    text("time: "+((millis()-timestart)/1000),30,180);
  } else {
    fill(0,0,0);
    int i = 0;
    for(i = 0; i < linecount; i++){
        text(lines[i],10,30+i*30);      
    }
    i++;
    if(wintime != 0) {text("your time:"+wintime,10,30+i*30);}
    image(sig,250,i*30);


    i++;
    text("space to play again!",10,30+i*30);
    
  }


}


//------------------------------------------

class movesprat extends sprat {
  float xs, ys;
  float mass,friction, rebound;
  //pmass = mass, pfriction is multipler to speed per frame, rebound is multiplier of speed on wall/floor collision
  movesprat(int px,int py, String imgname, float pmass, float pfriction, float prebound){
    super(px,py,imgname);
    friction = pfriction;
    mass = pmass;
    rebound = prebound;
  }
  movesprat(int px,int py, String[] imgname, float pmass, float pfriction, float prebound){
    super(px,py,imgname);
    friction = pfriction;
    mass = pmass;         
    rebound = prebound;

  }

  void collide(movesprat o){
    float temp;
    temp = o.xs; 
    o.xs =  xs;
    xs = temp;
    temp = o.ys; 
    o.ys =  ys;
    ys = temp;

    nonoverlap(o);




  }


  void    nonoverlap(movesprat o){
    //figure out which overlap is less, and make that the point where they push out       
    float hlap = spratOverlapHoriz(o).magnitude();
    float vlap = spratOverlapVert(o).magnitude();
    if(hlap < vlap){
      if(x < o.x){
        x -= hlap / 2.0; 
        o.x += hlap / 2.0; 
      } 
      else {
        x += hlap / 2.0; 
        o.x -= hlap / 2.0;             
      }
    } 
    else {
      if(y < o.y){
        if(o.y + o.h >= height){
          o.y = height - o.h;
          y = o.y - h; 
        } 
        else {
          y -= hlap / 2.0; 
          o.y += hlap / 2.0; 
        }
      } 
      else {
        if(y + h >= height){
          y = height - h;
          o.y = y - o.h; 
        } 
        else {
          y += hlap / 2.0; 
          o.y -= hlap / 2.0;             
        }
      }

    }

  }

  void  move(){
    xs *= friction;
    ys *= friction;
    x += xs;
    y += ys; 
  }
  void bounds(boolean b){
    bounds(); 
  }
  void bounds(){
    if(x < 0) {
      x = 0;
      xs = abs(xs) * rebound;
    } 
    if(x+w > width) {
      x = width-w;
      xs = abs(xs) * -rebound;
    } 
    if(y < 0) {
      y = 0;
      ys = abs(ys) * rebound;

    } 
    if(y+h > height) {
      // print("ys is "+ys);
      y = height-h;
      ys = abs(ys) * -rebound;
    } 


  }



}



class sprat{
  float x,y;
  int w,h;
  int framecount;
  int currentframe;
  PImage img[];
  sprat(int px,int py, String imgname){
    String s[] = new String[1];
    s[0] = imgname;
    init(px,py,s);
  } 
  sprat(int px,int py, String[] imgname){
    init(px,py,imgname);
  } 

  void init (int px,int py, String[] imgname){
    x = px; 
    y = py; 
    img = new PImage[imgname.length];
    for(int i = 0; i < imgname.length; i++){
      img[i] = loadImage(imgname[i]);      
    }
    changeframe(0);
  } 
  void changeframe(int whatframe){
    currentframe = whatframe;
    w = img[currentframe].width;
    h = img[currentframe].height;
  }

  void draw(){
    image(img[currentframe],x,y);

  }

  //so we have a physical x and y on screen
  //find the pixel for this thing
  //WARNING no bounds checking
  color pixelAtPhysicalLocation(int px, int py){
    int rx = px - int(x);
    int ry = py - int(y);
    return img[currentframe].pixels[rx + (ry * w)];
  }
  boolean overlap(sprat other){
    return overlap(other, false);
  }

  boolean overlap(sprat other, boolean boxonly){
    intRange vOverlap = spratOverlapVert(other);
    intRange hOverlap = spratOverlapHoriz(other);
    if(vOverlap == null || hOverlap == null){
      return false;
    }
    if(boxonly) return true;

    //hrrm, why couldn't this be <= ????
    for(int a = hOverlap.min; a < hOverlap.max; a++){
      for(int b = vOverlap.min; b < vOverlap.max; b++){
        if(alpha(this.pixelAtPhysicalLocation(a,b)) > 128 && alpha(other.pixelAtPhysicalLocation(a,b)) > 128    ){
          return true; 
        }
      }
    }

    return false;
  }

  // to see if things overlap on one dimension
  // we sort the 4 points. if both points of 
  // one thing are lesser than both points of the other,
  // they can't be overlapping...
  intRange spratOverlapHoriz(sprat b){
    sprat a = this;
    intWithRef vals[] = new intWithRef[4];
    vals[0] = new intWithRef((int)a.x,a);
    vals[1] = new intWithRef((int)(a.x+a.w),a);
    vals[2] = new intWithRef((int)b.x,b);
    vals[3] = new intWithRef((int)(b.x+b.w),b);
    Arrays.sort(vals);
    if (vals[0].src == vals[1].src){
      return null; 
    }
    return new intRange(vals[1].val,vals[2].val);
  }

  intRange spratOverlapVert(sprat b){
    sprat a = this;
    intWithRef vals[] = new intWithRef[4];
    vals[0] = new intWithRef((int)a.y,a);
    vals[1] = new intWithRef((int)(a.y+a.h),a);
    vals[2] = new intWithRef((int)b.y,b);
    vals[3] = new intWithRef((int)(b.y+b.h),b);
    Arrays.sort(vals);
    if (vals[0].src == vals[1].src){
      return null; 
    }
    return new intRange(vals[1].val,vals[2].val);

  }

}

class intRange{
  int min, max;
  intRange(int p1, int p2){
    min = p1<p2?p1:p2; 
    max = p1>p2?p1:p2; 
  }
  int magnitude(){
    return abs(max-min) ;
  }

}

class intWithRef implements Comparable{
  int val; 
  Object src;
  intWithRef(int pval,Object psrc){
    val = pval; 
    src = psrc;
  } 
  public int compareTo(Object o){
    return val - ((intWithRef)o).val;
  }

}




class gift extends movesprat {
  color color1,color2;
  gift(int px,int py, int pw, int ph, float pmass, float pfriction, float prebound){
    super(px,py,"lin.gif",pmass,pfriction,prebound);
    x = px;
    y = py;
    w = pw;
    h = ph;
    friction = pfriction;
    mass = pmass;         
    rebound = prebound;
    color1 = color(random(255),random(255),random(255));
    color2 = color(random(255),random(255),random(255));
  }


  void draw(){
    noStroke();    
    fill(color1);
    rect(x,y,w,h);
    fill(color2);
    rect(x+(w*3/8),y,w/4,h);
    rect(x,y+(h*3/8),w,h/4);


  }

  void drawBow(){
    noStroke();    
    fill(color2);
    float r = w / 4;
    ellipse(x+(w/2),y-(r*.5),r,r);

  }

}





class plum extends movesprat{

  void collide(movesprat o){

    nonoverlap(o);




  }


  plum(int px,int py, String[] imgname, float pmass, float pfriction, float prebound){
    super(px,py,  imgname,  pmass,  pfriction,  prebound); 
  }
  void jump(){

    //if on floor jump
    if(y+h >= height -2){
      ys = 15;
    }

    for(int i = 0; i < BOXCOUNT; i++){
      if(  spratOverlapHoriz(boxes[i]) != null){
        if(y+h >= boxes[i].y - 20){
          ys = 15; 
        }
      }

    }

  }

}