import processing.core.*; 
import processing.xml.*; 

import javax.imageio.*; 
import javax.imageio.stream.*; 

import java.applet.*; 
import java.awt.*; 
import java.awt.image.*; 
import java.awt.event.*; 
import java.io.*; 
import java.net.*; 
import java.text.*; 
import java.util.*; 
import java.util.zip.*; 
import java.util.regex.*; 

public class OnlineSketch extends PApplet {




PFont menufont;
Menu toolsmenu;
Menu actionsmenu;
Slider testslider;
ColorPicker strokecp;
ColorPicker fillcp;

PGraphics canvas;
PImage bgimage;

static final int RECTANGLE = 0;
static final int LINE = 1;
static final int LINE_DOWN = 11;
static final int TEXT = 2;
static final int TEXT_WRITE = 21;
static final int PENCIL = 3;
static final int BRUSH = 4;
static final int CROP = 5;
static final int COLORPICK_STROKE = 6;
static final int COLORPICK_STROKE_SELECTING = 61;
static final int COLORPICK_FILL = 7;
static final int COLORPICK_FILL_SELECTING = 71;
static final int FILL = 8;
static final int STROKEWEIGHT = 9;

int tool = LINE;
int prevtool = LINE;

int[] canvassize = {100, 100, 100, 100};

String[] toolsmenuitems = {"line","pencil","brush","rectangle","text","fill","canvas size"};
String[] actionsmenuitems = {"upload","fill color","stroke color", "stroke weight"};

int fillcolor = 100;
int strokecolor = 200;
int strokeweight = 10;
boolean colorPickerVisible = false;

String textstring = "";

int startx;
int starty;
int endx;
int endy;

int bgcolor;

public void setup(){
  size(600,600);
  noLoop();
  smooth();
  
  bgimage = loadImage("bgimage.png");
  //menufont = loadFont("ArialMT-24.vlw");
  menufont = loadFont("ArialMT-12.vlw");
  bgcolor = color(200);
  canvas = createGraphics(width, height, JAVA2D);
  canvas.endDraw();
  
  strokecp = new ColorPicker((width/2)-((255+60)/2), (width/2)-(255/2), 255+60, 255, 255);
  fillcp = new ColorPicker((width/2)-((255+60)/2), (width/2)-(255/2), 255+60, 255, 255);
  
  testslider = new Slider("testslider", 100, 100);
  
  toolsmenu = new Menu("tools", 3, 3, 3, true);
  toolsmenu.addRadioButton(toolsmenuitems);
  
  actionsmenu = new Menu("actions", 3, 26, 3, false);
  actionsmenu.addRadioButton(actionsmenuitems);
  
}

public void draw(){
  //image(bgimage, 0, 0, width, height);
  background(255);
  fill(220);
  noStroke();
  for(int i = 0; i < height; i+=20){
    for(int j = 0; j < width; j+=20){
      rect(j, i, 10, 10);
      rect(j+10, i+10, 10, 10);
    }
  }

  image(canvas, 0, 0);
  
  stroke(0);
  
  if (mousePressed == true && mouseButton == LEFT && !menuActions()) {
    if(tool == RECTANGLE){
      fill(fillcolor);
      stroke(strokecolor);
      rect(startx, starty, endx-startx, endy-starty); 
    } else if(tool == LINE_DOWN){
      stroke(strokecolor);
      line(startx, starty, endx, endy); 
    } else if(tool == PENCIL){
      stroke(strokecolor);
      line(pmouseX, pmouseY, mouseX, mouseY);
    }
  }
  
  if(tool == TEXT_WRITE){
      textFont(menufont);
      fill(fillcolor);
      textAlign(LEFT, LEFT);
      text(textstring, mouseX, mouseY);
  } else if(tool == CROP){
    noFill();
    stroke(0);
    rect(canvassize[0], canvassize[1], canvassize[2], canvassize[3]);
    fill(255);
    rect(canvassize[0]-2, canvassize[1]-2, 5, 5);
    rect(canvassize[0]+canvassize[2]-2, canvassize[1]-2, 5, 5);
    rect(canvassize[0]-2, canvassize[1]+canvassize[3]-2, 5, 5);
    rect(canvassize[0]+canvassize[2]-2, canvassize[1]+canvassize[3]-2, 5, 5);
  } else if(tool == STROKEWEIGHT){
    stroke(0);
    strokeWeight(strokeweight);
    line(0,0,width, height);
    
    
    stroke(strokecolor);
  }
  
  toolsmenu.drawMenu();
  actionsmenu.drawMenu();
  
  //testslider.update();
  
  if(colorPickerVisible) strokecp.render();
}


public void mousePressed() {
  println("mousePressed");
  
  if(mouseButton == LEFT){
    if(tool == LINE){
      tool = LINE_DOWN;
    } else if(tool == COLORPICK_STROKE){
      if(strokecp.hover()){
        tool = COLORPICK_STROKE_SELECTING;
      } else {
        colorPickerVisible = false;
        tool = prevtool;
        actionsmenu.getButtonByName("stroke color").selected = false;
      }
    } else if(tool == COLORPICK_FILL){
      if(strokecp.hover()){
        tool = COLORPICK_FILL_SELECTING;
      } else {
        colorPickerVisible = false;
        tool = prevtool;
        actionsmenu.getButtonByName("fill color").selected = false;
      }
    } else if(tool == FILL){
      
    }
      
       startx = mouseX;
      starty = mouseY;
      endx = startx;
      endy = starty;
      
  }
  
  redraw();
}

  

public void mouseReleased(){
  println("mouseReleased");
  
  if(!menuActions()){
  
  if (mouseButton == LEFT) {
    if(tool == RECTANGLE){
      canvas.beginDraw();
      canvas.fill(fillcolor);
      canvas.stroke(strokecolor);
      canvas.rect(startx, starty, endx-startx, endy-starty); 
      canvas.endDraw();
    } else if(tool == LINE_DOWN){
      if(dist(startx, starty, endx, endy) > 1){
        canvas.beginDraw();
        canvas.stroke(strokecolor);
        canvas.line(startx, starty, endx, endy); 
        canvas.endDraw();
      }
      tool = LINE;
    } else if(tool == TEXT){
      tool = TEXT_WRITE;
    } else if(tool == TEXT_WRITE){
      tool = TEXT;
      canvas.beginDraw();
      canvas.fill(fillcolor);
      canvas.textFont(menufont);
      canvas.textAlign(LEFT, LEFT);
      canvas.text(textstring, endx, endy);
      canvas.endDraw();
      textstring = "";
    } else if(tool == COLORPICK_STROKE_SELECTING){
      strokecolor = strokecp.c;
      tool = prevtool;
      colorPickerVisible = false;
      actionsmenu.getButtonByName("stroke color").selected = false;
    } else if(tool == COLORPICK_FILL_SELECTING){
      fillcolor = strokecp.c;
      tool = prevtool;
      colorPickerVisible = false;
      actionsmenu.getButtonByName("fill color").selected = false;
    } else if(tool == PENCIL){
      canvas.beginDraw();
      canvas.strokeWeight(1);
      canvas.stroke(strokecolor);
       canvas.line(mouseX, mouseY, mouseX, mouseY);
       canvas.endDraw();
    } else if(tool == BRUSH){
      canvas.beginDraw();
      canvas.strokeWeight(30);
      canvas.stroke(strokecolor);
       canvas.line(mouseX, mouseY, mouseX, mouseY);
       canvas.endDraw();
    }
    
  }
  
  }
  redraw();
}

public void mouseMoved(){
  toolsmenu.mouseMoved();
  actionsmenu.mouseMoved();
  redraw();
}

public void mouseDragged(){
  //println("mouseDragged");
  
  endx = mouseX;
  endy = mouseY;
  
  if(!menuActions()){
    if(tool == PENCIL){
      canvas.beginDraw();
      canvas.strokeWeight(1);
      canvas.stroke(strokecolor);
       canvas.line(pmouseX, pmouseY, mouseX, mouseY);
       canvas.endDraw();
    } else if(tool == BRUSH){
      canvas.beginDraw();
      canvas.strokeWeight(30);
      canvas.stroke(strokecolor);
       canvas.line(pmouseX, pmouseY, mouseX, mouseY);
       canvas.endDraw();
    } else if (tool == LINE && keyPressed && key == CODED && keyCode == SHIFT){
      if(abs(startx-endx) < 20) endx = startx;
      if(abs(starty-endy) < 20) endy = starty;
    }
  }
  redraw();
}


public void keyTyped() {
  println(tool);
  if(tool == TEXT_WRITE){
    textstring = textstring + PApplet.parseChar(key);
    redraw();
  }
}


public boolean menuActions(){
  String action = toolsmenu.mouseClicked();
  action += actionsmenu.mouseClicked();
  
  if(action.equals("")){
    return false;
  } else if(action.equals("upload")){
    upload();
  } else if(action.equals("line")){
    tool = LINE;
  } else if(action.equals("pencil")){
    tool = PENCIL;
  } else if(action.equals("brush")){
    tool = BRUSH;
  } else if(action.equals("rectangle")){
    tool = RECTANGLE;
  } else if(action.equals("text")){
    tool = TEXT;
  } else if(action.equals("canvas size")){
    tool = CROP;
  } else if(action.equals("stroke color")){
    Button temp = actionsmenu.getButtonByName("stroke color");
    strokecp.x = temp.x+3;
    strokecp.y = temp.y+temp.h+3;
    temp.selected = true;

    if(tool != COLORPICK_STROKE) prevtool = tool;
    tool = COLORPICK_STROKE;
    colorPickerVisible = true;
  } else if(action.equals("fill color")){
    Button temp = actionsmenu.getButtonByName("fill color");
    strokecp.x = temp.x+3;
    strokecp.y = temp.y+temp.h+3;
    temp.selected = true;
    
    if(tool != COLORPICK_FILL) prevtool = tool;
    tool = COLORPICK_FILL;
    colorPickerVisible = true;
  } else if(action.equals("stroke weight")){
    tool = STROKEWEIGHT;
  }
  return true;
} 







public void upload(){
  byte[] bytes = getCanvasAsBytes();
  
  String boundary = "|X-seltars-image-and-pdf-byte-array-uploader-X|";
    try{
      URL u = new URL("http://bredend.com/sketch/upload.php");
      HttpURLConnection c = (HttpURLConnection)u.openConnection();

      // post multipart data
      c.setDoOutput(true);
      c.setDoInput(true);
      c.setUseCaches(false);

      // set request headers
      c.setRequestProperty("Content-Type", "multipart/form-data; boundary="+boundary);

      // open a stream which can write to the url
      DataOutputStream dstream = new DataOutputStream(c.getOutputStream());

      // write content to the server, begin with the tag that says a content element is comming
      dstream.writeBytes("--"+boundary+"\r\n");

      // discribe the content
      dstream.writeBytes("Content-Disposition: form-data; name=\"sketch\"; filename=\"test.jpg\"\r\nContent-Type: image/png\r\nContent-Transfer-Encoding: binary\r\n\r\n");
      dstream.write(bytes,0,bytes.length);

      // close the multipart form request
      dstream.writeBytes("\r\n--"+boundary+"--\r\n\r\n");
      dstream.flush();
      dstream.close();

      StringBuffer response = new StringBuffer();
      // read the output from the URL
      try{
        BufferedReader in = new BufferedReader(new InputStreamReader(c.getInputStream()));
        // Get the server response code
        int responseCode = -1;
        try
        {
          responseCode = c.getResponseCode();
        }
        catch (IOException ioe)
        {
        }
        if(responseCode == 200){
          // Everything has gone well so far
          // Get the server response
          String responseLine = null;
          do{
            responseLine = in.readLine();
            if (responseLine != null)
            {
              response.append(responseLine + "\n");
              
              if(responseLine.substring(0,4).equals(("http").substring(0,4))){ // if it's an url
                if(true) this.link(responseLine, "_blank"); 
              }
              
            }
          }
          while(responseLine!=null);
          // output the response
          println(response.toString());
        }
      }
      catch(Exception e){
        e.printStackTrace();
      }
    }
    catch(Exception e){
      e.printStackTrace();
    }
  
  
}

public byte[] getCanvasAsBytes(){
  ByteArrayOutputStream baos = new ByteArrayOutputStream();
  try{
    ImageIO.write((BufferedImage)canvas.image, "png", baos);
  } catch (Exception e) {
    e.printStackTrace();
    return new byte[0]; // Problem
  }
  return baos.toByteArray();
}




class Button{
  
