/**
 * ---------------------------------------------------------------------
 * Simple and convenient web-safe color picker by pure DOM based JavaScript
 * ---------------------------------------------------------------------
 * Tested with Firefox 2, Opera 9 and IE 6/7
 * ---------------------------------------------------------------------
 * LICENSE: This source file is subject to the GNU Lesser General Public
 * License as published by the Free Software Foundation;
 * either version 2.1 of the License, or any later version
 * that is available through the world-wide-web at the following URI:
 * http://www.gnu.org/licenses/lgpl.html
 * If you did not have a copy of the GNU Lesser General Public License
 * and are unable to obtain it through the web, please write to
 * the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 * ---------------------------------------------------------------------
 * @version    1.1 (stable) issued March 23, 2007
 * @author     ucb.rcdtokyo http://www.rcdtokyo.com/ucb/
 * @license    GNU LGPL v2.1+ http://www.gnu.org/licenses/lgpl.html
 *
 * Usage example:
 * ---------------------------------------------------------------------
 * <head>
 *   <script src="color_picker.js"></script>
 * </head>
 * <body onload="colorPicker.init()">
 *   <form>
 *     <input onfocus="colorPicker.set(this, 'colorPicker.close(); alert(\'The color value is \' + colorValue)')">
 *     <input onfocus="colorPicker.set(this)">
 *   </form>
 * </body>
 * ---------------------------------------------------------------------
 */

