// events.js - Control the Keyboard and Mouse
//
// by Adam Grossman
// last updated 12/03/06
// 
// free beer / speech

function eventify(elem) {
    elem.delayDoubleClick = .2;
    elem.delayHold = 0;
    elem.delayOver = 0;
    
    elem.betweenClicks = false;
    elem.clickDontWait = false;
    
    elem.timerHold = 0;
    elem.timerRelease = 0;
    elem.timerClick = 0;
    elem.timerOver = 0;
    elem.timerOut = 0;
    
    elem.hold = function() {};
    elem.release = function() {};
    elem.doubleclick = function() {};
    elem.over = function() {};
    elem.out = function() {};
    
    
    elem.onmousedown = function(e) {
        e = e || window.event;
        
        clearTimeout(elem.timerRelease);
        elem.timerRelease = 0;
        elem.timerHold = setTimeout(function() {elem.hold()}, elem.delayHold * 1000);
        return true;
    },
    
    
    elem.onmouseup = function(e) {
        e = e || window.event;
        
        clearTimeout(elem.timerHold);
        elem.timerHold = 0;
        
        if(elem.betweenClicks) {
            elem.betweenClicks = false;
            elem.doubleclick();
        } else{
            elem.betweenClicks = true;
            if(elem.clickDontWait) {
                 elem.release();
                elem.timerRelease = setTimeout(function() {elem.betweenClicks = false;}, elem.delayDoubleClick * 1000);
            } else{
                elem.timerRelease = setTimeout(function() {elem.betweenClicks = false; elem.release();}, elem.delayDoubleClick * 1000);
            }
        }
        
        return true;
    },
    
    
    elem.onmouseover = function(e) {
        e = e || window.event;
        
        clearTimeout(elem.timerOut);
        elem.timerOut = 0;
        elem.timerOver = setTimeout(function() {elem.over()}, elem.delayOver * 1000);
        return true;
    },
    
    
    elem.onmouseout = function(e) {
        e = e || window.event;
        
        clearTimeout(elem.timerOver);
        elem.timerOver = 0;
        elem.out();
        return true;
    },
    
    
    elem.setHold = function(funct) {
        elem.hold = funct;
        return true;
    },
    
    elem.getHold = function() {return elem.hold;},
    
    elem.setRelease = function(funct) {
        elem.release = funct;
        return true;
    },
    
    elem.getRelease = function() {return elem.release;},
    
    elem.setClick = function(funct) {elem.setRelease(funct);},
    elem.getClick = function() {elem.getRelease();},
    
    elem.setOver = function(funct) {
        elem.over = funct;
        return true;
    },
    
    elem.getOver = function() {return elem.over;},
    
    elem.setOut = function(funct) {
        elem.out = funct;
        return true;
    },
    
    elem.getOut = function() {return elem.out;},
    
    elem.setDoubleClick = function(funct) {
        elem.doubleclick = funct;
        return true;
    },
    
    elem.getDoubleClick = function() {return elem.doubleclick;},
    
    elem.setDelayHold = function(time) {
        if(!isNumber(time)) {time = 0;}
        elem.delayHold = time;
        return true;
    },
    
    elem.getDelayHold = function() {return elem.delayHold;},
    
    elem.setDelayOver = function(time) {
        if(!isNumber(time)) {time = 0;}
        elem.delayOver = time;
        return true;
    },
    
    elem.getDelayOver = function() {return elem.delayOver;},
    
    elem.setDelayDoubleClick = function(time) {
        if(!isNumber(time)) {time = .2;}
        elem.delayDoubleClick = time;
        return true;
    },
    
    elem.getDelayDoubleClick = function() {return elem.delayDoubleClick;},
    
    elem.setClickDontWait = function(value) {
        if(isTrue(value)) {
            value = true;
        } else {
            value = false;
        }
        elem.clickDontWait = value;
        return true;
    },
    
    elem.getClickDontWait = function() {return elem.clickDontWait;}
}

//--------------------------------------------------