  String name;
  boolean hover;
  boolean selected;
  int x = 0;
  int y = 0;
  int w = 0;
  int h = 0;
  
  
  Button(String name){
    this.name = name;
    textFont(menufont);
    this.w = PApplet.parseInt(5+textWidth(name)+5);
    this.h = 20;
  }
  
  
  public void update(int x, int y){
    this.x = x;
    this.y = y;

    noStroke();
    fill(190);
    if(hover) fill(220);
    if(selected) fill(190, 200, 220);
    textFont(menufont);
    rect(x, y, w, h);
    fill(0);
    textAlign(CENTER, CENTER);
    text(name, x, y, w, h);
  }
  
  public void mouseMoved() {
    if(mouseX > x && mouseX < x+w && mouseY > y && mouseY < y+h){
      hover = true;
    } else {
      hover = false;
    }
  }
}

public class ColorPicker{
  int x, y, w, h, c;
  PImage cpImage;
	
  public ColorPicker ( int x, int y, int w, int h, int c )  {
    this.x = x;
    this.y = y;
    this.w = w;
    this.h = h;
    this.c = c;
		
    cpImage = new PImage( w, h );
		
    init();
  }
	
  private void init ()
  {
    // draw color.
    int cw = w - 60;
    for( int i=0; i<cw; i++ ) 
    {
      float nColorPercent = i / (float)cw;
      float rad = (-360 * nColorPercent) * (PI / 180);
      int nR = (int)(cos(rad) * 127 + 128) << 16;
      int nG = (int)(cos(rad + 2 * PI / 3) * 127 + 128) << 8;
      int nB = (int)(Math.cos(rad + 4 * PI / 3) * 127 + 128);
      int nColor = nR | nG | nB;
			
      setGradient( i, 0, 1, h/2, 0xFFFFFF, nColor );
      setGradient( i, (h/2), 1, h/2, nColor, 0x000000 );
    }
		
    // draw black/white.
    drawRect( cw, 0,   30, h/2, 0xFFFFFF );
    drawRect( cw, h/2, 30, h/2, 0 );
		
    // draw grey scale.
    for( int j=0; j<h; j++ )
    {
      int g = 255 - (int)(j/(float)(h-1) * 255 );
      drawRect( w-30, j, 30, 1, color( g, g, g ) );
    }
  }

