function penObj(){

	// how this works:
	//
	// calling page must remember to call setBoundaries() once ready.
	// on the outset, no divs exist yet. they are created dynamically as we need them.
	// * when the image detects a mousedown event, it calls penDown()
	// * penDown calls this.createNewLine().
	// * this.createNewLine adds a new line object to the pen object's "lines[]" array.
	// * this.createNewLine creates two handle divs, handle A and handle B.
	// * this.createNewLine creates a canvas div (to draw the line into.)
	// * lastly, we select the newly-made line, which fiddles with the dragHandle and fixedHandle pointers
	// * while the pen is "down", attach mousemove event handlers to the appropriate divs.
	// * the mousemove event handler makes repeated calls to makeLine and drawHandle;
	//
	// pointers are used for convenience:
	//      this.currLine is a pointer to the current active line object.
	//      this.currLine.dragHandle is the handle in motion.
	// 		this.currLine.fixedHandle is the fixed handle.
	//

	this.maxLines = 3;
	this.lines = [];
	this.idx = -1;
	this.down = false;
	this.currLine = false;
	this.lineRegex = /%(\d+);(\d+);(\d+);(\d+)/g;
	this.lineColor = "#FBBA55"
	this.boundaryCoords = false;
	this.heightUpperLegend = 16;
	this.heightChart = 120;
	this.labelYMin = false;
	this.labelYMax = false;
}


penObj.prototype.clearHTM = function(line){
	line.htm = [];
}

penObj.prototype.paint = function(line){

	line.canvas.innerHTML = line.htm.join("").replace(this.lineRegex,'<div class=t style=background:'+this.lineColor+';left:$1;top:$2;width:$3;height:$4></div>');

}

penObj.prototype.selectLine = function(idx, dragHandleId, fixedHandleId){

	this.currLine = this.lines[idx]
	this.currLine.dragHandle = (dragHandleId == "A")?this.currLine.handle.a:this.currLine.handle.b;
	this.currLine.fixedHandle = (fixedHandleId == "A")?this.currLine.handle.a:this.currLine.handle.b;
	this.modifyHandleIcon(this.currLine.dragHandle, true);

}

penObj.prototype.createNewLine = function(){

	// idx is optional - if not provided, we'll add to end of array.

	this.idx = (this.idx == this.maxLines - 1)?0:this.idx + 1;

	if (typeof(this.lines[this.idx]) == "undefined"){

		this.lines[this.idx] = {
			handle: this.createHandles(),
			htm:[],
			canvas: this.createCanvas(),
			deleted: false,
			divLabel: document.createElement("DIV")
		};

		var line = this.lines[this.idx];

		with (line.divLabel.style){

			position = "absolute";
			visibility = "hidden";
			left = "0px";
			top = "0px";
			width = "30px";
			fontFamily = "Helvetica";
			fontSize = "9px";
			backgroundColor = "#FFFFFF";
			border = "1px solid #777777";
			cursor = "default";
			zIndex = 2000;
		}

		line.divLabel.innerHTML = " ";

		document.body.appendChild(line.divLabel);


	}

	var myLine = this.lines[this.idx];
		myLine.dragHandle = myLine.handle.b;
		myLine.fixedHandle = myLine.handle.a;
		myLine.deleted = false;

	this.selectLine(this.idx, "B", "A");

	// activate 'remove lines' link
	document.getElementById("linkRemoveLines").className = "linkOn";

}

penObj.prototype.createHandles = function(){

	var handle = document.body.appendChild(document.createElement("IMG"));
		handle.id = "handleA" + this.lines.length;
		handle.className = "crosshair";
		handle.src = '/tdameritrade/images/cH0.gif';
		handle.style.backgroundImage
		handle.style.visibility = "hidden";
		handle.onmousedown = penDown;

	handle = null;

	handle = document.body.appendChild(document.createElement("IMG"));
		handle.id = "handleB" + this.lines.length;
		handle.className = "crosshair2";
		handle.src = '/tdameritrade/images/cH1.gif';
		handle.style.visibility = "hidden";
		handle.onmousedown = penDown;

	return {
		a: document.getElementById("handleA" + this.lines.length),
		b: document.getElementById("handleB" + this.lines.length),
		x0: 0,
		y0: 0
	}

}

penObj.prototype.modifyHandleIcon = function(handleObj, selected, forced){

	if (selected){

		if (handleObj.className != "crosshair2"){
			handleObj.src = '/tdameritrade/images/cH1.gif';
			handleObj.className = "crosshair2";
			handleObj.style.top = (parseInt(handleObj.style.top,10) - 8) + "px";
		}

	} else {

		if (handleObj.className != "crosshair"){
			handleObj.className = "crosshair";
			handleObj.src = '/tdameritrade/images/cH0.gif';
			handleObj.style.top = (((handleObj.style.top)?parseInt(handleObj.style.top,10):0) + 8) + "px";
		}

	}

}


penObj.prototype.createCanvas = function(){

	var div = document.body.appendChild(document.createElement("DIV"));
		div.id = "canvas" + this.lines.length;
		div.className = "myCanvas";

	return div;

}

