/****************************************************************
  *                                                              *
  *  curvyCorners                                                *
  *  ------------                                                *
  *                                                              *
  *  This script generates rounded corners for your divs.        *
  *                                                              *
  *                                                              *
  *  Version 1.00 beta                                           *
  *  Copyright (c) 2006 Cameron Cooke                            *
  *  By: Cameron Cooke and Tim Hutchison.                        *
  *                                                              *
  *  Website: http://www.curvycorners.net                        *
  *  Email:   info@totalinfinity.com                             *
  *                                                              *
  *                                                              *
  *  This library is free software; you can redistribute         *
  *  it and/or modify it under the terms of the GNU              *
  *  Lesser General Public License as published by the           *
  *  Free Software Foundation; either version 2.1 of the         *
  *  License, or (at your option) any later version.             *
  *                                                              *
  *  This library is distributed in the hope that it will        *
  *  be useful, but WITHOUT ANY WARRANTY; without even the       *
  *  implied warranty of MERCHANTABILITY or FITNESS FOR A        *
  *  PARTICULAR PURPOSE. See the GNU Lesser General Public       *
  *  License for more details.                                   *
  *                                                              *
  *  You should have received a copy of the GNU Lesser           *
  *  General Public License along with this library;             *
  *  Inc., 59 Temple Place, Suite 330, Boston,                   *
  *  MA 02111-1307 USA                                           *
  *                                                              *
  ****************************************************************/

// Attach load event
xAttachEventOnLoad("load", cornerInt);

function cornerInt(){
    // Get all DIV elements
    var divElements = document.getElementsByTagName("DIV");
    var divCount = divElements.length;
    var t = 0;
    objsArray = new Array();

    // Loop through all DIVs
    for(var i = 0; i < divCount; i++){
        var currentDiv = divElements[i];
        if(radius = currentDiv.getAttribute("radius")){
            if(!(corners = currentDiv.getAttribute("corners")))
                corners = "TR,TL,BR,BL";
            var newObj = new curvyCorners(currentDiv, radius, corners);
            objsArray[t] = newObj;
            t++;
        }
    }

    //alert(objsArray);
    var arrayLength = objsArray.length;
    for(var x = 0; x < arrayLength; x++){
        objsArray[x].doCorners();
    }
}

// ------------- curvyCorners OBJECT

