import processing.core.*; 
import processing.xml.*; 

import blobDetection.*; 
import megamu.shapetween.*; 

import megamu.shapetween.*; 
import blobDetection.*; 

import java.applet.*; 
import java.awt.Dimension; 
import java.awt.Frame; 
import java.awt.event.MouseEvent; 
import java.awt.event.KeyEvent; 
import java.awt.event.FocusEvent; 
import java.awt.Image; 
import java.io.*; 
import java.net.*; 
import java.text.*; 
import java.util.*; 
import java.util.zip.*; 
import java.util.regex.*; 

public class NightBeyondNight_App extends PApplet {





//static public void main(String args[]) {
  // PApplet.main(new String[] { "--present","--stop-color=#000000", "NightBeyondNight_App" });
 //}

//controls running for .exe file


//controls running for .exe file


//GLOBALS
BlobDetection theBlobDetection;
PImage img;
PApplet root = this;
//total words used in the applet
int newWidth;
int newHeight;



// ==================================================
// setup()
// ==================================================



String word;
float[] x;
float[] y;
String[] wordArray;
wordObject[] wordObjects;
String currentState = "start";
int timer=0;
int imageCounter=0;
String[] filenames;
float xAdjust = 0;
int lastMinute = minute();



public void setup()
{
    size(1024, 768);  
  smooth();  
  
//grab the txt files and the images

java.io.File folder = new java.io.File(dataPath("textFiles"));


java.io.FilenameFilter jpgFilter = new java.io.FilenameFilter() {
   public boolean accept(File dir, String name) {
   return name.toLowerCase().endsWith(".txt");
 }
};


// list the files in the data folder
filenames = folder.list(jpgFilter);

// get the number of jpg files
//println(filenames.length + " jpg files in specified directory");

//String randFileName = filenames[int(random(filenames.length))];
String randFileName = filenames[imageCounter];
//String randFileName = "p519868417.txt";
// print the filenames
//println(randFileName);
//for (int i = 0; i < filenames.length; i++) println(filenames[i]); 

  
  

  //grab the information for the images and the text
  byte b[] = loadBytes("textFiles/"+randFileName); 
  String imageText="";
  String[] imageTextList;
  // print each value, from 0 to 255 
  for (int i = 0; i < b.length; i++) { 
    // bytes are from -128 to 127, this converts to 0 to 255 
    int a = b[i] & 0xff; 
    imageText=imageText+PApplet.parseChar(a);
  } 
  imageTextList = split(imageText,"&&&");
  word = imageTextList[1].substring(0,800);

  String imageString = "pimages/p"+trim(imageTextList[0]);
  //String imageString="pImages/p1458870161.jpg";
  //print(imageString);
  // - end of the grab text

  x = new float[word.length()];
  y = new float[word.length()];
  wordArray = splitTokens(word);
  wordObjects = new wordObject[wordArray.length];


  frameRate(18);
  //setup the wordObjectArray start with one extra to account for elipse
  for(int i=1;i<wordArray.length;i++){
    wordObject thisGuy = new wordObject(wordArray[i-1]);
    wordObjects[i] = thisGuy;
  }


  img = loadImage(imageString);
  theBlobDetection = new BlobDetection(img.width, img.height);
  theBlobDetection.setPosDiscrimination(false);
  theBlobDetection.setThreshold(0.38f);
  theBlobDetection.computeBlobs(img.pixels);


  PFont fontA = loadFont("Garamond13.vlw");

  // Set the font and its size (in units of pixels)
  textFont(fontA,13);

  // Size of applet
  float imgMult = 768.000f/img.height;
   newWidth=round(img.width*imgMult);
   newHeight=round(img.height*imgMult);
  //newWidth=479;
  //newHeight=630;
  //println(1024-newWidth);
  xAdjust = (1024-newWidth)*.5f;
  
     
  textLineLength=(newWidth)/16;
  textX= PApplet.parseInt((xAdjust*.5f)+1024*.25f);

  drawBlobsAndEdges(false,true);
  setUpWordsLetters(0, 0, 0,1);


}

// ==================================================
// draw()
// ==================================================

public void draw()
{
  background(0,0,0);
  if(minute()%2==0&&lastMinute!=minute()){
    reset();
    lastMinute=minute();
    //currentState="start";
    //drawBlobsAndEdges(false,true);
    //setUpWordsLetters(0, 0, 0,1);

    timer=0;
  }
  else{
     timer++;
    if(currentState=="start"){
      this.startImage();
    }
    else if(mouseX<=65||mouseX>=width-65||mouseY<=115||mouseY>=height-65){	
      this.drawImage();
    }
    else{
      this.drawText();
    }
  }
}
// ==================================================
// drawBlobsAndEdges()
// ==================================================
public void drawBlobsAndEdges(boolean drawBlobs, boolean drawEdges)
{

  Blob b;
  EdgeVertex eA,eB,aA,aB;
  for (int n=0 ; n<theBlobDetection.getBlobNb(); n++)
  {
    b=theBlobDetection.getBlob(n);
    if (b!=null)
    {
      // Edges
      if (drawEdges)
      {

        int spacer=8;
        for (int m=0;m<((b.getEdgeNb()));m+=spacer)
        {
          stroke(random(255),random(255),random(255));
          eA = b.getEdgeVertexA(m);
          eB = b.getEdgeVertexB(m);

          if(m+spacer<b.getEdgeNb()){
            aA = b.getEdgeVertexA(m+spacer);
            aB = b.getEdgeVertexB(m+spacer);
          }
          else{
            //aA=eA;
            //aB=eB;
            break;
          }



          if (eA !=null && eB !=null&& aA !=null && aB !=null){



             /*
            float thisX=(eA.x*width+eB.x*width)*.5;
            float thisY=(eA.y*height+eB.y*height)*.5;
            float aheadX=(aA.x*width+aB.x*width)*.5;
            float aheadY=(aA.y*height+aB.y*height)*.5;
            */
            
            float thisX=(eA.x*newWidth+eB.x*newWidth)*.5f;
            float thisY=(eA.y*newHeight+eB.y*newHeight)*.5f;
            float aheadX=(aA.x*newWidth+aB.x*newWidth)*.5f;
            float aheadY=(aA.y*newHeight+aB.y*newHeight)*.5f;
            
            float nCheck=1.50f;

            float nCheckXP=thisX+nCheck;
            float nCheckXN=thisX-nCheck;
            float nCheckYP=thisY+nCheck;
            float nCheckYN=thisY-nCheck;

            if(aheadX<nCheckXP&&aheadX>thisX||aheadX>nCheckXN&&aheadX<thisX||aheadY<nCheckYP&&aheadY>thisY||aheadY>nCheckYN&&aheadY<thisY){

            }
            else{
              float dx =aheadX - thisX;
              float dy = aheadY - thisY;
              float angle = atan2(dy, dx);
              ///SUPER IMPORTANT WHERE WE SET UP THE WORD OBEJECTS
              setUpWordsLetters(thisX+xAdjust, thisY, angle,0); 

            }


          }
        }
      }




    }

  }

}

int wordCounter=1;
int count = 0;
int textX=0;
int textY = 75;
int textSpacing =9;
int textLineLength=0;
int textLineHeight = 28;
int textCount=0;
int newLineNow = 0;
int lastTextCount=0;
int totalChars=0;

public void setUpWordsLetters(float x, float y, float a, int last) {
  totalChars++;
  //add the elipses to the sketch
  if(last==1){

    wordObject thisGuy = new wordObject("..."); 
    wordObjects[0] = thisGuy;


    int prevLength=(wordObjects[wordCounter-1].letters.length)-2;
    float prevX = wordObjects[wordCounter-1].letters[prevLength].xposT;
    float prevY = wordObjects[wordCounter-1].letters[prevLength].yposT;

    wordObjects[0].letters[0].xposT= (prevX+textSpacing);
    wordObjects[0].letters[0].yposT= prevY;

    wordObjects[0].letters[1].xposT= (prevX+textSpacing*2);
    wordObjects[0].letters[1].yposT= prevY;
    wordObjects[0].letters[1].xposI=newWidth;
    wordObjects[0].letters[1].yposI=0;

    wordObjects[0].letters[2].xposT= (prevX+textSpacing*3);
    wordObjects[0].letters[2].yposT= prevY;
    wordObjects[0].letters[2].xposI=0;
    wordObjects[0].letters[2].yposI=newHeight;

  }

  //move through the wordObjects and their letters
  if (count>wordObjects[wordCounter].length-1){
    count=0;
    if(wordCounter<=wordArray.length-1){
      wordCounter++; 
      //check to see if the new word will break the line, if so start a new line


      if((wordObjects[wordCounter].length)>(textLineLength-(textCount%textLineLength)-1)){
        newLineNow = 1;
        ;
      }

    }
    else{
      wordCounter=0; 
    }
  }
  else{
    textCount++;
    //start a new line

    if(textCount%textLineLength==0||newLineNow==1){
      textCount=0;
      textY+=textLineHeight;
      newLineNow = 0;
    }

    wordObjects[wordCounter].letters[count].xposI=x;
    wordObjects[wordCounter].letters[count].yposI=y;
    //if we are at the begining of a word put in  a space
    wordObjects[wordCounter].letters[count].xposT=textX+textCount*textSpacing;
    wordObjects[wordCounter].letters[count].yposT=textY;
    wordObjects[wordCounter].letters[count].angle=a;
    count++; 
  }

}

class wordObject { 
  public float fader = 70;
  public String value;
  public int length;
  public letterObject [] letters;
  String thisLetter;
  public int flipper=1;
  float rand = random(5,12);

