
function Graphics(canvas) {
    this.canvas = canvas;
    this.cache = new Array;
    this.shapes = new Object;
    this.nObject = 0;

    // defaults
    this.penColor = "black";
    this.zIndex = 0;
}

Graphics.prototype.createPlotElement = function(x, y, w, h) {
    // detect canvas
    if (!this.oCanvas) {
        switch (typeof (this.canvas)) {
            case "string":
                this.oCanvas = document.getElementById(this.canvas);
                break;
            case "object":
                this.oCanvas = this.canvas;
                break;
            default:
                this.oCanvas = document.body;
                break;
        }
    }

    // retrieve DIV
    var oDiv;
    if (this.cache.length)
        oDiv = this.cache.pop();
    else {
        oDiv = document.createElement('div');
        this.oCanvas.appendChild(oDiv);

        oDiv.style.position = "absolute";
        oDiv.style.margin = "0px";
        oDiv.style.padding = "0px";
        oDiv.style.overflow = "hidden";
        oDiv.style.border = "0px";
    }

    // set attributes
    oDiv.style.zIndex = this.zIndex;
    oDiv.style.backgroundColor = this.penColor;

    oDiv.style.left = x;
    oDiv.style.top = y;
    oDiv.style.width = w + "px";
    oDiv.style.height = h + "px";

    oDiv.style.visibility = "visible";

//    var gr = new jsGraphics(document.getElementById("canvas"));
//    //Create jsColor object
//    var col = new jsColor("red");
//    //Create jsPen object
//    var pen = new jsPen(col, 1);
//    //Draw a Line between 2 points
//    var pt1 = new jsPoint(20, 30);
//    var pt2 = new jsPoint(120, 230);
//    gr.drawLine(pen, pt1, pt2);
//    //Draw filled circle with pt1 as center point and radius 30.
//    gr.fillCircle(col, pt1, 30);    

    return oDiv;
}

Graphics.prototype.releasePlotElement = function(oDiv) {
    oDiv.style.visibility = "hidden";
    this.cache.push(oDiv);
}

Graphics.prototype.addShape = function(shape) {
    shape.oGraphics = this;
    shape.graphicsID = this.nObject;
    this.shapes[this.nObject] = shape;
    this.nObject++;
    shape.draw();
    return shape;
}

Graphics.prototype.removeShape = function(shape) {
    if ((shape instanceof Object) &&
		(shape.oGraphics == this) &&
		(this.shapes[shape.graphicsID] == shape)) {
        shape.undraw();
        this.shapes[shape.graphicsID] = undefined;
        shape.oGraphics = undefined;
    }
}
Graphics.prototype.clear = function() {
    for (var i in this.shapes)
        this.removeShape(this.shapes[i]);
}


//=============================================================================
// Point
Graphics.prototype.drawPoint = function(x, y) {
    return this.addShape(new Point(x, y))
}

function Point(x, y) {
    this.x = x;
    this.y = y;
}
Point.prototype.draw = function() {
    this.oDiv = this.oGraphics.createPlotElement(this.x, this.y, 1, 1);
}
Point.prototype.undraw = function() {
    this.oGraphics.releasePlotElement(this.oDiv);
    this.oDiv = undefined;
}

//=============================================================================
// Line
Graphics.prototype.drawLine = function(x1, y1, x2, y2) {
    return this.addShape(new Line(x1, y1, x2, y2))
}

function Line(x1, y1, x2, y2) {
    this.x1 = x1;
    this.y1 = y1;
    this.x2 = x2;
    this.y2 = y2;
}

Line.prototype.draw = function() {
    this.plots = new Array;

    var dx = this.x2 - this.x1;
    var dy = this.y2 - this.y1;
    var x = this.x1;
    var y = this.y1;

    var n = Math.max(Math.abs(dx), Math.abs(dy));
    dx = dx / n;
    dy = dy / n;
    for (i = 0; i <= n; i++) {
        this.plots.push(this.oGraphics.createPlotElement(Math.round(x), Math.round(y), 1, 1));

        x += dx;
        y += dy;
    }
}
Line.prototype.undraw = function() {
    while (this.plots.length)
        this.oGraphics.releasePlotElement(this.plots.pop());
    this.plots = undefined;
}

//=============================================================================
// Circle
Graphics.prototype.drawCircle = function(x, y, r) {
    return this.addShape(new Circle(x, y, r))
}

function Circle(x, y, r) {
    this.x = x;
    this.y = y;
    this.radius = r;
}

Circle.prototype.draw = function() {
    this.plots = new Array;

    var r2 = this.radius * this.radius;
    var x = 0;
    var y = this.radius;

    while (x <= y) {
        this.plots.push(this.oGraphics.createPlotElement(Math.round(this.x + x), Math.round(this.y + y), 1, 1));
        this.plots.push(this.oGraphics.createPlotElement(Math.round(this.x - x), Math.round(this.y + y), 1, 1));
        this.plots.push(this.oGraphics.createPlotElement(Math.round(this.x + x), Math.round(this.y - y), 1, 1));
        this.plots.push(this.oGraphics.createPlotElement(Math.round(this.x - x), Math.round(this.y - y), 1, 1));
        this.plots.push(this.oGraphics.createPlotElement(Math.round(this.x + y), Math.round(this.y + x), 1, 1));
        this.plots.push(this.oGraphics.createPlotElement(Math.round(this.x + y), Math.round(this.y - x), 1, 1));
        this.plots.push(this.oGraphics.createPlotElement(Math.round(this.x - y), Math.round(this.y + x), 1, 1));
        this.plots.push(this.oGraphics.createPlotElement(Math.round(this.x - y), Math.round(this.y - x), 1, 1));

        x++;
        y = Math.round(Math.sqrt(r2 - x * x));
    }
}
Circle.prototype.undraw = Line.prototype.undraw;

//=============================================================================
// FillRectangle
Graphics.prototype.fillRectangle = function(x, y, w, h) {
    return this.addShape(new FillRectangle(x, y, w, h))
}

function FillRectangle(x, y, w, h) {
    this.x = x;
    this.y = y;
    this.w = w;
    this.h = h;
}

FillRectangle.prototype.draw = function() {
    this.oDiv = this.oGraphics.createPlotElement(this.x, this.y, this.w, this.h);
}
FillRectangle.prototype.undraw = Point.prototype.undraw;

//=============================================================================

function drawProp() {
    if (p) gr.removeShape(p);

    var x = Math.round(Math.sin(a) * 45);
    var y = Math.round(Math.cos(a) * 45);
    a -= Math.PI / 25;
    gr.penColor = "black";
    p = gr.drawLine(100 + x, 100 + y, 100 - x, 100 - y);
    window.setTimeout("drawProp();", 10);
}

function drawShapes() {
    gr.penColor = "red";
    gr.drawLine(10, 10, 190, 190);

    gr.penColor = "green";
    gr.drawLine(190, 10, 10, 190);

    gr.penColor = "blue";
    c = gr.drawCircle(100, 100, 45);

    gr.zIndex = 1;
    gr.penColor = "lime";
    gr.fillRectangle(50, 70, 100, 20);
    gr.zIndex = 0;

    drawProp();
}


