//some global vars
var canvas, c, canvastemp, ctemp, brushcanvas, brushc;
var ImageDir = "/images/";

var drawObject = null;

var currentColour = "ffffff";

//some globals
var PictureWidth = 150;
var PictureHeight = 150;

var BrushCanvasSize = 20;

var pixelDataSize = PictureWidth * PictureHeight;
var pixelData = new Array( pixelDataSize );

var lastDrawX = -5000;
var lastDrawY = -5000;

var DefaultPicBkgColour = "#333333";

var ButtonWidth = 30;
var ButtonHeight = 30;

var pencil_glyph, circle_glyph, square_glyph, fillcircle_glyph, fillsquare_glyph;
var ButtonSet = new Object();

function createBtnImage( src )
{
  var img = new Image( ButtonWidth, ButtonHeight );;
  img.src = src;
  return img;
}

function createButtonGlyph( upsrc, downsrc )
{
  return { up : createBtnImage( ImageDir + upsrc ), down : createBtnImage( ImageDir + downsrc ) };
}

//utility
function max( x, y )
{
  var ret;
  if( x > y )
  {
    ret = x;
  }
  else
  {
    ret = y;
  }
  
  return ret;
}

//min
function min( x, y )
{
  var ret;
  if( x < y )
  {
    ret = x;
  }
  else
  {
    ret = y
  }
  
  return ret;
}

//-------------------------------------------
//line object
function line(x1,y1,x2,y2) {
	this.x1 = x1;
  this.y1 = y1;
  this.x2 = x2;
  this.y2 = y2;
	
  this.Top = min( y1, y2 );
  this.Bottom = max( y1, y2 );
  
  //get the crossing pts between this line and a horizontal ray travelling right
  this.getXRayCross = function( yval )
  { 
    var ret = null;
  
    if( yval >= this.Top && yval <= this.Bottom )
    {
      //avoid pathological case of horizontal line seg
      if( this.y2 != this.y1 )
      {
        var t = ( yval - this.y1 ) / ( this.y2 - this.y1 );
        ret = this.x1 + t * ( this.x2 - this.x1 );
      }
      else
      {
        ret = this.x1;
      }
    }
    
    return ret;
  }
  
  this.length = function()
  {
    var xdiff = this.x2 - this.x1;
    var ydiff = this.y2 - this.y1;
    return Math.sqrt( xdiff * xdiff + ydiff * ydiff );
  }
  
  this.getPointAtT = function( t )
  {
    return { x : this.x1 + t * ( this.x2- this.x1 ), y : this.y1 + t * ( this.y2 - this.y1 ) };
  }
  
};

function preLoadImages()
{
  pencil_glyph = createButtonGlyph( "button_pencil_up.png", "button_pencil_down.png" );
  circle_glyph = createButtonGlyph( "button_circle_up.png", "button_circle_down.png" );
  square_glyph = createButtonGlyph( "button_square_up.png", "button_square_down.png" );
  fillcircle_glyph = createButtonGlyph( "button_fillcircle_up.png", "button_fillcircle_down.png" );
  fillsquare_glyph = createButtonGlyph( "button_fillsquare_up.png", "button_fillsquare_down.png" );
  
  ButtonSet[ "pencil" ] = pencil_glyph ;
  ButtonSet[ "square" ] = square_glyph;
  ButtonSet[ "circle" ] = circle_glyph;
  ButtonSet[  "fillsquare" ] = fillsquare_glyph;
  ButtonSet[ "fillcircle" ] = fillcircle_glyph;

}

function ButtonDown( downbtn )
{
  //put all buttons up unless it the downbtn
  for(var glyphname in ButtonSet) {
   var glyph = ButtonSet[glyphname];
   
   if( glyphname != downbtn )
   {
      document[ glyphname ].src = glyph.up.src;
   }
   else
   {
      document[ glyphname ].src = glyph.down.src;
   }
  }
}