penObj.prototype.makeLine = function(x1, y1, x2, y2, line){
	if(x1>x2){_x2=x2;_y2=y2;x2=x1;y2=y1;x1=_x2;y1=_y2;};dx=x2-x1;dy=Math.abs(y2-y1);x=x1;y=y1;yIncr=(y1>y2)?-1:1;if(dx>=dy){pr=dy<<1;pru=pr-(dx<<1);p=pr-dx;ox=x;while((dx--)>1){++x;if(p>0){line.htm[line.htm.length]='%'+ox+';'+y+';'+(x-ox)+';3';y+=yIncr;p+=pru;ox=x;}else p += pr;};line.htm[line.htm.length]='%'+ox+';'+y+';'+(x2-ox+2)+';3';}else{pr=dx<<1;pru=pr-(dy<<1);p=pr-dy;oy=y;if(y2<=y1){while((dy--)>1){if(p>0){line.htm[line.htm.length]='%'+(x++)+';'+y+';3;'+(oy-y+2);y+=yIncr;p+=pru;oy=y;}else{y+=yIncr;p+=pr;}};line.htm[line.htm.length]='%'+x2+';'+y2+';3;'+(oy-y2+2);}else{while((dy--)>1){y+=yIncr;if(p>0){line.htm[line.htm.length]='%'+(x++)+';'+oy+';3;'+(y-oy);p+=pru;oy=y;}else{p+=pr;}};line.htm[line.htm.length]='%'+x2+';'+oy+';3;'+(y2-oy+2);}}
};/*based on mkLine() from wz_jsgraphics.js  v. 2.3;Copyright (c) 2002-2004 Walter Zorn. All rights reserved.;Created 3. 11. 2002 by Walter Zorn (Web: http://www.walterzorn.com );Performance optimizations for Internet Explorer;by Thomas Frank and John Holdsworth;This program is free software;you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation;either version 2 of the License, or (at your option) any later version.This program is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied warranty of MERhandleANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the GNU General Public License at http://www.gnu.org/copyleft/gpl.html for more details.*/


penObj.prototype.drawHandle = function(handle, x0, y0){

	handle.style.left = (x0 - 5) + "px";
	handle.style.top = (y0 - 5) + "px";

	if (handle.style.visibility != "visible"){
		handle.style.visibility = "visible"
	}
}

penObj.prototype.setBoundaries = function(xMax,yMin,yMax){

	this.boundaryCoords = {xMax:parseInt(xMax), yMin:parseInt(yMin), yMax:parseInt(yMax)};

}

penObj.prototype.drawLabel = function(labelObj, x0, y0){

	with (labelObj.style){
		left = ((this.currLine.dragHandle.x0 > this.currLine.fixedHandle.x0)?(x0 + 5):(x0 - 35)) + "px";
		top = (y0 - 5) + "px";
	}

	if (labelObj.style.visibility != "visible"){
		labelObj.style.visibility = "visible"
	}

	labelObj.innerHTML = "&nbsp;" + this.getPctChange(
		this.getPctFromPx(this.currLine.fixedHandle.y0 - oY - this.heightUpperLegend),
		this.getPctFromPx(this.currLine.dragHandle.y0 - oY - this.heightUpperLegend)
	);

}

penObj.prototype.getPctFromPx = function(px){

	var pct = (100 * px) / this.heightChart;

	//window.status = "this.labelYMax = " + this.labelYMax

	return this.labelYMax - (((this.labelYMax - this.labelYMin)*pct) / 100);

}


penObj.prototype.setYAxisExtents = function(drawData){

	var data = drawData.split(",");

	this.labelYMax = data[0];
	this.labelYMin = data[1];

}

penObj.prototype.getPctChange = function(a, b){

	// a is previous, b is current.

	/*
	if (
		!isVal(a) ||
		!isVal(b) ||
		(a < 0 && b == 0) ||
		(a == 0 && b != 0) ||
		(a < 0 && b > 0) ||
		(a > 0 && b < 0)
	){
		return "NA"
	}
	*/

	return ((parseFloat(b) < parseFloat(a))?"-":"") + Math.round((Math.abs(b - a) / Math.abs(a)) * 100) + "%";

}


// EVENT HANDLERS


function penDown(e){

	if (!e) var e = window.event;

	if (pen.boundaryCoords && oX && oY){

		if (
			e.y - oY < pen.boundaryCoords.yMin ||
			e.y - oY > pen.boundaryCoords.yMax ||
			e.x - oX > pen.boundaryCoords.xMax
		){
			//return false;
		}

	}

	var srcElem = (e.srcElement) ? e.srcElement : e.currentTarget;

	// decide whether to create a new line or modify an existing one.

	if (/handle([AB])(\d+)/.test(srcElem.id)){

		var myHandle = RegExp.$1;

		if (myHandle == "A"){
			pen.selectLine(RegExp.$2, "A", "B");
		} else {
			pen.selectLine(RegExp.$2, "B", "A");
		}

	} else {

		pen.createNewLine();

	}

	chartEarnings.onmousemove = penTrack;
	chartEarnings.ondragstart = abortEvent;

	pen.currLine.dragHandle.onmouseover = penTrack;
	pen.currLine.dragHandle.onmousemove = penTrack;
	pen.currLine.dragHandle.ondragstart = abortEvent;

	if (e.pageX || e.pageY){

		posX = e.pageX;
		posY = e.pageY;

	} else if (e.clientX || e.clientY) {

		posX = e.clientX + document.body.scrollLeft;
		posY = e.clientY + document.body.scrollTop;

	} else {

		return false;

	}

	pen.down = true;

	if (srcElem.id == "chartEarnings"){
		pen.currLine.fixedHandle.x0 = posX;
		pen.currLine.fixedHandle.y0 = posY;
		pen.drawHandle(pen.currLine.fixedHandle, posX, posY);
	}

	pen.currLine.dragHandle.x0 = posX;
	pen.currLine.dragHandle.y0 = posY;

}