function curvyCorners(boxObj, radiusInt, cornersCSVStr) {
    // Set objects properties
    this.box      = boxObj;
    this.radius   = (Math.round(parseInt(radiusInt)/2))*2;
    this.corners  = cornersCSVStr.split(","); // Array

    // Setup global variables
    this.masterCorner     = null;
    this.masterCornerType = null;
    this.cornersAvailable = new Array("TR", "TL", "BR", "BL");

    // Get box formatting details and set properties
    this.boxHeight    = parseInt(((this.box.style.height != "")? this.box.style.height.substring(0, this.box.style.height.indexOf("px")) : this.box.scrollHeight));
    this.boxWidth     = parseInt(((this.box.style.width != "")? this.box.style.width.substring(0, this.box.style.width.indexOf("px")) : this.box.scrollWidth));
    this.borderWidth  = parseInt(((this.box.style.borderWidth != "")? this.box.style.borderWidth.slice(0, this.box.style.borderWidth.indexOf("px")) : 0));
    this.boxColour    = ((this.box.style.backgroundColor.substr(0, 3) == "rgb")? rgb2Hex(this.box.style.backgroundColor) : this.box.style.backgroundColor);
    this.borderColour = ((this.box.style.borderColor != "" && this.borderWidth > 0)? ((this.box.style.borderColor.substr(0, 3) == "rgb")? rgb2Hex(this.box.style.borderColor) : this.box.style.borderColor) : this.boxColour);
    this.borderRadius = parseInt(this.radius - this.borderWidth);
    this.borderString = this.borderWidth + "px" + " solid " + this.borderColour;
    this.posStart = (0 - this.radius);
    this.posAdjust = (Math.floor(Math.sqrt(Math.pow((this.radius - this.borderWidth),2)/2)));

    // Make box relative if not already absolute
    if(this.box.style.position != "absolute") this.box.style.position = "relative";

    // Builds the corners
    this.doCorners = function()
    {
        // Loop once for each corner specfied
        for(var i in this.cornersAvailable)
        {
            // Get current corner type from array
            var currentCorner = this.cornersAvailable[i];

            if(inArray(this.corners, currentCorner) === false)
            {
                // No corner is to be rounded so we generated a square to fill the gap
                var newCorner = document.createElement("DIV");

                // Setup corners properties
                newCorner.style.height   = this.radius - this.borderWidth + "px";
                newCorner.style.width    = this.radius - this.borderWidth + "px";
                newCorner.style.position = "absolute";
                newCorner.style.fontSize = "1px";
                newCorner.style.overflow = "hidden";
                newCorner.style.backgroundColor = this.boxColour;

                switch(currentCorner)
                {
                    case "TL":
                        newCorner.style.borderLeft = this.borderString;
                        newCorner.style.borderTop  = this.borderString;
                        break;
                    case "TR":
                        newCorner.style.borderRight = this.borderString;
                        newCorner.style.borderTop   = this.borderString;
                        break;
                    case "BL":
                        newCorner.style.borderLeft   = this.borderString;
                        newCorner.style.borderBottom = this.borderString;
                        break;
                    case "BR":
                        newCorner.style.borderRight  = this.borderString;
                        newCorner.style.borderBottom = this.borderString;
                        break;
                }
            }
            else{
                /*
        To increase performace we only ever generate one corner.
        This corner is the bottom right corner. If more that one corner is requested
        then the other corners will be a cloned version of the first corner.
        */
                if(this.masterCorner != null)
                {
                    // Create clone of the master corner
                    var newCorner = this.masterCorner.cloneNode(true);
                }
                else
                {
                    // First time round so generate the master corner
                    var newCorner = document.createElement("DIV");

                    // Setup corners properties
                    newCorner.style.height   = this.radius + "px";
                    newCorner.style.width    = this.radius + "px";
                    newCorner.style.position = "absolute";
                    newCorner.style.fontSize = "1px";
                    newCorner.style.overflow = "hidden";

                    // Cycle the x-axis
                    for(var intx = 0; intx < this.radius; intx++)
                    {
                        // Calculate the value of y1 which identifies the pixels inside the border
                        if((intx +1) >= this.borderRadius)
                            var y1 = -1;
                        else
                            var y1 = (Math.floor(Math.sqrt(Math.pow(this.borderRadius, 2) - Math.pow((intx+1), 2))) - 1);

                        // Only calculate y2 and y3 if there is a border defined
                        if(this.borderRadius != this.radius)
                        {
                            if((intx) >= this.borderRadius)
                                var y2 = -1;
                            else
                                var y2 = Math.ceil(Math.sqrt(Math.pow(this.borderRadius,2) - Math.pow(intx, 2)));
                            if((intx+1) >= this.radius)
                                var y3 = -1;
                            else
                                var y3 = (Math.floor(Math.sqrt(Math.pow(this.radius,2) - Math.pow((intx+1), 2))) - 1);
                        }

                        // Calculate y4
                        if((intx) >= this.radius)
                            var y4 = -1;
                        else
                            var y4 = Math.ceil(Math.sqrt(Math.pow(this.radius,2) - Math.pow(intx, 2)));

                        // Draw bar on inside of the border with foreground colour
                        if(y1 > -1) this.drawPixel(intx, 0, this.boxColour, 100, (y1+1), newCorner);

                        // Only draw border/foreground antialiased pixels and border if there is a border defined
                        if(this.borderRadius != this.radius)
                        {
                            // Cycle the y-axis
                            for(var inty = (y1 + 1); inty < y2; inty++)
                            {
                                // For each of the pixels that need anti aliasing between the foreground and border colour draw single pixel divs
                                var pixelcolour = BlendColour(this.boxColour, this.borderColour, pixelFraction(intx, inty, this.borderRadius));
                                this.drawPixel(intx, inty, pixelcolour, 100, 1, newCorner);
                            }

                            // Draw bar for the border
                            if(y3 >= y2)
                            {
                                if (y1 == -1)
                                    y1 = 0;
                                this.drawPixel(intx, y2, this.borderColour, 100, (y3 - y2 + 1), newCorner);
                            }

                            // Set the colour for the outside curve
                            var outsideColour = this.borderColour;
                        }
                        else
                        {
                            // Set the coour for the outside curve
                            var outsideColour = this.boxColour;
                            var y3 = y1;
                        }

                        // Cycle the y-axis and draw the anti aliased pixels on the outside of the curve
                        for(var inty = (y3 + 1); inty < y4; inty++)
                        {
                            // For each of the pixels that need anti aliasing between the foreground/border colour & background draw single pixel divs
                            this.drawPixel(intx, inty, outsideColour, (pixelFraction(intx, inty ,this.radius) * 100), 1, newCorner);
                        }
                    }
                    // Store corner as master corner
                    this.masterCorner = newCorner.cloneNode(true);
                    this.masterCornerType = "BR";
                }
            }

            /*
      Now we have a new corner we need to reposition all the pixels unless
      the current corner is the bottom right/
      */
            if(currentCorner != "BR")
            {
                // Loop through all children (pixel bars)
                var pixelCount = newCorner.childNodes.length;
                for(var t = 0; t < pixelCount; t++)
                {
                    // Get current pixel bar
                    var pixelBar = newCorner.childNodes[t];

                    // Get current top and left properties
                    var pixelBarTop    = parseInt(pixelBar.style.top.substring(0, pixelBar.style.top.indexOf("px")));
                    var pixelBarLeft   = parseInt(pixelBar.style.left.substring(0, pixelBar.style.left.indexOf("px")));
                    var pixelBarHeight = parseInt(pixelBar.style.height.substring(0, pixelBar.style.height.indexOf("px")));

                    // Reposition pixels
                    if(currentCorner == "TL" || currentCorner == "BL"){
                        pixelBar.style.left = this.radius -pixelBarLeft -1 + "px"; // Left
                    }
                    if(currentCorner == "TR" || currentCorner == "TL"){
                        pixelBar.style.top =  this.radius -pixelBarHeight -pixelBarTop + "px"; // Top
                    }
                }
            }

            // Position the container
            switch(currentCorner)
            {
                case "TL":
                    newCorner.style.top  = (this.posStart + this.posAdjust) + "px";
                    newCorner.style.left = (this.posStart + this.posAdjust) + "px";
                    break;

                case "TR":
                    newCorner.style.top  = (this.posStart + this.posAdjust) + "px";
                    newCorner.style.left = (this.boxWidth - this.posAdjust) + "px";
                    break;

                case "BL":
                    newCorner.style.top = (this.boxHeight - this.posAdjust) + "px";
                    newCorner.style.left = (this.posStart + this.posAdjust) + "px";
                    break;

                case "BR":
                    newCorner.style.top = (this.boxHeight - this.posAdjust)+ "px";
                    newCorner.style.left = (this.boxWidth - this.posAdjust)+ "px";
                    break;
            }

            // Append new corner
            this.box.appendChild(newCorner);

            /*
      We have now drawn all the corner required so we now need to
      put on the finishing touches.
      */

            // Draw bars ----------------------------------------------

            // Turn off current borders
            this.box.style.borderWidth = "0px";

            for(var s = 0; s < 4; s++)
            {
                // Create bar
                var bar = document.createElement("DIV");

                // Set the bars properties
                bar.style.height   = this.boxHeight + "px";
                bar.style.width    = this.boxWidth + "px";
                bar.style.position = "absolute";
                bar.style.fontSize = "1px";
                bar.style.overflow = "hidden";
                bar.style.backgroundColor = this.boxColour;
                //bar.style.backgroundColor = "#663322";

                switch(s)
                {
                    // Left
                    case 0:
                        bar.style.top = this.posAdjust + "px";
                        bar.style.left = (this.posStart + this.posAdjust) + "px";
                        bar.style.width = (this.radius - this.posAdjust - this.borderWidth) + "px";
                        bar.style.height = (this.boxHeight - (2 * this.posAdjust)) + "px";
                        bar.style.borderLeft = this.borderString;
                        break;
                    // Right
                    case 1:
                        bar.style.top = this.posAdjust + "px";
                        bar.style.right = (this.posStart + this.posAdjust) + "px";
                        bar.style.width = (this.radius - this.posAdjust - this.borderWidth) + "px";
                        bar.style.height = (this.boxHeight - (2 * this.posAdjust)) + "px";
                        bar.style.borderRight = this.borderString;
                        break;
                    // Top
                    case 2:
                        bar.style.top = (this.posStart + this.posAdjust) + "px";
                        bar.style.left = this.posAdjust + "px";
                        bar.style.height = (this.radius - this.posAdjust - this.borderWidth) + "px";
                        bar.style.width = (this.boxWidth - (2 * this.posAdjust)) + "px";
                        bar.style.borderTop = this.borderString;
                        break;
                    // Bottom
                    case 3:
                        bar.style.bottom = (this.posStart + this.posAdjust) + "px";
                        bar.style.left = this.posAdjust + "px";
                        bar.style.height = (this.radius - this.posAdjust - this.borderWidth) + "px";
                        bar.style.width = (this.boxWidth - (2 * this.posAdjust)) + "px";
                        bar.style.borderBottom = this.borderString;
                        break;
                }
                // Append bar
                this.box.appendChild(bar);
            }
        }
    }

    this.drawPixel = function(intx, inty, colour, transAmount, height, newCorner) {
        // Create pixel
        var pixel = document.createElement("DIV");
        pixel.style.height   = height + "px";
        pixel.style.width    = "1px";
        pixel.style.position = "absolute";
        pixel.style.fontSize = "1px";
        pixel.style.overflow = "hidden";
        pixel.style.backgroundColor = colour;

        // Set opacity if the transparency is anything other than 100
        if (transAmount != 100)
            setOpacity(pixel, transAmount);

        // Set the pixels position
        pixel.style.top = inty + "px";
        pixel.style.left = intx + "px";
        newCorner.appendChild(pixel);
    }
}