function drawer_setup()
{
 preLoadImages();
 
 //set up canvas
 canvas = document.getElementById('canvas');
 canvastemp = document.getElementById('canvastemp');
 brushcanvas = document.getElementById("brushcanvas");
 
 //check for IE6 get position wrong
 if( document.getElementById("IESix") )
 {
  document.getElementById("canvascont" ).style.left = "-55pt";
 }
 
 if(canvas.getContext) 
 {
   c = canvas.getContext("2d");
   ctemp = canvastemp.getContext("2d");
   
   if( brushcanvas )
   {
     brushc = brushcanvas.getContext("2d");
   }
   
   //set up defaults
   c.lineWidth = 1;
   c.strokeStyle = '#000';
   c.fillStyle = '#FFF';
   c.tertStyle = '#DDD';
   c.strokeFill = 1; //outline shapes


   c.fillRect(0, 0, canvas.width, canvas.height); //fill with background color (=not transparent)

   //set up events
   window.onmouseup = bodyUp;
   window.onmousemove = bodyMove;

   canvas.onmousedown = canvastemp.onmousedown = c_down;
   canvas.onmousemove = canvastemp.onmousemove = c_move;
   canvas.onmouseout = canvastemp.onmouseout = c_out;
   canvas.onmouseup = canvastemp.onmouseup = c_up;

   
   ClearPicture();
   selectCol( currentColour );
   selectPencilDraw();
 }
}


function getxy(e, o) {
//gets mouse position relative to object o

 if(c) {
 //IE madness
 if (!e) var e = window.event;
 var bo = getpos(o);

 var x = e.clientX - bo.x; //correct for canvas position, workspace scroll offset
 var y = e.clientY - bo.y;
 if( ! o.getBoundingClientRect ) //only correct if not IE...
 {
  x += document.documentElement.scrollLeft; //correct for window scroll offset
  y += document.documentElement.scrollTop;
 }
 x = (c.zoom) ? x/c.zoom : x; //correct for zoom
 y = (c.zoom) ? y/c.zoom : y;
 return { x: x-.5, y: y-.5 }; //-.5 prevents antialiasing of stroke lines
 }
}

function getpos(o) 
{
//gets position of object o
 var bo, x, y, b; x = y = 0;
 
 if (o.getBoundingClientRect) { //ie (??)
 bo = o.getBoundingClientRect(); //this is relative to screen position not including vertical scroll bar effect in y and presumably x
 x = bo.left; y = bo.top;
 } else if(document.getBoxObjectFor) { //moz
 bo = document.getBoxObjectFor(o);
 x = bo.x; y = bo.y;
 }else { //opera, safari etc
 while(o && o.nodeName != 'BODY') {
 x += o.offsetLeft;
 y += o.offsetTop;
 b = parseInt(document.defaultView.getComputedStyle(o,null).getPropertyValue('border-width'));
 if(b > 0) { x += b; y +=b; }
 o = o.offsetParent;
 }
 }
 return { x:x, y:y }
}

function c_down(e) 
{
  m = getxy(e, canvas);
  
  if( drawObject != null )
	{
		drawObject.OnClickDown( m.x,m.y );
    lastDrawX = m.x;
    lastDrawY = m.y;
	}
  
  return false;
}

//handles mouseup on the canvas depending on tool selected
function c_up(e) 
{
  m = getxy(e, canvas);

  if( e !=null )
  {
    e.stopPropagation();
  }

  if( drawObject != null )
  {
    drawObject.OnClickUp(m.x,m.y);
    lastDrawX = -5000;
    lastDrawY = -5000;
  }

  return false;
}

function c_move(e) {
  //IE madness
  m = getxy(e, canvas);
  
  if( e !=null )
  {
    e.stopPropagation();
  }

  if( drawObject != null )
  {
    drawObject.OnOver( m.x, m.y );
    lastDrawX = m.x;
    lastDrawY = m.y;
  }

  return false;
}

function c_out(e) {
 //var source = e.currentTarget;

}


function bodyMove(e) {
//lets the user move outside the canvas while drawing shapes and lines
}


function bodyUp(e) {
}

function updateBrushSize()
{
	if( drawObject != null )
	{
		var combobox = document.picturesearch.brushsize;
		var size = combobox.options[combobox.selectedIndex].value;
		drawObject.brushSize = parseInt(size);
    
    brushc.clearRect( 0, 0, brushcanvas.width, brushcanvas.height );
    
    var halfwidth = drawObject.brushSize / 2;
    
    brushc.beginPath();
    brushc.fillStyle = "#000000";
    var bcentre =  BrushCanvasSize / 2;
    
    brushc.fillRect( bcentre - halfwidth, bcentre - halfwidth, drawObject.brushSize, drawObject.brushSize ); 
	}
}

function FillRectInData( left, top, width, height, col )
{
  for( var x = left; x < left + width; x++ )
  {
    for( var y = top; y < top + height; y++ )
    {
      pixelData[ x + y * PictureWidth ] = col;
    }
  }
}