var mouse = {
    x : 0,
    y : 0,
    delayDoubleClick : .2,
    delayHold : 1,
    
    betweenClicks : false,
    clickDontWait : false,
    
    timerClick : 0,
    timerHold : 0,
    timerRelease : 0,
    
    hold : function() {},
    release : function() {},
    doubleclick : function() {},
    moveFunct : function() {},
    
    
    refreshPosition : function(e) {
        e = e || window.event;
        var that = this;
        
        if(e.pageX || e.pageY) {
            this.x = e.pageX;
            this.y = e.pageY;
        } else if(e.clientX || e.clientY) {
            this.x = e.clientX + document.body.scrollLeft + document.documentElement.scrollLeft;
            this.y = e.clientY + document.body.scrollTop + document.documentElement.scrollTop;
        }
    },
    
    
    move : function(e) {
        this.refreshPosition(e);
        this.moveFunct();
    },
    
    
    down : function(e) {
        e = e || window.event;
        var that = this;
        
        clearTimeout(this.timerRelease);
        this.timerRelease = 0;
        this.timerHold = setTimeout(function() {that.hold()}, this.delayHold * 1000);
        return this;
    },
    
    
    up : function(e) {
        e = e || window.event;
        var that = this;
        
        clearTimeout(this.timerHold);
        this.timerHold = 0;
        
        if(this.betweenClicks) {
            this.betweenClicks = false;
            this.doubleclick();
        } else{
            this.betweenClicks = true;
            if(this.clickDontWait) {
                 this.release();
                this.timerRelease = setTimeout(function() {that.betweenClicks = false;}, this.delayDoubleClick * 1000);
            } else{
                this.timerRelease = setTimeout(function() {that.betweenClicks = false; that.release();}, this.delayDoubleClick * 1000);
            }
        }
        
        return this;
    },
    
    
    setMove : function(funct) {
        this.moveFunct = funct;
        return true;
    },
    
    getMove : function() {return this.moveFunct;},
    
    setHold : function(funct) {
        this.hold = funct;
        return true;
    },
    
    getHold : function() {return this.hold;},
    
    setRelease : function(funct) {
        this.release = funct;
        return true;
    },
    
    getRelease : function() {return this.release;},
    
    setClick : function(funct) {this.setRelease(funct);},
    getClick : function() {this.getRelease();},
    
    setDoubleClick : function(funct) {
        this.doubleclick = funct;
        return true;
    },
    
    getDoubleClick : function() {return this.doubleclick;},
    
    setDelayHold : function(time) {
        if(!isNumber(time)) {time = 0;}
        this.delayHold = time;
        return true;
    },
    
    getDelayHold : function() {return this.delayHold;},
    
    setDelayDoubleClick : function(time) {
        if(!isNumber(time)) {time = .2;}
        this.delayDoubleClick = time;
        return true;
    },
    
    getDelayDoubleClick : function() {return this.delayDoubleClick;},
    
    setClickDontWait : function(value) {
        if(isTrue(value)) {
            value = true;
        } else {
            value = false;
        }
        this.clickDontWait = value;
        return true;
    },
    
    getClickDontWait : function() {return this.clickDontWait;}
}

//--------------------------------------------------