// ------------- UTILITY FUNCTIONS

/*
Blends the two colours by the fraction
returns the resulting colour as a string in the format "#FFFFFF"
*/
function BlendColour(Col1, Col2, Col1Fraction) {
    var red1 = parseInt(Col1.substr(1,2),16);
    var green1 = parseInt(Col1.substr(3,2),16);
    var blue1 = parseInt(Col1.substr(5,2),16);
    var red2 = parseInt(Col2.substr(1,2),16);
    var green2 = parseInt(Col2.substr(3,2),16);
    var blue2 = parseInt(Col2.substr(5,2),16);

    if(Col1Fraction > 1 || Col1Fraction < 0) Col1Fraction = 1;

    var endRed = Math.round((red1 * Col1Fraction) + (red2 * (1 - Col1Fraction)));
    if(endRed > 255) endRed = 255;
    if(endRed < 0) endRed = 0;

    var endGreen = Math.round((green1 * Col1Fraction) + (green2 * (1 - Col1Fraction)));
    if(endGreen > 255) endGreen = 255;
    if(endGreen < 0) endGreen = 0;

    var endBlue = Math.round((blue1 * Col1Fraction) + (blue2 * (1 - Col1Fraction)));
    if(endBlue > 255) endBlue = 255;
    if(endBlue < 0) endBlue = 0;

    return "#" + IntToHex(endRed)+ IntToHex(endGreen)+ IntToHex(endBlue);
}