function  FillCentredRectInData( x, y, width, height, col )
{
  x = Math.floor(x);
  y = Math.floor(y);
  
  var halfwidth = Math.round( width / 2 );
  var halfheight = Math.round( height / 2 );
  var top = y - halfheight;
  var left = x - halfwidth;
  
  FillRectInData( left, top, width, height, col );
}

//draw a rect centred on x y
function DrawCentredRect( x, y, width, height )
{
  x = Math.floor(x);
  y = Math.floor(y);
  
  var halfwidth = Math.round( width / 2 );
  var halfheight = Math.round( height / 2 );
  var top = y - halfheight;
  var left = x - halfwidth;
  
  DrawRect( left, top, width, height );
}


//draw a rect in canvas and datam with current col
function DrawRect( left, top, width, height )
{
    var strColor = "#" + currentColour;
    c.beginPath();
    c.strokeStyle =  strColor;
    c.fillStyle = strColor;
    
    c.fillRect( left, top, width, height );
    
    //represent rect in data
    FillRectInData( left, top, width, height, strColor );
}

function DrawDataLine( lne )
{
  var strColor = "#" + currentColour;
  FillCentredRectInData( lne.x1, lne.y1, drawObject.brushSize, drawObject.brushSize, strColor );
  FillCentredRectInData( lne.x2, lne.y2, drawObject.brushSize, drawObject.brushSize, strColor );
  
  //how many rects to this line approx
  var steps = lne.length() / drawObject.brushSize;
  
  if( steps > 2 )
  {
    for( var t = 1; t < steps; t++ )
    {
      steppoint = lne.getPointAtT( t / steps );
      FillCentredRectInData( steppoint.x, steppoint.y, drawObject.brushSize, drawObject.brushSize, strColor );
    }
  }
}

//draw line in data and screen
function DrawLine( lne )
{
  //draw rect at start and stop points
  DrawCentredRect( lne.x1, lne.y1, drawObject.brushSize, drawObject.brushSize );
  DrawCentredRect( lne.x2, lne.y2, drawObject.brushSize, drawObject.brushSize );
  
  //how many rects to this line approx
  var steps = lne.length() / drawObject.brushSize;
  
  if( steps > 2 )
  {
    for( var t = 0.5; t < steps;  )
    {
      steppoint = lne.getPointAtT( t / steps );
      DrawCentredRect( steppoint.x, steppoint.y, drawObject.brushSize, drawObject.brushSize );
      t = t + 0.5;
    }
  }
}

function ClearSelectCanvas()
{
//clear selection canvas
  ctemp.beginPath();
  ctemp.clearRect(0,0,canvastemp.width, canvastemp.height);
}


function PixelDataToCanvas()
{
  for( var y = 0; y < PictureHeight; y++ )
  {
    var startx = 0;
    var startcol = pixelData[ y * PictureWidth ];
    var endx = 0;
    
    for( var x = 0; x < PictureWidth; x++ )
    {
      var index = x + y * PictureWidth;
      if( pixelData[ index ] == startcol && x != PictureWidth - 1)
      {
        endx = x;
      }
      else
      {
        c.beginPath();
        c.strokeStyle = startcol;
        c.fillStyle = startcol;
        c.fillRect( startx, y, endx - startx, 1 );
        
        startx= x;
        startcol = pixelData[ index ]
      }
    }
  }
}

//clear the picture, fill with current colour selection
function ClearPicture()
{
	var setColour =  DefaultPicBkgColour;
  c.beginPath();
  c.fillStyle = setColour;
  c.fillRect(0,0,PictureWidth,PictureHeight);
  
  //clear data
  for( var i = 0; i < PictureHeight * PictureWidth; i++ )
  {
    pixelData[ i ] = DefaultPicBkgColour;
  }
}

function PencilClickUp( x, y )
{
	drawObject.penDown = 0;
}

//while pen selected mouse clicked a cell
function PencilClickDown( x, y )
{
  drawObject.penDown = 1;
  
  DrawCentredRect( x, y, drawObject.brushSize, drawObject.brushSize );
}


//while pen selected mouse over given cell
function PencilOver( x, y )
{
	if( drawObject.penDown && ( x != lastDrawX || y != lastDrawY ) )
	{
  
    var mline = new line( lastDrawX, lastDrawY, x, y );
    DrawLine(mline);
	}
}