var colorPicker = {

    /**
     * Configuration.
     */
    style: "wide",                 // Look of the color picker is either tall or wide.
    position: "right",             // Relative alignment of the color picker against the target input element (left|right).
    margin: [5, 5],                // Top and left margin of the color picker from the position above (pixels).
    cellSize: 15,                  // Size of each cell (pixels).
    background: "#36f",            // Background style of the color picker.
    border: "1px solid #000",      // Border style of the color picker.
    closeButtonSize: 12,           // Size of the close button (pixels).
    closeButtonMargin: 3,          // Margin of the close button (pixels).
    closeButtonColor: "#666",      // Foreground color of the close button.
    closeButtonBgColor: "#fff",    // Background color of the close button.
    closeButtonHoverColor: "#f09", // Rollover color of the close button.

    /**
     * Set target elements and make the color picker visible.
     *
     * The first paramter is the target (input) element object (not ID)
     * where the hexadecimal color value will be placed.
     * The optional second paramter is the string expression of the function
     * which will be performed on the click event of each cell.
     *
     * @param  object targetInputElement
     * @param  string additionalAction
     * @return void
     */
    set: function (targetInputElement, additionalAction)
    {
        if (typeof(targetInputElement) == "object" && typeof(this.matrix) == "object") {
            this.closeButton.style.backgroundColor = this.closeButtonBgColor;
            document.body.appendChild(this.matrix);
            this.targetInputElement = targetInputElement;
            this.matrix.style.top = (this.getOffset(this.targetInputElement, "top") + this.margin[0]) + "px";
            var offsetLeft = this.getOffset(this.targetInputElement, "left") + this.margin[1];
            if (this.position == "right") {
                offsetLeft += this.targetInputElement.offsetWidth;
            }
            this.matrix.style.left = offsetLeft + "px";
            if (typeof(additionalAction) == "string") {
                this.additionalAction = additionalAction;
            } else {
                this.additionalAction = null;
            }
        }
    },

    /**
     * Create the color picker.
     *
     * @return void
     */
    init: function ()
    {
        if (typeof(document.getElementById) != "undefined") {
            this.matrix = document.createElement("div");
            // To suppress display flickering on Firefox
            document.body.appendChild(this.matrix);
            document.body.removeChild(this.matrix);
            this.matrix.style.position = "absolute";
            this.matrix.style.margin = 0;
            this.matrix.style.padding = 0;
            this.matrix.style.border = this.border;
            var banner = document.createElement("div");
            this.matrix.appendChild(banner);
            banner.style.margin = 0;
            banner.style.padding = this.closeButtonMargin + "px";
            banner.style.color = "#fff";
            banner.style.background = this.background;
            this.closeButton = document.createElement("div");
            banner.appendChild(this.closeButton);
            this.closeButton.style.margin = 0;
            this.closeButton.style.padding = 0;
            this.closeButton.style.overflow = "hidden";
            this.closeButton.style.width = this.closeButtonSize + "px";
            this.closeButton.style.height = this.closeButtonSize + "px";
            this.closeButton.style.border = "1px solid " + this.closeButtonColor;
            this.closeButton.style.backgroundColor = this.closeButtonBgColor;
            this.closeButton.style.cursor = "pointer";
            this.closeButton.onmouseover = function () {
                colorPicker.closeButton.style.backgroundColor = colorPicker.closeButtonHoverColor;
            }
            this.closeButton.onmouseout = function () {
                colorPicker.closeButton.style.backgroundColor = colorPicker.closeButtonBgColor;
            }
            this.closeButton.onclick = function () {
                colorPicker.close();
            }
            for (var i = 0; i < this.closeButtonSize; i++) {
                var slashDot = document.createElement("div");
                this.closeButton.appendChild(slashDot);
                slashDot.style.position = "relative";
                slashDot.style.top = "0px";
                slashDot.style.left = i + "px";
                slashDot.style.margin = 0;
                slashDot.style.padding = 0;
                slashDot.style.width = "1px";
                slashDot.style.height = "1px";
                slashDot.style.backgroundColor = this.closeButtonColor;
            }
            for (var i = 0; i < this.closeButtonSize; i++) {
                var slashDot = document.createElement("div");
                this.closeButton.appendChild(slashDot);
                slashDot.style.position = "relative";
                slashDot.style.top = "-" + this.closeButtonSize + "px";
                slashDot.style.left = this.closeButtonSize -1 - i + "px";
                slashDot.style.margin = 0;
                slashDot.style.padding = 0;
                slashDot.style.width = "1px";
                slashDot.style.height = "1px";
                slashDot.style.backgroundColor = this.closeButtonColor;
            }
            var table = document.createElement("table");
            this.matrix.appendChild(table);
            table.style.borderCollapse = "collapse";
            table.style.cursor = "pointer";
            var tbody = document.createElement("tbody");
            table.appendChild(tbody);
            tbody.style.margin = 0;
            tbody.style.padding = 0;
            var i = 0;
            for (var r = 0x00; r <= 0xff; r += 0x33) {
                for (var g = 0x00; g <= 0xff; g += 0x33) {
                    for (var b = 0x00; b <= 0xff; b += 0x33) {
                        if (i == 0) {
                            var tr = document.createElement("tr");
                            tbody.appendChild(tr);
                            tr.style.margin = 0;
                            tr.style.padding = 0;
                            i++;
                        } else if ((this.style != "wide" && i == 11) || (this.style == "wide" && i == 17) ) {
                            i = 0;
                        } else {
                            i++;
                        }
                        var color = ((r == 0)? "00": r.toString(16))
                            + ((g == 0)? "00": g.toString(16))
                            + ((b == 0)? "00": b.toString(16));
                        var td = document.createElement("td");
                        tr.appendChild(td);
                        td.id = color;
                        td.title = color;
                        td.style.width = this.cellSize + "px";
                        td.style.height = this.cellSize + "px";
                        td.style.border = this.border;
                        td.style.margin = 0;
                        td.style.padding = 0;
                        td.style.color = "#fff";
                        td.style.backgroundColor = "#" + color;
                        td.onclick = function () {
                            colorPicker.notify(this.id);
                        };
                    }
                }
            }
        }
    },

    /**
     * Dismiss the color picker.
     *
     * @return void
     */
    close: function ()
    {
        if (this.matrix.parentNode != null) {
            document.body.removeChild(this.matrix);
        }
    },

    /**
     * Set the hexadecimal color value to the value attribute of the target (input) element
     * and do the additional action if set.
     * This is called on the click event of each cell.
     *
     * @param  string colorValue
     * @return void
     */
    notify: function (colorValue)
    {
        if (typeof(this.targetInputElement) == "object") {
            this.targetInputElement.value = colorValue;
        }
        if (typeof(this.additionalAction) == "string") {
            eval(this.additionalAction);
        }
    },

    /**
     * Get the top/left offset of the element.
     *
     * @param  object  element
     * @param  string  which (top|left)
     * @return integer
     */
    getOffset: function (element, which)
    {
      var offset = (which == "top")? element.offsetTop: element.offsetLeft;
      while ((element = element.offsetParent) != null) {
        if (element.tagName.toLowerCase() != 'html'){
            offset += (which == "top")? element.offsetTop: element.offsetLeft;
        }
      }
      return offset;
    }
}