/*
Converts a number to hexadecimal format
*/
function IntToHex(strNum) {
    base = strNum / 16;
    rem = strNum % 16;
    base = base - (rem / 16);
    baseS = MakeHex(base);
    remS = MakeHex(rem);
    return baseS + '' + remS;
}


/*
gets the hex bits of a number
*/
function MakeHex(x) {
    if((x >= 0) && (x <= 9))
    {
        return x;
    }
    else
    {
        switch(x)
        {
            case 10:
                return "A";
            case 11:
                return "B";
            case 12:
                return "C";
            case 13:
                return "D";
            case 14:
                return "E";
            case 15:
                return "F";
        }
    }
}


/*
For a pixel cut by the line determines the fraction of the pixel on the 'inside' of the
line.  Returns a number between 0 and 1
*/
function pixelFraction(x, y, r) {
    var pixelfraction = 0;

    /*
  determine the co-ordinates of the two points on the perimeter of the pixel that the
  circle crosses
  */
    var xvalues = new Array(1);
    var yvalues = new Array(1);
    var point = 0;
    var whatsides = "";

    // x + 0 = Left
    var intersect = Math.sqrt((Math.pow(r,2) - Math.pow(x,2)));

    if ((intersect >= y) && (intersect < (y+1))) {
        whatsides = "Left";
        xvalues[point] = 0;
        yvalues[point] = intersect - y;
        point =  point + 1;
    }
    // y + 1 = Top
    var intersect = Math.sqrt((Math.pow(r,2) - Math.pow(y+1,2)));

    if ((intersect >= x) && (intersect < (x+1))) {
        whatsides = whatsides + "Top";
        xvalues[point] = intersect - x;
        yvalues[point] = 1;
        point = point + 1;
    }
    // x + 1 = Right
    var intersect = Math.sqrt((Math.pow(r,2) - Math.pow(x+1,2)));

    if ((intersect >= y) && (intersect < (y+1))) {
        whatsides = whatsides + "Right";
        xvalues[point] = 1;
        yvalues[point] = intersect - y;
        point =  point + 1;
    }
    // y + 0 = Bottom
    var intersect = Math.sqrt((Math.pow(r,2) - Math.pow(y,2)));

    if ((intersect >= x) && (intersect < (x+1))) {
        whatsides = whatsides + "Bottom";
        xvalues[point] = intersect - x;
        yvalues[point] = 0;
    }

    /*
  depending on which sides of the perimeter of the pixel the circle crosses calculate the
  fraction of the pixel inside the circle
  */
    switch (whatsides) {
        case "LeftRight":
            pixelfraction = Math.min(yvalues[0],yvalues[1]) + ((Math.max(yvalues[0],yvalues[1]) - Math.min(yvalues[0],yvalues[1]))/2);
            break;
        case "TopRight":
            pixelfraction = 1-(((1-xvalues[0])*(1-yvalues[1]))/2);
            break;
        case "TopBottom":
            pixelfraction = Math.min(xvalues[0],xvalues[1]) + ((Math.max(xvalues[0],xvalues[1]) - Math.min(xvalues[0],xvalues[1]))/2);
            break;
        case "LeftBottom":
            pixelfraction = (yvalues[0]*xvalues[1])/2;
            break;
        default:
            pixelfraction = 1;
    }

    return pixelfraction;
}