function penUp(e){

	if (!e) var e = window.event;

	pen.down = false;

	if (pen.currLine.dragHandle){

		pen.modifyHandleIcon(pen.currLine.dragHandle, false)

		chartEarnings.onmousemove = abortEvent;

		if (pen.currLine){

			pen.currLine.dragHandle.onmouseover = abortEvent;
			pen.currLine.dragHandle.onmousemove = abortEvent;
			pen.currLine.dragHandle.ondragstart = abortEvent;

		}
	}

}

function penTrack(e){

	// called with each mousemove event

	if (!e) var e = window.event;

	if (isLocked || !pen.down){return false;}

	if (e.pageX || e.pageY){

		posX = e.pageX;
		posY = e.pageY;

	} else if (e.clientX || e.clientY) {

		posX = e.clientX + document.body.scrollLeft;
		posY = e.clientY + document.body.scrollTop;

	} else {

		return false;

	}

	if (
		posY - oY < pen.boundaryCoords.yMin ||
		posY - oY > pen.boundaryCoords.yMax ||
		posX - oX > pen.boundaryCoords.xMax ||
		posX - oX < 0
	){
		return false;
	}

	pen.currLine.dragHandle.x0 = posX;
	pen.currLine.dragHandle.y0 = posY;
	pen.clearHTM(pen.currLine);

	pen.makeLine(
		pen.currLine.fixedHandle.x0 - 2,
		pen.currLine.fixedHandle.y0 - 2,
		posX - 2,
		posY - 2,
		pen.currLine
	);
	pen.paint(pen.currLine);
	pen.drawHandle(pen.currLine.dragHandle, posX, posY - 8);

	if (pen.labelYMin && pen.labelYMax){
		pen.drawLabel(pen.currLine.divLabel, posX, posY);
	}


	abortEvent(e);

}

function deleteLines(){

	var line;

	for (var x=0; x < pen.lines.length; x++){

		line = pen.lines[x]

		pen.clearHTM(line);
		line.canvas.innerHTML = "";
		line.dragHandle.style.visibility = "hidden";
		line.fixedHandle.style.visibility = "hidden";
		line.divLabel.style.visibility = "hidden";
		line.deleted = true;

	}

	pen.idx = -1;

	// deactivate 'remove lines' link
	document.getElementById("linkRemoveLines").className = "linkOff";

}

function hideLines(idx){

	// idx is optional, if provided we'll only hide one line.

	for (var x=0; x < pen.lines.length; x++){

		if (!idx || x == idx){

			pen.clearHTM(pen.lines[x]);
			pen.lines[x].canvas.innerHTML = "";
			pen.lines[x].dragHandle.style.visibility = "hidden";
			pen.lines[x].fixedHandle.style.visibility = "hidden";
			pen.lines[x].divLabel.style.visibility = "hidden";

		}

	}

	// deactivate 'remove lines' link
	document.getElementById("linkRemoveLines").className = "linkOff";

}

function restoreLines(){

	for (var x=0; x < pen.lines.length; x++){

		pen.clearHTM(pen.lines[x]);
		pen.lines[x].canvas.innerHTML = "";

	}

	var line

	for (var x=0; x < pen.lines.length; x++){

		line = pen.lines[x]

		if (!line.deleted){

			pen.makeLine(
				line.fixedHandle.x0 - 2,
				line.fixedHandle.y0 - 2,
				line.dragHandle.x0 - 2,
				line.dragHandle.y0 - 2,
				line
			);

			pen.drawHandle(line.dragHandle,line.dragHandle.x0, line.dragHandle.y0);
			pen.drawHandle(line.dragHandle, line.dragHandle.x0, line.dragHandle.y0);

			line.dragHandle.style.visibility = "visible";
			line.fixedHandle.style.visibility = "visible";
			line.divLabel.style.visibility = "visible";

			pen.paint(line);
		}

	}

	// reactivate 'remove lines' link

	for (var x=0; x < pen.lines.length; x++){
		if (!pen.lines[x].deleted){
			document.getElementById("linkRemoveLines").className = "linkOn";
		}
	}

}





// preloads
var gifCrosshair = new Image();			gifCrosshair.src='/tdameritrade/images/cH0.gif'
var gifCrosshair2 = new Image();		gifCrosshair2.src='/tdameritrade/images/cH1.gif'