// Copyright 2010, Jason McDonald - http://www.McDonaldLand.info
//
// This code is free to use provided that this entire message remains
// in place. You may modify this code as you see fit.
//
// This code may NOT be sold as part of a widget, plugin, or any other
// sort of control without prior written consent. You may use this code 
// as part of a larger product intended for retail provided that this
// code is not the centerpiece for the product.

// ===================================================================
// Known improvement opportunities:
//
// 1. When mouse moves fast, lines have gaps in them. It would be pretty
//    easy to write an algorithm that figures out empty squares between
//    two points and fills them in. Alternatively, it wouldn't be too 
//    difficult to handle this without tables by tracking the mouse 
//    location within the DIV then drawing points/lines.
//
// ===================================================================

var Canvas = function (canvas_id, canvas_width, canvas_height, isReadOnly, seedData) {

    var self = this;

    self.backgroundImage = "./spacer.gif";
    var img = new Image(1, 1);
    img.src = self.backgroundImage; // Preload...

    self.eraseColor = "#FFFFFF";
    self.fillColor = "#000000";
    
    self.canvas_id = canvas_id;
    self.width = canvas_width;
    self.height = canvas_height;
    
    self.readOnly = (isReadOnly == true);
    
    self.colors = null;
    self.cellValues = null;

    var mousedown = false;

    if (seedData != null) {
        prepareLoadData(seedData);
    }


    function init() {
    
        if (!self.readOnly) {
            document.onmousedown=function() {
                mousedown = true;
            };

            document.onmouseup=function() {
                mousedown = false;
            };
        }
        
        if (!document.getElementById) {
            displayBrowserMessage();
            return;
        }
    
        var canvas = document.getElementById(self.canvas_id);
        canvas.innerHTML = "";
        
        if(!canvas.addEventListener && !canvas.attachEvent) {
            displayBrowserMessage();
            return;
        }
    
    
        var grid = document.createElement("table");
        grid.cellSpacing = 0;
        grid.cellPadding = 0;
        canvas.appendChild(grid);
    
        var grid_body = document.createElement("tbody");
        grid.appendChild(grid_body);
    
 
        for (r = 0;r < self.height;r++) {
            var row = document.createElement("tr");
            grid_body.appendChild(row);

            for (c = 0;c < self.width;c++) {
                var cell = document.createElement("td");
                cell.id = "r" + r + "c" + c;
                cell.innerHTML = "<img src=\"" + self.backgroundImage + "\"/>";
                setCellColor(cell);                
                row.appendChild(cell);
            
                if (!self.readOnly) {
                    if (cell.addEventListener) {
                        cell.addEventListener("click", fill, false);
                        cell.addEventListener("mouseover", fill, false);
                    } else {
                        cell.attachEvent("onclick", fill);
                        cell.attachEvent("onmouseover", fill);
                    }
                }
            }
        }

        self.colors = null;
        self.cellValues = null;
    }
            
    function fill(event) {

        if (!event) {
            event = window.event;
        }
	
        var target = null;
        if (event.target) {
            target = event.target;    
        } else if (event.srcElement) {
            target = event.srcElement;
        }
    
        if (target.nodeType == 3) {
            target = target.parentNode;
        }
    
        var click = false;
        if (event.type) {
            click = (event.type == "click");
        }
   
        if (mousedown || click) {
            if (event.shiftKey) {
                target.style.backgroundColor = self.eraseColor;
            } else {
                target.style.backgroundColor = self.fillColor;
            }
        }
    
    
        if (typeof target.onselectstart != "undefined") {//IE route
            target.onselectstart = function() { return false };
        } else if (typeof target.style.MozUserSelect != "undefined") {//Firefox route
            target.style.MozUserSelect = "none";
        } else { //All other route (ie: Opera)
            target.onmousedown = function() { return false };
        }    
    }
    
    function convertToHex(rgbString) {

        var parts = rgbString.match(/^rgb\((\d+),\s*(\d+),\s*(\d+)\)$/);

        delete (parts[0]);
        for (var i = 1; i <= 3; ++i) {
            parts[i] = parseInt(parts[i]).toString(16);
            if (parts[i].length == 1) parts[i] = '0' + parts[i];
        }
        var hex = "#" + parts.join('');
        
        return hex.replace("##", "#");
    }
    
    function setCellColor(cell) {
        
        var colorSet = false;
        if (self.cellValues != null) {
            var color = self.cellValues[cell.id];
            
            if (color == "x") {
                cell.style.backgroundColor = self.fillColor;
                colorSet = true;
            } else if (self.colors != null) {
                color = self.colors[color];
                if (color != null && color != "") {
                    cell.style.backgroundColor = color;
                    colorSet = true;
                }
            }
        }
        
        if (!colorSet) {
            cell.style.backgroundColor = self.eraseColor;
        }
    }
    
    function handleSave() {        
        var colors = [];
        var colorIndexes = {};
        var cells = {};
        
        var basics = {
            "readOnly" : self.readOnly,
            "width" : self.width,
            "height" : self.height,
            "fillColor" : self.fillColor,
            "eraseColor" : self.eraseColor
        };

        var colorCount = -1;
        
        self.fillColor = self.fillColor.toUpperCase();
        self.eraseColor = self.eraseColor.toUpperCase();
        
        for (r = 0;r < self.height;r++) {
            for (c = 0;c < self.width;c++) {
                var cell = "r" + r + "c" + c;                
                var bg = document.getElementById(cell).style.backgroundColor;
                
                if (bg == null || bg == "") {
                    bg = self.eraseColor;
                }
                
                if (bg.indexOf("rgb") != -1) {
                    bg = convertToHex(bg);
                }
                
                bg = bg.toUpperCase()
                
                if (bg == self.fillColor) {
                    cells[cell] = "x"
                } else if (bg != self.eraseColor) {
                    
                    index = colorIndexes[bg];
                   
                    if (index == null) {
                        colorCount++;
                        colorIndexes[bg] = colorCount;
                        colors[colorCount] = bg;                        
                    }
                    
                    cells[cell] = colorCount;
                }
            }
        }
        
        var data = {
            "basics" : basics,
            "colors" : colors,
            "cells" : cells
        };
        
        return JSON.stringify(data);
    }

    function prepareLoadData(data, overrideWidth, overrideHeight) {
        data = JSON.parse(data);

        if (data["basics"]["readOnly"]) {
            self.readOnly = data["basics"]["readOnly"];
        }

        if (overrideWidth) {
            self.width = overrideWidth;
        } else if (data["basics"]["width"]) {
            self.width = data["basics"]["width"];
        }

        if (overrideHeight) {
            self.height = overrideHeight;
        } else if (data["basics"]["height"]) {
            self.height = data["basics"]["height"];
        }

        if (data["basics"]["fillColor"]) {
            self.fillColor = data["basics"]["fillColor"];
        }

        if (data["basics"]["eraseColor"]) {
            self.eraseColor = data["basics"]["eraseColor"];
        }

        if (data["colors"]) {
            self.colors = data["colors"];
        }

        if (data["cells"]) {
            self.cellValues = data["cells"];
        }
    }
        
        
    function displayBrowserMessage() {
        document.getElementById(canvas_id).innerHTML = "Your browser does not support this functionality. Please download the latest version of a modern browser.";
    }        
    
    
    init();

    return {
        setFillColor: function(hexColor) {
            self.fillColor = hexColor;
        },
        
        setEraseColor: function(hexColor) {
            self.eraseColor = hexColor;
        },
        
        save: function() {
            return handleSave();
        },
        
        load: function(data) {
            prepareLoadData(data);
            init();
        },
        
        resize: function(canvas_width, canvas_height) {
            var data = handleSave();
            prepareLoadData(data, canvas_width, canvas_height);
            init();
        },
        
        clear: function() {
            init();
        }
    };

};

function debug(toDebug) {
    document.getElementById("debug").innerHTML += toDebug + "<br/>";
}
