
 /****************************************************************
  *                                                              *
  *  curvyCorners                                                *
  *  ------------                                                *
  *                                                              *
  *  This script generates rounded corners for your divs.        *
  *                                                              *
  *  Usage:                                                      *
  *                                                              *
  *    var radius = 20;                                          *
  *    var myObj = new curvyCorners("myDivId", radius);          *
  *    myObj.doCorners("TL,TR,BL,BR");                           *
  *                                                              *
  *  Version 0.10 alpha                                          *
  *  Copyright (c) 2006 Cameron Cooke                            *
  *  By: Cameron Cooke and Tim Hutchison.                        *
  *                                                              *
  *  Website: http://www.roundedcorners.net                      *
  *  Email:   info@roundedcorners.net                            *
  *                                                              *
  *                                                              *
  *  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                                           *
  *                                                              *
  ****************************************************************/
  
  function curvyCorners(boxName, radius){
      
    // Set div object
    this.box  = document.getElementById(boxName);   
    
    // Get box height
    if(this.box.style.height != "")
      this.boxHeight = this.box.style.height.substring(0, this.box.style.height.indexOf("px"));
    else
      this.boxHeight = this.box.scrollHeight;
      
    // Get box width
    if(this.box.style.width != "")
      this.boxWidth = this.box.style.width.substring(0, this.box.style.width.indexOf("px"));
    else
      this.boxWidth  = this.box.scrollWidth;
      
    // Make box relative     
    if(this.box.style.position != "absolute"){
      this.box.style.position = "relative";
    }               
    
    /*
    * Get border info
    *
    * As border is returned in the format Xpx Xpx Xpx Xpx on Firefox and Safari we will take the
    * first border width and use this, stripping off the px.
    */
    this.borderWidth = parseInt(((this.box.style.borderWidth != "")? this.box.style.borderWidth.slice(0, this.box.style.borderWidth.indexOf("px")) : 0));
    
    // Get border color if border set
    if(this.box.style.borderColor != "" && this.borderWidth > 0){
        
        // Retrieve from either RGB format of Hex format
        if(this.box.style.borderColor.substr(0, 3) == "rgb"){
            
            // Colour is stored in RGB format so convert to hexadecimal
            this.borderColor = rgb2Hex(this.box.style.borderColor); 
        }
        else{
            
            // Colour is stored in Hex format
            this.borderColor = this.box.style.borderColor;
        }
    }
    else{
        
        // No border
        this.borderColor = "";
    }
    
    // Turn off existing border
    this.box.style.borderWidth = "0px";
    
    // Sets the radius property - fix to make the size property an even number to sort bug with odd numbers      
    this.radius = (Math.round(parseInt(radius)/2))*2; 
     
    // This method builds the rounded corners
    this.doCorners = function(cornersCSV)
        {
        
        /*
        Get box foreground colour, if rgb convert
        */
        if(this.box.style.backgroundColor.substr(0, 3) == "rgb")
          foregroundColour = rgb2Hex(this.box.style.backgroundColor);
        else
          foregroundColour = this.box.style.backgroundColor;
          
        // Get corners to round
        var cornersReq = cornersCSV.split(",");
        
        // Loop through each corner
        for(var key in cornersReq){
            
            // Get current corner
            var currentCorner = cornersReq[key];
            
            // Create bar
            var bar = document.createElement("DIV");
            
            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 = foregroundColour;
            
            // Create cornerContainer
            var cornerContainer = document.createElement("DIV");
            
            cornerContainer.style.height = this.radius + "px";
            cornerContainer.style.width = this.radius + "px";
            cornerContainer.style.position = "absolute";
            cornerContainer.style.fontSize = "1px";
            cornerContainer.style.overflow = "hidden";
            //cornerContainer.style.backgroundColor = "#ff0000";

            // Get corners and bar start positions            
            var posStart = 0 - this.radius;
 //           var barStart = posStart + this.borderWidth;
                        
            // Position the container
            switch(currentCorner)
                {
                case "TL":
                  cornerContainer.style.top  =  posStart + "px";
                  cornerContainer.style.left = posStart + "px";
                  
                  // Left Bar
                  bar.style.top = "0px";
                  bar.style.left = posStart + "px";                  
                  bar.style.width = this.radius - this.borderWidth + "px";
                  
                  // Apply existing border
                  bar.style.borderLeftStyle = "solid";
                  bar.style.borderLeftColor = this.borderColor;
                  bar.style.borderLeftWidth = this.borderWidth + "px";
                  break;
                
                case "TR":
                  cornerContainer.style.top  = posStart + "px";
                  cornerContainer.style.right = posStart + "px";

                  // Right Bar
                  bar.style.top = "0px";
                  bar.style.right = posStart + "px";                  
                  bar.style.width = this.radius + this.borderWidth + "px";

                  // Apply existing border
                  bar.style.borderRightStyle = "solid";
                  bar.style.borderRightColor = this.borderColor;
                  bar.style.borderRightWidth = this.borderWidth + "px";
                  break;
                
                case "BL":
                  cornerContainer.style.bottom = posStart + "px";
                  cornerContainer.style.left = posStart + "px";
                  
                  // Top Bar
                  bar.style.top = posStart + "px";
                  bar.style.left = "0px";                  
                  bar.style.height = this.radius - this.borderWidth + "px";
                  
                  // Apply existing border
                  bar.style.borderTopStyle = "solid";
                  bar.style.borderTopColor = this.borderColor;
                  bar.style.borderTopWidth = this.borderWidth + "px";
                  break;
                
                case "BR":
                  cornerContainer.style.bottom = posStart + "px";
                  cornerContainer.style.right = posStart + "px";

                  // Bottom Bar
                  bar.style.bottom = posStart + "px";
                  bar.style.left = "0px";                  
                  bar.style.height = this.radius - this.borderWidth + "px";
                  
                  // Apply existing border
                  bar.style.borderBottomStyle = "solid";
                  bar.style.borderBottomColor = this.borderColor;
                  bar.style.borderBottomWidth = this.borderWidth + "px";
                  break;
                }
                
                // Append container
                this.box.appendChild(cornerContainer);
                
            // Get boxes parent
            var boxParent = this.box.parentNode;

            // Get parent background colour
            do{
            
                // Get colour property
                if(boxParent.style.backgroundColor != "undefined") var styleColour = boxParent.style.backgroundColor;
            }
            while(styleColour == "" && boxParent.tagName != "body" && (boxParent = boxParent.parentNode))

            // If colour is in RGB format convert to hexadecimal
            if(styleColour.substr(0, 3) == "rgb")
              styleColour = rgb2Hex(styleColour);
            
            /*
            We now need to get the border colour, but if no border we need to set
            border colour anyway to the box foreground colour.
            */
            if(this.borderColor == ""){
                
                if(this.box.style.backgroundColor.substr(0, 3) == "rgb")
                  bordercol = rgb2Hex(this.box.style.backgroundColor)
                else
                  bordercol = this.box.style.backgroundColor;
            }
            else{
                
                // Set border colour
                var bordercol = this.borderColor;
            }
            
            // Loop through x axis
            for(var intx = 0; intx < this.radius; intx++)
                {

                // Pixel bar height counter
                var prevPixelColour = "";
                var prevTransAmount = "";
                                
                // Loop through y axis
                for(var inty = 0; inty < this.radius; inty++)
                    {
                    //if(pixelStatus(intx, inty, this.radius - ((this.borderWidth == "")? 0 : this.borderWidth)) != "outside")
                    
                    if(pixelStatus(intx, inty, this.radius) != "outside")
                        {
                     
                        var pixelColourArray = pixelColour(intx, inty, this.radius, ((this.borderWidth == "")? 0 : this.borderWidth), foregroundColour, bordercol, styleColour);
                         
                        // Get colour of current pixel
                        var currentPixelColour = pixelColourArray[0];
                        var currentTransAmount = pixelColourArray[1];
                        // if the previous pixel colour has not yet been set then make it the current pixel colour
                        if (prevPixelColour == "")
                            {
                            // Set previous pixel colour to new colour
                            prevPixelColour = currentPixelColour;          
                            prevTransAmount = currentTransAmount;
                            // Set previous pixel y
                            prevPixelY = inty;
                            // Reset pixelHeight
                            pixelHeight = 1;
                            }
                        else
                            {
                            // if the current pixel is the same as the previous pixel then just change the height of the div
                            if (prevPixelColour == currentPixelColour && prevTransAmount == currentTransAmount)
                                {
                                // Increment pixel height
                                pixelHeight++;
                                }
                            else
                                {
                                // BUILD PIXEL (BAR)
                                drawPixel(prevPixelY, intx, prevPixelColour, prevTransAmount, pixelHeight, currentCorner, cornerContainer);
                                // Set previous pixel colour to new colour
                                prevPixelColour = currentPixelColour;          
                                prevTransAmount = currentTransAmount;
                                // Set previous pixel y
                                prevPixelY = inty;
                                // Reset pixelHeight
                                pixelHeight = 1;								

								}
							} 
						}
						if(inty == this.radius-1) 
							{
							                     // if this is the last value of inty then we must draw a div
                            // BUILD PIXEL (BAR)
                         //   alert("drawing last y");
                            drawPixel(prevPixelY, intx, prevPixelColour, prevTransAmount, pixelHeight, currentCorner, cornerContainer);
                            }  
                        
                    }
                }
                
                // Append corner container, we do this at the end because it is cleaner
                // Also append the bars
                this.box.appendChild(bar);
            }
        }       
    }
  
  function drawPixel(inty, intx, colour, transAmount, height, currentCorner, cornerContainer)
  {
      // 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
      setOpacity(pixel, transAmount);
      
      // Position the pixel
      switch(currentCorner)
          {
          case "TL":
            pixel.style.bottom = inty + "px";
            pixel.style.right = intx + "px";
          break;
          
          case "TR":
            pixel.style.bottom = inty + "px";
            pixel.style.left = intx + "px";
          break;
          
          case "BL":
            pixel.style.top = inty + "px";
            pixel.style.right = intx + "px";
          break;
          
          case "BR":
            pixel.style.top = inty + "px";
            pixel.style.left = intx + "px";
          break;
          }
      
      //alert("drawing  X: " + intx + " Y: " + inty); 
      cornerContainer.appendChild(pixel);
  }

  
  /*
  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";  
            }
        }
    }

   /*
  Determines if the pixel whos co-ordinates are passed to the function is 
  on the inside of the circle the outside or 'cut' by the circle
  */
  function pixelStatus(x, y, r){
  
    // determine the distance from the corner of the square to the near corner of the pixel
    var near = (Math.sqrt(Math.pow(x,2) + Math.pow(y,2)));
    // determine the distance from the corner of the square to the far corner of the pixel
    var far = (Math.sqrt(Math.pow((x+1),2) + Math.pow((y+1),2)));

    if (r >= far) 
        {
        return "inside";
        }
    else 
        {
        if (r <= near)
            {
            return "outside";
            }
            else 
                { 
                return "cut";
                }
        } 
    }    
 

   /*
  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;      
            }
       }
       
       
       var returnValue = (pixelfraction);
       //alert(returnValue);
       
       return returnValue;
    }
    
  /*
  Determines the colour of the pixel whos co-ordinates are passed to the function 
  returns the resulting colour as a string in the format "#FFFFFF"
  */
  function pixelColour(x, y, radius, borderwidth, foregroundcolour, bordercolour, backgroundcolour)
    {
    
    var borderstatus = pixelStatus(x, y ,(radius - borderwidth));
    var pixelPercent = 100; // solid
    
    if (borderwidth < 1)
        {
        var radiusstatus = borderstatus;
        }
    else
        { 
        var radiusstatus = pixelStatus(x, y, radius);
        }
        
    // determine the pixel's relationship to the border and radius
    var combinedstatus = borderstatus + " " + radiusstatus
    
    switch (combinedstatus)
        {
        case "inside inside": 
            {
            var pixelcolour = foregroundcolour;
            break;
            }
        case "inside outside":    // this case should never occur
            {
            var pixelcolour = foregroundcolour;
            break;
            }
        case "inside cut":    // this case should never occur
            {
            var pixelcolour = foregroundcolour;
            break;
            }    
        case "cut inside":
            {
            
            // Get pixel fraction
            var iPixelFraction = pixelFraction(x, y ,(radius - borderwidth));
            var pixelcolour = BlendColour(foregroundcolour, bordercolour, pixelFraction(x, y ,(radius - borderwidth)));
            break;
            }    
        case "cut outside":   // this case should never occur
            {
            var pixelcolour = BlendColour(foregroundcolour, bordercolour, pixelFraction(x, y ,(radius - borderwidth)));
            break;
            }
        case "cut cut":   
            {
            // Get pixel fraction
            var iPixelFraction = pixelFraction(x, y ,radius);
            
            var pixelcolour = foregroundcolour;
            var pixelPercent = iPixelFraction * 100;
            break;
            }    
        case "outside inside":   
            {
            var pixelcolour = bordercolour;
            var pixelPercent = 100;           
            break;
            }
        case "outside outside":   
            {
            var pixelcolour = backgroundcolour;
            var pixelPercent = 100;           
            break;
            }            
        case "outside cut":   
            {
            // Get pixel fraction
            var iPixelFraction = pixelFraction(x, y ,radius);
            
            var pixelcolour = bordercolour;
            var pixelPercent = iPixelFraction * 100;
            break;
            }    
          }
      
      // Return pixel colour and transparency percentage
      var returnArray = new Array();
      returnArray[0] = pixelcolour;
      returnArray[1] = Math.round(pixelPercent);
      
      
      return returnArray;
    }
    
    // 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;
    }