  private void setGradient(int x, int y, float w, float h, int c1, int c2 )
  {
    float deltaR = red(c2) - red(c1);
    float deltaG = green(c2) - green(c1);
    float deltaB = blue(c2) - blue(c1);

    for (int j = y; j<(y+h); j++)
    {
      int c = color( red(c1)+(j-y)*(deltaR/h), green(c1)+(j-y)*(deltaG/h), blue(c1)+(j-y)*(deltaB/h) );
      cpImage.set( x, j, c );
    }
  }
	
  private void drawRect( int rx, int ry, int rw, int rh, int rc )
  {
    for(int i=rx; i<rx+rw; i++) 
    {
      for(int j=ry; j<ry+rh; j++) 
      {
        cpImage.set( i, j, rc );
      }
    }
  }
  
  public boolean hover(){
    return mousePressed && mouseX >= x && mouseX < x + w && mouseY >= y && mouseY < y + h;
  }
	
  public void render ()
  {
    noStroke();
    fill(190, 200, 220);
    rect(x-3, y-3, w+6, h+6);
    image( cpImage, x, y );
    if( mousePressed && hover() )
    {
      c = get( mouseX, mouseY );
    }
    fill( c );
    rect( x, y+h+10, 20, 20 );
  }
}
class Menu{
  