function CircleUp( x, y )
{
  drawObject.penDown = 0;
  
  var radius = Math.sqrt( ( x - CircleCentreX ) * ( x - CircleCentreX ) + ( y - CircleCentreY ) * ( y - CircleCentreY ) );
  var strColor = "#" + currentColour;
  
  //clear temp canvas
  ClearSelectCanvas();
  
  //render this circle onto main canvas and data
  c.beginPath();
  c.lineWidth = drawObject.brushSize;
  c.strokeStyle = strColor;
  c.arc( CircleCentreX, CircleCentreY, radius, 0, Math.PI * 2, false );
  c.stroke();
  
  //draw in data
  var ytop = Math.floor( CircleCentreY - radius );
  var ybottom = Math.floor( CircleCentreY + radius );
  
  //do top and bottom
  var halfwidth = Math.ceil( drawObject.brushSize / 2 );
  FillRectInData( CircleCentreX - halfwidth, ytop - halfwidth, halfwidth, halfwidth, strColor );
  FillRectInData( CircleCentreX - halfwidth, ybottom - halfwidth, halfwidth, halfwidth, strColor );
  
  var prey = ytop;
  var preyinv = ybottom;
  var prex1 = CircleCentreX;
  var prex2 = CircleCentreX;
  
  for( var y = ytop + 1; y <= CircleCentreY; y++ )
  {
    var reff =  CircleCentreY - y;
    var dr = radius - reff;
    var chord = Math.sqrt( radius * radius - reff * reff )
    var x1 = Math.round( CircleCentreX - chord );
    var x2 = Math.round( CircleCentreX + chord );
    
    var yinv = ybottom - (y-ytop) ;
    
    DrawDataLine( new line( prex1, prey, x1, y ) );
    DrawDataLine( new line( prex2, prey, x2, y ) );
      
    if( y != yinv )
    {
      DrawDataLine( new line( prex1, preyinv, x1, yinv ) );
      DrawDataLine( new line( prex2, preyinv, x2, yinv ) );
    }
    
    prey = y;
    preyinv = yinv;
    prex1 = x1;
    prex2 = x2;
  }
}

var CircleCentreX = -5000;
var CircleCentreY = -5000;

function CircleDown( x, y )
{
  drawObject.penDown = 1;
  
  CircleCentreX = x;
  CircleCentreY = y;
}

function CircleOver( x, y )
{
  if( drawObject.penDown && ( x != lastDrawX || y != lastDrawY ) )
  {
      ClearSelectCanvas();
      
      var radius = Math.sqrt( ( x - CircleCentreX ) * ( x - CircleCentreX ) + ( y - CircleCentreY ) * ( y - CircleCentreY ) );
      var strColor = "#" + currentColour;
      
      ctemp.beginPath();
      ctemp.lineWidth = drawObject.brushSize;
      ctemp.strokeStyle = strColor;
      ctemp.arc( CircleCentreX, CircleCentreY, radius, 0, Math.PI * 2, false );
      ctemp.stroke();
  }
}


function FillCircleDown( x, y )
{
  drawObject.penDown = 1;
  
  CircleCentreX = Math.ceil( x );
  CircleCentreY = Math.ceil( y );
}

function FillCircleOver( x, y )
{
  if( drawObject.penDown && ( x != lastDrawX || y != lastDrawY ) )
  {
      ClearSelectCanvas();
      
      var radius = Math.sqrt( ( x - CircleCentreX ) * ( x - CircleCentreX ) + ( y - CircleCentreY ) * ( y - CircleCentreY ) );
      var strColor = "#" + currentColour;
      
      ctemp.beginPath();
      ctemp.lineWidth = 1;
      ctemp.fillStyle = strColor;
      ctemp.arc( CircleCentreX, CircleCentreY, radius, 0, Math.PI * 2, false );
      ctemp.fill();
  }
}

function FillCircleUp( x, y )
{
  drawObject.penDown = 0;
  
  var radius = Math.sqrt( ( x - CircleCentreX ) * ( x - CircleCentreX ) + ( y - CircleCentreY ) * ( y - CircleCentreY ) );
  var strColor = "#" + currentColour;
  
  //clear temp canvas
  ClearSelectCanvas();
  
  //render this circle onto main canvas and data
  c.beginPath();
  c.lineWidth = 1;
  c.fillStyle = strColor;
  c.arc( CircleCentreX, CircleCentreY, radius, 0, Math.PI * 2, false );
  c.fill();
  
  //draw in data
  var ytop = Math.floor( CircleCentreY - radius );
  var ybottom = Math.floor( CircleCentreY + radius );
  
  //do top and bottom
  FillRectInData( CircleCentreX, ytop, 1, 1, strColor );
  FillRectInData( CircleCentreX, ybottom, 1, 1, strColor );
  
  for( var y = ytop + 1; y <= CircleCentreY; y++ )
  {
    var reff =  CircleCentreY - y;
    var dr = radius - reff;
    var chord = Math.sqrt( radius * radius - reff * reff )
    var x1 = Math.floor( CircleCentreX - chord );
    var x2 = Math.floor( CircleCentreX + chord );
    
    var yinv = Math.floor( CircleCentreY + reff );
    
    for( var xline = x1; xline <= x2; xline++ )
    {
      pixelData[ xline + y * PictureWidth ] = strColor;
      
      if( y != yinv )
      {
        pixelData[ xline + yinv * PictureWidth ]= strColor;
      }
    }
  }
}

