/**
 * Configurations is the namespace where the settings are specified.
*/

function Configurations() {
}

Configurations.prototype.getServerUrl = function() {
	//return "http://localhost:8070/gluewiki/";
	return "http://www.toonsket.com/";
}

// GLOBAL

var configurations = new Configurations();

/**
 * The Point is just a tuple representing a two-dimensional
 * space.  The 'Point' could also represent dimensions.
*/

function Point(_x, _y) {
	this.x = _x;
	this.y = _y;
}

Point.prototype.setX = function(x) {
	this.x = x;
}

Point.prototype.setY = function(y) {
	this.y = y;
}

Point.prototype.getX = function() {
	return this.x;
}

Point.prototype.getY = function() {
	return this.y;
}

Point.prototype.setTime = function(time) {
	this.time = time;
}

Point.prototype.getTime = function() {
	return this.time;
}

/**
 * The Rectangle defines a two-dimensional rectangular area
 * in terms of x (left), y (top), width and height.
*/

function Rectangle(_x, _y, _width, _height) {
	this.x = _x;
	this.y = _y;
	this.width = _width;
	this.height = _height;
}

Rectangle.prototype.getX = function() {
	return this.x;
}

Rectangle.prototype.getY = function() {
	return this.y;
}

Rectangle.prototype.getWidth = function() {
	return this.width;
}

Rectangle.prototype.getHeight = function() {
	return this.height;
}

/**
 * Utils is a namespace containing algorithms that can be
 * used by different classes.
*/

function Utils() {
	this.commandBaseUrl = "";
	this.clipboard = null;
}

/**
 * The following inheritance function
 * was devised by Troels Knak-Nielsen (author of indite? the realtime validating wysiwyg widget)
 * as explained on the website http://www.sitepoint.com/blogs/2006/01/17/javascript-inheritance/
*/