  wordObject (String word) {
    value = word;
    length = word.length()+1;
    letters = new letterObject[length+1];
    for(int i=0;i<length;i++){
      //pad the word with a space afterward.
      if(i<length-1){
        thisLetter=word.substring(i,i+1);
      }
      else{
        thisLetter = " ";
      }
      letterObject letter = new letterObject(thisLetter,width*.5f,height*.5f);
      letters[i] = letter;
    }  
  }
  public void update(){
    if(currentState=="image"){
      fader+=rand*flipper;
      if(fader>235||fader<70){
        flipper*=-1; 
      }  
    }
    if(currentState=="text"){
      if(fader<235){
        fader+=rand;
      }
      else{
        fader=234; 
      }
    }

  }

  //letterObject
  class letterObject { 
    public float x,y,xposI, yposI,xposT, yposT,angle;
    public Tween ani;

    float randJit=random(.05f,.25f);
    float randSpacer = random(.95f,1.25f);
    String value;
    int inPlace =  0;
    int playing = 0;
    letterObject (String letter,float thisX,float thisY) {
      ani = new Tween(root,240*random(1.1f,1.9f), Tween.FRAMES);
      ani.start();
      value=letter;
      x=thisX;
      y=thisY;
    } 

    float myAngle;
    int flipper=1;
    int flipCounter=0;
    int mode = PApplet.parseInt(random(0,3));
    public void update(String state){

      if(state=="image"){
        //if letter is in place
        if (x ==xposI&&y==yposI&&myAngle==angle){
          inPlace=1;
        }
        else{
          if(inPlace==0){
            x = lerp( x, xposI,  ani.position() );
            y = lerp( y, yposI,  ani.position() );
            myAngle = lerp(myAngle, angle, ani.position() );
          }
        }
        if(inPlace==1){
          if(x>xposI+randSpacer||y>yposI+randSpacer||x<xposI-randSpacer||y<yposI-randSpacer){
            flipper*=-1;
            flipCounter++;
            if(flipCounter*.5f==1){
              mode = PApplet.parseInt(random(0,4));
              flipCounter=0;
            }
          }   
          if(mode==0){
            y-=randJit*.5f*flipper;
            x-=randJit*.5f*flipper;
          }
          if(mode==1){
            x+=randJit*flipper;
          }
          if(mode==2){
            y+=randJit*flipper;
          }
          if(mode==3){
            y+=randJit*flipper;
            x+=randJit*flipper;
          }

        }

      }
      else{
        x = lerp( x, xposT, ani.position() );
        y = lerp( y, yposT, ani.position() );
        myAngle = lerp(myAngle,(myAngle*-1), ani.position() );
      }
      pushMatrix();
      translate(x,y);
      rotate(myAngle);
      stroke(0,0,0);
      fill(fader,fader,fader);
      text(this.value, 0,0);
      popMatrix(); 

    }    

  }//end of LETTER OBJECT CLASS
}//end of WORD OBJECT CLASS



public void startImage(){
  for(int l=0; l<wordCounter;l++){
    for(int w=0; w<wordObjects[l].letters.length-1;w++){
      if(currentState!="image"){
        wordObjects[l].letters[w].inPlace=0;
        wordObjects[l].letters[w].ani = new Tween(root,240*random(.5f,1.8f), Tween.FRAMES,Shaper.COSINE);
        wordObjects[l].letters[w].ani.start();


      }
      wordObjects[l].letters[w].update("image");
    }

    wordObjects[l].update();
  }
  currentState="image";
}


public void drawImage(){
  for(int l=0; l<wordCounter;l++){
    for(int w=0; w<wordObjects[l].letters.length-1;w++){
      if(currentState!="image"){
        wordObjects[l].letters[w].inPlace=0;
        wordObjects[l].letters[w].ani = new Tween(root,142*random(.5f,2.2f), Tween.FRAMES,Shaper.COSINE);
        wordObjects[l].letters[w].ani.start();

      }
      wordObjects[l].letters[w].update("image");


    }
    wordObjects[l].update();
  }

  currentState="image";

}


public void drawText(){

  for(int l=0; l<wordCounter;l++){
    for(int w=0; w<wordObjects[l].letters.length-1;w++){
      if(currentState!="text"){
        wordObjects[l].letters[w].inPlace=0;
        wordObjects[l].letters[w].ani = new Tween(root,142*random(.5f,1.8f), Tween.FRAMES,Shaper.COSINE);
        wordObjects[l].letters[w].ani.start();

      }
      wordObjects[l].letters[w].update("text");
    }
    wordObjects[l].update();
  }

  currentState="text";


}


public void reset(){
  imageCounter++;
  if(imageCounter>60){
    imageCounter=0;
  }
  //println("ImageCounter:"+imageCounter);
 // wordArray= null;
 // wordObjects= null;
   x = null;
   y = null;
  currentState="start";
  String randFileName = filenames[imageCounter];
  
 wordCounter=1;
 count = 0;
 textX=0;
 textY = 75;
 textSpacing =9;
 textLineLength=0;
 textLineHeight = 28;
 textCount=0;
 newLineNow = 0;
 lastTextCount=0;
 totalChars=0;
  
// print the filenames
//println(randFileName);
//for (int i = 0; i < filenames.length; i++) println(filenames[i]); 

  
  

  //grab the information for the images and the text
  byte b[] = loadBytes("textFiles/"+randFileName); 
  String imageText="";
  String[] imageTextList;

  // print each value, from 0 to 255 
  for (int i = 0; i < b.length; i++) { 
    // bytes are from -128 to 127, this converts to 0 to 255 
    int a = b[i] & 0xff; 
    imageText=imageText+PApplet.parseChar(a);
  } 


  imageTextList = split(imageText,"&&&");
  word = imageTextList[1].substring(0,850);

  String imageString = "pimages/p"+trim(imageTextList[0]);
  //println(randFileName);

  //String imageString="pImages/p519868417.jpg";
  //print(imageString);
  // - end of the grab text

  x = new float[word.length()];
  y = new float[word.length()];
  wordArray = splitTokens(word);
  wordObjects = new wordObject[wordArray.length];

  //setup the wordObjectArray start with one extra to account for elipse
  for(int i=1;i<wordArray.length;i++){
    wordObject thisGuy = new wordObject(wordArray[i-1]);
    wordObjects[i] = thisGuy;
  }
    
 // println(wordObjects.length);
  img = loadImage(imageString);
  theBlobDetection = new BlobDetection(img.width, img.height);
  theBlobDetection.setPosDiscrimination(false);
  theBlobDetection.setThreshold(0.38f);
  theBlobDetection.computeBlobs(img.pixels);
    float imgMult = 768.000f/img.height;
   newWidth=round(img.width*imgMult);
   newHeight=round(img.height*imgMult);
   //newHeight = 630;
  //textX= (newWidth/4)-10; 
  //textLineLength=(newWidth)/16;
  textLineLength=(newWidth)/16;
  //textX= (1024/4)-10;
  xAdjust = (1024-newWidth)*.5f;
  textX= PApplet.parseInt((xAdjust*.5f)+1024*.25f);



  drawBlobsAndEdges(false,true);
   
  setUpWordsLetters(0, 0, 0,1);

  
}


  static public void main(String args[]) {
    PApplet.main(new String[] { "--bgcolor=#FFFFFF", "NightBeyondNight_App" });
  }
}
