function ColorPicker()
{
    var id;

    var strCurrentColor = "#ffffff";
    var intSelected = 0;
    var intUserColor = 0;
    var aUserColors = [];

    this.div = null;

    // predifined colors
    var aColors = [
        new Color("ff8080"),new Color("ffff80"),new Color("80ff80"),new Color("00ff80"),new Color("80ffff"),
            new Color("0080ff"),new Color("ff80c0"),new Color("ff80ff"),
        new Color("ff0000"),new Color("ffff00"),new Color("80ff00"),new Color("00ff40"),new Color("00ffff"),
            new Color("0080c0"),new Color("8080c0"),new Color("ff00ff"),
        new Color("804040"),new Color("ff8040"),new Color("00ff00"),new Color("008080"),new Color("004080"),
            new Color("8080ff"),new Color("800040"),new Color("ff0080"),
        new Color("800000"),new Color("ff8000"),new Color("008000"),new Color("008040"),new Color("0000ff"),
            new Color("0000a0"),new Color("800080"),new Color("8000ff"),
        new Color("400000"),new Color("804000"),new Color("004000"),new Color("004040"),new Color("000080"),
            new Color("000040"),new Color("400040"),new Color("400080"),
        new Color("000000"),new Color("808000"),new Color("808040"),new Color("808080"),new Color("408080"),
            new Color("c0c0c0"),new Color("400040"),new Color("ffffff")
    ];

    function dechex( intParam, intMinLength )
    {
        if( intMinLength == null ) {
            intMinLength = 2;
        }
        var aHex = [ "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f" ];

        strReturn = "";
        intParam = parseInt( intParam );
        while( intParam != 0) {
            strReturn = aHex[intParam%16].toString() + strReturn;
            intParam = intParam >> 4;
        }
        if( strReturn.length < intMinLength ) {
            while( strReturn.length < intMinLength ) {
                strReturn = "0" + strReturn;
            }
        }
        return strReturn;
    }

    function hexdec( strHex )
    {
        var aHex = {0:0,1:1,2:2,3:3,4:4,5:5,6:6,7:7,8:8,9:9,a:10,b:11,c:12,d:13,e:14,f:15};
        var intReturn=0;
        for( var i=0; i<strHex.length; ++i ) {
            intReturn += parseInt(aHex[strHex.charAt(i)]) * Math.pow(16, strHex.length-i-1);
        }
        return intReturn;
    }

    function saveUserColors()
    {
        var i, strCookie="";
        for( i=0; i<16; ++i ) {
            strCookie += aUserColors[i].htmlValue().replace(/#/, "") + ";";
        }
        strCookie = strCookie.substr(0, strCookie.length-1);
        setCookie( "usercolors", strCookie, 60*60*24*30 );
    }

    function loadUserColors()
    {
        var i, aCookie=getCookie("usercolors");
        if( aCookie != null ) {
            aCookie = aCookie.split(";")
        } else {
            aCookie = [];
        }
        for( i=0; i<16; ++i ) {
            if( aCookie[i] != null ) {
                aUserColors.push( new Color( aCookie[i] ) );
            } else {
                aUserColors.push( new Color( 'ffffff' ) );
            }
        }
    }

    function setCookie(name, value, seconds, path, domain, secure)
    {
        if( seconds>0 ) {
            var expires = new Date();
            expires.setTime(expires.getTime() + (seconds*1000));
        }

        var curCookie = name + "=" + escape(value) +
                        ((seconds>0) ? ";"+" expires=" + expires.toGMTString() : "") +
                        ((path) ? ";"+" path=" + path : "") +
                        ((domain) ? ";"+" domain=" + domain : "") +
                        ((secure) ? ";"+" secure" : "");
        document.cookie = curCookie;
    }

    function getCookie(name)
    {
        var prefix = name + "=";
        var begin = document.cookie.indexOf(";"+" " + prefix);
        if (begin == -1) {
            begin = document.cookie.indexOf(prefix);
            if (begin != 0) {
                return null;
            }
        } else {
            begin += 2;
        }
        var end = document.cookie.indexOf(";", begin);
        if (end == -1) {
            end = document.cookie.length;
        }
        return unescape(document.cookie.substring(begin + prefix.length, end));
    }

    // public functions
    this.showColor = function(i)
    {
        document.getElementById("color"+intSelected+"_"+id).style.borderColor = "#808080 #ffffff #ffffff #808080";
        if( aColors[i] != null ) {
            document.getElementById("colorPreview" + id).style.backgroundColor = aColors[i].htmlValue();
            document.getElementById("r" + id).value = hexdec(aColors[i].r);
            document.getElementById("g" + id).value = hexdec(aColors[i].g);
            document.getElementById("b" + id).value = hexdec(aColors[i].b);
            strCurrentColor = aColors[i].htmlValue();
        } else if( aUserColors[i-aColors.length] != null ) {
            // its a user color
            document.getElementById("colorPreview" + id).style.backgroundColor = aUserColors[i-aColors.length].htmlValue();
            document.getElementById("r" + id).value = hexdec(aUserColors[i-aColors.length].r);
            document.getElementById("g" + id).value = hexdec(aUserColors[i-aColors.length].g);
            document.getElementById("b" + id).value = hexdec(aUserColors[i-aColors.length].b);
            strCurrentColor = aUserColors[i-aColors.length].htmlValue();
        }
        document.getElementById("color"+i+"_"+id).style.borderColor = "#000000";
        intSelected = i;

        if( aUserColors[intSelected-aColors.length] != null ) {
            intUserColor = intSelected-aColors.length;
        }
    };

    this.updateDiv = function() {
        var strRed, strGreen, strBlue;

        strRed   = dechex( document.getElementById("r" + id).value );
        strGreen = dechex( document.getElementById("g" + id).value );
        strBlue  = dechex( document.getElementById("b" + id).value );

        strCurrentColor = "#" + strRed + strGreen + strBlue;
        document.getElementById("colorPreview" + id).style.backgroundColor = strCurrentColor;
    };

    this.init = function( callbackOk ) {
        loadUserColors();

        id = Math.round( Math.random()*10000 );
        var div = document.createElement("div");
        div.className = "colorContainer";
        div.id = "colorContainer" + id;

        var divLeft = document.createElement("div");
        divLeft.id = "left" + id;
        divLeft.className = "left";
        divLeft.appendChild( document.createTextNode( "Grundfarben:" ) );
        var table = document.createElement("table");
        table.id = "tblBaseColors" + id;
        table.className = "tblBaseColor";

        var btn, divRight, canvas, ctx, image, div1, div2;
        var i, elmRow, elmCol, elmDiv, table, elmInput;
        for( i=0; i<aColors.length; ++i ) {
            if( i%8==0 ) {
                elmRow = table.insertRow( table.rows.length );
            }

            elmCol = document.createElement('td');
            elmDiv = document.createElement('div');
            elmDiv.className = "color";
            elmDiv.style.backgroundColor = aColors[i].htmlValue();
            elmDiv.id = "color"+i+"_"+id;
            elmDiv.onclick = new Function('this.showColor('+i+')').bind(this);
            elmCol.appendChild(elmDiv);
            elmRow.appendChild(elmCol);
        }
        divLeft.appendChild( table );

        /////////////////////////////////////
        table = document.createElement("table");
        table.id = "tblUserColors" + id;
        table.className = "tblUserColor";

        // user Colors
        for( i=0; i<aUserColors.length; ++i ) {
            if( i%8==0 ) {
                elmRow = table.insertRow( table.rows.length );
            }

            elmCol = document.createElement('td');
            elmDiv = document.createElement('div');
            elmDiv.className = "userColor";
            elmDiv.style.backgroundColor = aUserColors[i].htmlValue();
            elmDiv.id = "color"+(i+aColors.length)+"_"+id;
            elmDiv.onclick = new Function('this.showColor('+(i+aColors.length)+')').bind(this);
            elmCol.appendChild(elmDiv);
            elmRow.appendChild(elmCol);
        }
        divLeft.appendChild( document.createTextNode( "Benutzerdefinierte Farben:" ) );
        divLeft.appendChild( table );

        btn = document.createElement("input");
        btn.id = "btnDefine"+id;
        btn.onclick = function() {
            document.getElementById('colorContainer'+id).style.width = '470px';
            document.getElementById('left'+id).style.width = '50%';
            document.getElementById('right'+id).style.display = 'block';
            document.getElementById('btnDefine'+id).disabled = true;
        };
        btn.type = "button";
        btn.value = "Farbe definieren >>";
        btn.style.textAlign = "center";
        btn.style.width = "100%";
        divLeft.appendChild( btn );

        btn = document.createElement("input");
        btn.id = "btnOk"+id;
        btn.onclick = function() {
            callbackOk( strCurrentColor );
            this.hide();
        }.bind(this);
        btn.type = "button";
        btn.value = "Ok";
        btn.style.width = "75px";
        divLeft.appendChild( btn );

        btn = document.createElement("input");
        btn.id = "btnCancel"+id;
        btn.onclick = this.hide.bind(this);
        btn.type = "button";
        btn.value = "Abbrechen";
        btn.style.width = "75px";
        divLeft.appendChild( btn );

        //////////////////////////
        // right side

        divRight = document.createElement("div");
        divRight.id = "right" + id;
        divRight.className = "right";

        canvas = document.createElement("canvas");
        divRight.appendChild(canvas);

        canvas.setAttribute( "width", "175" );
        canvas.setAttribute( "height", "187" );
        canvas.id = "imgColor" + id;
        ctx = canvas.getContext( "2d" );
        image = new Image();
        image.src = "color.png";
        try {
            ctx.drawImage( image, 0, 0 );
        } catch( e ) {
            // for firefox: delay painting of the image
            $(image).addEvent( "load", function( ctx ) { ctx.drawImage( this, 0, 0 ); }.pass( ctx, image ) );
        }

        div1 = document.createElement("div");
        div1.style.cssFloat = "left";
        div1.style.styleFloat = "left";
        div2 = document.createElement("div");
        div2.className = "colorPreview";
        div2.id = "colorPreview" + id;
        div1.appendChild(div2);
        div1.appendChild( document.createTextNode( "Farbe|Basis" ) );

        divRight.appendChild( div1 );

        // 3 selectboxen
        div1 = document.createElement("div");
        div1.style.cssFloat = "left";
        div1.style.styleFloat = "left";
        div1.style.paddingLeft = "5px";
        table = document.createElement("table");

        elmRow = table.insertRow( table.rows.length );
        elmCol = document.createElement("td");
        elmCol.appendChild( document.createTextNode( "Farbt.:" ) );
        elmRow.appendChild( elmCol );
        elmCol = document.createElement("td");
        elmInput = document.createElement("input");
        elmInput.type = "text";
        elmInput.maxlength = "3";
        elmInput.style.width = "30px";
        elmCol.appendChild( elmInput );
        elmRow.appendChild( elmCol );
        div1.appendChild( table );

        elmRow = table.insertRow( table.rows.length );
        elmCol = document.createElement("td");
        elmCol.appendChild( document.createTextNode( "Sätt.:" ) );
        elmRow.appendChild( elmCol );
        elmCol = document.createElement("td");
        elmInput = document.createElement("input");
        elmInput.type = "text";
        elmInput.maxlength = "3";
        elmInput.style.width = "30px";
        elmCol.appendChild( elmInput );
        elmRow.appendChild( elmCol );
        div1.appendChild( table );

        elmRow = table.insertRow( table.rows.length );
        elmCol = document.createElement("td");
        elmCol.appendChild( document.createTextNode( "Hell.:" ) );
        elmRow.appendChild( elmCol );
        elmCol = document.createElement("td");
        elmInput = document.createElement("input");
        elmInput.type = "text";
        elmInput.maxlength = "3";
        elmInput.style.width = "30px";
        elmCol.appendChild( elmInput );
        elmRow.appendChild( elmCol );
        div1.appendChild( table );

        divRight.appendChild( div1 );

        // 3 farb selectboxen
        div1 = document.createElement("div");
        div1.style.cssFloat = "left";
        div1.style.styleFloat = "left";
        div1.style.paddingLeft = "5px";
        table = document.createElement("table");

        elmRow = table.insertRow( table.rows.length );
        elmCol = document.createElement("td");
        elmCol.appendChild( document.createTextNode( "Farbt.:" ) );
        elmRow.appendChild( elmCol );
        elmCol = document.createElement("td");
        elmInput = document.createElement("input");
        elmInput.id = "r" + id;
        elmInput.type = "text";
        elmInput.maxlength = "3";
        elmInput.style.width = "30px";
        elmInput.onchange = this.updateDiv.bind(this);
        elmCol.appendChild( elmInput );
        elmRow.appendChild( elmCol );
        div1.appendChild( table );

        elmRow = table.insertRow( table.rows.length );
        elmCol = document.createElement("td");
        elmCol.appendChild( document.createTextNode( "Sätt.:" ) );
        elmRow.appendChild( elmCol );
        elmCol = document.createElement("td");
        elmInput = document.createElement("input");
        elmInput.id = "g" + id;
        elmInput.type = "text";
        elmInput.maxlength = "3";
        elmInput.style.width = "30px";
        elmInput.onchange = this.updateDiv.bind(this);
        elmCol.appendChild( elmInput );
        elmRow.appendChild( elmCol );
        div1.appendChild( table );

        elmRow = table.insertRow( table.rows.length );
        elmCol = document.createElement("td");
        elmCol.appendChild( document.createTextNode( "Hell.:" ) );
        elmRow.appendChild( elmCol );
        elmCol = document.createElement("td");
        elmInput = document.createElement("input");
        elmInput.id = "b" + id;
        elmInput.type = "text";
        elmInput.maxlength = "3";
        elmInput.style.width = "30px";
        elmInput.onchange = this.updateDiv.bind(this);
        elmCol.appendChild( elmInput );
        elmRow.appendChild( elmCol );
        div1.appendChild( table );

        divRight.appendChild( div1 );

        btn = document.createElement("input");
        btn.type = "button";
        btn.value = "Farbe hinzufügen";
        btn.id = "btnAdd" + id;
        btn.onclick = function() {
            aUserColors[intUserColor].r = dechex( document.getElementById("r"+id).value );
            aUserColors[intUserColor].g = dechex( document.getElementById("g"+id).value );
            aUserColors[intUserColor].b = dechex( document.getElementById("b"+id).value );
            document.getElementById( "color"+(intUserColor+aColors.length)+"_"+id ).style.backgroundColor = aUserColors[intUserColor].htmlValue();
            intUserColor = (++intUserColor)%16;
            saveUserColors();
        };
        btn.style.width = "100%";
        divRight.appendChild( btn );

        div.appendChild( divLeft );
        div.appendChild( divRight );

        div.style.position = "absolute";
        div.style.display = "none";
        div.style.top = "100px";
        div.style.left = "150px";

        this.div = div;

        $(this.div).makeDraggable();
        return this.div;
    };

    this.hide = function() {
        this.div.style.display = "none";
    };

    this.show = function( intZIndex ) {
        document.getElementById("colorContainer"+id).style.width = "220px";
        document.getElementById("left"+id).style.width = "100%";
        document.getElementById("right"+id).style.display = "none";
        document.getElementById("btnDefine"+id).disabled = false;

        this.div.style.display = "block";

        if( intZIndex ) {
            this.div.style.zIndex = intZIndex;
        }
    };
}

function Color()
{
    if( arguments.length == 1 ) {
        // hex value
        var strHex = arguments[0].replace(/#/, "");
        this.r = strHex.charAt(0) + strHex.charAt(1);
        this.g = strHex.charAt(2) + strHex.charAt(3);
        this.b = strHex.charAt(4) + strHex.charAt(5);
    } else if( arguments.length == 3 ) {
        // 3 integers (r,g,b)
        this.r = dechex(parseInt(arguments[0]));
        this.g = dechex(parseInt(arguments[1]));
        this.b = dechex(parseInt(arguments[2]));
    } else {
        alert( 'Incorrect Usage of Color()' );
    }

    this.htmlValue = function() {
        return "#" + this.r + this.g + this.b;
    };
}