/* Canvas 2d context - roundRect
 *
 * Accepts 5 parameters, the start_x and start_y points, the end_x and end_y points, and the radius of the corners
 * 
 * No return value
 */

interface CanvasRenderingContext2D {
    roundRect  (x: number, y: number, w: number, h: number, r: number);
    dashedLine  (x1: number, y1: number, x2: number, y2: number, dashLen: number);
    dashedRect (x: number, y: number, w: number, h: number, dashLen: number);
}

let __CanvasRenderingContext2DPrototype: CanvasRenderingContext2D
    = CanvasRenderingContext2D.prototype;

__CanvasRenderingContext2DPrototype.roundRect = function (x, y, w, h, r) {
    let ex = x + w;
    let ey = y + h;

    let r2d = Math.PI / 180;

    // ensure that the radius isn't too large for x
    if ((ex - x) - (2 * r) < 0)
        r = ((ex - x) / 2);

    // ensure that the radius isn't too large for y
    if ((ey - y) - (2 * r) < 0)
        r = ((ey - y) / 2);

    this.beginPath();
    this.moveTo(x + r, y);
    this.lineTo(ex - r, y);
    this.arc(ex - r, y + r, r, r2d * 270, r2d * 360, false);
    this.lineTo(ex, ey - r);
    this.arc(ex - r, ey - r, r, r2d * 0, r2d * 90, false);
    this.lineTo(x + r, ey);
    this.arc(x + r, ey - r, r, r2d * 90, r2d * 180, false);
    this.lineTo(x, y + r);
    this.arc(x + r, y + r, r, r2d * 180, r2d * 270, false);
    this.closePath();
};

__CanvasRenderingContext2DPrototype.dashedLine = function (x1, y1, x2, y2,
                                                           dashLen) {

    this.moveTo(x1, y1);

    let dX = x2 - x1;
    let dY = y2 - y1;
    let dashes = Math.floor(Math.sqrt(dX * dX + dY * dY) / dashLen);
    let dashX = dX / dashes;
    let dashY = dY / dashes;

    let q = 0;
    while (q++ < dashes) {
        x1 += dashX;
        y1 += dashY;
        this[q % 2 == 0 ? 'moveTo' : 'lineTo'](x1, y1);
    }
    this[q % 2 == 0 ? 'moveTo' : 'lineTo'](x2, y2);
};

__CanvasRenderingContext2DPrototype.dashedRect = function (x, y, w, h, dashLen) {
    if (dashLen == 0) {
        this.beginPath();
        this.rect(x, y, w, h);
        this.closePath();
    } else {
        this.beginPath();
        let ex = x + w;
        let ey = y + h;
        this.dashedLine(x, y, ex, y, dashLen);
        this.dashedLine(ex, y, ex, ey, dashLen);
        this.dashedLine(ex, ey, x, ey, dashLen);
        this.dashedLine(x, ey, x, y, dashLen);
        this.closePath();
    }
};