var SquareStartX = -5000;
var SquareStartY = -5000;

function FillSquareOver( x, y )
{
  if( drawObject.penDown && ( x != lastDrawX || y != lastDrawY ) )
  {
    ClearSelectCanvas();
    var strColor = "#" + currentColour;
    
    ctemp.fillStyle = strColor;

    ctemp.fillRect( SquareStartX, SquareStartY, x - SquareStartX, y - SquareStartY );
  }

}

function FillSquareDown( x, y )
{
  drawObject.penDown = 1;
  
  SquareStartX = x;
  SquareStartY = y;
}

function FillSquareUp( x, y )
{
  drawObject.penDown = 0;
  ClearSelectCanvas();

  DrawRect( Math.round( SquareStartX ), Math.round( SquareStartY ), Math.round( x - SquareStartX ), Math.round( y - SquareStartY ) );
}

function SquareDown( x, y )
{
  drawObject.penDown = 1;
  
  SquareStartX = x;
  SquareStartY = y;
}

function SquareOver( x, y )
{
  if( drawObject.penDown && ( x != lastDrawX || y != lastDrawY ) )
  {
    ClearSelectCanvas();
    var strColor = "#" + currentColour;
    
    ctemp.strokeStyle = strColor;
    ctemp.fillStyle = strColor;
    ctemp.lineWidth = drawObject.brushSize;
    ctemp.strokeRect( SquareStartX, SquareStartY, x - SquareStartX, y - SquareStartY );
  }
}

function SquareUp( x, y )
{
  drawObject.penDown = 0;
  ClearSelectCanvas();
  
  var left = Math.round( SquareStartX );
  var top = Math.round( SquareStartY );
  var width = Math.round( x - SquareStartX );
  var height = Math.round( y - SquareStartY );

  DrawLine( new line( left, top, left + width, top ) );
  DrawLine( new line( left + width, top, left + width, top + height ) );
  DrawLine( new line( left + width, top + height, left, top + height ) );
  DrawLine( new line( left, top + height, left, top ) );
}

//display and set selected colour
function selectCol( col )
{
	var disp = document.getElementById("displaycolour")
	
	disp.style.backgroundColor = "#" + col;
	
	currentColour = col;
  lastDrawCell = null;
}


//setup object for pen draw
function selectPencilDraw()
{
	drawObject = new Object();
	drawObject.OnOver = PencilOver;
	drawObject.OnClickDown = PencilClickDown;
  drawObject.OnClickUp = PencilClickUp;
	drawObject.penDown = 0;
  updateBrushSize();
  
  ButtonDown( "pencil" );
}

function selectCircle()
{
  drawObject = new Object();
  drawObject.OnOver = CircleOver;
  drawObject.OnClickDown = CircleDown;
  drawObject.OnClickUp = CircleUp;
  drawObject.penDown = 0;
  updateBrushSize();
  
  ButtonDown( "circle" );
}

function selectFillCircle()
{
  drawObject = new Object();
  drawObject.OnOver = FillCircleOver;
  drawObject.OnClickDown = FillCircleDown;
  drawObject.OnClickUp = FillCircleUp;
  drawObject.penDown = 0;
  updateBrushSize();
  
  ButtonDown( "fillcircle" );
}

function selectSquare()
{
  drawObject = new Object();
  
  drawObject.OnOver = SquareOver;
  drawObject.OnClickDown = SquareDown;
  drawObject.OnClickUp = SquareUp;
  drawObject.penDown = 0;
  updateBrushSize();
  
  ButtonDown( "square" );
}

function selectFillSquare()
{
  drawObject = new Object();
  drawObject.OnOver = FillSquareOver;
  drawObject.OnClickDown = FillSquareDown;
  drawObject.OnClickUp = FillSquareUp;
  drawObject.penDown = 0;
  updateBrushSize();
  
  ButtonDown( "fillsquare" );
}