Utils.prototype.copyPrototype = function(descendant, parent) {
   var code = parent.toString();
   // checking for constructors
   var matchName = code.match( /\s*function (.*)\s*\(/ );
   // appending the superclass constructor to the child's list
   if ( matchName != null ) {
   		descendant.prototype[matchName[1].replace(/^\s*|\s*$/g,"")] = parent;
   }
    // copying methods from parent to child
    for (var methodName in parent.prototype) {
    	if (descendant.prototype[methodName] != null) {
    		descendant.prototype["super_"+methodName] = parent.prototype[methodName];
    	} else {
	        descendant.prototype[methodName] = parent.prototype[methodName];
	    }
    }
}

Utils.prototype.cancelBubble = function(e) {
	curevent=(typeof event=='undefined'?e:event) 
	curevent.cancelBubble = true;
	if (curevent.stopPropagation) curevent.stopPropagation();
}

Utils.prototype.getDimensions = function(point1, point2) {
	var x1 = point1.getX();
	var y1 = point1.getY();
	var x2 = point2.getX();
	var y2 = point2.getY();
	var left = x1 ;
	var width = x2 - x1;
	if (x2 < x1) {
		left = x2;
		width = x1 - x2;
	}
	var top = y1 ;
	var height = y2 - y1;
	if (y2 < y1) {
		top = y2;
		height = y1 - y2;
	}
	return new Rectangle(left, top, width, height);
}

/**
 * There's an easy way to make this more efficient (you don't need to take the signs into account) ... but is it worth it to make the improvement?
*/
Utils.prototype.getDistance = function(point1, point2) {
	var rectangle = this.getDimensions(point1, point2);
	return Math.sqrt(rectangle.getWidth()*rectangle.getWidth() + rectangle.getHeight()*rectangle.getHeight());
}

Utils.prototype.doNothing = function() {
}

Utils.prototype.getBaseUrl = function() {
	return "http://www.floranta.com/ink/version_1_0_0/";
}

Utils.prototype.setCommandBaseUrl = function(commandBaseUrl) {
	this.commandBaseUrl = commandBaseUrl;
}

Utils.prototype.getCommandBaseUrl = function() {
	return this.commandBaseUrl;
}

Utils.prototype.setClipboard = function(image) {
	return this.clipboard = image;
}

Utils.prototype.getClipboard = function() {
	return this.clipboard;
}

Utils.prototype.isIE = function() {
	return navigator.appName == "Microsoft Internet Explorer";
}

Utils.prototype.preloadKeyImages = function(images) {
	var j;
	for (j = 0 ; j < images.length ; ++j) {
		var im = new Image();
		im.src = images[j];
	}
}

// Two utility functions by Peter-Paul Koch & Alex Tingle at http://blog.firetree.net/2005/07/04/javascript-find-position/
// Alex Tingle modified the functions originally designed by Peter-Paul Koch on his ‘quirksmode‘ site.

  function findPosX(obj)
  {
    var curleft = 0;
    if(obj.offsetParent)
        while(1) 
        {
          curleft += obj.offsetLeft;
          if(!obj.offsetParent)
            break;
          obj = obj.offsetParent;
        }
    else if(obj.x)
        curleft += obj.x;
    return curleft;
  }

  function findPosY(obj)
  {
    var curtop = 0;
    if(obj.offsetParent)
        while(1)
        {
          curtop += obj.offsetTop;
          if(!obj.offsetParent)
            break;
          obj = obj.offsetParent;
        }
    else if(obj.y)
        curtop += obj.y;
    return curtop;
  }


// GLOBAL

var utils = new Utils();

function CanvasEventHandler() {
	this.listeners = new Array();
	this.logger = new Logger();
}

// Listeners implement four methods
// 1.  handleNew()
// 2.  handleEdit(id)
// 3.  handleDelete(id)
// 4.  handleRead(id)

CanvasEventHandler.prototype.addListener = function(listener) {
	this.listeners.push(listener);
}

CanvasEventHandler.prototype.handleNew = function(id, type, cardid) {
	for (i = 0 ; i < this.listeners.length ; ++i) {
		this.listeners[i].handleNew(id, type, cardid);
	}
	
	this.logger.debug("New: "+id + " of type " + type);
}

CanvasEventHandler.prototype.handleEdit = function(id) {
	for (i = 0 ; i < this.listeners.length ; ++i) {
		this.listeners[i].handleEdit(id);
	}
	
	this.logger.debug("Edit: "+id);
}

CanvasEventHandler.prototype.handleUndo = function(id) {
	for (i = 0 ; i < this.listeners.length ; ++i) {
		this.listeners[i].handleUndo(id);
	}
	
	this.logger.debug("Undo: "+id);
}

CanvasEventHandler.prototype.handleRedo = function(id) {
	for (i = 0 ; i < this.listeners.length ; ++i) {
		this.listeners[i].handleRedo(id);
	}
	
	this.logger.debug("Redo: "+id);
}

CanvasEventHandler.prototype.handleDelete = function(id) {
	for (i = 0 ; i < this.listeners.length ; ++i) {
		this.listeners[i].handleDelete(id);
	}
	
	this.logger.debug("Delete: "+id);
}

CanvasEventHandler.prototype.handleRead = function(id, strSerialized) {
	for (i = 0 ; i < this.listeners.length ; ++i) {
		this.listeners[i].handleRead(id, strSerialized);
	}
	
	alert("CanvasEventHandler read "+id);
	this.logger.debug("Read: "+id);
}

CanvasEventHandler.prototype.handleCommandFailure = function(command, id, message) {
	for (i = 0 ; i < this.listeners.length ; ++i) {
		this.listeners[i].handleCommandFailure(command, id, message);
	}
	
	this.logger.debug("Command "+command+" failed: "+id+" "+message);
}

// GLOBAL

var canvasEventHandler = new CanvasEventHandler();

// Toolietip class has the following methods
// 1.  show()
// 2.  hide()
// 3.  setText(text)
// 4.  setPosition(x, y)

function Toolietip(container) {
	this.text = '';
	this.state = 'invisible';
	var divId = 'tooltip';
	this.div = document.createElement('div');
	this.div.id = divId;
	container.parentNode.parentNode.appendChild(this.div);
}

Toolietip.prototype.show = function() {
	//clearTimeout();
	if (Toolietip.prototype.def_tooltip != null && Toolietip.prototype.def_tooltip != this) {
		Toolietip.prototype.def_tooltip.hide();
	}
	Toolietip.prototype.def_tooltip = this;
	this.div.style.display='block';
	//alert('Showing '+this.text+' at '+this.div.style.left+' and '+this.div.style.top);
}

Toolietip.prototype.hideDelayed = function() {
	clearTimeout();
	//Toolietip.prototype.def_tooltip = this;
	setTimeout('hideTooltip()',500);
}

Toolietip.prototype.hideLastUsed = function() {
	if (Toolietip.prototype.def_tooltip != null) {
		Toolietip.prototype.def_tooltip.hide();
	}
}

Toolietip.prototype.hide = function() {
	this.div.style.display='none';
}

Toolietip.prototype.setText = function(text) {
	this.text = text;
	var inDiv = document.createElement('div');
	inDiv.style.background='orange';
	inDiv.style.padding = '5px';
	inDiv.innerHTML = text;
	this.div.appendChild(inDiv);
}

Toolietip.prototype.setRelatedCommands = function(array) {
	this.relatedCommands = array;
	var j = 0;
	for (j = 0 ; j < this.relatedCommands.length ; ++j) {
		this.relatedCommands[j].displayOnContainerStatic(this.div);
	}
}

Toolietip.prototype.setPosition = function(x, y) {
	this.div.style.left = x+'px';
	this.div.style.top  = y+'px';
}

function hideTooltip() {
	if (Toolietip.prototype.def_tooltip != null) {
		Toolietip.prototype.def_tooltip.hide();
	}
}

// RENDERABLE SHAPES
// Class with two methods:
//   a) display
//   b) destructor

function RenderableShape(container) {
	this.container = container;
	this.color = 'blue';
	this.size = 24;
	this.font = 'arial';
	this.zIndex = 1;
}

RenderableShape.prototype.setBounds = function(rectangle) {
	this.left = rectangle.getX();
	this.top = rectangle.getY();
	this.width = rectangle.getWidth();
	this.height = rectangle.getHeight();
}

RenderableShape.prototype.setColor = function(color) {
	this.color = color;
}

RenderableShape.prototype.setSize = function(size) {
	this.size = size;
}

RenderableShape.prototype.setFont = function(font) {
	this.font = font;
}

RenderableShape.prototype.resize = function(width, height) {
	this.width = width;
	this.height = height;
	if (this.imageDiv != null) {
		this.imageDiv.style.width = width+'px';
		this.imageDiv.style.height = height+'px';
	}
}

RenderableShape.prototype.move = function(left, top) {
	this.left = left;
	this.top = top;
	if (this.imageDiv != null) {
		this.imageDiv.style.left = left+'px';
		this.imageDiv.style.top = top+'px';
	}
}

RenderableShape.prototype.display = function() {
	var divId = 'graphical_unit';
	this.imageDiv = document.createElement('div');
	this.imageDiv.id = divId;
	this.imageDiv.style.left = this.left+'px';
	this.imageDiv.style.top = this.top+'px';
	this.imageDiv.style.width = this.width+'px';
	this.imageDiv.style.height = this.height+'px';
	//this.imageDiv.style.border = '1px solid #000000';
	//this.imageDiv.style.background = '#ffffff';
	this.imageDiv.style.font=this.size+"pt "+this.font;
	this.imageDiv.style.color=this.color;
	this.imageDiv.style.zIndex = this.zIndex;
	this.container.appendChild(this.imageDiv);
}

RenderableShape.prototype.destructor = function() {
	this.container.removeChild(this.imageDiv);
}

// TEXT BOXES
function TextBoxShape(container) {
	this.RenderableShape(container);
}

TextBoxShape.prototype.setText = function(text) {
	this.imageDiv.innerHTML = this.escapeHtml(text);
}

TextBoxShape.prototype.escapeHtml = function(text) {
	var t = text.split("&").join("&amp;").split( "<").join("&lt;").split(">").join("&gt;").split("\n").join("<br/>");
	//alert(t);
	return t;
}

utils.copyPrototype(TextBoxShape, RenderableShape);

// TEXT BOXES WITH MARGINS
function TextBoxWithMarginShape(container) {
	this.TextBoxShape(container);
}

TextBoxWithMarginShape.prototype.setText = function(text) {
	this.imageDiv.style.padding = '5px';
	this.imageDiv.innerHTML = this.escapeHtml(text);
}

utils.copyPrototype(TextBoxWithMarginShape, TextBoxShape);

// IMAGES
// PreloadedImage built using instructions at http://www.webreference.com/programming/javascript/gr/column3/

function PreloadedImage(container, imageUrl) {
	this.container = container;
	this.url = imageUrl;
	this.clickable = false;
	this.alternateText = "image";
	this.zIndex = 1;
	
	//this.image = new Image();
	//this.image.preloader = this;
	//this.image.onload = PreloadedImage.prototype.onload;
	//this.image.onerror = PreloadedImage.prototype.onerror;
	//this.image.onabort = PreloadedImage.prototype.onabort;
}

PreloadedImage.prototype.display = function() {
	var divId = 'graphical_unit';
	this.imageDiv = document.createElement('div');
	this.imageDiv.id = divId;
	this.imageDiv.style.left = this.left+'px';
	this.imageDiv.style.top = this.top+'px';
	this.imageDiv.style.width = this.width+'px';
	this.imageDiv.style.height = this.height+'px';
	this.imageDiv.style.zIndex = this.zIndex;
	this.container.appendChild(this.imageDiv);

	var mouseEventHandling = "";
	if (this.clickable == false) {
		//mouseEventHandling = "onmousedown=\"curevent=(typeof event=='undefined'?e:event); if (curevent.stop) { curevent.stop(); } return false;\" ondrag = \"onmousedown=\"curevent=(typeof event=='undefined'?e:event); if (curevent.stop) { curevent.stop(); } return false;\" ";
		mouseEventHandling = "onmousedown=\"return false;\"";
	}
	this.imageDiv.ondragstart = function() { return false; };
	this.imageDiv.innerHTML = "<img src="+this.url+" alt="+this.alternateText+" width="+this.width+" height="+this.height+" "+mouseEventHandling+">";
	//this.image.src = this.url;
}

PreloadedImage.prototype.setZIndex = function(index) {
	this.zIndex = index;
}

PreloadedImage.prototype.setClickable = function(flag) {
	this.clickable = flag;
}

PreloadedImage.prototype.setAlternateText = function(text) {
	this.alternateText = text;
}

PreloadedImage.prototype.setBounds = function(rectangle) {
	this.left = rectangle.getX();
	this.top = rectangle.getY();
	this.width = rectangle.getWidth();
	this.height = rectangle.getHeight();
}

PreloadedImage.prototype.resize = function(width, height) {
	this.width = width;
	this.height = height;
	if (this.imageDiv != null) {
		this.imageDiv.style.width = width+'px';
		this.imageDiv.style.height = height+'px';
		this.imageDiv.firstChild.style.width = width+'px';
		this.imageDiv.firstChild.style.height = height+'px';
	}
}

PreloadedImage.prototype.move = function(left, top) {
	this.left = left;
	this.top = top;
	if (this.imageDiv != null) {
		this.imageDiv.style.left = left+'px';
		this.imageDiv.style.top = top+'px';
	}
}

PreloadedImage.prototype.getNativeImage = function() {
	this.imageDiv.firstChild;
}

PreloadedImage.prototype.destructor = function() {
	this.container.removeChild(this.imageDiv);
}

PreloadedImage.prototype.onload = function() {
	// Do something with the image
	alert("image loaded!");
	this.preloader.imageDiv.appendChild(this);
}

PreloadedImage.prototype.onerror = function() {
	alert("The image at "+this.preloader.url+" could not be loaded");
}

PreloadedImage.prototype.onabort = function() {
	alert("Aborted loading image at "+this.preloader.url);
}

// Resizable Boundary

function ResizableBoundary(preloadedImage) {
	this.preloadedImage = preloadedImage;
	this.container = preloadedImage.container;
	this.height = 20;
	this.width = 20;
	this.url = "images/resize1.gif";
	this.alternateText = "resize";
	this.clickable = true;
}

ResizableBoundary.prototype.setColor = function(color) {
	this.preloadedImage.setColor(color);
}

ResizableBoundary.prototype.setSize = function(size) {
	this.preloadedImage.setSize(size);
}

ResizableBoundary.prototype.setFont = function(font) {
	this.preloadedImage.setFont(font);
}

ResizableBoundary.prototype.setText = function(text) {
	this.preloadedImage.setText(text);
}

ResizableBoundary.prototype.display = function() {
	this.preloadedImage.display();

	this.top = this.preloadedImage.top + this.preloadedImage.height - this.height;
	this.left = this.preloadedImage.left + this.preloadedImage.width - this.width;

	var space = 0;
	var divId = 'graphical_unit';
	this.imageDiv = document.createElement('div');
	this.imageDiv.id = divId;
	this.imageDiv.style.cursor = 'se-resize'; 
	this.imageDiv.style.left = this.left-space + 'px';
	this.imageDiv.style.top = this.top-space + 'px';
	this.imageDiv.style.width = (this.width + 2*space) +'px';
	this.imageDiv.style.height = (this.height + 2*space)+'px';
	this.imageDiv.style.zIndex = 5;
	this.container.appendChild(this.imageDiv);

	var mouseEventHandling = "";
	//if (this.clickable == false) {
		//mouseEventHandling = "onmousedown=\"curevent=(typeof event=='undefined'?e:event); if (curevent.stop) { curevent.stop(); } return false;\" ondrag = \"onmousedown=\"curevent=(typeof event=='undefined'?e:event); if (curevent.stop) { curevent.stop(); } return false;\" ";
		mouseEventHandling = "onmousedown=\"return false;\"";
	//} else {
		this.imageDiv.onmousedown = ResizableBoundary.prototype.onMouseDownHandler;
		this.imageDiv.ondragstart = function() { return false; };
		this.imageDiv.resizableBoundary = this;
	//}
	this.imageDiv.innerHTML = "<img src="+this.url+" alt="+this.alternateText+" width="+(this.width + 2*space)+" height="+(this.height + 2*space)+" "+mouseEventHandling+">";
	//this.image.src = this.url;
}

ResizableBoundary.prototype.cancelBubble = function(e) {
	utils.cancelBubble(e);
}

ResizableBoundary.prototype.resize = function(diffWidth, diffHeight) {
	if ((diffWidth > 0 && this.preloadedImage.width < 50) || (diffHeight > 0 && this.preloadedImage.height < 50))
		return;
	this.moveGrip(this.imageDiv.style.left.split('p')[0]-diffWidth, this.imageDiv.style.top.split('p')[0]-diffHeight);
	this.preloadedImage.resize(this.preloadedImage.imageDiv.style.width.split('p')[0]-diffWidth, this.preloadedImage.imageDiv.style.height.split('p')[0]-diffHeight);
	this.imageMoveDiv.style.width = this.preloadedImage.width;
	this.imageMoveDiv.style.height = this.preloadedImage.height;
	this.stroke.getPoints()[1].setX(this.stroke.getPoints()[1].getX()-diffWidth);
	this.stroke.getPoints()[1].setY(this.stroke.getPoints()[1].getY()-diffHeight);
}

ResizableBoundary.prototype.moveGrip = function(left, top) {
	this.imageDiv.style.left = left+'px';
	this.imageDiv.style.top = top+'px';
}

ResizableBoundary.prototype.onMouseDownHandler = function(e) {
	//alert('down');
	if (this.resizableBoundary.canvas != null) {
		this.resizableBoundary.canvas.setModeResizing();
		this.resizableBoundary.canvas.setSelectedObject(this.resizableBoundary);
	}
}

ResizableBoundary.prototype.onResizeHandler = function(e) {
	//for handling events in ie vs. w3c 
	curevent=(typeof event=='undefined'?e:event);
	//gets position of click 
	var diffPosX=curevent.clientX - this.lastPosX;
	var diffPosY=curevent.clientY - this.lastPosY;
	this.lastPosX = curevent.clientX;
	this.lastPosY = curevent.clientY;
	this.resize(-diffPosX, -diffPosY);
}

ResizableBoundary.prototype.destructor = function() {
	this.container.removeChild(this.imageDiv);
	this.preloadedImage.destructor();
}

// Resizable and Movable Boundary

function ResizableMovableBoundary(preloadedImage, canvas) {
	this.ResizableBoundary(preloadedImage);
	this.moveUrl = "images/brushes/globs/circle_transparent.png";
	this.canvas = canvas;
}

ResizableMovableBoundary.prototype.display = function() {
	this.super_display();

	var top = this.preloadedImage.top;
	var left = this.preloadedImage.left;

	var divId = 'graphical_unit';
	this.imageMoveDiv = document.createElement('div');
	this.imageMoveDiv.id = divId;
	this.imageMoveDiv.style.cursor = 'move'; 
	this.imageMoveDiv.style.left = left + 'px';
	this.imageMoveDiv.style.top = top + 'px';
	this.imageMoveDiv.style.width = this.preloadedImage.width;
	this.imageMoveDiv.style.height = this.preloadedImage.height;
	this.imageMoveDiv.style.border = '1px dashed black';
	this.imageMoveDiv.style.zIndex = 4;
	//mouseEventHandling = "onmousedown=\"curevent=(typeof event=='undefined'?e:event); if (curevent.stop) { curevent.stop(); } return false;\" ondrag = \"onmousedown=\"curevent=(typeof event=='undefined'?e:event); if (curevent.stop) { curevent.stop(); } return false;\" ";
	mouseEventHandling = "onmousedown=\"return false;\"";
	this.imageMoveDiv.innerHTML = "<img src="+this.moveUrl+" width="+this.preloadedImage.width+" height="+this.preloadedImage.height+" "+mouseEventHandling+">";
	
	this.imageCloseDiv = document.createElement('div');
	this.imageCloseDiv.id = divId;
	this.imageCloseDiv.style.cursor = 'move'; 
	this.imageCloseDiv.style.left = left + 'px';
	this.imageCloseDiv.style.top = top + 'px';
	this.imageCloseDiv.style.width = '20px';
	this.imageCloseDiv.style.height = '20px';
	this.imageCloseDiv.style.border = '1px dashed red';
	this.imageCloseDiv.style.zIndex = 4;
	//mouseEventHandling = "onmousedown=\"curevent=(typeof event=='undefined'?e:event); if (curevent.stop) { curevent.stop(); } return false;\" ondrag = \"onmousedown=\"curevent=(typeof event=='undefined'?e:event); if (curevent.stop) { curevent.stop(); } return false;\" ";
	mouseEventHandling = "onmousedown=\"return false;\"";
	this.imageCloseDiv.innerHTML = "<img src='images/delete1.gif' width=20 height=20 "+mouseEventHandling+">";
	
	//alert('before cursor '+left+":"+top+":"+this.imageMoveDiv.style.width+":"+this.imageMoveDiv.style.height);
	this.container.appendChild(this.imageMoveDiv);
	this.container.appendChild(this.imageCloseDiv);

	this.imageMoveDiv.onmousedown = ResizableMovableBoundary.prototype.onMouseDownHandler;
	this.imageMoveDiv.ondragstart = function() { return false; };
	
	this.imageCloseDiv.onmousedown = ResizableMovableBoundary.prototype.close;
	this.imageCloseDiv.ondragstart = function() { return false; };
	
	this.imageMoveDiv.resizableMovableBoundary = this;
	this.imageCloseDiv.resizableMovableBoundary = this;
	this.moveState = 'up';
	//alert('after handlers');
}

ResizableMovableBoundary.prototype.move = function(diffWidth, diffHeight) {
	this.moveGrip(this.imageDiv.style.left.split('p')[0]-diffWidth, this.imageDiv.style.top.split('p')[0]-diffHeight);
	this.imageMoveDiv.style.left = (this.imageMoveDiv.style.left.split('p')[0]-diffWidth)+'px';
	this.imageMoveDiv.style.top = (this.imageMoveDiv.style.top.split('p')[0]-diffHeight)+'px';
	this.imageCloseDiv.style.left = (this.imageCloseDiv.style.left.split('p')[0]-diffWidth)+'px';
	this.imageCloseDiv.style.top = (this.imageCloseDiv.style.top.split('p')[0]-diffHeight)+'px';
	this.preloadedImage.move(this.preloadedImage.imageDiv.style.left.split('p')[0]-diffWidth, this.preloadedImage.imageDiv.style.top.split('p')[0]-diffHeight);
	this.stroke.getPoints()[0].setX(this.stroke.getPoints()[0].getX()-diffWidth);
	this.stroke.getPoints()[0].setY(this.stroke.getPoints()[0].getY()-diffHeight);
	this.stroke.getPoints()[1].setX(this.stroke.getPoints()[1].getX()-diffWidth);
	this.stroke.getPoints()[1].setY(this.stroke.getPoints()[1].getY()-diffHeight);
}

ResizableMovableBoundary.prototype.close = function(e) {
	utils.cancelBubble(e);
	if (confirm('Are you sure you want to delete this?!')) {
		this.resizableMovableBoundary.canvas.builder.deleteStroke(this.resizableMovableBoundary.stroke);
	}
}

ResizableMovableBoundary.prototype.onMouseDownHandler = function(e) {
	//alert('down');
	if (this.resizableMovableBoundary.canvas != null) {
		this.resizableMovableBoundary.canvas.setModeMoving();
		this.resizableMovableBoundary.canvas.setSelectedObject(this.resizableMovableBoundary);
	}
}

ResizableMovableBoundary.prototype.onMoveHandler = function(e) {
	//alert('move');
	//for handling events in ie vs. w3c 
	curevent=(typeof event=='undefined'?e:event);
	//gets position of click 
	var diffPosX=curevent.clientX - this.lastPosX;
	var diffPosY=curevent.clientY - this.lastPosY;
	this.lastPosX = curevent.clientX;
	this.lastPosY = curevent.clientY;
	this.move(-diffPosX, -diffPosY);
	//this.cancelBubble(e);
}

utils.copyPrototype(ResizableMovableBoundary, ResizableBoundary);

// Matrix

function Matrix(c_rows, c_columns) {
	this.contents = new Array();
	var i;
	for (i = 0; i < c_rows ; ++i) {
		this.contents[i] = new Array();
	} 
	this.c_rows = c_rows;
	this.c_columns = c_columns;
}

Matrix.prototype.getValue = function(row, column) {
	if (row >= this.c_rows)
		return null;
	if (column >= this.c_columns)
		return null;
	return this.contents[row][column];
}

Matrix.prototype.setValue = function(row, column, value) {
	if (row >= this.c_rows)
		return;
	if (column >= this.c_columns)
		return;
	this.contents[row][column] = value;
}

Matrix.prototype.getNumberOfRows = function() {
	return this.c_rows;
}

Matrix.prototype.getNumberOfColumns = function() {
	return this.c_columns;
}

Matrix.prototype.multiply = function(otherMatrix) {
	var i;
	var j;
	var k;
	if (this.getNumberOfColumns() != otherMatrix.getNumberOfRows()) {
		return null;
	}
	var matrixTemp = new Matrix(this.getNumberOfRows(), otherMatrix.getNumberOfColumns());
	for (i = 0 ; i < this.getNumberOfRows() ; ++i) {
		for (j = 0 ; j < otherMatrix.getNumberOfColumns() ; ++j) {
			matrixTemp.setValue(i,j,0); // init to zero
		}
	}
	for (i = 0 ; i < this.getNumberOfRows() ; ++i) {
		for (j = 0 ; j < otherMatrix.getNumberOfColumns() ; ++j) {
			for (k = 0 ; k < this.getNumberOfColumns() ; ++k) {
				var value = this.getValue(i, k) * otherMatrix.getValue(k, j);
				matrixTemp.setValue(i, j, matrixTemp.getValue(i, j) + value);
			}
		}
	}
	return matrixTemp;
}

// Cardinal spline
// NOT MULTITHREADED ... use one object per thread
function CardinalSpline(tension) {
	this.tension = tension;
	
	var s = (1 - this.tension) / 2;
	
	this.cardinalMatrix = new Matrix(4,4);
	
	this.cardinalMatrix.setValue(0,0,-s);
	this.cardinalMatrix.setValue(0,1,2-s);
	this.cardinalMatrix.setValue(0,2,s-2);
	this.cardinalMatrix.setValue(0,3,s);

	this.cardinalMatrix.setValue(1,0,s+s);
	this.cardinalMatrix.setValue(1,1,s-3);
	this.cardinalMatrix.setValue(1,2,3-s-s);
	this.cardinalMatrix.setValue(1,3,-s);

	this.cardinalMatrix.setValue(2,0,-s);
	this.cardinalMatrix.setValue(2,1,0);
	this.cardinalMatrix.setValue(2,2,s);
	this.cardinalMatrix.setValue(2,3,0);

	this.cardinalMatrix.setValue(3,0,0);
	this.cardinalMatrix.setValue(3,1,1);
	this.cardinalMatrix.setValue(3,2,0);
	this.cardinalMatrix.setValue(3,3,0);
	
	this.xMatrix = new Matrix(4,1);
	this.yMatrix = new Matrix(4,1);
	this.uMatrix = new Matrix(1,4);
}

// u is a value between 0 and 1 that determines the distance of the returned point from P1.
// P1 and P2 are the control points between which the spline points are generated.
// P0 and P3 determine the tangents at P1 and P2.
// The returned object is a Point and so are P0, P1, P2 and P3.

CardinalSpline.prototype.getPoint = function(P0, P1, P2, P3, u) {
	this.xMatrix.setValue(0,0,P0.getX());
	this.xMatrix.setValue(1,0,P1.getX());
	this.xMatrix.setValue(2,0,P2.getX());
	this.xMatrix.setValue(3,0,P3.getX());

	this.yMatrix.setValue(0,0,P0.getY());
	this.yMatrix.setValue(1,0,P1.getY());
	this.yMatrix.setValue(2,0,P2.getY());
	this.yMatrix.setValue(3,0,P3.getY());
	
	this.uMatrix.setValue(0,0,u*u*u);
	this.uMatrix.setValue(0,1,u*u);
	this.uMatrix.setValue(0,2,u);
	this.uMatrix.setValue(0,3,1);
	
	var intermediateMatrix = this.uMatrix.multiply(this.cardinalMatrix);
	
	return new Point(intermediateMatrix.multiply(this.xMatrix).getValue(0,0),intermediateMatrix.multiply(this.yMatrix).getValue(0,0));
}

// n is the number of intermediate points to add
CardinalSpline.prototype.getIntermediatePoints = function(P0, point1, point2, P3, n) {
	var array = new Array();
	var i;
	for(i = 1 ; i < (n+1) ; i += 1) {
		var p = this.getPoint(P0,point1,point2,P3,i/(n+1));
		array.push(p);
	}
	return array;
}

// GLOBAL
var xmlReq = null;

/**
The persistence tool stores a string on the server.
Only use sequentially.  This class is not thread safe!
The tool stores the id of the image so only use one per image.
*/

function PersistenceTool(id) {
	this.url = configurations.getServerUrl()+'createimage.php';
	this.id = id;
	this.undos = 0;

	this.width = 600;
	this.height = 400;
	this.backgroundId = null;
	this.backgroundType = null;
	this.shared = true;
}

PersistenceTool.prototype.completeDelete = function() {
    if (xmlReq.readyState == 4) {
        if (xmlReq.status == 200) {
		    var response = xmlReq.responseText;
		    if (response.split("\n")[0] == "success") {
			    canvasEventHandler.handleDelete(xmlReq.persistenceTool.id);
			    xmlReq.persistenceTool.id = null;
				//alert("Completed delete "+xmlReq.persistenceTool.id);
				//alert("Deleted");
				//window.location.reload();
			} else {
			    canvasEventHandler.handleCommandFailure('Delete', xmlReq.persistenceTool.id, response.split("\n")[2]);
			}
		} else {
			alert("The website is having some problems ... the code returned is "+xmlReq.status);
		}
    } else {
		//alert("received file with status "+xmlReq.readyState);
    }
}

PersistenceTool.prototype.completeNew = function() {
    if (xmlReq.readyState == 4) {
        if (xmlReq.status == 200) {
		    var response = xmlReq.responseText;
		    if (response.split("\n")[0] == "success") {
			    xmlReq.persistenceTool.id = response.split("\n")[1];
			    var type = response.split("\n")[2];
			    var cardid = response.split("\n")[3];
			    canvasEventHandler.handleNew(xmlReq.persistenceTool.id, type, cardid);
				//alert("Completed write "+xmlReq.persistenceTool.id);
				//alert("New image created");
			} else {
				alert("The server was not able to save the new image");
			}
		} else {
			alert("The website is having some problems ... the code returned is "+xmlReq.status);
		}
    } else {
		//alert("received file with status "+xmlReq.readyState);
    }
}

PersistenceTool.prototype.completeWrite = function() {
    if (xmlReq.readyState == 4) {
        if (xmlReq.status == 200) {
		    var response = xmlReq.responseText;
		    if (response.split("\n")[0] == "success") {
			    xmlReq.persistenceTool.id = response.split("\n")[1];
			    xmlReq.persistenceTool.undos = response.split("\n")[2];
				//alert("PersistenceTool completed write "+xmlReq.persistenceTool.id);
			    canvasEventHandler.handleEdit(xmlReq.persistenceTool.id);
			} else {
				alert("The server was not able to save the edited image");
			}
		} else {
			alert("The website is having some problems ... the code returned is "+xmlReq.status);
		}
    } else {
		//alert("received file with status "+xmlReq.readyState);
    }
}

PersistenceTool.prototype.completeUndo = function() {
    if (xmlReq.readyState == 4) {
        if (xmlReq.status == 200) {
		    var response = xmlReq.responseText;
		    if (response.split("\n")[0] == "success") {
			    xmlReq.persistenceTool.id = response.split("\n")[1];
			    xmlReq.persistenceTool.undos = response.split("\n")[2];
				//alert("PersistenceTool completed write "+xmlReq.persistenceTool.id);
			    canvasEventHandler.handleUndo(xmlReq.persistenceTool.id);
			} else {
				alert("The server was not able to undo the last stroke");
			}
		} else {
			alert("The website is having some problems ... the code returned is "+xmlReq.status);
		}
    } else {
		//alert("received file with status "+xmlReq.readyState);
    }
}

PersistenceTool.prototype.completeRedo = function() {
    if (xmlReq.readyState == 4) {
        if (xmlReq.status == 200) {
		    var response = xmlReq.responseText;
		    if (response.split("\n")[0] == "success") {
			    xmlReq.persistenceTool.id = response.split("\n")[1];
			    xmlReq.persistenceTool.undos = response.split("\n")[2];
				//alert("PersistenceTool completed write "+xmlReq.persistenceTool.id);
			    canvasEventHandler.handleRedo(xmlReq.persistenceTool.id);
			} else {
				alert("The server was not able to redo the last stroke");
			}
		} else {
			alert("The website is having some problems ... the code returned is "+xmlReq.status);
		}
    } else {
		//alert("received file with status "+xmlReq.readyState);
    }
}

PersistenceTool.prototype.completeRead = function() {
    if (xmlReq.readyState == 4) {
        if (xmlReq.status == 200) {
		    response = xmlReq.responseText;
		    if (response.split("\n")[0] == "success") {
			    xmlReq.persistenceTool.id = response.split("\n")[1];
				alert("Completed read "+xmlReq.persistenceTool.id);
			    canvasEventHandler.handleRead(xmlReq.persistenceTool.id, response.split("\n")[2]);
				//alert("Read");
			} else {
				alert("The server was not able to save the edited image");
			}
		} else {
			alert("The website is having some problems ... the code returned is "+xmlReq.status);
		}
    } else {
		//alert("received file with status "+xmlReq.readyState);
    }
}

PersistenceTool.prototype.post = function(url, parameterString, callback) {
    if (window.XMLHttpRequest) {
	   	xmlReq = new XMLHttpRequest();
	} else if (window.ActiveXObject) {
		xmlReq = new ActiveXObject("Microsoft.XMLHTTP");
	}
	//alert(url+"?"+parameterString);
	xmlReq.persistenceTool = this;
	xmlReq.open("POST",url,true); 
	xmlReq.onreadystatechange = callback;
	xmlReq.setRequestHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8"); 
	xmlReq.send(parameterString);
}

PersistenceTool.prototype.validate = function() {
	if (this.width == null || this.width <= 0) {
		//alert("Validation found width and height to be null!");
		this.width = 600;
	}
	if (this.height == null || this.height <= 0)
		this.height = 400;
}

PersistenceTool.prototype.create = function(serializedImage) {
	this.validate();
	//alert(this.width);
	var str = 'command=New&string='+serializedImage+'&width='+this.width+'&height='+this.height;
	if (this.backgroundId != null) {
		str += '&bId='+this.backgroundId+'&bType='+this.backgroundType;
	} 
	if (this.shared == false) {
		str += '&shared=f';
	} else {
		str += '&shared=s';
	}
	if (this.type != null) {
		str += '&type='+this.type;
	}
	this.post(this.url, str, PersistenceTool.prototype.completeNew);
}

PersistenceTool.prototype.edit = function(id, serializedImage) {
	this.validate();
	//alert(this.width);
	var str = 'command=Edit&id='+id+'&string='+serializedImage+'&width='+this.width+'&height='+this.height; 
	this.post(this.url, str, PersistenceTool.prototype.completeWrite);
}

PersistenceTool.prototype.add = function(id, serializedImage) {
	this.validate();
	//alert(this.width);
	var str = 'command=Add&id='+id+'&string='+serializedImage+'&width='+this.width+'&height='+this.height; 
	this.post(this.url, str, PersistenceTool.prototype.completeWrite);
}

PersistenceTool.prototype.view = function(id) {
	var str = 'command=View&id='+id; 
	this.post(this.url, str, PersistenceTool.prototype.completeRead);
}

PersistenceTool.prototype.undo = function() {
	this.validate();
	//alert(this.width);
	var str = 'command=Undo&id='+this.id+'&width='+this.width+'&height='+this.height; 
	this.post(this.url, str, PersistenceTool.prototype.completeUndo);
}

PersistenceTool.prototype.redo = function() {
	this.validate();
	//alert(this.width);
	var str = 'command=Redo&id='+this.id+'&width='+this.width+'&height='+this.height; 
	this.post(this.url, str, PersistenceTool.prototype.completeRedo);
}

PersistenceTool.prototype.save = function(serializedImage) {
	if (this.id == null)
		this.create(serializedImage);
	else
		this.edit(this.id, serializedImage);
}

PersistenceTool.prototype.setSize = function(width, height) {
	this.width = width;
	this.height = height;
}

PersistenceTool.prototype.displayBackground = function(id, type) {
	this.backgroundId = id;
	this.backgroundType = type;
}

PersistenceTool.prototype.setShared = function(flag) {
	this.shared = flag;
}

PersistenceTool.prototype.setType = function(type) {
	this.type = type;
}

PersistenceTool.prototype.load = function() {
	this.view(this.id);
}

PersistenceTool.prototype.getId = function() {
	return this.id;
}

PersistenceTool.prototype.del = function() {
	var str = 'command=Delete&id='+this.id; 
	this.post(this.url, str, PersistenceTool.prototype.completeDelete);
}

function IncrementalPersistenceTool(id) {
	this.PersistenceTool(id);
}

IncrementalPersistenceTool.prototype.edit = function(id, serializedImage) {
	this.add(id, serializedImage);
	//this.validate();
	//alert(this.getWidth());
	//var str = 'command=Add&id='+id+'&string='+serializedImage+'&width='+this.width+'&height='+this.height; 
	//this.post(this.url, str, PersistenceTool.prototype.completeWrite);
}

utils.copyPrototype(IncrementalPersistenceTool, PersistenceTool);

/**
The serializer converts an image into a form that can be persisted.
*/
function Serializer() {
}

/**
The dynamic HTML serializer is an object that helps convert an image into
a dynamic HTML representation.
*/

function DynamicHtmlSerializer() {
	this.Serializer();
}

DynamicHtmlSerializer.prototype.getSerialized = function(baseUrl, strokes, canvaspeer) {
	var array = new Array();
	array.push("<HTML><HEAD>");
	array.push("<META NAME=\"CHANGEDBY\" CONTENT=\"Cohan Carlos\">");
	array.push("<TITLE>Ink Test</TITLE>");
	array.push("</HEAD>");
	array.push("<BODY LANG=\"en-US\" TEXT=\"#000000\" BGCOLOR=\"#ffffff\" id=\"root\">");
	array.push("<script type=\"text/javascript\" src=\""+baseUrl+"ink.js\">");
	array.push("</script>");
	array.push("<style type=\"text/css\">");
	array.push("<!--");
	array.push("  @import url("+baseUrl+"ink.css);");
	array.push("  -->");
	array.push("</style>");
	array.push("<div style=\"position: absolute; display: block; overflow: hidden; left: 0px; top: 0px; width: "+canvaspeer.style.width+"; height: "+canvaspeer.style.height+"; background: "+canvaspeer.style.background+"\" id=\"yellow_box\"></div>");
	array.push("<script type=\"text/javascript\">");
	array.push("<!--");
	array.push("utils.setCommandBaseUrl(\""+baseUrl+"\");");
	array.push("var canvas = new DrawingCanvas(document.getElementById('yellow_box'));");
	array.push("new ControlPanel(canvas);");
	var currentBrush = null;
	//alert("Brush is "+currentBrush.getClassName());
	for (i = 0 ; i < strokes.length ; ++i) {
		if (strokes[i].getBrush() != currentBrush) {
			currentBrush = strokes[i].getBrush();
			array.push("canvas.builder.setBrush(new "+currentBrush.getClassName()+"());");
		}
		var points = strokes[i].getPoints();
		for (j = 0 ; j < points.length ; ++j) {
			if (j == 0) {
				array.push("canvas.builder.beginStroke("+points[j].getX()+","+points[j].getY()+");");
			} else if (j == points.length - 1) {
				array.push("canvas.builder.endStroke("+points[j].getX()+","+points[j].getY()+");");
			} else {
				array.push("canvas.builder.continueStroke("+points[j].getX()+","+points[j].getY()+");");
			}
		}
	}
	array.push("//-->");
	array.push("</script>");
	array.push("</BODY></HTML>");
	return array;
}

utils.copyPrototype(DynamicHtmlSerializer, Serializer);

/**
The static HTML serializer is an object that helps convert an image into
a static HTML representation.
*/

function StaticHtmlSerializer() {
	this.Serializer();
}

StaticHtmlSerializer.prototype.getImageSerialized = function(points, i, baseUrl, brush) {
	var distance = brush.getDistanceBetweenJoinedPoints();
	var imageUrl = brush.getImageUrl(points[i], points[i-distance]);
	var rectangle = brush.getDisplayRectangle(points[i], points[i-distance]);
	return ("<div style=\"left: "+rectangle.getX()+"px; top: "+rectangle.getY()+"px; width: "+rectangle.getWidth()+"px; height: "+rectangle.getHeight()+"px;\" id=\"graphical_unit\"><img src=\""+baseUrl+imageUrl+"\" alt=\"image\" height=\""+rectangle.getHeight()+"\" width=\""+rectangle.getWidth()+"\"></div>");
}

StaticHtmlSerializer.prototype.getStrokeSerialized = function(array, baseUrl, stroke) {
	var brush = stroke.getBrush();
	var points = stroke.getPoints();
	for (j = 0 ; j < points.length ; ++j) {
		if (j >= brush.getDistanceBetweenJoinedPoints()) {
			var rectangle = brush.getDisplayRectangle(points[j], points[j-brush.getDistanceBetweenJoinedPoints()]);
			var left = rectangle.getX();
			var top = rectangle.getY();
			var width = rectangle.getWidth();
			var height = rectangle.getHeight();
			array.push(this.getImageSerialized(points, j, baseUrl, brush));
		}
	}
	return array;
}

StaticHtmlSerializer.prototype.getSerialized = function(baseUrl, strokes) {
	var array = new Array();
	array.push("<HTML><HEAD>");
	array.push("<META NAME=\"CHANGEDBY\" CONTENT=\"Cohan Carlos\">");
	array.push("<TITLE>Ink Test</TITLE>");
	array.push("</HEAD>");
	array.push("<BODY>");
	array.push("<style type=\"text/css\">");
	array.push("<!--");
	array.push("  @import url("+baseUrl+"ink.css);");
	array.push("  -->");
	array.push("</style>");
	for (i = 0 ; i < strokes.length ; ++i) {
		this.getStrokeSerialized(array, baseUrl, strokes[i]);
	}
	array.push("</BODY></HTML>");
	return array;
}

utils.copyPrototype(StaticHtmlSerializer, Serializer);

/**
The integer serializer is an object that helps convert an image into
an integer sequence representation.
*/

function IntegerSerializer() {
	this.Serializer();
	this.lastBrush = null;
}

IntegerSerializer.prototype.getStrokeSerialized = function(baseUrl, stroke) {
	var brush = stroke.getBrush();
    var str = "";
	var lastX = 0;
	var lastY = 0;

	if (this.lastBrush != brush) {
    	str = brush.getClassName();
    	this.lastBrush = brush;
    }
	var points = stroke.getPoints();
	for (j = 0 ; j < points.length ; ++j) {
		str = str + "_" + (points[j].getX() - lastX) + "*" + (points[j].getY() - lastY);
		if (stroke.isTrackingTime) {
			str = str + "*" + (points[j].getTime());
		}
		lastX = points[j].getX();
		lastY = points[j].getY();
	}
	var chrSpecial = String.fromCharCode(1);
	//return str + "~" + stroke.getState() + "_@_";
	return str + chrSpecial + stroke.getState() + "_@_";
}

IntegerSerializer.prototype.getSerialized = function(baseUrl, strokes) {
	var array = new Array();
	var str = "";
	for (i = 0 ; i < strokes.length ; ++i) {
		str = str + this.getStrokeSerialized(baseUrl, strokes[i]);
	}
	array.push(escape(str));
	return array;
}

utils.copyPrototype(IntegerSerializer, Serializer);

/**
The deserializer recreates an image from its persisted form.
*/
function Deserializer() {
}

/**
The dynamic HTML deserializer is an object that helps convert a string representation
into a dynamic HTML image.

One per image since this stores state info per image.
*/

function DynamicHtmlDeserializer(strStrokes) {
	this.Deserializer();
	this.steps = 0;
	this.array = strStrokes.split("_@_");
	this.brush = "";
}

DynamicHtmlDeserializer.prototype.isDeserialized = function() {
	return this.steps >= this.array.length; 
}

DynamicHtmlDeserializer.prototype.deserializeOnto = function(aCanvas, steps) {
	var isTrackingTimeSaved = aCanvas.builder.isTrackingTime;
	if (steps == null)
		steps = this.array.length;
	for (var i = this.steps ; i < this.array.length && steps > 0; ++i) {
		--steps;
		++this.steps;
		
		var txt = this.array[i];

		// TODO: There's an empty line at the end of the image because of the _@_ at the end of the serialized form .. the following code eliminates it ... maybe a better way would be to iterate only upto 'array.length - 1' ?
		if (txt == "")
			continue;

		//var tempState = txt.replace(/[^~]*~/,"");
		//txt = txt.replace(/~.*/,"");
		chrSpecial = String.fromCharCode(1);
		var array = txt.split(chrSpecial);
		var tempState = "";
		if (array.length > 1)
			tempState = array[1];
		txt = array[0];
		var tempBrush = txt.replace(/_(.)*/,"");
		if (tempBrush != "") {
			this.brush = tempBrush;
			//alert(tempBrush);
			aCanvas.builder.setBrush(new (eval(this.brush))());
		}
		if (this.brush == "") {
			alert("empty brush ... corruption in saved file");
		}
		var points = txt.replace(/([^_])*_/,"").split("_");
		var pointX = 0;
		var pointY = 0;
		//alert("new stroke "+i+" of "+this.array.length);
		for (var j = 0 ; j < points.length ; ++j) {
			var pointXY = points[j].split("*");
			var pointX = pointX + parseInt(pointXY[0]);
			var pointY = pointY + parseInt(pointXY[1]);
			var time = null;
			if (pointXY.length > 2) {
				time = parseInt(pointXY[2]);
			}
			if (j == 0) {
				if (time != null) {
					aCanvas.builder.setTrackingTime(true);
				} else {
					aCanvas.builder.setTrackingTime(false);
				}
				aCanvas.builder.beginStroke(pointX,pointY,time);
			} else if (j == points.length - 1) {
				aCanvas.builder.endStroke(pointX,pointY,time,tempState);
			} else {
				aCanvas.builder.continueStroke(pointX,pointY,time);
			}
		}
		//alert("ending stroke "+i+" of "+this.array.length);
	}
	aCanvas.builder.setTrackingTime(isTrackingTimeSaved);
	//return strokes;
}

utils.copyPrototype(DynamicHtmlDeserializer, Deserializer);

function ServerRenderedDeserializer(strStrokes, imageId) {
	this.DynamicHtmlDeserializer(strStrokes);
	this.imageId = imageId;
}

ServerRenderedDeserializer.prototype.deserializeOnto = function(aCanvas, steps) {
	if (steps == null) {
		var url = configurations.getServerUrl() + 'viewbinaryimage.php?command=View&id=' + this.imageId + '&time=' + new Date().getTime();
		if (this.imageId == 477)
			alert("Renderer rendering background "+url);
		aCanvas.builder.displayBackground(url, aCanvas.getWidth(), aCanvas.getHeight());
	}
}

utils.copyPrototype(ServerRenderedDeserializer, DynamicHtmlDeserializer);

/**
The Brush is a type that contains the functionality for drawing
the smallest structural elements of a stroke.  A brush converts
a set of points marking the path of a stroke into images that
can be rendered on a screen, to make the stroke have a particular
appearance.
*/

function Brush() {
}

Brush.prototype.setCanvas = function(canvas) {
	this.canvas = canvas;
}

Brush.prototype.getCanvas = function() {
	return this.canvas;
}

Brush.prototype.getImageDirectory = function() {
	return "images/brushes/globs/";
}

Brush.prototype.getImageUrl = function() {
	return this.getImageDirectory()+"circle_graded_black.png";
}

Brush.prototype.getClassName = function() {
	return "Brush";
}

Brush.prototype.getImage = function(container, points, i) {
	return this.getImageAtPoint(container, points[i]);
}

Brush.prototype.getImageAtPoint = function(container, point1) {
	var x1 = point1.getX();
	var y1 = point1.getY();
	imageUrl = this.getImageUrl();
	var preloadedImage = new PreloadedImage(container, imageUrl);
	var rectangle = utils.getDimensions(new Point(x1-7,y1-7), new Point(x1+7,y1+7));
	preloadedImage.setBounds(rectangle);
	return preloadedImage;
}

Brush.prototype.getRenderable = function(container, point1, point2) {
	var x1 = point1.getX();
	var y1 = point1.getY();
	var x2 = point2.getX();
	var y2 = point2.getY();
	imageUrl = this.getImageUrl();
	var preloadedImage = new RenderableShape(container);
	var rectangle = utils.getDimensions(new Point(x1,y1), new Point(x2,y2));
	preloadedImage.setBounds(rectangle);
	return preloadedImage;
}

Brush.prototype.getDisplayRectangle = function (point1, point2) {
	var x1 = point1.getX();
	var y1 = point1.getY();
	var x2 = point2.getX();
	var y2 = point2.getY();
	if (x1 == x2) {
		x1 = x1 - 1;
		x2 = x2 + 1;
	}
	if (y1 == y2) {
		y1 = y1 - 1;
		y2 = y2 + 1;
	}
	return utils.getDimensions(new Point(x1,y1), new Point(x2,y2));
}

Brush.prototype.getDistanceBetweenJoinedPoints = function() {
	return 1;
}

Brush.prototype.getIntermediatePoints = function(point1, point2, prevPoint, nextPoint) {
	return new Array();
}

Brush.prototype.isRenderedDifferentlyUponCompletion = function() {
	return false;
}

Brush.prototype.isOnlyEndPointsUseful = function() {
	return false;
}

Brush.prototype.isEditable = function() {
	return false;
}

function RoundBrush() {
	this.Brush();
	this.cs = new CardinalSpline(0);
}

RoundBrush.prototype.getClassName = function() {
	return "RoundBrush";
}

RoundBrush.prototype.getExtrapolationDistance = function(point2, nextPoint) {
	if (point2 == nextPoint)
		return 20;
	return 2;
}

RoundBrush.prototype.getIntermediatePoints = function(point1, point2, prevPoint, nextPoint) {
//	document.writeln(point1.getX()+","+point1.getY()+" "+point2.getX()+","+point2.getY()+" "+prevPoint.getX()+","+prevPoint.getY()+" "+nextPoint.getX()+","+nextPoint.getY());
	/*
	var array = new Array();
	var rectangle = utils.getDimensions(point1, point2);
	var distance = rectangle.getWidth();
	if (rectangle.getWidth() > rectangle.getHeight()) {
		var ratio = rectangle.getHeight() / rectangle.getWidth();
		var x_inc = 1;
		var y_inc = 1*ratio;
		if (point2.getX() < point1.getX()) {
			x_inc = -1;
		}
		if (point2.getY() < point1.getY()) {
			y_inc = -1*ratio;
		}
	} else {
		distance = rectangle.getHeight();
		var ratio = rectangle.getWidth() / rectangle.getHeight();
		var x_inc = 1*ratio;
		var y_inc = 1;
		if (point2.getX() < point1.getX()) {
			x_inc = -1*ratio;
		}
		if (point2.getY() < point1.getY()) {
			y_inc = -1;
		}
	}
	var i;
	for (i = 1 ; i < distance ; i += this.getExtrapolationDistance()) {
		array.push(new Point(point1.getX() + (x_inc*i), point1.getY() + (y_inc*i)));
	}
	return array;
	*/
	return this.cs.getIntermediatePoints(prevPoint,point1,point2,nextPoint,utils.getDistance(point1, point2)/this.getExtrapolationDistance(point2, nextPoint));
	//return new Array();
}

RoundBrush.prototype.isRenderedDifferentlyUponCompletion = function() {
	return true;
}

utils.copyPrototype(RoundBrush, Brush);

function SmallRoundBrush() {
	this.RoundBrush();
}

SmallRoundBrush.prototype.getClassName = function() {
	return "SmallRoundBrush";
}

SmallRoundBrush.prototype.getImageAtPoint = function(container, point1) {
	var x1 = point1.getX();
	var y1 = point1.getY();
	imageUrl = this.getImageUrl();
	var preloadedImage = new PreloadedImage(container, imageUrl);
	var rectangle = utils.getDimensions(new Point(x1-3,y1-3), new Point(x1+3,y1+3));
	preloadedImage.setBounds(rectangle);
	return preloadedImage;
}

utils.copyPrototype(SmallRoundBrush, RoundBrush);

function BlueSmallRoundBrush() {
	this.SmallRoundBrush();
}

BlueSmallRoundBrush.prototype.getClassName = function() {
	return "BlueSmallRoundBrush";
}

BlueSmallRoundBrush.prototype.getImageUrl = function() {
	return this.getImageDirectory()+"circle_graded_blue.png";
}

utils.copyPrototype(BlueSmallRoundBrush, SmallRoundBrush);

function GreenSmallRoundBrush() {
	this.SmallRoundBrush();
}

GreenSmallRoundBrush.prototype.getClassName = function() {
	return "GreenSmallRoundBrush";
}

GreenSmallRoundBrush.prototype.getImageUrl = function() {
	return this.getImageDirectory()+"circle_graded_green.png";
}

utils.copyPrototype(GreenSmallRoundBrush, SmallRoundBrush);

function BrownSmallRoundBrush() {
	this.SmallRoundBrush();
}

BrownSmallRoundBrush.prototype.getClassName = function() {
	return "BrownSmallRoundBrush";
}

BrownSmallRoundBrush.prototype.getImageUrl = function() {
	return this.getImageDirectory()+"circle_graded_brown.png";
}

utils.copyPrototype(BrownSmallRoundBrush, SmallRoundBrush);

function CyanSmallRoundBrush() {
	this.SmallRoundBrush();
}

CyanSmallRoundBrush.prototype.getClassName = function() {
	return "CyanSmallRoundBrush";
}

CyanSmallRoundBrush.prototype.getImageUrl = function() {
	return this.getImageDirectory()+"circle_graded_cyan.png";
}

utils.copyPrototype(CyanSmallRoundBrush, SmallRoundBrush);

function CyanSmallRoundBrush() {
	this.SmallRoundBrush();
}

CyanSmallRoundBrush.prototype.getClassName = function() {
	return "CyanSmallRoundBrush";
}

CyanSmallRoundBrush.prototype.getImageUrl = function() {
	return this.getImageDirectory()+"circle_graded_cyan.png";
}

utils.copyPrototype(CyanSmallRoundBrush, SmallRoundBrush);

function YellowSmallRoundBrush() {
	this.SmallRoundBrush();
}

YellowSmallRoundBrush.prototype.getClassName = function() {
	return "YellowSmallRoundBrush";
}

YellowSmallRoundBrush.prototype.getImageUrl = function() {
	return this.getImageDirectory()+"circle_graded_yellow.png";
}

utils.copyPrototype(YellowSmallRoundBrush, SmallRoundBrush);

function YellowSmallRoundBrush() {
	this.SmallRoundBrush();
}

YellowSmallRoundBrush.prototype.getClassName = function() {
	return "YellowSmallRoundBrush";
}

YellowSmallRoundBrush.prototype.getImageUrl = function() {
	return this.getImageDirectory()+"circle_graded_yellow.png";
}

utils.copyPrototype(YellowSmallRoundBrush, SmallRoundBrush);

function PinkSmallRoundBrush() {
	this.SmallRoundBrush();
}

PinkSmallRoundBrush.prototype.getClassName = function() {
	return "PinkSmallRoundBrush";
}

PinkSmallRoundBrush.prototype.getImageUrl = function() {
	return this.getImageDirectory()+"circle_graded_pink.png";
}

utils.copyPrototype(PinkSmallRoundBrush, SmallRoundBrush);

function OrangeSmallRoundBrush() {
	this.SmallRoundBrush();
}

OrangeSmallRoundBrush.prototype.getClassName = function() {
	return "OrangeSmallRoundBrush";
}

OrangeSmallRoundBrush.prototype.getImageUrl = function() {
	return this.getImageDirectory()+"circle_graded_orange.png";
}

utils.copyPrototype(OrangeSmallRoundBrush, SmallRoundBrush);

function WhiteOutBrush() {
	this.RoundBrush();
}

WhiteOutBrush.prototype.getImageUrl = function() {
	return this.getImageDirectory()+"circle_graded_white.png";
}

WhiteOutBrush.prototype.getClassName = function() {
	return "WhiteOutBrush";
}

utils.copyPrototype(WhiteOutBrush, RoundBrush);

function GlobShooterBrush() {
	this.Brush();
}

GlobShooterBrush.prototype.getImageDirectory = function() {
	return "images/brushes/globs/";
}

GlobShooterBrush.prototype.getImageUrl = function(point1, point2) {
	return this.getImageDirectory()+"circle_graded_black.png";
}

GlobShooterBrush.prototype.getClassName = function() {
	return "GlobShooterBrush";
}

GlobShooterBrush.prototype.getImage = function(container, points, i) {
	var distance = this.getDistanceBetweenJoinedPoints();
	var imageUrl = this.getImageUrl(points[i], points[i-distance]);
	var preloadedImage = new PreloadedImage(container, imageUrl);
	var rectangle = this.getDisplayRectangle(points[i], points[i-distance]);
	preloadedImage.setBounds(rectangle);
	return preloadedImage;
}

GlobShooterBrush.prototype.getDistanceBetweenJoinedPoints = function() {
	return 2;
}

utils.copyPrototype(GlobShooterBrush, Brush);

function LineBrush() {
	this.Brush();
}

LineBrush.prototype.getImageDirectory = function() {
	return "images/brushes/lines/";
}

LineBrush.prototype.getImageUrl = function(point1, point2) {
	var imageUrl = null;
	var x1 = point1.getX();
	var y1 = point1.getY();
	var x2 = point2.getX();
	var y2 = point2.getY();
	if ((x1 - x2) * (y1 - y2) > 0) {
		imageUrl = this.getImageDirectory()+"line_1001_graded_black.png";
	} else {
		imageUrl = this.getImageDirectory()+"line_0011_graded_black.png";
	}
	if (x1 == x2) {
		imageUrl = this.getImageDirectory()+"line_x_graded_black.png";
	}
	if (y1 == y2) {
		imageUrl = this.getImageDirectory()+"line_y_graded_black.png";
	}
	return imageUrl;
}

LineBrush.prototype.getClassName = function() {
	return "LineBrush";
}

LineBrush.prototype.getImage = function(container, points, i) {
	var distance = this.getDistanceBetweenJoinedPoints();
	var imageUrl = this.getImageUrl(points[i], points[i-distance]);
	var preloadedImage = new PreloadedImage(container, imageUrl);
	var rectangle = this.getDisplayRectangle(points[i], points[i-distance]);
	preloadedImage.setBounds(rectangle);
	return preloadedImage;
}

LineBrush.prototype.getDistanceBetweenJoinedPoints = function() {
	return 1;
}

utils.copyPrototype(LineBrush, Brush);

function StrokeBrush() {
	this.LineBrush();
}

StrokeBrush.prototype.getClassName = function() {
	return "StrokeBrush";
}

StrokeBrush.prototype.getImageUrl = function(point1, point2) {
	var imageUrl = null;
	var x1 = point1.getX();
	var y1 = point1.getY();
	var x2 = point2.getX();
	var y2 = point2.getY();
	if ((x1 - x2) * (y1 - y2) > 0) {
		imageUrl = this.getImageDirectory()+"line_0011_graded_black.png";
	} else {
		imageUrl = this.getImageDirectory()+"line_1001_graded_black.png";
	}
	if (x1 == x2) {
		imageUrl = this.getImageDirectory()+"line_x_graded_black.png";
	}
	if (y1 == y2) {
		imageUrl = this.getImageDirectory()+"line_y_graded_black.png";
	}
	return imageUrl;
}

StrokeBrush.prototype.getDistanceBetweenJoinedPoints = function() {
	return 2;
}

utils.copyPrototype(StrokeBrush, LineBrush);

function SmoothLineBrush() {
	this.LineBrush();
}

SmoothLineBrush.prototype.getClassName = function() {
	return "SmoothLineBrush";
}

SmoothLineBrush.prototype.getImageUrl = function(point1, point2) {
	var angle = null;
	var prefix = null;
	var x1 = point1.getX();
	var y1 = point1.getY();
	var x2 = point2.getX();
	var y2 = point2.getY();
	if (x1 == x2) {
		angle = "0_graded_black.png";
	} else if (y1 == y2) {
		angle = "90_graded_black.png";
	} else {
		angle = Math.atan2(x2-x1,y1-y2)*180/Math.PI;
		angle = Math.floor(angle/10)*10;
		if (angle >= 180) {
			angle = angle - 180;
		}
		while (angle < 0) {
			angle = angle + 180;
		}
		if (angle == 0) {
			angle = 10;
		}
		if (angle == 40 || angle == 50)
			angle = 45;
		if (angle == 130 || angle == 140)
			angle = 135;
		angle = angle+"_graded_black.png";
	}
	var distance = Math.sqrt( ((x1 - x2) * (x1 - x2)) + ((y1 - y2) * (y1 - y2)) );
//	if (distance > 40) {
//		prefix = "line_l_";
//	} else 
	if (distance > 10) {
		prefix = "line_";
//	} else 
//	if (distance > 10) {
//		prefix = "line_s_";
	} else {
		prefix = "line_p_";
		angle = "0_graded_black.png";
	}
	imageUrl = this.getImageDirectory()+prefix+angle;
	//document.writeln(distance+" "+prefix+angle);
	return imageUrl;
}

SmoothLineBrush.prototype.getDisplayRectangle = function (point1, point2) {
	var x1 = point1.getX();
	var y1 = point1.getY();
	var x2 = point2.getX();
	var y2 = point2.getY();
	if (x1 == x2) {
		x1 = x1 - 1;
		x2 = x2 + 1;
	}
	if (y1 == y2) {
		y1 = y1 - 1;
		y2 = y2 + 1;
	}
	return utils.getDimensions(new Point(x1,y1), new Point(x2,y2));
}

SmoothLineBrush.prototype.getDistanceBetweenJoinedPoints = function() {
	return 4;
}

utils.copyPrototype(SmoothLineBrush, LineBrush);

function StraightEdgeBrush() {
	this.RoundBrush();
}

StraightEdgeBrush.prototype.getClassName = function() {
	return "StraightEdgeBrush";
}

StraightEdgeBrush.prototype.isRenderedDifferentlyUponCompletion = function() {
	return false;
}

StraightEdgeBrush.prototype.isOnlyEndPointsUseful = function() {
	return true;
}

StraightEdgeBrush.prototype.renderSelf = function(canvasPeer, pointsHistory, points, flagComplete) {
	this.extrapolatedPoints = new Array();
	
	if (points.length >= 1) {
		this.extrapolatedPoints.push(points[0]);
	}

	var temp = this.getIntermediatePoints(points[0], points[points.length-1], points[0], points[points.length-1]);
	
	for (j = 0 ; j < temp.length ; ++j) {
		this.extrapolatedPoints.push(temp[j]);
	}
	
	this.extrapolatedPoints.push(points[points.length-1]);
	
	if (flagComplete == true) {
		for (i = 0 ; i < this.extrapolatedPoints.length ; ++i) {
			if (i > this.getDistanceBetweenJoinedPoints()) {
				this.preloadedImage = this.getImage(canvasPeer, this.extrapolatedPoints, i);
				this.preloadedImage.display();
				pointsHistory.push(this.preloadedImage);
			}
		}
	} else {
			this.preloadedImage = this.getImage(canvasPeer, points, 0);
			this.preloadedImage.display();
			pointsHistory.push(this.preloadedImage);

			this.preloadedImage = this.getImageAtPoint(canvasPeer, new Point(points[0].getX()+(points[points.length-1].getX()-points[0].getX())/4,points[0].getY()+(points[points.length-1].getY()-points[0].getY())/4));
			this.preloadedImage.display();
			pointsHistory.push(this.preloadedImage);

			this.preloadedImage = this.getImageAtPoint(canvasPeer, new Point((points[0].getX()+points[points.length-1].getX())/2,(points[0].getY()+points[points.length-1].getY())/2));
			this.preloadedImage.display();
			pointsHistory.push(this.preloadedImage);

			this.preloadedImage = this.getImageAtPoint(canvasPeer, new Point(points[0].getX()+(points[points.length-1].getX()-points[0].getX())*3/4,points[0].getY()+(points[points.length-1].getY()-points[0].getY())*3/4));
			this.preloadedImage.display();
			pointsHistory.push(this.preloadedImage);

			this.preloadedImage = this.getImage(canvasPeer, points, points.length-1);
			this.preloadedImage.display();
			pointsHistory.push(this.preloadedImage);
	}
}

StraightEdgeBrush.prototype.getExtrapolationDistance = function(point2, nextPoint) {
	return 2;
}

utils.copyPrototype(StraightEdgeBrush, RoundBrush);

function RectangleBrush(canvas) {
	this.StraightEdgeBrush(canvas);
	this.canvas = canvas;
}

RectangleBrush.prototype.getClassName = function() {
	return "RectangleBrush";
}

RectangleBrush.prototype.isEditable = function() {
	return true;
}

RectangleBrush.prototype.openEditor = function(canvasPeer, pointsHistory, points, flagComplete, firstTime, stroke) {
		this.renderSelf(canvasPeer, pointsHistory, points, flagComplete, firstTime, stroke);
}

RectangleBrush.prototype.renderSelf = function(canvasPeer, pointsHistory, points, flagComplete) {
	
/*
	this.extrapolatedPoints = new Array();
	
	if (points.length >= 1) {
		this.extrapolatedPoints.push(points[0]);
	}

	var point = new Point(points[0].getX(), points[points.length-1].getY());
	var temp = this.getIntermediatePoints(points[0], point, points[0], point);
	for (j = 0 ; j < temp.length ; ++j) {
		this.extrapolatedPoints.push(temp[j]);
	}
	temp = this.getIntermediatePoints(point, points[points.length-1], point, points[points.length-1]);
	for (j = 0 ; j < temp.length ; ++j) {
		this.extrapolatedPoints.push(temp[j]);
	}
	point = new Point(points[points.length-1].getX(), points[0].getY());
	var temp = this.getIntermediatePoints(points[0], point, points[0], point);
	for (j = 0 ; j < temp.length ; ++j) {
		this.extrapolatedPoints.push(temp[j]);
	}
	temp = this.getIntermediatePoints(point, points[points.length-1], point, points[points.length-1]);
	for (j = 0 ; j < temp.length ; ++j) {
		this.extrapolatedPoints.push(temp[j]);
	}
	
	this.extrapolatedPoints.push(points[points.length-1]);
	
	if (flagComplete == true) {
		for (i = 0 ; i < this.extrapolatedPoints.length ; ++i) {
			if (i > this.getDistanceBetweenJoinedPoints()) {
				this.preloadedImage = this.getImage(canvasPeer, this.extrapolatedPoints, i);
				this.preloadedImage.display();
				pointsHistory.push(this.preloadedImage);
			}
		}
	} else {
*/
	
	if (flagComplete == true) {
			this.preloadedImage = this.getRenderable(canvasPeer, points[0], points[points.length-1]);
			this.preloadedImage.display();
			pointsHistory.push(this.preloadedImage);
	} else {
			this.preloadedImage = this.getImage(canvasPeer, points, 0);
			this.preloadedImage.display();
			pointsHistory.push(this.preloadedImage);

			this.preloadedImage = this.getImageAtPoint(canvasPeer, new Point(points[points.length-1].getX(),points[0].getY()));
			this.preloadedImage.display();
			pointsHistory.push(this.preloadedImage);

			this.preloadedImage = this.getImageAtPoint(canvasPeer, new Point(points[0].getX(),points[points.length-1].getY()));
			this.preloadedImage.display();
			pointsHistory.push(this.preloadedImage);

			this.preloadedImage = this.getImage(canvasPeer, points, points.length-1);
			this.preloadedImage.display();
			pointsHistory.push(this.preloadedImage);
	}
}

RectangleBrush.prototype.getRenderable = function(container, point1, point2) {
	var x1 = point1.getX();
	var y1 = point1.getY();
	var x2 = point2.getX();
	var y2 = point2.getY();
	//imageUrl = this.getImageUrl();
	var preloadedImage = new TextBoxWithMarginShape(container);
	var rectangle = utils.getDimensions(new Point(x1,y1), new Point(x2,y2));
	preloadedImage.setBounds(rectangle);
	return new ResizableMovableBoundary(preloadedImage, this.canvas);
	//return preloadedImage;
}

utils.copyPrototype(RectangleBrush, StraightEdgeBrush);

function TextBrushEditor(canvasPeer, pointsHistory, points, flagComplete, firstTime, stroke, textBrush) {
	this.container = canvasPeer;
	this.pointsHistory = pointsHistory;
	this.points = points;
	this.flagComplete = flagComplete;
	this.firstTime = firstTime;
	this.stroke = stroke;
	this.brush = textBrush;
	this.isDisplayed = false;
	this.size = textBrush.getSize();
	this.color = textBrush.getColor();
	this.font = textBrush.getFont();
	this.textBrush = textBrush;
	
	this.buttonSpace = 20;
	
	this.setBounds(utils.getDimensions(points[0], points[1]));
	if (this.getRoot().currentEditor == null) {
		this.display();
	} else {
		this.getBrush().getCanvas().builder.undoLastStroke();
	}
}

TextBrushEditor.prototype.getRoot = function() {
	if (this.getBrush() != null)
		return this.getBrush().getCanvas();
	else
		return this.container.parentNode;
}

TextBrushEditor.prototype.getBrush = function() {
	return this.textBrush;
}

TextBrushEditor.prototype.setBounds = function(rectangle) {
	this.left = rectangle.getX();
	this.top = rectangle.getY();
	this.width = rectangle.getWidth();
	this.height = rectangle.getHeight();
}

TextBrushEditor.prototype.display = function() {
	//var text = prompt("Enter the text for the box", "Type your text here");
	//this.stroke.setState(text);
	//this.complete();
	var divId = 'graphical_unit';
	this.imageDiv = document.createElement('div');
	this.imageDiv.id = divId;
	this.imageDiv.style.left = this.left+'px';
	this.imageDiv.style.top = this.top+'px';
	this.imageDiv.style.width = this.width+'px';
	this.imageDiv.style.height = (this.height+this.buttonSpace)+'px';
	this.imageDiv.style.border = '1px solid #000000';
	this.imageDiv.style.font=this.size+"pt "+this.font;
	this.imageDiv.style.background = '#e0e0e0';
	this.imageDiv.onmousedown = TextBrushEditor.prototype.onClickHandler;
	this.imageDiv.onmouseover = TextBrushEditor.prototype.onMouseOverHandler;
	this.imageDiv.onmouseup = utils.cancelBubble;
	this.imageDiv.style.zIndex=8;

	this.getRoot().currentEditor = this;

	this.container.appendChild(this.imageDiv);
	
	this.createTextBox(this.imageDiv, this.left, this.top, this.width, this.height);

	this.createButtons(this.imageDiv, this.left, this.top, this.width, this.height);
	
	this.isDisplayed = true;
}

TextBrushEditor.prototype.onClickHandler = function(e) {
	utils.cancelBubble(e);
}

TextBrushEditor.prototype.onMouseOverHandler = function(e) {
	utils.cancelBubble(e);
}

TextBrushEditor.prototype.createTextBox = function(container, left, top, width, height) {
	var padding = 5;
	var divId = 'text_editor';
	
	// Using an input element of type text didn't work because it does not wrap.

	//this.editorTextBox = document.createElement("input");
	//this.editorTextBox.type = 'text';
	//this.editorTextBox.value = "Type your text here";

	// ... so we use a textarea instead.
	this.editorTextBox = document.createElement("div");
	this.editorTextBox.id = divId;
	this.editorTextBox.style.left = padding+'px';
	this.editorTextBox.style.top = padding+'px';
	this.editorTextBox.style.font=this.size+"pt "+this.font;
	this.editorTextBox.style.color=this.color;
	this.editorTextBox.style.width = (this.width - 2 * padding)+'px';
	this.editorTextBox.style.height = (this.height - 2 * padding + 1)+'px';
	this.editorTextBox.style.zIndex = 6;

	var editor = 'text_area_editor';
	var html = "Type your text here";
	this.editorTextBox.innerHTML = '<textarea name="' + editor + '" id="' + editor + '" cols="39" rows="10" style="position:absolute; visibility:visible; width:'+(this.width - 2 * padding)+'px;height:'+(this.height - 2 * padding)+'px; left:0px; top:0px; border:1px solid #000000; font-size:12pt; font-name:arial">' + html + '</textarea>'

	container.appendChild(this.editorTextBox);
}

TextBrushEditor.prototype.createButtons = function(container, left, top, width, height) {
	var divId = 'text_editor';
	this.button1 = document.createElement("input");
	this.button1.type = 'button';
	this.button1.value = "Save";
	this.button1.id = divId;
	this.button1.style.left = (this.width / 2 - this.width / 8)+'px';
	this.button1.style.top = (this.height)+'px';
	this.button1.style.font="8pt arial"
	this.button1.style.width = (this.width / 4 )+'px';
	this.button1.style.height = (this.buttonSpace)+'px';
	this.button1.texteditor = this;
	this.button1.onmouseup = TextBrushEditor.prototype.onSaveHandler;

	container.appendChild(this.button1);
}

TextBrushEditor.prototype.onSaveHandler = function(e) {
	this.texteditor.stroke.setState(this.texteditor.editorTextBox.childNodes[0].value);
	this.texteditor.destructor();
	this.texteditor.complete();
	utils.cancelBubble(e);
}

TextBrushEditor.prototype.onCancelHandler = function(e) {
	this.texteditor.getBrush().getCanvas().builder.undoLastStroke();
	this.texteditor.destructor();
}

TextBrushEditor.prototype.complete = function() {
	this.brush.renderSelf(this.container, this.pointsHistory, this.points, this.flagComplete, this.firstTime, this.stroke);
}

TextBrushEditor.prototype.destructor = function() {
	this.container.removeChild(this.imageDiv);
	if (this.getRoot().currentEditor != null && this.getBrush() != null) {
		this.getBrush().getCanvas().builder.setBrush(new RoundBrush());
	}
	this.getRoot().currentEditor = null;
}

function TextBrush() {
	this.RectangleBrush();
	this.color = 'black';
	this.size = 24;
	this.font = 'arial';
}

TextBrush.prototype.getClassName = function() {
	return "TextBrush";
}

TextBrush.prototype.isEditable = function() {
	return true;
}

TextBrush.prototype.setColor = function(color) {
	this.color = color;
}

TextBrush.prototype.setSize = function(size) {
	this.size = size;
}

TextBrush.prototype.setFont = function(font) {
	this.font = font;
}

TextBrush.prototype.getColor = function() {
	return this.color ;
}

TextBrush.prototype.getSize = function() {
	return this.size ;
}

TextBrush.prototype.getFont = function() {
	return this.font ;
}

TextBrush.prototype.openEditor = function(canvasPeer, pointsHistory, points, flagComplete, firstTime, stroke) {
	if (stroke.getState() == null) {
		//var text = prompt("Enter the text for the box", "Type your text here");
		//stroke.setState(text);
		var editor = new TextBrushEditor(canvasPeer, pointsHistory, points, flagComplete, firstTime, stroke, this);
	} else {
		this.renderSelf(canvasPeer, pointsHistory, points, flagComplete, firstTime, stroke);
	}
}

TextBrush.prototype.renderSelf = function(canvasPeer, pointsHistory, points, flagComplete, firstTime, stroke) {
	var point = new Point(points[0].getX(), points[points.length-1].getY());

	if (flagComplete == true) {
			this.preloadedImage = this.getRenderable(canvasPeer, points[0], points[points.length-1]);
			this.preloadedImage.setColor(this.color);
			this.preloadedImage.setSize(this.size);
			this.preloadedImage.setFont(this.font);
			this.preloadedImage.stroke = stroke;
			this.preloadedImage.display();
			pointsHistory.push(this.preloadedImage);
			this.preloadedImage.setText(stroke.getState());
			//alert("Rendering text "+stroke.getState());
	} else {
			this.preloadedImage = this.getImage(canvasPeer, points, 0);
			this.preloadedImage.display();
			pointsHistory.push(this.preloadedImage);

			this.preloadedImage = this.getImageAtPoint(canvasPeer, new Point(points[points.length-1].getX(),points[0].getY()));
			this.preloadedImage.display();
			pointsHistory.push(this.preloadedImage);

			this.preloadedImage = this.getImageAtPoint(canvasPeer, new Point(points[0].getX(),points[points.length-1].getY()));
			this.preloadedImage.display();
			pointsHistory.push(this.preloadedImage);

			this.preloadedImage = this.getImage(canvasPeer, points, points.length-1);
			this.preloadedImage.display();
			pointsHistory.push(this.preloadedImage);
	}
}

utils.copyPrototype(TextBrush, RectangleBrush);

function GeneralTextBrushEditor(canvasPeer, pointsHistory, points, flagComplete, firstTime, stroke, textBrush) {
	this.TextBrushEditor(canvasPeer, pointsHistory, points, flagComplete, firstTime, stroke, textBrush);
	this.color = textBrush.getColor();
	this.size = textBrush.getSize();
	this.font = textBrush.getFont();
}

GeneralTextBrushEditor.prototype.createButtons = function(container, left, top, width, height) {
	var padding = 5;
	var divId = 'text_editor';
	this.button1 = document.createElement("input");
	this.button1.type = 'button';
	this.button1.value = "Save";
	this.button1.id = divId;
	this.button1.style.left = (this.width / 2 + this.width / 4)+'px';
	this.button1.style.top = (this.height - padding)+'px';
	this.button1.style.font="8pt arial"
	this.button1.style.width = (this.width / 6 )+'px';
	this.button1.style.height = (this.buttonSpace)+'px';
	this.button1.texteditor = this;
	this.button1.onmouseup = GeneralTextBrushEditor.prototype.onSaveHandler;

	var div2 = document.createElement("div");
	div2.id = divId;
	div2.innerHTML = '<form><select id="selos1" name="selos" size="1"><option value="6">6</option><option value="8">8</option><option value="10">10</option><option value="12">12</option><option value="16">16</option><option value="20" selected="selected">20</option><option value="24">24</option><option value="28">28</option><option value="32">32</option><option value="36">36</option><option value="40">40</option><option value="48">48</option><option value="60">60</option><option value="76">76</option></select></form>';
	div2.style.left = (this.width / 2)+'px';
	div2.style.top = (this.height - padding)+'px';
	div2.style.width = (this.width / 4 )+'px';
	div2.style.height = (this.buttonSpace)+'px';

	var div3 = document.createElement("div");
	div3.id = divId;
	div3.innerHTML = '<form><select id="selos2" name="selos" size="1"><option value="aqua" style="background: aqua">aqua</option><option value="black" selected="selected" style="background: black; color: white;">black</option><option value="blue" style="background: blue; color: white;">blue</option><option value="brown" style="background: brown; color: white;">brown</option><option value="fuchsia" style="background: fuchsia; color: white;">fuchsia</option><option value="gray" style="background: gray; color: white;">gray</option><option value="green" style="background: green; color: white;">green</option><option value="lime" style="background: lime">lime</option><option value="maroon" style="background: maroon; color: white;">maroon</option><option value="navy" style="background: navy; color: white;">navy</option><option value="orange" style="background: orange">orange</option><option value="pink" style="background: pink">pink</option><option value="purple" style="background: purple; color: white;">purple</option><option value="red" style="background: red; color: white;">red</option><option value="silver" style="background: silver">silver</option><option value="yellow" style="background: yellow">yellow</option><option value="white">white</option></select></form>';
	div3.style.left = (this.width / 2 - this.width / 4  - this.width / 4)+'px';
	div3.style.top = (this.height - padding)+'px';
	div3.style.width = (this.width / 4 )+'px';
	div3.style.height = (this.buttonSpace)+'px';

	var div4 = document.createElement("div");
	div4.id = divId;
	div4.innerHTML = '<form><select id="selos3" name="selos" size="1"><option value="arial">arial</option><option value="century">century</option><option value="comic sans ms" selected="selected">comic</option><option value="courier new">courier</option><option value="mistral">mistral</option><option value="times">times</option><option value="verdana">verdana</option></select></form>';
	div4.style.left = (this.width / 2 - this.width / 4)+'px';
	div4.style.top = (this.height - padding)+'px';
	div4.style.width = (this.width / 4 )+'px';
	div4.style.height = (this.buttonSpace)+'px';

	var div5 = document.createElement("div");
	div5.id = divId;
	div5.style.cursor = "pointer";
	div5.innerHTML = '<img src="images/delete1.gif"/>';
	div5.texteditor = this;
	div5.onmousedown = GeneralTextBrushEditor.prototype.onCancelHandler;
	div5.style.left = (this.width / 2 + this.width / 4 + this.width / 8 + this.width / 16)+'px';
	div5.style.top = (this.height - padding + 5)+'px';
	div5.style.width = (this.width / 16 )+'px';
	div5.style.height = (this.buttonSpace)+'px';

	container.appendChild(this.button1);
	container.appendChild(div2);
	container.appendChild(div3);
	container.appendChild(div4);
	container.appendChild(div5);
}

GeneralTextBrushEditor.prototype.onSaveHandler = function(e) {
	//alert(document.getElementById('selos1').value);
	//alert(document.getElementById('selos2').value);
	//alert(document.getElementById('selos3').value);
	this.texteditor.stroke.setState(document.getElementById('selos2').value+','+document.getElementById('selos1').value+','+document.getElementById('selos3').value+','+this.texteditor.editorTextBox.childNodes[0].value);
	this.texteditor.destructor();
	this.texteditor.complete();
	utils.cancelBubble(e);
}

utils.copyPrototype(GeneralTextBrushEditor, TextBrushEditor);

function GeneralTextBrush() {
	this.TextBrush();
	this.color = 'yellow';
	this.size = 24;
	this.font = 'arial';
}

GeneralTextBrush.prototype.getClassName = function() {
	return "GeneralTextBrush";
}

GeneralTextBrush.prototype.openEditor = function(canvasPeer, pointsHistory, points, flagComplete, firstTime, stroke) {
	if (stroke.getState() == null) {
		var editor = new GeneralTextBrushEditor(canvasPeer, pointsHistory, points, flagComplete, firstTime, stroke, this);
	} else {
		this.renderSelf(canvasPeer, pointsHistory, points, flagComplete, firstTime, stroke);
	}
}

GeneralTextBrush.prototype.renderSelf = function(canvasPeer, pointsHistory, points, flagComplete, firstTime, stroke) {
	var point = new Point(points[0].getX(), points[points.length-1].getY());

	if (flagComplete == true) {
		//alert (stroke.getState());
		var stateArr = stroke.getState().split(',');
		var color = stateArr[0];
		var size = stateArr[1];
		var font = stateArr[2];
		var text = stroke.getState().substring((color+size+font).length+3, stroke.getState().length);
		this.preloadedImage = this.getRenderable(canvasPeer, points[0], points[points.length-1]);
		this.preloadedImage.setColor(color);
		this.preloadedImage.setSize(size);
		this.preloadedImage.setFont(font);
		this.preloadedImage.stroke = stroke;
		this.preloadedImage.display();
		pointsHistory.push(this.preloadedImage);
		this.preloadedImage.setText(text);
		//alert("Rendering text "+stroke.getState());
	} else {
		this.preloadedImage = this.getImage(canvasPeer, points, 0);
		this.preloadedImage.display();
		pointsHistory.push(this.preloadedImage);

		this.preloadedImage = this.getImageAtPoint(canvasPeer, new Point(points[points.length-1].getX(),points[0].getY()));
		this.preloadedImage.display();
		pointsHistory.push(this.preloadedImage);

		this.preloadedImage = this.getImageAtPoint(canvasPeer, new Point(points[0].getX(),points[points.length-1].getY()));
		this.preloadedImage.display();
		pointsHistory.push(this.preloadedImage);

		this.preloadedImage = this.getImage(canvasPeer, points, points.length-1);
		this.preloadedImage.display();
		pointsHistory.push(this.preloadedImage);
	}
}

utils.copyPrototype(GeneralTextBrush, TextBrush);

function ImageFetchTool(container, page, divId, imageId, submode, category, search, searchType) {
	this.url = configurations.getServerUrl()+'background_selector_toonsket.php';
	this.container = container;
	this.page = page;
	this.divId = divId;
	this.imageId = imageId;
	this.submode = submode;
	if (this.submode == null) {
		this.submode = 'foreground';
	}
	this.category = category;
	this.search = search;
	this.searchType = searchType;
}

ImageFetchTool.prototype.view = function() {
	var str = 'mode=ajax&submode='+this.submode+'&page='+this.page+'&divId='+this.divId;
	if (this.imageId != null)
		str = str + '&imageId=' + this.imageId;
	if (this.category != null)
		str = str + '&category=' + this.category;
	if (this.search != null)
		str = str + '&search=' + this.search + '&type=' + this.searchType;
	//alert(str);
	this.post(this.url, str, ImageFetchTool.prototype.completeRead);
}

ImageFetchTool.prototype.completeRead = function() {
    if (xmlReq.readyState == 4) {
        if (xmlReq.status == 200) {
		    response = xmlReq.responseText;
			//alert("received "+response);
		    this.persistenceTool.container.innerHTML = response;
		} else {
			alert("The website is having some problems ... the code returned is "+xmlReq.status);
		}
    } else {
		//alert("received file with status "+xmlReq.readyState);
    }
}

ImageFetchTool.prototype.post = function(url, parameterString, callback) {
    if (window.XMLHttpRequest) {
	   	xmlReq = new XMLHttpRequest();
	} else if (window.ActiveXObject) {
		xmlReq = new ActiveXObject("Microsoft.XMLHTTP");
	}
	//alert(url+"?"+parameterString);
	xmlReq.persistenceTool = this;
	xmlReq.open("POST",url,true); 
	xmlReq.onreadystatechange = callback;
	xmlReq.setRequestHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8"); 
	xmlReq.send(parameterString);
}

function viewImagePage(container, pageNumber, divId, imageId, submode, category, search, searchType) {
	//alert(container);
	imageFetcher = new ImageFetchTool(container, pageNumber, divId, imageId, submode, category, search, searchType);
	imageFetcher.view();
}

function ImageBrushEditor(canvasPeer, pointsHistory, points, flagComplete, firstTime, stroke, textBrush) {
	this.TextBrushEditor(canvasPeer, pointsHistory, points, flagComplete, firstTime, stroke, textBrush);
}

ImageBrushEditor.prototype.display = function() {
	//var text = prompt("Enter the text for the box", "Type your text here");
	//this.stroke.setState(text);
	//this.complete();
	var divId = 'graphical_unit';
	this.imageDiv = document.createElement('div');
	this.imageDiv.id = divId;
	this.imageDiv.style.left = 0+'px';
	this.imageDiv.style.top = 0+'px';
	this.imageDiv.style.width = this.container.style.width;
	this.imageDiv.style.height = this.container.style.height;
	//this.imageDiv.style.border = '1px solid #000000';
	this.imageDiv.style.font=this.size+"pt arial";
	this.imageDiv.style.background = '#e0e0e0';
	this.imageDiv.style.padding = '5px';
	this.imageDiv.style.margin = '0px';
	this.imageDiv.onmousedown = ImageBrushEditor.prototype.onClickHandler;
	this.imageDiv.onmouseover = ImageBrushEditor.prototype.onMouseOverHandler;
	this.imageDiv.onmouseup = utils.cancelBubble;
	this.imageDiv.style.zIndex=6;

	if (this.getRoot().currentEditor != null) {
		this.getRoot().currentEditor.destructor();
	}

	this.getRoot().currentEditor = this;

	this.container.appendChild(this.imageDiv);
	
	this.createTextBox(this.imageDiv, 0, 0, this.container.style.width.split('p')[0], this.container.style.height.split('p')[0]);

	//this.createButtons(this.imageDiv, 0, 0, this.container.style.width.split('p')[0], this.container.style.height.split('p')[0]);
	
	this.isDisplayed = true;
}

ImageBrushEditor.prototype.createTextBox = function(container, left, top, width, height) {
	var padding = 5;
	var divId = 'text_editor_'+Math.ceil(Math.random()*10000);
	
	// Using an input element of type text didn't work because it does not wrap.

	//this.editorTextBox = document.createElement("input");
	//this.editorTextBox.type = 'text';
	//this.editorTextBox.value = "Type your text here";

	// ... so we use a textarea instead.
	this.editorTextBox = document.createElement("div");
	this.editorTextBox.id = divId;
	this.editorTextBox.style.left = '0px';
	this.editorTextBox.style.top = '0px';
	//alert ('top = '+this.editorTextBox.style.top);
	this.editorTextBox.style.font=12+"pt arial";
	this.editorTextBox.style.color=this.color;
	this.editorTextBox.style.background='white';
	this.editorTextBox.style.overflow='auto';
	this.editorTextBox.style.padding = '0px';
	this.editorTextBox.style.margin = '0px';
	//alert("Width = "+width);
	this.editorTextBox.style.width = (width - 2 * padding - 2)+'px';
	this.editorTextBox.style.height = (height - 2 * padding - 2)+'px';
	this.editorTextBox.innerHTML = '<br/><center>Loading ...</center><br/><center><a href="javascript:closeNonBG(document.getElementById(\''+divId+'\').texteditor);">Close [x]</a></center>';

	var editor = 'text_area_editor';

		this.editorTextBox.texteditor = this;	
		viewImagePage(this.editorTextBox, 0, divId, this.brush.imageId, this.textBrush.getSubmode(), this.textBrush.getCanvas().getType());

		container.appendChild(this.editorTextBox);
}

ImageBrushEditor.prototype.createButtons = function(container, left, top, width, height) {
	var divId = 'text_editor';
	this.button1 = document.createElement("input");
	this.button1.type = 'button';
	this.button1.value = "Save";
	this.button1.id = divId;
	this.button1.style.left = (width / 2 - width / 8)+'px';
	this.button1.style.top = (height-this.buttonSpace-2)+'px';
	this.button1.style.font="8pt arial"
	this.button1.style.width = (width / 4 )+'px';
	this.button1.style.height = (this.buttonSpace)+'px';
	this.button1.texteditor = this;

	container.appendChild(this.button1);
}

ImageBrushEditor.prototype.onSaveHandler = function(number, type, width, height) {
	var availableWidth = this.imageDiv.style.width.split('p')[0];
	var availableHeight = this.imageDiv.style.height.split('p')[0];
	if (this.textBrush.getCanvas().getType() == 'cartoon') {
		preferredWidth = 150;
		preferredHeight = 250;
	} else {
		preferredWidth = availableWidth;
		preferredHeight = availableHeight;
	}
	if (width != null) {
		if (width > preferredWidth) {
			height = height * preferredWidth / width;
			width = preferredWidth;
		}
		if (height > preferredHeight) {
			width = width * preferredHeight / height;
			height = preferredHeight;
		}
		this.stroke.getPoints()[0].setX(availableWidth/2 - width/2);
		this.stroke.getPoints()[1].setX(availableWidth/2 + width/2);
	}
	if (height != null) {
		this.stroke.getPoints()[0].setY(availableHeight/2 - height/2);
		this.stroke.getPoints()[1].setY(availableHeight/2 + height/2);
	}
	this.stroke.setState(number+','+type);
	this.destructor();
	this.complete();
}

utils.copyPrototype(ImageBrushEditor, TextBrushEditor);

function ImageBrush(imageId, submode) {
	this.imageId = imageId;
	this.submode = submode;
	this.TextBrush();
}

ImageBrush.prototype.getClassName = function() {
	return "ImageBrush";
}

ImageBrush.prototype.getSubmode = function() {
	return this.submode;
}

ImageBrush.prototype.openEditor = function(canvasPeer, pointsHistory, points, flagComplete, firstTime, stroke) {
	if (stroke.getState() == null) {
		//var text = prompt("Enter the image number and type", "660,image");
		//stroke.setState(text);
		//this.renderSelf(canvasPeer, pointsHistory, points, flagComplete, firstTime, stroke);
		var editor = new ImageBrushEditor(canvasPeer, pointsHistory, points, flagComplete, firstTime, stroke, this);
	} else {
		this.renderSelf(canvasPeer, pointsHistory, points, flagComplete, firstTime, stroke);
	}
}

ImageBrush.prototype.getImageUrlFromNumberAndType = function(number, type) {
	return configurations.getServerUrl() + "viewbinaryimage.php?id="+number+"&type="+type+"&command=View";
}

ImageBrush.prototype.getImageFromNumberAndType = function(container, number, type, point1, point2) {
	var x1 = point1.getX();
	var y1 = point1.getY();
	var x2 = point2.getX();
	var y2 = point2.getY();
	imageUrl = this.getImageUrlFromNumberAndType(number, type);
	var preloadedImage = new PreloadedImage(container, imageUrl);
	preloadedImage.setZIndex(1);
	var rectangle = utils.getDimensions(new Point(x1,y1), new Point(x2,y2));
	preloadedImage.setBounds(rectangle);
	return new ResizableMovableBoundary(preloadedImage, this.canvas);
	//return preloadedImage;
}

ImageBrush.prototype.renderSelf = function(canvasPeer, pointsHistory, points, flagComplete, firstTime, stroke) {
	var point = new Point(points[0].getX(), points[points.length-1].getY());

	if (flagComplete == true) {
			var state = stroke.getState();
			var number = state.split(',')[0];
			var type = state.split(',')[1];
			this.preloadedImage = this.getImageFromNumberAndType(canvasPeer, number, type, points[0], points[points.length-1]);
			this.preloadedImage.stroke = stroke;
			this.preloadedImage.display();
			pointsHistory.push(this.preloadedImage);
			//this.preloadedImage.setText(stroke.getState());
			//alert("Rendering text "+stroke.getState());
	} else {
			this.preloadedImage = this.getImage(canvasPeer, points, 0);
			this.preloadedImage.display();
			pointsHistory.push(this.preloadedImage);

			this.preloadedImage = this.getImageAtPoint(canvasPeer, new Point(points[points.length-1].getX(),points[0].getY()));
			this.preloadedImage.display();
			pointsHistory.push(this.preloadedImage);

			this.preloadedImage = this.getImageAtPoint(canvasPeer, new Point(points[0].getX(),points[points.length-1].getY()));
			this.preloadedImage.display();
			pointsHistory.push(this.preloadedImage);

			this.preloadedImage = this.getImage(canvasPeer, points, points.length-1);
			this.preloadedImage.display();
			pointsHistory.push(this.preloadedImage);
	}
}

utils.copyPrototype(ImageBrush, TextBrush);

function BorderBrush(imageId, submode) {
	this.ImageBrush(imageId, submode);
}

BorderBrush.prototype.getImageFromNumberAndType = function(container, number, type, point1, point2) {
	var x1 = point1.getX();
	var y1 = point1.getY();
	var x2 = point2.getX();
	var y2 = point2.getY();
	imageUrl = this.getImageUrlFromNumberAndType(number, type);
	var preloadedImage = new PreloadedImage(container, imageUrl);
	preloadedImage.setZIndex(1);
	var rectangle = utils.getDimensions(new Point(x1,y1), new Point(x2,y2));
	preloadedImage.setBounds(rectangle);
	return preloadedImage;
}

utils.copyPrototype(BorderBrush, ImageBrush);

function BackgroundFetchTool(container, page, divId, submode, category, search, searchType){
	this.ImageFetchTool(container, page, divId, null, submode, category, search, searchType);
}

BackgroundFetchTool.prototype.view = function() {
	var str = 'mode=ajax&submode='+this.submode+'&page='+this.page+'&divId='+this.divId;
	if (this.category != null)
		str = str + '&category=' + this.category;
	if (this.search != null)
		str = str + '&search=' + this.search + '&type=' + this.searchType;
	//alert(str);
	this.post(this.url, str, ImageFetchTool.prototype.completeRead);
}

utils.copyPrototype(BackgroundFetchTool, ImageFetchTool);

function viewBackgroundPage(container, pageNumber, divId, imageId, submode, category, search, searchType) {
	//alert(container);
	imageFetcher = new BackgroundFetchTool(container, pageNumber, divId, submode, category, search, searchType);
	imageFetcher.view();
}

function BackgroundBrushEditor(canvas, canvasPeer) {
	this.canvas = canvas;
	this.container = canvasPeer;
}

BackgroundBrushEditor.prototype.getRoot = function() {
	return this.canvas;
}

BackgroundBrushEditor.prototype.display = function() {
	//var text = prompt("Enter the text for the box", "Type your text here");
	//this.stroke.setState(text);
	//this.complete();
	var divId = 'graphical_unit';
	this.imageDiv = document.createElement('div');
	this.imageDiv.id = divId;
	this.imageDiv.style.left = 0+'px';
	this.imageDiv.style.top = 0+'px';
	this.imageDiv.style.width = this.container.style.width;
	this.imageDiv.style.height = this.container.style.height;
	
	//this.imageDiv.style.border = '1px solid #000000';
	this.imageDiv.style.background = '#e0e0e0';
	this.imageDiv.style.padding = '5px';
	this.imageDiv.style.margin = '0px';

	this.imageDiv.onmousedown = BackgroundBrushEditor.prototype.onClickHandler;
	this.imageDiv.onmouseover = BackgroundBrushEditor.prototype.onMouseOverHandler;
	this.imageDiv.onmouseup = utils.cancelBubble;

	this.imageDiv.style.zIndex=6;

	if (this.getRoot().currentEditor != null) {
		this.getRoot().currentEditor.destructor();
	}

	this.getRoot().currentEditor = this;

	this.container.appendChild(this.imageDiv);

	this.createTextBox(this.imageDiv, 0, 0, this.container.style.width.split('p')[0], this.container.style.height.split('p')[0]);

	//this.createButtons(this.imageDiv, 0, 0, this.container.style.width.split('p')[0], this.container.style.height.split('p')[0]);
	
	this.isDisplayed = true;
}

BackgroundBrushEditor.prototype.createTextBox = function(container, left, top, width, height) {
	var padding = 5;
	var divId = 'text_editor_'+Math.ceil(Math.random()*10000);
	
	// Using an input element of type text didn't work because it does not wrap.

	//this.editorTextBox = document.createElement("input");
	//this.editorTextBox.type = 'text';
	//this.editorTextBox.value = "Type your text here";

	// ... so we use a textarea instead.
	this.editorTextBox = document.createElement("div");
	this.editorTextBox.id = divId;
	this.editorTextBox.style.left = '0px';
	this.editorTextBox.style.top = '0px';
	//alert ('top = '+this.editorTextBox.style.top);
	this.editorTextBox.style.font=12+"pt arial";
	this.editorTextBox.style.color=this.color;
	this.editorTextBox.style.background='white';
	this.editorTextBox.style.overflow='auto';
	this.editorTextBox.style.padding = '0px';
	this.editorTextBox.style.margin = '0px';
	//alert("Width = "+width);
	this.editorTextBox.style.width = (width - 2 * padding - 2)+'px';
	this.editorTextBox.style.height = (height - 2 * padding - 2)+'px';
	this.editorTextBox.innerHTML = '<br/><center>Loading ...</center><br/><center><a href="javascript:document.getElementById(\''+divId+'\').texteditor.destructor();">Close [x]</a></center>';
	
	var editor = 'text_area_editor';

	this.editorTextBox.texteditor = this;	
	viewBackgroundPage(this.editorTextBox, 0, divId, null, 'background', this.canvas.getType());

	container.appendChild(this.editorTextBox);
}

BackgroundBrushEditor.prototype.onSaveHandler = function(number, type) {
	//this.stroke.setState(number+','+type);
	this.destructor();
	this.canvas.displayBackground(number, type);
	//this.complete();
}

utils.copyPrototype(BackgroundBrushEditor, ImageBrushEditor);

function CartoonBrushEditor(canvas, canvasPeer, displayArea) {
	this.canvas = canvas;
	this.container = canvasPeer;
	this.displayArea = displayArea;
}

CartoonBrushEditor.prototype.getRoot = function() {
	return this.canvas;
}

CartoonBrushEditor.prototype.display = function() {
	//var text = prompt("Enter the text for the box", "Type your text here");
	//this.stroke.setState(text);
	//this.complete();
	var divId = 'graphical_unit';
	this.imageDiv = document.createElement('div');
	this.imageDiv.id = divId;
	this.imageDiv.style.left = 0+'px';
	this.imageDiv.style.top = 0+'px';
	this.imageDiv.style.width = this.container.style.width;
	this.imageDiv.style.height = this.container.style.height;
	
	//this.imageDiv.style.border = '1px solid #000000';
	this.imageDiv.style.background = '#e0e0e0';
	this.imageDiv.style.padding = '5px';
	this.imageDiv.style.margin = '0px';

	this.imageDiv.onmousedown = BackgroundBrushEditor.prototype.onClickHandler;
	this.imageDiv.onmouseover = BackgroundBrushEditor.prototype.onMouseOverHandler;
	this.imageDiv.onmouseup = utils.cancelBubble;

	this.imageDiv.style.zIndex=6;

/*
	if (this.getRoot().currentEditor != null) {
		this.getRoot().currentEditor.destructor();
	}

	this.getRoot().currentEditor = this;
*/

	this.displayArea.appendChild(this.imageDiv);

	this.createTextBox(this.imageDiv, 0, 0, this.container.style.width.split('p')[0], this.container.style.height.split('p')[0]);

	//this.createButtons(this.imageDiv, 0, 0, this.container.style.width.split('p')[0], this.container.style.height.split('p')[0]);
	
	this.isDisplayed = true;
}

CartoonBrushEditor.prototype.createTextBox = function(container, left, top, width, height) {
	var padding = 5;
	var divId = 'text_editor_'+Math.ceil(Math.random()*10000);
	
	// Using an input element of type text didn't work because it does not wrap.

	//this.editorTextBox = document.createElement("input");
	//this.editorTextBox.type = 'text';
	//this.editorTextBox.value = "Type your text here";

	// ... so we use a textarea instead.
	this.editorTextBox = document.createElement("div");
	this.editorTextBox.id = divId;
	this.editorTextBox.style.left = '0px';
	this.editorTextBox.style.top = '0px';
	//alert ('top = '+this.editorTextBox.style.top);
	this.editorTextBox.style.font=12+"pt arial";
	this.editorTextBox.style.color=this.color;
	//this.editorTextBox.style.background='white';
	this.editorTextBox.style.overflow='auto';
	this.editorTextBox.style.padding = '0px';
	this.editorTextBox.style.margin = '0px';
	//alert("Width = "+width);
	this.editorTextBox.style.width = (width - 2 * padding - 2)+'px';
	this.editorTextBox.style.height = (height - 2 * padding - 2)+'px';
	this.editorTextBox.innerHTML = '<br/><center>Loading ...</center><br/><center><a href="javascript:document.getElementById(\''+divId+'\').texteditor.destructor();">Close [x]</a></center>';
	
	var editor = 'text_area_editor';

	this.editorTextBox.texteditor = this;	
	//viewBackgroundPage(this.editorTextBox, 0, divId, null, 'background', this.canvas.getType());
	viewImagePage(this.editorTextBox, 0, divId, null, 'foreground', this.canvas.getType());

	container.appendChild(this.editorTextBox);
}

CartoonBrushEditor.prototype.onSaveHandler = function(number, type, width, height) {
	var availableWidth = this.imageDiv.style.width.split('p')[0];
	var availableHeight = this.imageDiv.style.height.split('p')[0];
	if (this.canvas.getType() == 'cartoon') {
		preferredWidth = 150;
		preferredHeight = 250;
	} else {
		preferredWidth = availableWidth;
		preferredHeight = availableHeight;
	}
	if (width != null) {
		if (width > preferredWidth) {
			height = height * preferredWidth / width;
			width = preferredWidth;
		}
		if (height > preferredHeight) {
			width = width * preferredHeight / height;
			height = preferredHeight;
		}
		//this.stroke.getPoints()[0].setX(availableWidth/2 - width/2);
		//this.stroke.getPoints()[1].setX(availableWidth/2 + width/2);
	}
	if (width != null && height != null) {
		//this.stroke.getPoints()[0].setY(availableHeight/2 - height/2);
		//this.stroke.getPoints()[1].setY(availableHeight/2 + height/2);
		var brush = new ImageBrush(this.canvas.getId(), 'foreground');
		brush.setCanvas(this.canvas);
		this.canvas.builder.setBrush(brush);
		this.canvas.builder.beginStroke(availableWidth/2 - width/2, availableHeight/2 - height/2);
		this.canvas.builder.endStroke(availableWidth/2 + width/2, availableHeight/2 + height/2,number+','+type);
		this.canvas.builder.setBrush(new RoundBrush());
	}
	//this.stroke.setState();
	//this.destructor();
	//this.complete();
}

CartoonBrushEditor.prototype.destructor = function() {
	this.displayArea.removeChild(this.imageDiv);
	if (this.getRoot().currentEditor != null && this.getBrush() != null) {
		this.getBrush().getCanvas().builder.setBrush(new RoundBrush());
	}
	this.getRoot().currentEditor = null;
}

utils.copyPrototype(CartoonBrushEditor, BackgroundBrushEditor);

function TextBalloonRD() {
	this.TextBrush();
}

TextBalloonRD.prototype.getClassName = function() {
	return "TextBalloonRD";
}

TextBalloonRD.prototype.renderSelf = function(canvasPeer, pointsHistory, points, flagComplete, firstTime, stroke) {

	this.super_renderSelf(canvasPeer, pointsHistory, points, flagComplete, firstTime, stroke);

	var rectangle = utils.getDimensions(points[0], points[points.length-1]);

	if (flagComplete == true && rectangle.getWidth() > 60) {
			this.preloadedImage = this.getAlternateImageAtPoint(canvasPeer,new Point(rectangle.getX() + rectangle.getWidth() - 60, rectangle.getY() + rectangle.getHeight() + 6));
			this.preloadedImage.display();
			pointsHistory.push(this.preloadedImage);
	}
}

TextBalloonRD.prototype.getAlternateImageAtPoint = function(container, point1) {
	var x1 = point1.getX();
	var y1 = point1.getY();
	imageUrl = this.getAlternateImageUrl();
	var preloadedImage = new PreloadedImage(container, imageUrl);
	var rectangle = utils.getDimensions(new Point(x1,y1), new Point(x1+40,y1+50));
	preloadedImage.setBounds(rectangle);
	return preloadedImage;
}

TextBalloonRD.prototype.getAlternateImageDirectory = function() {
	return "images/brushes/images/";
}

TextBalloonRD.prototype.getAlternateImageUrl = function(point1, point2) {
	return this.getAlternateImageDirectory()+"arrow_right_down.png";
}

utils.copyPrototype(TextBalloonRD, TextBrush);

function TextBalloonLD() {
	this.TextBalloonRD();
}

TextBalloonLD.prototype.getClassName = function() {
	return "TextBalloonLD";
}

TextBalloonLD.prototype.getAlternateImageUrl = function(point1, point2) {
	return this.getAlternateImageDirectory()+"arrow_left_down.png";
}

utils.copyPrototype(TextBalloonLD, TextBalloonRD);

function TextBalloonRU() {
	this.TextBalloonRD();
}

TextBalloonRU.prototype.getClassName = function() {
	return "TextBalloonRU";
}

TextBalloonRU.prototype.renderSelf = function(canvasPeer, pointsHistory, points, flagComplete, firstTime, stroke) {

	this.super_super_renderSelf(canvasPeer, pointsHistory, points, flagComplete, firstTime, stroke);

	var rectangle = utils.getDimensions(points[0], points[points.length-1]);

	if (flagComplete == true && rectangle.getWidth() > 60) {
			this.preloadedImage = this.getAlternateImageAtPoint(canvasPeer,new Point(rectangle.getX() + rectangle.getWidth() - 60, rectangle.getY() - 50 + 6));
			this.preloadedImage.display();
			pointsHistory.push(this.preloadedImage);
	}
}

TextBalloonRU.prototype.getAlternateImageUrl = function(point1, point2) {
	return this.getAlternateImageDirectory()+"arrow_right_up.png";
}

utils.copyPrototype(TextBalloonRU, TextBalloonRD);

function TextBalloonLU() {
	this.TextBalloonRU();
}

TextBalloonLU.prototype.getClassName = function() {
	return "TextBalloonLU";
}

TextBalloonLU.prototype.getAlternateImageUrl = function(point1, point2) {
	return this.getAlternateImageDirectory()+"arrow_left_up.png";
}

utils.copyPrototype(TextBalloonLU, TextBalloonRU);

function Stroke(brush) {
	this.id = "Stroke_"+(new Date().getTime());
	this.index = -1;
	this.points = new Array();
	this.extrapolatedPoints = new Array();
	this.brush = brush;
	this.isTrackingTime = false;
	this.lastTime = null;
	this.state = null;
}

Stroke.prototype.getId = function() {
	return this.id;
}

Stroke.prototype.getIndex = function() {
	return this.index;
}

Stroke.prototype.setIndex = function(i) {
	this.index = i ;
}

Stroke.prototype.getBrush = function() {
	return this.brush;
}

Stroke.prototype.getTime = function() {
	if (this.lastTime == null)
		this.lastTime = 0;
	return 10-this.lastTime;
}

Stroke.prototype.addPoint = function(x,y,t) {
	var newPoint = new Point(x,y);
	
	if (this.isTrackingTime) {
		if (t == null)
			newPoint.setTime(this.getTime());
		else
			newPoint.setTime(t);
	}
	
	if (this.isOnlyEndPointsUseful()) {
		if (this.points.length == 0)
			this.points[this.points.length] = newPoint;
		else
			this.points[1] = newPoint;
	} else {
		if (this.points.length > 0) {
			var temp = null;
			if (this.points.length == 1)
				temp = this.brush.getIntermediatePoints(this.points[this.points.length-1], newPoint, this.points[this.points.length-1], newPoint);
			else
				temp = this.brush.getIntermediatePoints(this.points[this.points.length-1], newPoint, this.points[this.points.length-2], newPoint);
			var j;
			for (j = 0 ; j < temp.length ; ++j) {
				this.extrapolatedPoints.push(temp[j]);
			}
		}

		this.points[this.points.length] = newPoint;
		this.extrapolatedPoints.push(newPoint);
	}
}

Stroke.prototype.complete = function() {
	if (this.brush.isRenderedDifferentlyUponCompletion()) {
		this.extrapolatedPoints = new Array();
		
		if (this.points.length >= 1) {
			this.extrapolatedPoints.push(this.points[0]);
		}
		
		var i;
		for (i = 1 ; i < this.points.length ; ++i) {
			var temp = null;
			if (i == 1 && this.points.length == 2) {
				temp = this.brush.getIntermediatePoints(this.points[i-1], this.points[i], this.points[i-1], this.points[i]);
			} else if (i == 1 && this.points.length > 2) {
				temp = this.brush.getIntermediatePoints(this.points[i-1], this.points[i], this.points[i-1], this.points[i+1]);
			} else if (i < this.points.length-1) {
				temp = this.brush.getIntermediatePoints(this.points[i-1], this.points[i], this.points[i-2], this.points[i+1]);
			} else {
				temp = this.brush.getIntermediatePoints(this.points[i-1], this.points[i], this.points[i-2], this.points[i]);
			}
			var j;
			for (j = 0 ; j < temp.length ; ++j) {
				this.extrapolatedPoints.push(temp[j]);
			}
			this.extrapolatedPoints.push(this.points[i]);
		}
	
	}
}

Stroke.prototype.isOnlyEndPointsUseful = function() {
	return this.brush.isOnlyEndPointsUseful();
}

Stroke.prototype.renderSelf = function(canvasPeer, pointsHistory, complete, firstTime) {
	if (this.brush.isEditable() && complete == true && this.state == null) {
		this.brush.openEditor(canvasPeer, pointsHistory, this.points, complete, firstTime, this);
	} else 
		this.brush.renderSelf(canvasPeer, pointsHistory, this.points, complete, firstTime, this);
}

Stroke.prototype.setState = function(state) {
	this.state = state;
}

Stroke.prototype.getState = function() {
	return this.state;
}

Stroke.prototype.getPoints = function() {
	return this.points;
}

Stroke.prototype.getExtrapolatedPoints = function() {
	return this.extrapolatedPoints;
}

Stroke.prototype.setTrackingTime = function(flag) {
	this.isTrackingTime = flag;
}

function Ink() {
	this.strokes = new Array();
	this.discardedStrokes = new Array();
}

Ink.prototype.deleteStroke = function(stroke) {
	for (i = 0 ; i < this.strokes.length ; ++i) {
		if (this.strokes[i] == stroke) {
			this.strokes.splice(i, 1);
		}
	}
	//this.strokes.splice(stroke.getIndex(), 1);
}

Ink.prototype.addStroke = function(stroke) {
	stroke.setIndex(this.strokes.length);
	this.strokes[this.strokes.length] = stroke;
	this.discardedStrokes = new Array();
}

Ink.prototype.undoLastStroke = function() {
	if (this.strokes.length > 0) {
		this.discardedStrokes.push(this.getLastStroke());
		this.strokes.pop();
	}
}

Ink.prototype.getLastStroke = function() {
	if (this.strokes.length == 0)
		return null;
	else
		return this.strokes[this.strokes.length-1];
}

Ink.prototype.getLastDiscardedStroke = function() {
	if (this.discardedStrokes.length == 0)
		return null;
	else
		return this.discardedStrokes[this.discardedStrokes.length-1];
}

Ink.prototype.redoLastStroke = function() {
	if (this.discardedStrokes.length > 0) {
		this.strokes.push(this.getLastDiscardedStroke());
		this.discardedStrokes.pop();
		return this.getLastStroke();
	}
	return null;
}

Ink.prototype.getStrokes = function() {
	return this.strokes;
}

Ink.prototype.clearStrokes = function() {
	this.strokes = new Array();
	this.discardedStrokes = new Array();
}

Ink.prototype.getSerialized = function(baseUrl, serializer, canvaspeer) {
	return serializer.getSerialized(baseUrl, this.strokes, canvaspeer);
}

function Renderer(parentDiv) {
	this.map = new Object();
	this.canvaspeer = parentDiv;
	this.backgroundImage = null;
}

Renderer.prototype.getCanvasPeer = function(stroke) {
	return this.canvaspeer;
}

Renderer.prototype.renderBackground = function(url, width, height) {
	var image = new PreloadedImage(this.canvaspeer, url);
	image.setZIndex(0);
	var rectangle = new Rectangle(0, 0, width, height);
	image.setBounds(rectangle);
	image.display();
	this.backgroundImage = image;
	//alert("Image "+url+" displayed!");
}

Renderer.prototype.clearBackground = function() {
	if (this.backgroundImage != null) {
		this.backgroundImage.destructor();
		this.backgroundImage = null;
	}
}

Renderer.prototype.setStatus = function(message) {
	if (this.statusCanvas == null) {
		this.statusCanvas = document.createElement('div');
		this.statusCanvas.style.top = '0px';
		this.statusCanvas.style.left = '0px';
		this.statusCanvas.style.valign = 'middle';
		this.statusCanvas.style.align = 'center';
		this.statusCanvas.style.width = this.parentDiv.style.width;
		this.statusCanvas.style.height = this.parentDiv.style.height;
		this.statusCanvas.style.position = 'absolute';
		this.statusCanvas.style.display = 'block';
		this.statusCanvas.style.zIndex = 10;
		this.statusCanvas.innerHTML = '<table width=60% height=100%><tr align=center valign=middle><td><div width=40% height=40% style="background: white; border: 5px solid black; padding:20px"><font face="comic sans ms" size=8><font color=gray><b>'+message+'</b></font></font></div></td></tr></table>';
		this.canvaspeer.appendChild(this.statusCanvas);
	}
}

Renderer.prototype.clearStatus = function() {
	if (this.statusCanvas != null)
		this.canvaspeer.removeChild(this.statusCanvas);
	this.statusCanvas = null;
}

Renderer.prototype.render = function(stroke, complete, firstTime) {
	if (stroke.isOnlyEndPointsUseful()) {
		if (this.map[stroke.getId()] == null) {
			this.map[stroke.getId()] = new Array();
		}
		if (this.map[stroke.getId()].length > 0) {
			this.undoStroke(stroke);
		}
		stroke.renderSelf(this.getCanvasPeer(stroke), this.map[stroke.getId()], complete, firstTime);
	} else {
		var points = stroke.getExtrapolatedPoints();
		if (this.map[stroke.getId()] == null) {
			this.map[stroke.getId()] = new Array();
		}
		for (i = this.map[stroke.getId()].length; i < points.length ; ++i) {
			var imageUrl = null;
			if (i > stroke.getBrush().getDistanceBetweenJoinedPoints()) {
				this.preloadedImage = stroke.getBrush().getImage(this.getCanvasPeer(stroke), points, i);
				this.preloadedImage.display();
				this.map[stroke.getId()].push(this.preloadedImage);
			}
		}
	}
}

Renderer.prototype.deleteStroke = function(stroke) {
	this.undoStroke(stroke);
}

Renderer.prototype.undoStroke = function(stroke) {
	if (this.map[stroke.getId()] == null) {
		this.map[stroke.getId()] = new Array();
	} else {
		var imagesToDelete = this.map[stroke.getId()];
		this.map[stroke.getId()] = new Array();
		for (i = 0 ; i < imagesToDelete.length ; ++i) {
			imagesToDelete[i].destructor();
		}
	}
	//alert(stroke.getId());
}

function FastRenderer(parentDiv) {
	this.Renderer(parentDiv);
	this.parentDiv = parentDiv;
}

FastRenderer.prototype.createChildPeer = function() {
	var divCanvas = document.createElement('div');
	divCanvas.style.top = '0px';
	divCanvas.style.left = '0px';
	divCanvas.style.width = this.parentDiv.style.width;
	divCanvas.style.height = this.parentDiv.style.height;
	divCanvas.style.position = 'absolute';
	divCanvas.style.display = 'block';
	//divCanvas.style.background = '#ff0000';
	return divCanvas;
}

FastRenderer.prototype.getCanvasPeer = function(stroke) {
	if (stroke.canvaspeer != null)
		return stroke.canvaspeer;

	var childPeer = this.createChildPeer();
	stroke.canvaspeer = childPeer;
	this.canvaspeer.appendChild(childPeer);

	return childPeer;
}

FastRenderer.prototype.undoStroke = function(stroke) {
	this.super_undoStroke(stroke);
	if (stroke.canvaspeer != null) {
		this.canvaspeer.removeChild(stroke.canvaspeer);
		stroke.canvaspeer = null;
	}
}

utils.copyPrototype(FastRenderer, Renderer);

function Builder(canvaspeer, brush) {
	this.state = "IGNORE_MOUSE_EVENTS";
	this.stroke = null;
	this.brush = brush;
	this.ink = new Ink();
	this.canvaspeer = canvaspeer;
	this.renderer = new FastRenderer(canvaspeer);
	this.isTrackingTime = false;
}

Builder.prototype.displayBackground = function(url, width, height) {
	this.renderer.clearBackground();
	this.renderer.renderBackground(url, width, height);
}

Builder.prototype.beginStroke = function(x,y) {
	// delegates to another member function
	this.continueStroke(x,y);
}

Builder.prototype.continueStroke = function(x,y) {
	if (this.stroke == null) {
		this.stroke = new Stroke(this.brush);
		this.stroke.setTrackingTime(this.isTrackingTime);
	}
	this.stroke.addPoint(x,y);
	this.renderer.render(this.stroke);
}

Builder.prototype.endStroke = function(x,y,state) {
	var complete = true;
	var firstTime = true;
	this.continueStroke(x,y);
	this.stroke.complete(); // Let the stroke know that it's been completed
	this.renderer.deleteStroke(this.stroke); // clear cache in renderer
	this.ink.addStroke(this.stroke);
	if (state != null) {
		this.stroke.setState(state);
		this.renderer.render(this.stroke, complete, firstTime);
	} else {
		this.renderer.render(this.stroke, complete, firstTime);
	}
	this.stroke = null;
}

Builder.prototype.deleteStroke = function(stroke) {
	this.renderer.deleteStroke(stroke);
	this.ink.deleteStroke(stroke);
	return true;
}

Builder.prototype.clearStrokes = function() {
	while (this.ink.getLastStroke() != null) {
		this.renderer.undoStroke(this.ink.getLastStroke());
		this.renderer.clearBackground();
		this.ink.undoLastStroke();
	}
	this.ink.clearStrokes();
}

Builder.prototype.undoLastStroke = function() {
	if (this.ink.getLastStroke() != null) {
		this.renderer.undoStroke(this.ink.getLastStroke());
		this.ink.undoLastStroke();
		return true;
	} else {
		return false;
	}
}

Builder.prototype.redoLastStroke = function() {
	var complete = true;
	var firstTime = false;
	var stroke = this.ink.redoLastStroke();
	if (stroke != null) {
		this.renderer.render(stroke, complete, firstTime);
	}
}

Builder.prototype.setTrackingTime = function(flag) {
	this.isTrackingTime = flag;
}

Builder.prototype.getInk = function() {
	return this.ink;
}

Builder.prototype.getInkSerialized = function(serializer) {
	return this.ink.getSerialized("", serializer, this.canvaspeer);
}

Builder.prototype.getInkSerializedToWeb = function(serializer) {
	return this.ink.getSerialized(utils.getBaseUrl(), serializer, this.canvaspeer);
}

Builder.prototype.deserialize = function(deserializer) {
	deserializer.deserializeOnto(this.canvaspeer.canvas);
}

// A brush is an object with the following methods
// 1.  getImage(x1, y1, x2, y2);
Builder.prototype.setBrush = function(brush) {
	this.brush = brush;
}

Builder.prototype.getBrush = function() {
	return this.brush;
}

// LOGGING

function Logger() {
}

Logger.prototype.debug = function(str) {
	window.status = str;
}

// COMMANDS

function Command() {
	this.preferredWidth = 28;
	this.preferredHeight = 28;
}

Command.prototype.addToControlPanel = function(controlPanel) {
	controlPanel.addCommand(this);
}

Command.prototype.getPreferredSize = function() {
	return new Point(this.preferredWidth, this.preferredHeight);
}

Command.prototype.getImageUrl = function() {
	return null;
}

Command.prototype.getMouseDownImageUrl = function() {
	return this.getImageUrl();
}

Command.prototype.getMouseOverImageUrl = function() {
	return this.getImageUrl();
}

Command.prototype.getImage = function() {
	return new PreloadedImage(this.div, utils.getCommandBaseUrl()+this.getImageUrl());
}

Command.prototype.getMouseDownImage = function() {
	return new PreloadedImage(this.div, utils.getCommandBaseUrl()+this.getMouseDownImageUrl());
}

Command.prototype.getMouseOverImage = function() {
	return new PreloadedImage(this.div, utils.getCommandBaseUrl()+this.getMouseOverImageUrl());
}

Command.prototype.displayOnContainer = function(container, x, y) {
	var divId = 'command'
	this.div = document.createElement('div');
	this.div.id = divId;
	this.div.style.left = x+'px';
	this.div.style.top = y+'px';
	if (!utils.isIE() && container.parentNode.style.position != 'absolute') {
		this.div.style.left = (x+findPosX(container))+'px';
		this.div.style.top = (y+findPosY(container))+'px';
	}
	this.div.style.width = this.preferredWidth+'px';
	this.div.style.height = this.preferredHeight+'px';

	// Tooltip
	this.toolietip = new Toolietip(container);
	this.toolietip.setPosition(x+this.preferredWidth+5, y+(this.preferredHeight/2));
	this.toolietip.setText(this.getAlternateText());
	this.toolietip.setRelatedCommands(this.getRelatedCommands());

	this.image = this.getImage();
	this.image.setClickable(true);
	this.image.setAlternateText(this.getAlternateText());
	this.image.setBounds(new Rectangle(0,0,this.preferredWidth,this.preferredHeight));
	this.image.display();
	this.div.onmousedown = Command.prototype.mouseDownHandler;
	this.div.ink_command = this;
	this.div.onmousemove = utils.cancelBubble;
	this.div.onmouseup = Command.prototype.mouseUpHandler;
	this.div.onmouseover = Command.prototype.mouseOverHandler;
	this.div.onmouseout = Command.prototype.mouseOutHandler;

	this.state = 'up';
	
	this.standardImage = this.createImage(this.getImage());
	this.mouseOverImage = this.createImage(this.getMouseOverImage());
	this.mouseDownImage = this.createImage(this.getMouseDownImage());
	
	var prelIma = new Array();
	prelIma.push(this.standardImage);
	prelIma.push(this.mouseOverImage);
	prelIma.push(this.mouseDownImage);
	utils.preloadKeyImages(prelIma);
	
	container.appendChild(this.div);
}

Command.prototype.displayOnContainerStatic = function(container, x, y) {
	var divId = 'command_static'
	this.div = document.createElement('div');
	//this.div.style.background = 'blue';
	this.div.innerHTML = '<br/><a href="javascript:utils.doNothing()"><img width="'+this.preferredWidth+'" height="'+this.preferredHeight+'" src="'+utils.getCommandBaseUrl()+this.getImageUrl()+'"/> '+this.getAlternateText()+'</a>';

	this.div.onmousedown = Command.prototype.mouseDownHandler;
	this.div.ink_command = this;
	this.div.onmousemove = utils.cancelBubble;

	this.state = 'up';
	
	//this.standardImage = this.createImage(this.getImage());
	//this.mouseOverImage = this.createImage(this.getMouseOverImage());
	//this.mouseDownImage = this.createImage(this.getMouseDownImage());
	
	container.appendChild(this.div);
}

Command.prototype.createImage = function(image) {
	image.setClickable(true);
	image.setAlternateText(this.getAlternateText());
	image.setBounds(new Rectangle(0,0,this.preferredWidth,this.preferredHeight));
	return image;
}

Command.prototype.displayImage = function(image) {
	this.image = image;
	this.image.display();
}

Command.prototype.mouseDownHandler = function(e) {
	Toolietip.prototype.hideDelayed();
	if (this.ink_command.mouseDownImage != null)
		this.ink_command.displayImage(this.ink_command.mouseDownImage);
	utils.cancelBubble(e);
	this.ink_command.run();
	this.ink_command.state = 'down';
}

Command.prototype.mouseUpHandler = function(e) {
	//this.ink_command.displayImage(this.ink_command.mouseOverImage);
	utils.cancelBubble(e);
	this.ink_command.state = 'up';
}

Command.prototype.mouseOverHandler = function(e) {
	this.ink_command.toolietip.show();
	if (this.ink_command.state == 'up') {
		this.ink_command.displayImage(this.ink_command.mouseOverImage);
	}
	utils.cancelBubble(e);
	this.ink_command.state = 'over';
}

Command.prototype.mouseOutHandler = function(e) {
	//this.ink_command.toolietip.hide();
	//this.ink_command.toolietip.hideDelayed();
	this.ink_command.displayImage(this.ink_command.standardImage);
	utils.cancelBubble(e);
	this.ink_command.state = 'up';
}

Command.prototype.getAlternateText = function() {
	return "Executes a Command";
}

Command.prototype.getRelatedCommands = function() {
	return new Array();
}

Command.prototype.getName = function() {
	return "a command";
}

function DrawingCommand() {
	this.Command();
}

DrawingCommand.prototype.getCategory = function() {
	return "drawing";
}

utils.copyPrototype(DrawingCommand, Command);

function BrushCommand() {
	this.Command();
}

BrushCommand.prototype.getCategory = function() {
	return "brush";
}

utils.copyPrototype(BrushCommand, Command);

function SaveCommand(canvas) {
	this.DrawingCommand();
	this.canvas = canvas;
}

SaveCommand.prototype.getInkSerialized = function() {
	return this.canvas.builder.getInkSerialized(new DynamicHtmlSerializer());
}

SaveCommand.prototype.getName = function() {
	return "save";
}

SaveCommand.prototype.getAlternateText = function() {
	return "Save";
}

SaveCommand.prototype.getImageUrl = function() {
	return "images/tools/savebuttonnew1.gif";
}

SaveCommand.prototype.getMouseDownImageUrl = function() {
	return "images/tools/savebuttonnew2.gif";
}

SaveCommand.prototype.getMouseOverImageUrl = function() {
	return "images/tools/savebuttonnew3.gif";
}

SaveCommand.prototype.run = function() {
	var array = this.getInkSerialized(); // returns an array of strings
	var view = window.open();
	//alert("Writing image of "+array.length+" segments.");
	//utils.writeHeader(view.document);
	if (view != null) {
		for (i = 0 ; i < array.length ; ++i) {
			view.document.writeln(array[i]);
		}
	}
	//utils.writeFooter(view.document);
	//alert("Image written.");
}

utils.copyPrototype(SaveCommand, DrawingCommand);

function SaveToWebCommand(canvas) {
	this.SaveCommand();
	this.canvas = canvas;
}

SaveToWebCommand.prototype.getInkSerialized = function() {
	return this.canvas.builder.getInkSerializedToWeb(new DynamicHtmlSerializer());
}

SaveToWebCommand.prototype.getName = function() {
	return "save_to_web";
}

SaveToWebCommand.prototype.getAlternateText = function() {
	return "Save to Web";
}

SaveToWebCommand.prototype.getImageUrl = function() {
	return "images/tools/save_web.gif";
}

SaveToWebCommand.prototype.getMouseDownImageUrl = function() {
	return "images/tools/save_web.gif";
}

SaveToWebCommand.prototype.getMouseOverImageUrl = function() {
	return "images/tools/save_web.gif";
}

utils.copyPrototype(SaveToWebCommand, SaveCommand);

function SaveOnServerCommand(canvas) {
	this.DrawingCommand();
	this.canvas = canvas;
	this.preferredWidth = 36;
	this.preferredHeight = 37;
}

SaveOnServerCommand.prototype.getInkSerialized = function() {
	return this.canvas.builder.getInkSerialized(new IntegerSerializer());
}

SaveOnServerCommand.prototype.getName = function() {
	return "save on server";
}

SaveOnServerCommand.prototype.getAlternateText = function() {
	return "Save";
}

SaveOnServerCommand.prototype.getImageUrl = function() {
	return "images/tools/savebuttonnew1.gif";
}

SaveOnServerCommand.prototype.getMouseDownImageUrl = function() {
	return "images/tools/savebuttonnew2.gif";
}

SaveOnServerCommand.prototype.getMouseOverImageUrl = function() {
	return "images/tools/savebuttonnew3.gif";
}

SaveOnServerCommand.prototype.run = function() {
	this.canvas.builder.renderer.setStatus('Saving ...');
	var array = this.getInkSerialized(); // returns an array of strings
	var string = array[0];
	this.canvas.persistenceTool.save(string);
}

utils.copyPrototype(SaveOnServerCommand, DrawingCommand);

function ExportCommand(canvas) {
	this.SaveCommand();
	this.canvas = canvas;
}

ExportCommand.prototype.getInkSerialized = function() {
	return this.canvas.builder.getInkSerialized(new IntegerSerializer());
}

ExportCommand.prototype.getName = function() {
	return "export";
}

ExportCommand.prototype.getAlternateText = function() {
	return "Export";
}

ExportCommand.prototype.getImageUrl = function() {
	return "images/tools/export.gif";
}

ExportCommand.prototype.getMouseDownImageUrl = function() {
	return "images/tools/export.gif";
}

ExportCommand.prototype.getMouseOverImageUrl = function() {
	return "images/tools/export.gif";
}

utils.copyPrototype(ExportCommand, SaveCommand);

function ExportToWebCommand(canvas) {
	this.SaveCommand();
	this.canvas = canvas;
}

ExportToWebCommand.prototype.getInkSerialized = function() {
	return this.canvas.builder.getInkSerializedToWeb(new IntegerSerializer());
}

ExportToWebCommand.prototype.getName = function() {
	return "export_to_web";
}

ExportToWebCommand.prototype.getAlternateText = function() {
	return "Export to Web";
}

ExportToWebCommand.prototype.getImageUrl = function() {
	return "images/tools/export_web.gif";
}

ExportToWebCommand.prototype.getMouseDownImageUrl = function() {
	return "images/tools/export_web.gif";
}

ExportToWebCommand.prototype.getMouseOverImageUrl = function() {
	return "images/tools/export_web.gif";
}

utils.copyPrototype(ExportToWebCommand, SaveCommand);

function CopyCommand(canvas) {
	this.DrawingCommand();
	this.canvas = canvas;
}

CopyCommand.prototype.getInkSerialized = function() {
	return this.canvas.builder.getInkSerialized(new IntegerSerializer());
}

CopyCommand.prototype.getName = function() {
	return "copy";
}

CopyCommand.prototype.getAlternateText = function() {
	return "Copy";
}

CopyCommand.prototype.getImageUrl = function() {
	return "images/tools/copy.gif";
}

CopyCommand.prototype.getMouseDownImageUrl = function() {
	return "images/tools/copy.gif";
}

CopyCommand.prototype.getMouseOverImageUrl = function() {
	return "images/tools/copy.gif";
}

CopyCommand.prototype.run = function() {
	utils.setClipboard(this.getInkSerialized()[0]); // returns an array of strings
	alert("Copied");
}

utils.copyPrototype(CopyCommand, DrawingCommand);

function PasteCommand(canvas) {
	this.DrawingCommand();
	this.canvas = canvas;
}

PasteCommand.prototype.deserialize = function() {
	if (utils.getClipboard() != null) {
		this.canvas.builder.deserialize(new DynamicHtmlDeserializer(utils.getClipboard()));
		alert("Pasted");
	} else {
		alert("The clipboard is empty");
	}
}

PasteCommand.prototype.getName = function() {
	return "paste";
}

PasteCommand.prototype.getAlternateText = function() {
	return "Paste";
}

PasteCommand.prototype.getImageUrl = function() {
	return "images/tools/paste.gif";
}

PasteCommand.prototype.getMouseDownImageUrl = function() {
	return "images/tools/paste.gif";
}

PasteCommand.prototype.getMouseOverImageUrl = function() {
	return "images/tools/paste.gif";
}

PasteCommand.prototype.run = function() {
	this.deserialize(utils.getClipboard()) ; // returns an array of strings
}

utils.copyPrototype(PasteCommand, DrawingCommand);

function DeleteCommand(canvas) {
	this.DrawingCommand();
	this.canvas = canvas;
	this.preferredWidth = 72;
	this.preferredHeight = 20;
}

DeleteCommand.prototype.getName = function() {
	return "delete";
}

DeleteCommand.prototype.getAlternateText = function() {
	return "Delete";
}

DeleteCommand.prototype.getImageUrl = function() {
	return "images/tools/deletebutton.gif";
}

DeleteCommand.prototype.getMouseDownImageUrl = function() {
	return "images/tools/delete1.gif";
}

DeleteCommand.prototype.getMouseOverImageUrl = function() {
	return "images/tools/delete1.gif";
}

DeleteCommand.prototype.run = function() {
	if ( this.canvas.persistenceTool.id != null ) {
		if ( confirm("Are you sure you want to delete image "+this.canvas.persistenceTool.id) ) {
			this.canvas.disposeSelf();
		}
	} else {
		alert("This image has not been saved and hence cannot be deleted.");
	}
}

utils.copyPrototype(DeleteCommand, DrawingCommand);

function UndoCommand(canvas) {
	this.DrawingCommand();
	this.canvas = canvas;
	this.preferredWidth = 36;
	this.preferredHeight = 37;
}

UndoCommand.prototype.getName = function() {
	return "undo";
}

UndoCommand.prototype.getAlternateText = function() {
	return "Undo";
}

UndoCommand.prototype.getImageUrl = function() {
	return "images/tools/undobuttonnew1.gif";
}

UndoCommand.prototype.getMouseDownImageUrl = function() {
	return "images/tools/undobuttonnew2.gif";
}

UndoCommand.prototype.getMouseOverImageUrl = function() {
	return "images/tools/undobuttonnew3.gif";
}

UndoCommand.prototype.run = function() {
	if (this.canvas.builder.undoLastStroke() == false) {
		this.canvas.builder.renderer.setStatus('Undoing ...');
		this.canvas.persistenceTool.undo();
//		if (!this.canvas.hasBackground())
//			alert('There is nothing in the editor to undo');
//		else {
//			alert('Cannot undo a background.  Refresh the editor or choose another background.');
//		}
	}
}

utils.copyPrototype(UndoCommand, DrawingCommand);

function RedoCommand(canvas) {
	this.DrawingCommand();
	this.canvas = canvas;
	this.preferredWidth = 36;
	this.preferredHeight = 37;
}

RedoCommand.prototype.getName = function() {
	return "redo";
}

RedoCommand.prototype.getAlternateText = function() {
	return "Redo";
}

RedoCommand.prototype.getImageUrl = function() {
	return "images/tools/redobuttonnew1.gif";
}

RedoCommand.prototype.getMouseDownImageUrl = function() {
	return "images/tools/redobuttonnew2.gif";
}

RedoCommand.prototype.getMouseOverImageUrl = function() {
	return "images/tools/redobuttonnew3.gif";
}

RedoCommand.prototype.run = function() {
	//alert(this.canvas.persistenceTool.undos);
	if (this.canvas.persistenceTool.undos > 0) {
		this.canvas.builder.renderer.setStatus('Redoing ...');
		this.canvas.persistenceTool.redo();
	} else {
		//alert('Attempting JS redo');
		this.canvas.builder.redoLastStroke();
	}
}

utils.copyPrototype(RedoCommand, DrawingCommand);

function RoundBrushCommand(canvas) {
	this.BrushCommand();
	this.canvas = canvas;
}

RoundBrushCommand.prototype.getName = function() {
	return "round brush";
}

RoundBrushCommand.prototype.getAlternateText = function() {
	return "Round Brush";
}

RoundBrushCommand.prototype.getRelatedCommands = function() {
	return new Array(new RoundBrushCommand(this.canvas),new GlobShooterBrushCommand(this.canvas),new LineBrushCommand(this.canvas),new RectangleBrushCommand(this.canvas),new StraightEdgeBrushCommand(this.canvas),new WhiteOutBrushCommand(this.canvas));
}

RoundBrushCommand.prototype.getImageUrl = function() {
	return "images/tools/brushbuttonnew1.gif";
}

RoundBrushCommand.prototype.getMouseDownImageUrl = function() {
	return "images/tools/brushbuttonnew2.gif";
}

RoundBrushCommand.prototype.getMouseOverImageUrl = function() {
	return "images/tools/brushbuttonnew3.gif";
}

RoundBrushCommand.prototype.run = function() {
	this.canvas.builder.setBrush(new RoundBrush());
}

utils.copyPrototype(RoundBrushCommand, BrushCommand);

function SmallRoundBrushCommand(canvas) {
	this.BrushCommand();
	this.canvas = canvas;
	this.preferredWidth = 22;
	this.preferredHeight = 24;
}

SmallRoundBrushCommand.prototype.getPreferredSize = function() {
	return new Point(this.preferredWidth, this.preferredHeight);
}

SmallRoundBrushCommand.prototype.getName = function() {
	return "small round brush";
}

SmallRoundBrushCommand.prototype.getAlternateText = function() {
	return "Small Round Brush";
}

SmallRoundBrushCommand.prototype.getImageUrl = function() {
	return "images/tools/black.jpg";
}

SmallRoundBrushCommand.prototype.getMouseDownImageUrl = function() {
	return "images/tools/black.jpg";
}

SmallRoundBrushCommand.prototype.getMouseOverImageUrl = function() {
	return "images/tools/black_mo.jpg";
}

SmallRoundBrushCommand.prototype.run = function() {
	this.canvas.builder.setBrush(new SmallRoundBrush());
}

utils.copyPrototype(SmallRoundBrushCommand, BrushCommand);

function BlueSmallRoundBrushCommand(canvas) {
	this.SmallRoundBrushCommand(canvas);
	this.preferredWidth = 20;
	this.preferredHeight = 24;
}

BlueSmallRoundBrushCommand.prototype.getName = function() {
	return "blue small round brush";
}

BlueSmallRoundBrushCommand.prototype.getImage = function() {
	return new PreloadedImage(this.div, "images/tools/blue.jpg");
}

BlueSmallRoundBrushCommand.prototype.getImageUrl = function() {
	return "images/tools/blue.jpg";
}

BlueSmallRoundBrushCommand.prototype.getMouseDownImageUrl = function() {
	return "images/tools/blue.jpg";
}

BlueSmallRoundBrushCommand.prototype.getMouseOverImageUrl = function() {
	return "images/tools/blue_mo.jpg";
}

BlueSmallRoundBrushCommand.prototype.run = function() {
	this.canvas.builder.setBrush(new BlueSmallRoundBrush());
}

utils.copyPrototype(BlueSmallRoundBrushCommand, SmallRoundBrushCommand);

function GreenSmallRoundBrushCommand(canvas) {
	this.SmallRoundBrushCommand(canvas);
	this.preferredWidth = 23;
	this.preferredHeight = 24;
}

GreenSmallRoundBrushCommand.prototype.getName = function() {
	return "green small round brush";
}

GreenSmallRoundBrushCommand.prototype.getImage = function() {
	return new PreloadedImage(this.div, "images/tools/green.jpg");
}

GreenSmallRoundBrushCommand.prototype.getImageUrl = function() {
	return "images/tools/green.jpg";
}

GreenSmallRoundBrushCommand.prototype.getMouseDownImageUrl = function() {
	return "images/tools/green.jpg";
}

GreenSmallRoundBrushCommand.prototype.getMouseOverImageUrl = function() {
	return "images/tools/green_mo.jpg";
}

GreenSmallRoundBrushCommand.prototype.run = function() {
	this.canvas.builder.setBrush(new GreenSmallRoundBrush());
}

utils.copyPrototype(GreenSmallRoundBrushCommand, SmallRoundBrushCommand);

function PinkSmallRoundBrushCommand(canvas) {
	this.SmallRoundBrushCommand(canvas);
	this.preferredWidth = 20;
	this.preferredHeight = 23;
}

PinkSmallRoundBrushCommand.prototype.getName = function() {
	return "pink small round brush";
}

PinkSmallRoundBrushCommand.prototype.getImageUrl = function() {
	return "images/tools/pink.jpg";
}

PinkSmallRoundBrushCommand.prototype.getMouseDownImageUrl = function() {
	return "images/tools/pink.jpg";
}

PinkSmallRoundBrushCommand.prototype.getMouseOverImageUrl = function() {
	return "images/tools/pink_mo.jpg";
}

PinkSmallRoundBrushCommand.prototype.run = function() {
	this.canvas.builder.setBrush(new PinkSmallRoundBrush());
}

utils.copyPrototype(PinkSmallRoundBrushCommand, SmallRoundBrushCommand);

function OrangeSmallRoundBrushCommand(canvas) {
	this.SmallRoundBrushCommand(canvas);
	this.preferredWidth = 23;
	this.preferredHeight = 23;
}

OrangeSmallRoundBrushCommand.prototype.getName = function() {
	return "orange small round brush";
}

OrangeSmallRoundBrushCommand.prototype.getImageUrl = function() {
	return "images/tools/orange.jpg";
}

OrangeSmallRoundBrushCommand.prototype.getMouseDownImageUrl = function() {
	return "images/tools/orange.jpg";
}

OrangeSmallRoundBrushCommand.prototype.getMouseOverImageUrl = function() {
	return "images/tools/orange_mo.jpg";
}

OrangeSmallRoundBrushCommand.prototype.run = function() {
	this.canvas.builder.setBrush(new OrangeSmallRoundBrush());
}

utils.copyPrototype(OrangeSmallRoundBrushCommand, SmallRoundBrushCommand);

function CyanSmallRoundBrushCommand(canvas) {
	this.SmallRoundBrushCommand(canvas);
	this.preferredWidth = 22;
	this.preferredHeight = 23;
}

CyanSmallRoundBrushCommand.prototype.getName = function() {
	return "cyan small round brush";
}

CyanSmallRoundBrushCommand.prototype.getImage = function() {
	return new PreloadedImage(this.div, "images/tools/cyan.jpg");
}

CyanSmallRoundBrushCommand.prototype.getImageUrl = function() {
	return "images/tools/cyan.jpg";
}

CyanSmallRoundBrushCommand.prototype.getMouseDownImageUrl = function() {
	return "images/tools/cyan.jpg";
}

CyanSmallRoundBrushCommand.prototype.getMouseOverImageUrl = function() {
	return "images/tools/cyan_mo.jpg";
}

CyanSmallRoundBrushCommand.prototype.run = function() {
	this.canvas.builder.setBrush(new CyanSmallRoundBrush());
}

utils.copyPrototype(CyanSmallRoundBrushCommand, SmallRoundBrushCommand);

function BrownSmallRoundBrushCommand(canvas) {
	this.SmallRoundBrushCommand(canvas);
	this.preferredWidth = 20;
	this.preferredHeight = 24;
}

BrownSmallRoundBrushCommand.prototype.getName = function() {
	return "brown small round brush";
}

BrownSmallRoundBrushCommand.prototype.getImage = function() {
	return new PreloadedImage(this.div, "images/tools/brown.jpg");
}

BrownSmallRoundBrushCommand.prototype.getImageUrl = function() {
	return "images/tools/brown.jpg";
}

BrownSmallRoundBrushCommand.prototype.getMouseDownImageUrl = function() {
	return "images/tools/brown.jpg";
}

BrownSmallRoundBrushCommand.prototype.getMouseOverImageUrl = function() {
	return "images/tools/brown_mo.jpg";
}

BrownSmallRoundBrushCommand.prototype.run = function() {
	this.canvas.builder.setBrush(new BrownSmallRoundBrush());
}

utils.copyPrototype(BrownSmallRoundBrushCommand, SmallRoundBrushCommand);

function YellowSmallRoundBrushCommand(canvas) {
	this.SmallRoundBrushCommand(canvas);
	this.preferredWidth = 20;
	this.preferredHeight = 23;
}

YellowSmallRoundBrushCommand.prototype.getName = function() {
	return "yellow small round brush";
}

YellowSmallRoundBrushCommand.prototype.getImageUrl = function() {
	return "images/tools/yellow.jpg";
}

YellowSmallRoundBrushCommand.prototype.getMouseDownImageUrl = function() {
	return "images/tools/yellow.jpg";
}

YellowSmallRoundBrushCommand.prototype.getMouseOverImageUrl = function() {
	return "images/tools/yellow_mo.jpg";
}

YellowSmallRoundBrushCommand.prototype.run = function() {
	this.canvas.builder.setBrush(new YellowSmallRoundBrush());
}

utils.copyPrototype(YellowSmallRoundBrushCommand, SmallRoundBrushCommand);

function WhiteOutBrushCommand(canvas) {
	this.BrushCommand();
	this.canvas = canvas;
}

WhiteOutBrushCommand.prototype.getName = function() {
	return "white eraser brush";
}

WhiteOutBrushCommand.prototype.getAlternateText = function() {
	return "White Eraser";
}

WhiteOutBrushCommand.prototype.getImage = function() {
	return new PreloadedImage(this.div, "images/tools/Erase.jpg");
}

WhiteOutBrushCommand.prototype.getImageUrl = function() {
	return "images/tools/Erase.jpg";
}

WhiteOutBrushCommand.prototype.getMouseDownImageUrl = function() {
	return "images/tools/Erase.jpg";
}

WhiteOutBrushCommand.prototype.getMouseOverImageUrl = function() {
	return "images/tools/Erase.jpg";
}

WhiteOutBrushCommand.prototype.run = function() {
	this.canvas.builder.setBrush(new WhiteOutBrush());
}

utils.copyPrototype(WhiteOutBrushCommand, BrushCommand);

function GlobShooterBrushCommand(canvas) {
	this.BrushCommand();
	this.canvas = canvas;
}

GlobShooterBrushCommand.prototype.getName = function() {
	return "glob shooter";
}

GlobShooterBrushCommand.prototype.getAlternateText = function() {
	return "Glob Shooter";
}

GlobShooterBrushCommand.prototype.getImageUrl = function() {
	return "images/tools/glob_shooter_brush.gif";
}

GlobShooterBrushCommand.prototype.getMouseDownImageUrl = function() {
	return "images/tools/glob_shooter_brush.gif";
}

GlobShooterBrushCommand.prototype.getMouseOverImageUrl = function() {
	return "images/tools/glob_shooter_brush.gif";
}

GlobShooterBrushCommand.prototype.run = function() {
	this.canvas.builder.setBrush(new GlobShooterBrush());
}

utils.copyPrototype(GlobShooterBrushCommand, BrushCommand);

function LineBrushCommand(canvas) {
	this.BrushCommand();
	this.canvas = canvas;
}

LineBrushCommand.prototype.getName = function() {
	return "line brush";
}

LineBrushCommand.prototype.getAlternateText = function() {
	return "Line Brush";
}

LineBrushCommand.prototype.getImage = function() {
	return new PreloadedImage(this.div, "images/tools/Curve.jpg");
}

LineBrushCommand.prototype.getImageUrl = function() {
	return "images/tools/Curve.jpg";
}

LineBrushCommand.prototype.getMouseDownImageUrl = function() {
	return "images/tools/Curve.jpg";
}

LineBrushCommand.prototype.getMouseOverImageUrl = function() {
	return "images/tools/Curve.jpg";
}

LineBrushCommand.prototype.run = function() {
	this.canvas.builder.setBrush(new SmoothLineBrush());
}

utils.copyPrototype(LineBrushCommand, BrushCommand);

function StrokeBrushCommand(canvas) {
	this.BrushCommand();
	this.canvas = canvas;
}

StrokeBrushCommand.prototype.getName = function() {
	return "stroke brush";
}

StrokeBrushCommand.prototype.getAlternateText = function() {
	return "Stroke Brush";
}

StrokeBrushCommand.prototype.getImage = function() {
	return new PreloadedImage(this.div, "images/tools/stroke_brush.gif");
}

StrokeBrushCommand.prototype.getImageUrl = function() {
	return "images/tools/stroke_brush.gif";
}

StrokeBrushCommand.prototype.getMouseDownImageUrl = function() {
	return "images/tools/stroke_brush.gif";
}

StrokeBrushCommand.prototype.getMouseOverImageUrl = function() {
	return "images/tools/stroke_brush.gif";
}

StrokeBrushCommand.prototype.run = function() {
	this.canvas.builder.setBrush(new StrokeBrush());
}

utils.copyPrototype(StrokeBrushCommand, BrushCommand);

function StraightEdgeBrushCommand(canvas) {
	this.BrushCommand();
	this.canvas = canvas;
}

StraightEdgeBrushCommand.prototype.getName = function() {
	return "straight edge brush";
}

StraightEdgeBrushCommand.prototype.getAlternateText = function() {
	return "Straight Line";
}

StraightEdgeBrushCommand.prototype.getImageUrl = function() {
	return "images/tools/Line.jpg";
}

StraightEdgeBrushCommand.prototype.getMouseDownImageUrl = function() {
	return "images/tools/Line.jpg";
}

StraightEdgeBrushCommand.prototype.getMouseOverImageUrl = function() {
	return "images/tools/Line.jpg";
}

StraightEdgeBrushCommand.prototype.run = function() {
	this.canvas.builder.setBrush(new StraightEdgeBrush());
}

utils.copyPrototype(StraightEdgeBrushCommand, BrushCommand);

function RectangleBrushCommand(canvas) {
	this.BrushCommand();
	this.canvas = canvas;
}

RectangleBrushCommand.prototype.getName = function() {
	return "rectangle brush";
}

RectangleBrushCommand.prototype.getAlternateText = function() {
	return "Rectangle";
}

RectangleBrushCommand.prototype.getImage = function() {
	return new PreloadedImage(this.div, this.getImageUrl());
}

RectangleBrushCommand.prototype.getImageUrl = function() {
	return "images/tools/outline.jpg";
}

RectangleBrushCommand.prototype.getMouseDownImageUrl = function() {
	return "images/tools/outline.jpg";
}

RectangleBrushCommand.prototype.getMouseOverImageUrl = function() {
	return "images/tools/outline.jpg";
}

RectangleBrushCommand.prototype.run = function() {
	this.canvas.builder.setBrush(new RectangleBrush(this.canvas));
}

utils.copyPrototype(RectangleBrushCommand, BrushCommand);

function TextBrushCommand(canvas) {
	this.BrushCommand();
	this.canvas = canvas;
}

TextBrushCommand.prototype.getName = function() {
	return "text brush";
}

TextBrushCommand.prototype.getAlternateText = function() {
	return "Text";
}

TextBrushCommand.prototype.getImageUrl = function() {
	return "images/tools/textnew1.gif";
}

TextBrushCommand.prototype.getMouseDownImageUrl = function() {
	return "images/tools/textnew2.gif";
}

TextBrushCommand.prototype.getMouseOverImageUrl = function() {
	return "images/tools/textnew3.gif";
}

TextBrushCommand.prototype.run = function() {
	//this.canvas.builder.setBrush(new GeneralTextBrush());
	var brush = new GeneralTextBrush();
	brush.setCanvas(this.canvas);
	this.canvas.builder.setBrush(brush);
	this.canvas.builder.beginStroke(this.canvas.getWidth()/4,this.canvas.getHeight()/4);
	this.canvas.builder.endStroke(this.canvas.getWidth()/4*3,this.canvas.getHeight()/4*3);
}

utils.copyPrototype(TextBrushCommand, BrushCommand);

function ImageBrushCommand(canvas) {
	this.TextBrushCommand(canvas);
}

ImageBrushCommand.prototype.getName = function() {
	return "image brush";
}

ImageBrushCommand.prototype.getAlternateText = function() {
	return "Foreground";
}

ImageBrushCommand.prototype.setDisplayArea = function(container) {
	this.displayArea = container;
}

ImageBrushCommand.prototype.getImageUrl = function() {
	return "images/tools/foregroundnew1.gif";
}

ImageBrushCommand.prototype.getMouseDownImageUrl = function() {
	return "images/tools/foregroundnew2.gif";
}

ImageBrushCommand.prototype.getMouseOverImageUrl = function() {
	return "images/tools/foregroundnew3.gif";
}

ImageBrushCommand.prototype.run = function() {
	var brush = new ImageBrush(this.canvas.getId(), 'foreground');
	brush.setCanvas(this.canvas);
	this.canvas.builder.setBrush(brush);
	this.canvas.builder.beginStroke(0,0);
	this.canvas.builder.endStroke(this.canvas.getWidth()/2,this.canvas.getHeight()/2);
}

utils.copyPrototype(ImageBrushCommand, TextBrushCommand);

function CartoonBrushCommand(canvas) {
	this.ImageBrushCommand(canvas);
}

CartoonBrushCommand.prototype.getName = function() {
	return "cartoon brush";
}

CartoonBrushCommand.prototype.getAlternateText = function() {
	return "Cartoon";
}

CartoonBrushCommand.prototype.getImageUrl = function() {
	return "images/tools/cartooncmd.gif";
}

CartoonBrushCommand.prototype.getMouseDownImageUrl = function() {
	return "images/tools/cartooncmd.gif";
}

CartoonBrushCommand.prototype.getMouseOverImageUrl = function() {
	return "images/tools/cartooncmd.gif";
}

CartoonBrushCommand.prototype.run = function() {
	var editor = new CartoonBrushEditor(this.canvas, this.canvas.canvaspeer, this.displayArea);
	editor.display();
}

utils.copyPrototype(CartoonBrushCommand, ImageBrushCommand);

function BorderBrushCommand(canvas) {
	this.TextBrushCommand(canvas);
}

BorderBrushCommand.prototype.getName = function() {
	return "border brush";
}

BorderBrushCommand.prototype.getAlternateText = function() {
	return "Border";
}

BorderBrushCommand.prototype.getImageUrl = function() {
	return "images/tools/bordernew1.gif";
}

BorderBrushCommand.prototype.getMouseDownImageUrl = function() {
	return "images/tools/bordernew2.gif";
}

BorderBrushCommand.prototype.getMouseOverImageUrl = function() {
	return "images/tools/bordernew3.gif";
}

BorderBrushCommand.prototype.run = function() {
	var brush = new BorderBrush(this.canvas.getId(), 'border');
	brush.setCanvas(this.canvas);
	this.canvas.builder.setBrush(brush);
	this.canvas.builder.beginStroke(0,0);
	this.canvas.builder.endStroke(this.canvas.getWidth(),this.canvas.getHeight());
}

utils.copyPrototype(BorderBrushCommand, TextBrushCommand);

function BackgroundBrushCommand(canvas) {
	this.TextBrushCommand(canvas);
}

BackgroundBrushCommand.prototype.getName = function() {
	return "background brush";
}

BackgroundBrushCommand.prototype.getAlternateText = function() {
	return "Background";
}

BackgroundBrushCommand.prototype.getImageUrl = function() {
	return "images/tools/backgroundbuttonnew1.gif";
}

BackgroundBrushCommand.prototype.getMouseDownImageUrl = function() {
	return "images/tools/backgroundbuttonnew2.gif";
}

BackgroundBrushCommand.prototype.getMouseOverImageUrl = function() {
	return "images/tools/backgroundbuttonnew3.gif";
}

BackgroundBrushCommand.prototype.run = function() {
	if (this.canvas.persistenceTool.id != null) {
		alert('Sorry, the background can only be set and saved once!');
	} else {
		var editor = new BackgroundBrushEditor(this.canvas, this.canvas.canvaspeer);
		editor.display();
	}
}

utils.copyPrototype(BackgroundBrushCommand, TextBrushCommand);

function CartoonFrameBrushCommand(canvas) {
	this.BackgroundBrushCommand(canvas);
}

CartoonFrameBrushCommand.prototype.setDisplayArea = function(container) {
	this.displayArea = container;
}

CartoonFrameBrushCommand.prototype.getName = function() {
	return "cartoon frame brush";
}

CartoonFrameBrushCommand.prototype.getAlternateText = function() {
	return "Frames";
}

CartoonFrameBrushCommand.prototype.run = function() {
	var editor = new CartoonBrushEditor(this.canvas, this.canvas.canvaspeer, this.displayArea);
	editor.display();
}

utils.copyPrototype(CartoonFrameBrushCommand, BackgroundBrushCommand);

function TextBalloonRDCommand(canvas) {
	this.BrushCommand();
	this.canvas = canvas;
}

TextBalloonRDCommand.prototype.getName = function() {
	return "text balloon RD";
}

TextBalloonRDCommand.prototype.getAlternateText = function() {
	return "Text Balloon";
}

TextBalloonRDCommand.prototype.getImage = function() {
	return new PreloadedImage(this.div, "images/tools/balloon_rd.gif");
}

TextBalloonRDCommand.prototype.run = function() {
	this.canvas.builder.setBrush(new TextBalloonRD());
}

utils.copyPrototype(TextBalloonRDCommand, BrushCommand);

function TextBalloonLDCommand(canvas) {
	this.BrushCommand();
	this.canvas = canvas;
}

TextBalloonLDCommand.prototype.getName = function() {
	return "text balloon LD";
}

TextBalloonLDCommand.prototype.getImage = function() {
	return new PreloadedImage(this.div, "images/tools/balloon_ld.gif");
}

TextBalloonLDCommand.prototype.run = function() {
	this.canvas.builder.setBrush(new TextBalloonLD());
}

utils.copyPrototype(TextBalloonLDCommand, BrushCommand);

function TextBalloonRUCommand(canvas) {
	this.BrushCommand();
	this.canvas = canvas;
}

TextBalloonRUCommand.prototype.getName = function() {
	return "text balloon RU";
}

TextBalloonRUCommand.prototype.getImage = function() {
	return new PreloadedImage(this.div, "images/tools/balloon_ru.gif");
}

TextBalloonRUCommand.prototype.run = function() {
	this.canvas.builder.setBrush(new TextBalloonRU());
}

utils.copyPrototype(TextBalloonRUCommand, BrushCommand);

function TextBalloonLUCommand(canvas) {
	this.BrushCommand();
	this.canvas = canvas;
}

TextBalloonLUCommand.prototype.getName = function() {
	return "text balloon LU";
}

TextBalloonLUCommand.prototype.getImage = function() {
	return new PreloadedImage(this.div, "images/tools/balloon_lu.gif");
}

TextBalloonLUCommand.prototype.run = function() {
	this.canvas.builder.setBrush(new TextBalloonLU());
}

utils.copyPrototype(TextBalloonLUCommand, BrushCommand);

// Controller

function ControlPanel(aCanvas, aCanvasPeer) {
	this.commands = new Array();
	this.canvas = aCanvas;
	this.loadCommands();
	if (aCanvasPeer == null)
		this.displayedOn = this.canvas.getPeer();
	else
		this.displayedOn = aCanvasPeer;
	this.displayOnContainer(this.displayedOn);
}

ControlPanel.prototype.loadCommands = function() {
	//new DeleteCommand(this.canvas).addToControlPanel(this);
	new UndoCommand(this.canvas).addToControlPanel(this);
	new RedoCommand(this.canvas).addToControlPanel(this);
	new SaveOnServerCommand(this.canvas).addToControlPanel(this);
	new RoundBrushCommand(this.canvas).addToControlPanel(this);
	//new GlobShooterBrushCommand(this.canvas).addToControlPanel(this);
	//new LineBrushCommand(this.canvas).addToControlPanel(this);
	//new WhiteOutBrushCommand(this.canvas).addToControlPanel(this);
	//new StraightEdgeBrushCommand(this.canvas).addToControlPanel(this);
	new BlueSmallRoundBrushCommand(this.canvas).addToControlPanel(this);
	new GreenSmallRoundBrushCommand(this.canvas).addToControlPanel(this);
	new PinkSmallRoundBrushCommand(this.canvas).addToControlPanel(this);
	new OrangeSmallRoundBrushCommand(this.canvas).addToControlPanel(this);
	new SmallRoundBrushCommand(this.canvas).addToControlPanel(this);
	new YellowSmallRoundBrushCommand(this.canvas).addToControlPanel(this);
	new BrownSmallRoundBrushCommand(this.canvas).addToControlPanel(this);
	new CyanSmallRoundBrushCommand(this.canvas).addToControlPanel(this);
	new TextBrushCommand(this.canvas).addToControlPanel(this);
	new ImageBrushCommand(this.canvas).addToControlPanel(this);
	new BorderBrushCommand(this.canvas).addToControlPanel(this);
	new BackgroundBrushCommand(this.canvas).addToControlPanel(this);
}

/**
 * Takes care of layout of the commands.  This has only been stubbed out for now.
 */
ControlPanel.prototype.getSuitablePosition = function(command) {
	if (command.getName() == "undo") {
		return new Point(0+1, 15);
	} else if (command.getName() == "redo") {
		return new Point(50+2, 15);
	} else if (command.getName() == "save on server") {
		return new Point((25)+0+1, (7)+65+1);
		//return new Point(0+1, 65+1);
	} else if (command.getName() == "white eraser brush") {
		return new Point(50+2, 280+5);
	} else if (command.getName() == "round brush") {
		return new Point(0+1, 280+5);
	} else if (command.getName() == "black small round brush") {
		return new Point(50+2, 130+2);
	} else if (command.getName() == "straight edge brush") {
		return new Point(0+1, 330+6);
	} else if (command.getName() == "line brush") {
		return new Point(50+2, 330+6);
	} else if (command.getName() == "text brush") {
		return new Point(0+1, 230+4);
	} else if (command.getName() == "white text brush") {
		return new Point(50+2, 230+4);
	} else if (command.getName() == "text balloon RD") {
		return new Point(0+1, 280+5);
	} else if (command.getName() == "text balloon LD") {
		return new Point(50+2, 280+5);
	} else if (command.getName() == "text balloon RU") {
		return new Point(0+1, 330+6);
	} else if (command.getName() == "text balloon LU") {
		return new Point(50+2, 330+6);
	} else if (command.getName() == "blue small round brush") {
		return new Point(50+2, 130+2);
	} else if (command.getName() == "green small round brush") {
		return new Point(75+1+2, 130+2);
	} else if (command.getName() == "pink small round brush") {
		return new Point(50+2, 155+1+2);
	} else if (command.getName() == "orange small round brush") {
		return new Point(75+1+2, 155+1+2);
	} else if (command.getName() == "small round brush") {
		return new Point(0+1, 130+2);
	} else if (command.getName() == "brown small round brush") {
		return new Point(25+2, 130+2);
	} else if (command.getName() == "cyan small round brush") {
		return new Point(0+1, 155+1+2);
	} else if (command.getName() == "yellow small round brush") {
		return new Point(25+2, 155+1+2);
	} else if (command.getName() == "blue text brush") {
		return new Point(0+1, 230+4);
	} else if (command.getName() == "border brush") {
		return new Point(0+1, 230+4);
	} else if (command.getName() == "green text brush") {
		return new Point(50+2, 330+6);
	} else if (command.getName() == "red text brush") {
		return new Point(50+2, 230+4);
	//} else if (command.getName() == "yellow text brush") {
	//	return new Point(50+2, 330+6);
	} else if (command.getName() == "image brush") {
		return new Point(0+1, 180+3);
	} else if (command.getName() == "background brush") {
		return new Point(50+2, 180+3);
	}
}

// NEW
ControlPanel.prototype.getSuitablePosition = function(command) {
	if (command.getName() == "undo") {
		return new Point(15-4+1, 290+5);
	} else if (command.getName() == "delete") {
		return new Point(15+1, 385);
	} else if (command.getName() == "redo") {
		return new Point(50+4+2, 290+5);
	} else if (command.getName() == "save on server") {
		return new Point((30)+0+1, 335+6);
	} else if (command.getName() == "round brush") {
		return new Point(15+1, 175+3);
	} else if (command.getName() == "blue small round brush") {
		return new Point(50+2, 225+1+2);
	} else if (command.getName() == "green small round brush") {
		return new Point(70+1, 225+1+2);
	} else if (command.getName() == "pink small round brush") {
		return new Point(50+2, 250+1+2);
	} else if (command.getName() == "orange small round brush") {
		return new Point(70+1, 250+1+2);
	} else if (command.getName() == "small round brush") {
		return new Point(10, 225+1+2);
	} else if (command.getName() == "brown small round brush") {
		return new Point(30+2, 225+1+2);
	} else if (command.getName() == "cyan small round brush") {
		return new Point(10, 250+1+2);
	} else if (command.getName() == "yellow small round brush") {
		return new Point(30+2, 250+1+2);
	} else if (command.getName() == "border brush") {
		return new Point(35+2, 70+1);
	} else if (command.getName() == "text brush") {
		return new Point(55+2, 175+3);
	} else if (command.getName() == "image brush") {
		return new Point(35+2, 125+2);
	} else if (command.getName() == "background brush") {
		return new Point(35+2, 20);
	}
	/*} else if (command.getName() == "white eraser brush") {
		return new Point(15+1, 175+3);
	} else if (command.getName() == "black small round brush") {
		return new Point(10+1, 250+1+2);
	} else if (command.getName() == "straight edge brush") {
		return new Point(15+1, 20);
	} else if (command.getName() == "line brush") {
		return new Point(15+1, 70+1);*/
}

ControlPanel.prototype.createContainer = function() {
	var divId = 'control_panel'
	var mainFrame = document.createElement('div');
	mainFrame.id = divId;
	mainFrame.style.left = 0+'px';
	mainFrame.style.top = 0+'px';
	mainFrame.style.width = 100+3+'px';
	mainFrame.style.height = (15+350+15+10)+'px';
	return mainFrame;
}

ControlPanel.prototype.displayOnContainer = function(container) {
	this.mainFrame = this.createContainer();

	// The following lines are here so createContainer can be overridden
	this.mainFrame.onmousedown = utils.cancelBubble;
	this.mainFrame.onmousemove = utils.cancelBubble;
	this.mainFrame.onmouseup = utils.cancelBubble;

	container.appendChild(this.mainFrame);

	for (i = 0 ; i < this.commands.length ; ++i) {
		this.displayCommand(this.commands[i]);
	}
}

ControlPanel.prototype.addCommand = function(command) {
	this.commands.push(command);
}

ControlPanel.prototype.removeFromContainer = function(container) {
	container.removeChild(this.mainFrame);
}

ControlPanel.prototype.hide = function() {
	this.removeFromContainer(this.displayedOn);
}

ControlPanel.prototype.setPosition = function(x, y) {
	this.mainFrame.parentNode.style.left = x+'px';
	this.mainFrame.parentNode.style.top = y+'px';
}

ControlPanel.prototype.getPosition = function() {
	return new Point(
			parseInt(this.mainFrame.style.left.split('p')[0]),
			parseInt(this.mainFrame.style.top.split('p')[0])
		);
}

// A command has the following methods
// 1.  displayOnContainer(container)
// 2.  Point getPreferredSize()
ControlPanel.prototype.displayCommand = function(command) {
	var position = this.getSuitablePosition(command);
	if (position != null)
		command.displayOnContainer(this.mainFrame, position.getX(), position.getY());
}

// Second Controller
function LowerControlPanel(aCanvas, aCanvasPeer) {
	this.ControlPanel(aCanvas, aCanvasPeer);
}

LowerControlPanel.prototype.loadCommands = function() {
	new DeleteCommand(this.canvas).addToControlPanel(this);
}

LowerControlPanel.prototype.getSuitablePosition = function(command) {
	if (command.getName() == "delete") {
		return new Point(0, 0);
	}
}

LowerControlPanel.prototype.createContainer = function() {
	var divId = 'lower_control_panel'
	var mainFrame = document.createElement('div');
	mainFrame.id = divId;
	mainFrame.style.left = 0+'px';
	mainFrame.style.top = 0+'px';
	mainFrame.style.width = 100+3+'px';
	mainFrame.style.height = 21+'px';
	return mainFrame;
}

utils.copyPrototype(LowerControlPanel, ControlPanel);

// Second Controller
function CartoonControlPanel(aCanvas, aCanvasPeer, aDisplayAreaPeer) {
	this.displayArea = aDisplayAreaPeer;
	this.ControlPanel(aCanvas, aCanvasPeer);
}

CartoonControlPanel.prototype.loadCommands = function() {
	new UndoCommand(this.canvas).addToControlPanel(this);
	new RedoCommand(this.canvas).addToControlPanel(this);
	new SaveOnServerCommand(this.canvas).addToControlPanel(this);
	new RoundBrushCommand(this.canvas).addToControlPanel(this);
	new BlueSmallRoundBrushCommand(this.canvas).addToControlPanel(this);
	new GreenSmallRoundBrushCommand(this.canvas).addToControlPanel(this);
	new PinkSmallRoundBrushCommand(this.canvas).addToControlPanel(this);
	new OrangeSmallRoundBrushCommand(this.canvas).addToControlPanel(this);
	new SmallRoundBrushCommand(this.canvas).addToControlPanel(this);
	new YellowSmallRoundBrushCommand(this.canvas).addToControlPanel(this);
	new BrownSmallRoundBrushCommand(this.canvas).addToControlPanel(this);
	new CyanSmallRoundBrushCommand(this.canvas).addToControlPanel(this);
	new TextBrushCommand(this.canvas).addToControlPanel(this);
	new WhiteOutBrushCommand(this.canvas).addToControlPanel(this);
	var cbc = new CartoonBrushCommand(this.canvas);
	cbc.addToControlPanel(this);
	//alert(this.displayArea);
	cbc.setDisplayArea(this.displayArea);
	cbc.run();
	//new BorderBrushCommand(this.canvas).addToControlPanel(this);
	var cfbc = new CartoonFrameBrushCommand(this.canvas);
	cfbc.addToControlPanel(this);
	cfbc.setDisplayArea(this.displayArea);
}

CartoonControlPanel.prototype.getSuitablePosition = function(command) {
	if (command.getName() == "undo") {
		return new Point(15-4+1, 290+5);
	} else if (command.getName() == "delete") {
		return new Point(15+1, 385);
	} else if (command.getName() == "redo") {
		return new Point(50+4+2, 290+5);
	} else if (command.getName() == "save on server") {
		return new Point((30)+0+1, 335+6);
	} else if (command.getName() == "round brush") {
		return new Point(35+2, 70+1);
	} else if (command.getName() == "blue small round brush") {
		return new Point(50+2, 225+1+2);
	} else if (command.getName() == "green small round brush") {
		return new Point(70+1, 225+1+2);
	} else if (command.getName() == "pink small round brush") {
		return new Point(50+2, 250+1+2);
	} else if (command.getName() == "orange small round brush") {
		return new Point(70+1, 250+1+2);
	} else if (command.getName() == "small round brush") {
		return new Point(10, 225+1+2);
	} else if (command.getName() == "brown small round brush") {
		return new Point(30+2, 225+1+2);
	} else if (command.getName() == "cyan small round brush") {
		return new Point(10, 250+1+2);
	} else if (command.getName() == "yellow small round brush") {
		return new Point(30+2, 250+1+2);
	} else if (command.getName() == "border brush") {
		return new Point(35+2, 70+1);
	} else if (command.getName() == "text brush") {
		return new Point(35+2, 20);
	//} else if (command.getName() == "cartoon brush") {
	//	return new Point(35+2, 70+1);
	//} else if (command.getName() == "cartoon frame brush") {
	//	return new Point(35+2, 20);
	} else if (command.getName() == "white eraser brush") {
		return new Point(35+2, 125+3);
	}
}

utils.copyPrototype(CartoonControlPanel, ControlPanel);

function EventHandler(parentDiv) {
	// The states are :
	// a) IGNORE_MOUSE_EVENTS
	// b) TRACK_MOUSE_EVENTS
	this.listeners = new Array();
	this.canvaspeer = parentDiv;
}

// Listeners implement three methods
// 1.  beginStroke(x,y)
// 2.  continueStroke(x,y)
// 3.  endStroke(x,y)

EventHandler.prototype.addListener = function(listener) {
	this.listeners.push(listener);
	this.logger = new Logger();
	this.state = "IGNORE_MOUSE_EVENTS";
}

EventHandler.prototype.getX = function(e) {
	var curevent=(typeof event=='undefined'?e:event) 

	//gets position of click 
	//alert(this.canvaspeer.style.left);
	var curPosX=curevent.clientX;
	if (this.canvaspeer.style.position == 'absolute') {
		curPosX = curPosX - this.canvaspeer.parentNode.style.left.split('p')[0] - this.canvaspeer.style.left.split('p')[0];
	} else {
		// If IE
		if (utils.isIE())
			curPosX = curPosX - findPosX(this.canvaspeer);
	}
	var xOffset = document.body.scrollLeft + this.canvaspeer.scrollLeft;

	return (curPosX+xOffset);
}

EventHandler.prototype.getY = function(e) {
	var curevent=(typeof event=='undefined'?e:event) 

	//gets position of click 
	var curPosY=curevent.clientY;
	if (this.canvaspeer.style.position == 'absolute') {
		curPosY = curPosY - this.canvaspeer.parentNode.style.top.split('p')[0] - this.canvaspeer.style.top.split('p')[0];
	} else {
		// If IE
		if (utils.isIE())
			curPosY = curPosY - findPosY(this.canvaspeer);
	}
	var yOffset = document.body.scrollTop + this.canvaspeer.scrollTop;

	return (curPosY+yOffset);
}

EventHandler.prototype.onmousedown = function(e) {
	this.state = "TRACK_MOUSE_EVENTS";
	
	for (i = 0 ; i < this.listeners.length ; ++i) {
		this.listeners[i].beginStroke(this.getX(e), this.getY(e));
	}
	
	this.logger.debug("Down to position: "+this.getX(e)+" and "+this.getY(e));
}

EventHandler.prototype.onmousemove = function(e) {
	if (this.state == "TRACK_MOUSE_EVENTS") {
		for (i = 0 ; i < this.listeners.length ; ++i) {
			this.listeners[i].continueStroke(this.getX(e), this.getY(e));
		}
		this.logger.debug("Move to position: "+this.getX(e)+" and "+this.getY(e));
	}
}

EventHandler.prototype.onmouseup = function(e) {
	for (i = 0 ; i < this.listeners.length ; ++i) {
		this.listeners[i].endStroke(this.getX(e), this.getY(e));
	}

	this.state = "IGNORE_MOUSE_EVENTS";

	this.logger.debug("Up at position: "+this.getX(e)+" and "+this.getY(e));
}

// The canvas

function DrawingCanvas(parentDiv, imageId, serializedString) {
	this.canvaspeer = parentDiv;
	this.builder = new Builder(this.canvaspeer, new RoundBrush());
	this.builder.setTrackingTime(true);
	this.eventHandler = new EventHandler(this.canvaspeer);
	this.eventHandler.addListener(this.builder);
	this.canvaspeer.canvas = this;
	this.canvaspeer.onmousedown = DrawingCanvas.prototype.RECORDMOUSEDOWN;
	this.canvaspeer.onmouseup = DrawingCanvas.prototype.RECORDMOUSEUP;
	this.canvaspeer.onmousemove = DrawingCanvas.prototype.RECORDMOUSEMOVE;
	if (imageId != null) {
		this.persistenceTool = new IncrementalPersistenceTool(imageId);
	} else {
		this.persistenceTool = new IncrementalPersistenceTool();
	}
	if (serializedString == null)
		this.serializedString = '';
	else
		this.serializedString = serializedString;
	this.deserializer = new ServerRenderedDeserializer(this.serializedString, imageId);
	this.isEditable = true;
	this.isDisplayed = false;
	
	this.mode = 'drawing';
	this.selectedObject = null;
	
	// Properties
	this.width = 600;
	this.height = 400;
	this.backgroundId = null;
	this.backgroundType = null; 
	this.shared = true;
	this.type = 'painting';
}

DrawingCanvas.prototype.getType = function() {
	return this.type;
}

DrawingCanvas.prototype.setType = function(type) {
	this.type = type;
	this.persistenceTool.setType(type);
}

DrawingCanvas.prototype.setSize = function(width, height) {
	this.width = width;
	this.height = height;
	this.canvaspeer.style.width = width+'px';
	this.canvaspeer.style.height = height+'px';
	this.persistenceTool.setSize(width, height);
	this.refreshBackground();
}

DrawingCanvas.prototype.setPosition = function(x, y) {
	this.canvaspeer.parentNode.style.left = x+'px';
	this.canvaspeer.parentNode.style.top = y+'px';
}

DrawingCanvas.prototype.getPosition = function() {
	return new Point(
			parseInt(this.canvaspeer.parentNode.style.left.split('p')[0]),
			parseInt(this.canvaspeer.parentNode.style.top.split('p')[0])
		);
}

DrawingCanvas.prototype.setShared = function(flag) {
	this.shared = flag;
	this.persistenceTool.setShared(flag);
}

DrawingCanvas.prototype.hasBackground = function() {
	return this.backgroundId != null;
}

DrawingCanvas.prototype.displayBackground = function(id, type) {
	this.backgroundId = id;
	this.backgroundType = type;
	var url = this.private_getBackgroundUrl(id, type);
	//alert(url);
	this.builder.displayBackground(url, this.width, this.height);
	this.persistenceTool.displayBackground(id, type);
}

DrawingCanvas.prototype.refreshBackground = function() {
	if (this.backgroundId != null) {
		this.displayBackground(this.backgroundId, this.backgroundType);
	}
}

DrawingCanvas.prototype.private_getBackgroundUrl = function(id, type) {
	return configurations.getServerUrl()+'viewbinaryimage.php?id='+id+'&command=View&type='+type;
}

DrawingCanvas.prototype.getMode = function() {
	return this.mode;
}

DrawingCanvas.prototype.setModeMoving = function() {
	this.mode = 'moving';
}

DrawingCanvas.prototype.setModeResizing = function() {
	this.mode = 'resizing';
}

DrawingCanvas.prototype.setModeDrawing = function() {
	this.mode = 'drawing';
}

DrawingCanvas.prototype.setSelectedObject = function(object) {
	this.selectedObject = object;
	//alert(object);
}

DrawingCanvas.prototype.getWidth = function() {
	return this.width;
}

DrawingCanvas.prototype.getHeight = function() {
	return this.height;
}

DrawingCanvas.prototype.getBackgroundId = function() {
	return this.backgroundId;
}

DrawingCanvas.prototype.getBackgroundType = function() {
	return this.backgroundType;
}

DrawingCanvas.prototype.getId = function() {
	return this.persistenceTool.getId();
}

DrawingCanvas.prototype.save = function() {
	new SaveOnServerCommand(this).run();
}

DrawingCanvas.prototype.display = function() {
	if (this.isDisplayed == false && this.serializedString != null) {
		this.deserializer.deserializeOnto(this);
		this.isDisplayed = true;
	}
	//this.canvaspeer.style.display = 'block';
}

DrawingCanvas.prototype.displayOneStep = function() {
	if (this.isDisplayed == false && this.serializedString != null) {
		this.deserializer.deserializeOnto(this, 1);
		this.isDisplayed = this.deserializer.isDeserialized();
	}
	//this.canvaspeer.style.display = 'block';
}

DrawingCanvas.prototype.clear = function() {
	this.isDisplayed = false;
	this.builder.clearStrokes();
	this.builder.renderer.clearStatus();
}

DrawingCanvas.prototype.show = function() {
	this.canvaspeer.style.display = 'block';
}

DrawingCanvas.prototype.hide = function() {
	this.canvaspeer.style.display = 'none';
}

DrawingCanvas.prototype.setEditable = function(isEditable) {
	this.isEditable = isEditable;
}

DrawingCanvas.prototype.disposeSelf = function() {
	if (this.isEditable && this.persistenceTool != null && this.persistenceTool.id != null) {
		this.persistenceTool.del();
	}
}

DrawingCanvas.prototype.isSaved = function() {
	return this.persistenceTool.id != null;
}

DrawingCanvas.prototype.setUndos = function(undos) {
	this.persistenceTool.undos = undos;
}

DrawingCanvas.prototype.cancelBubble = function(e) {
	curevent=(typeof event=='undefined'?e:event) 
	curevent.cancelBubble = true;
	if (curevent.stop) curevent.stop();
}

DrawingCanvas.prototype.RECORDMOUSEDOWN = function(e) {
	if ((this.canvas.mode == 'moving' || this.canvas.mode == 'resizing') && this.canvas.selectedObject != null) {
		//for handling events in ie vs. w3c 
		curevent=(typeof event=='undefined'?e:event);
		//gets position of click 
		this.canvas.selectedObject.lastPosX=curevent.clientX;
		this.canvas.selectedObject.lastPosY=curevent.clientY;
		//alert(curPosX + ":" + curPosY);
		//this.resizableMovableBoundary.cancelBubble(e);
	} else if (this.canvas.isEditable) {
		this.canvas.eventHandler.onmousedown(e);
	}
	this.canvas.cancelBubble(e);
}

DrawingCanvas.prototype.RECORDMOUSEMOVE = function(e) {
	if (this.canvas.mode == 'moving' && this.canvas.selectedObject != null) {
		this.canvas.selectedObject.onMoveHandler(e);
	} else if (this.canvas.mode == 'resizing' && this.canvas.selectedObject != null) {
		this.canvas.selectedObject.onResizeHandler(e);
	} else if (this.canvas.isEditable) {
		this.canvas.eventHandler.onmousemove(e);
	}
	this.canvas.cancelBubble(e);
}

DrawingCanvas.prototype.RECORDMOUSEUP = function(e) {
	if (this.canvas.mode == 'moving' && this.canvas.selectedObject != null) {
		//alert('Bingo!');
		this.canvas.mode = 'drawing';
		this.canvas.selectedObject = null;
	} else if (this.canvas.mode == 'resizing' && this.canvas.selectedObject != null) {
		//alert('Bingo!');
		this.canvas.mode = 'drawing';
		this.canvas.selectedObject = null;
	} else if (this.canvas.isEditable) {
		this.canvas.eventHandler.onmouseup(e);
	}
	this.canvas.cancelBubble(e);
}

DrawingCanvas.prototype.getPeer = function() {
	return this.canvaspeer;
}