var keyboard = {
    state : {},         //the state of each key on the keyboard
    delayHold : {},     //delay time for holds
    timerHold : {},     //timer for holds
    hold : {},          //function calls for holds
    release : {},       //function calls for releases
    
    
    down : function(e) {
        e = e || window.event;
        var that = this;
        
        //find keycode
        var key;
        if(isTrue(e.keyCode)) {
            key = e.keyCode;
        } else if(isTrue(e.which)) {
            key = e.which;
        } else{
            return this;
        }
        
        
        //set states
        this.state[key] = true;
        if(e.ctrlKey) {this.state["control"] = true;} else {this.state["control"] = false;}
        if(e.shiftKey) {this.state["shift"] = true;} else {this.state["shift"] = false;}
        if(e.altKey) {this.state["alt"] = true;} else {this.state["alt"] = false;}
        
        
        //call event functions
        var delay = this.delayHold[key] || 0;
        
        if(isTrue(this.hold[key]) && !isTrue(this.timerHold[key])) {
            var funct = function() {that.hold[key]();}
        } else{
            var funct = function() {};
        }
        
        this.timerHold[key] = setTimeout(funct, delay * 1000);
        
        return this;
    },
    
    
    up : function(e) {
        e = e || window.event;
        var that = this;
        
        //find keycode
        var key;
        if(isTrue(e.keyCode)) {
            key = e.keyCode;
        } else if(isTrue(e.which)) {
            key = e.which;
        } else{
            return this;
        }
        
        
        //set states
        this.state[key] = false;
        if(e.ctrlKey) {this.state["control"] = true;} else {this.state["control"] = false;}
        if(e.shiftKey) {this.state["shift"] = true;} else {this.state["shift"] = false;}
        if(e.altKey) {this.state["alt"] = true;} else {this.state["alt"] = false;}
        
        
        //call event functions
        clearTimeout(this.timerHold[key]);
        this.timerHold[key] = 0;
        
        if(isFunction(this.release[key])) {this.release[key]();}
        
        return this;
    },
    
    
    getKey : function(chr) {
        var key;
        
        if(isUndefined(chr)) {return false;}
        chr = chr.toUpperCase();
        
        switch(chr) {
            case "LEFT": key = 37; break;
            case "UP": key = 38; break;
            case "RIGHT": key = 39; break;
            case "DOWN": key = 40; break;
            case "ESC": key = 27; break;
            case "RETURN": key = 13; break;
            case "DELETE": key = 8; break;
            case "FORWARD DELETE": key = 46; break;
            case "PAGE UP": key = 33; break;
            case "PAGE DOWN": key = 34; break;
            case "END": key = 35; break;
            case "HOME": key = 36; break;
            case "CONTROL": key = "control"; break;
            case "SHIFT": key = "shift"; break;
            case "ALT": key = "alt"; break;
            default: key = chr.charCodeAt(0); break;
        }
        
        return key;
    },
    
    
    getState : function(chr) {
        var key = this.getKey(chr);
        if(!isTrue(key)) {return false;}
        var state = this.state[key];
        if(isBoolean(state)) {
            return state;
        } else{
            return false;
        }
    },
    
    
    setHold : function(chr, funct) {
        var key = this.getKey(chr);
        if(!isTrue(key)) {return false;}
        this.hold[key] = funct;
        return true;
    },
    
    getHold : function(chr) {
        var key = this.getKey(chr);
        if(!isTrue(key)) {return false;}
        return this.hold[key];
    },
    
    setRelease : function(chr, funct) {
        var key = this.getKey(chr);
        if(!isTrue(key)) {return false;}
        this.release[key] = funct;
        return true;
    },
    
    getRelease : function(chr) {
        var key = this.getKey(chr);
        if(!isTrue(key)) {return false;}
        return this.release[key];
    },
    
    setPress : function(chr, funct) {this.setRelease(chr, funct);},
    getPress : function(chr) {this.getRelease(chr);},
    
    setDelayHold : function(chr, time) {
        var key = this.getKey(chr);
        if(!isTrue(key)) {return false;}
        if(!isNumber(time)) {time = 0;}
        this.delayHold[key] = time;
        return true;
    },
    
    getDelayHold : function(chr) {
        var key = this.getKey(chr);
        if(!isTrue(key)) {return false;}
        return this.delayHold[key];
    }
}

//--------------------------------------------------

document.onkeydown = function(e) {keyboard.down(e)};
document.onkeyup = function(e) {keyboard.up(e)};
document.onmousedown = function(e) {mouse.down(e)};
document.onmouseup = function(e) {mouse.up(e)};
document.onmousemove = function(e) {mouse.move(e)};

//--------------------------------------------------

//Object typeof checks
function isBoolean(a) {
    return typeof a == 'boolean';
}

function isFunction(a) {
    return typeof a == 'function';
}

function isNumber(a) {
    return typeof a == 'number' && isFinite(a);
}

function isUndefined(a) {
    return typeof a == 'undefined';
}

function isTrue(a) {
    return a != undefined && (a == true || a != 0);
}