// This function converts CSS rgb(x, x, x) to hexadecimal
function rgb2Hex(rgbColour) {
    try{
        // Remove rgb()
        var rgbValues = rgbColour.substring(4, rgbColour.indexOf(")"));

        // Split RGB into array
        var rgbArray = rgbValues.split(", ");

        // Get RGB values
        var red   = parseInt(rgbArray[0]);
        var green = parseInt(rgbArray[1]);
        var blue  = parseInt(rgbArray[2]);

        // Build hex colour code
        var hexColour = "#" + IntToHex(red) + IntToHex(green) + IntToHex(blue);
    }
    catch(e){
        alert("There was an error converting the RGB value to Hexadecimal in function rgb2Hex");
    }

    return hexColour;
}

// Function by Simon Willison from sitepoint.com
function setOpacity(obj, opacity) {
    opacity = (opacity == 100)?99.999:opacity;

    // IE/Win
    obj.style.filter = "alpha(opacity:"+opacity+")";

    // Safari<1.2, Konqueror
    obj.style.KHTMLOpacity = opacity/100;

    // Older Mozilla and Firefox
    obj.style.MozOpacity = opacity/100;

    // Safari 1.2, newer Firefox and Mozilla, CSS3
    obj.style.opacity = opacity/100;
}

/*
Returns index if the passed value is found in the
array otherwise returns false.
*/
function inArray(array, value) {
    for(var i = 0; i < array.length; i++){

        // Matches identical (===), not just similar (==).
        if (array[i] === value) return i;
    }
    return false;
}

/*
Returns true if the passed value is found as a key
in the array otherwise returns false.
*/
function inArrayKey(array, value) {
    for(key in array){
        // Matches identical (===), not just similar (==).
        if(key === value) return true;
    }
    return false;
}

// Attaches onload event cross browser
function xAttachEventOnLoad(event, func) {
    // Attach event
    if(window.addEventListener)
        window.addEventListener(event, func, false);
    else if(window.attachEvent)
        window.attachEvent("on" + event, func);
    else
        window.onload = func;
}