  ArrayList buttons;
  int selectedOption = 0;
  String name;
  int x;
  int y;
  int margin;
  boolean radiobutton;
  
  
  Menu(String name, int x, int y, int margin, boolean radiobutton){
    this.name = name;
    this.x = x;
    this.y = y;
    this.margin = margin;
    this.radiobutton = radiobutton;
    buttons = new ArrayList();
  }
  
  
  public void drawMenu(){
    int startx = x;
    for(int i = 0; i < buttons.size(); i++){
      Button temp = (Button)buttons.get(i);
      temp.update(startx, y);
      startx = temp.x + temp.w + margin;
    }
  }
  
  public void addRadioButton(String[] names){
    for(int i = 0; i < names.length; i++){
      buttons.add(new Button(names[i]));
    }
  }
  
  public Button getButtonByName(String name){
    for(int i = 0; i < buttons.size(); i++){
      Button temp = (Button)buttons.get(i);
      if(temp.name.equals(name)){
        return temp;
      }
    }
    return null;
  }
    
  
  public void mouseMoved(){
    for(int i = 0; i < buttons.size(); i++){
      Button temp = (Button)buttons.get(i);
      temp.mouseMoved();
    }
  }
  
  public String mouseClicked() {
    String action = "";
    
    for(int i = 0; i < buttons.size(); i++){
      Button temp = (Button)buttons.get(i);
      if(temp.hover){
        if(radiobutton){
          for(int j = 0; j < buttons.size(); j++){
            Button temp2 = (Button)buttons.get(j);
            temp2.selected = false;
          }
          temp.selected = true;
        }
        action = temp.name;
      }
    }

    return action;
  }
  
  public void roundedRect(int x, int y, int w, int h, int r){
    noStroke();
    rect(x, y+r, w, h-(2*r));
    rect(x+r, y, w-(2*r), h);
    
    ellipseMode(RADIUS);
    ellipse(x+r, y+r, r, r);
    ellipse(x+w-r, y+r, r, r);
    ellipse(x+w-r, y+h-r, r, r);
    ellipse(x+r, y+h-r, r, r);
  }

}

class Slider{
  
  String name;
  boolean hover;
  boolean selected;
  int x = 0;
  int y = 0;
  int w = 0;
  int h = 0;
  
  
  Slider(String name, int x, int y){
    this.name = name;
    textFont(menufont);
    this.x = x;
    this.y = y;
    this.w = PApplet.parseInt(5+textWidth(name)+5);
    this.h = 100;
  }
  
  
  public void update(){
    strokeCap(PROJECT);
    strokeWeight(3);
    stroke(190);
    line(x, y, x, y+h);
    
    strokeWeight(1);
    stroke(255);
    line(x, y, x, y+h);
    
    noStroke();
    fill(150);
    rect(x-2, y+40, 5, 5);

  }
  
  public void mouseMoved() {
    if(mouseX > x && mouseX < x+w && mouseY > y && mouseY < y+h){
      hover = true;
    } else {
      hover = false;
    }
  } 
}


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

