//prep & namespace
var mlf = {
    "targetCol": [255, 255, 255], //rgb array
    "stepsInFade": 8,
    "objInst": [],
    "origColsStorer": [], //track the real original colours of links before the colour is messed about with (often interruptive) mouseovers/outs
    "mode": 1 //if 1, fades to target col and back to orig col both on mouseover. if 0, fades to target col on mouseover and back to orig col on mouseout.
}



//unify event handling
function registerEvent(on, ev, func) {
    if (document.all) {
        if (on == window) on = window.document;
        on.attachEvent("on"+ev, func); //IE
    }
    else
    on.addEventListener(ev, func, false); //Opera, FF etc
}



//object
mlf.obj = function(trigger, reverse) {

	//get current colour			
	var col = document.all ? trigger.currentStyle.color : getComputedStyle(trigger, null).color;
	
	//reversing? hardwire into obj if so so readable by anim func
	if (reverse) this.reverse = reverse;
	
    //convert to hex so we can easily alter it mathmatically (FF returns current colour in RGB, so no need)
    rgb = col.match(/[0-9]{1,3}, [0-9]{1,3}, [0-9]{1,3}/i);
    if (rgb) { //already RGB
        col = rgb.toString().replace(/ /g, '').split(',');
    } else { //hex - convert
        col = col.substr(0, 1) == "#" ? col.substr(1) : col; //strip hash before handling
        
        if (col.length == 6) //6-piece hash colour (e.g. fa92s0)
        col = [col.substr(0, 2), col.substr(2, 2), col.substr(4, 2)];
        else {//assume 3-piece hash colour(e.g. f90), turn into 6-piece
        	col = [col.substr(0, 1), col.substr(1, 1), col.substr(2, 1)];
        	for (var e in col) col[e] += col[e];
        }
        for (var y in col) col[y] = parseInt(col[y], 16);
    }
    this.col = col;
    
    //if this link's original colour has yet to be stored globally for future use, add now. the purpose of this is as follows:
    //if you mouseover, then mouseout but mouseover again before the mouseout transition returns the link to its original colour, the new mouseover will start from the current colour, not the true orig, since it was never reached. since our script dynamically detects the colour, doesn't depend on a style tag etc, we need some way of knowing what our ultimate start colour was.
    if (!mlf.origColsStorer[trigger.toString()]) mlf.origColsStorer[trigger.toString()] = [this.col[0], this.col[1], this.col[2]];
    
    if (!this.origCol) this.origCol = this.col.concat([0]);
    
    //hardwire a few things
    this.targetCol = !reverse ? mlf.targetCol : reverse;            
	this.trigger = trigger;
	this.steps = [];

	//undo weirdness
	if (this.targetCol.length == 4) this.targetCol = [this.targetCol[0], this.targetCol[1], this.targetCol[2]];
	if (this.origCol.length == 4) this.origCol = [this.origCol[0], this.origCol[1], this.origCol[2]];

	//work what addition or subtraction to make on each of the 3 RGB values in each step en route to target colour
    for (var n in this.col) {
        this.steps[n] = {
            "amount": Math.round(Math.abs((this.diff = this.targetCol[n] - this.col[n])) / mlf.stepsInFade),
            "direction": this.diff >= 0 ? "up" : "down"
        }
    }
    
    //fade animation
    mlf.obj.prototype.fade_do = function() {

        if (this.fadeInt_counter < mlf.stepsInFade) {
        	
        	this.newCol = this.col;
        	
        	this.fadeInt_counter++;

            for (var t in this.col)
            	this.newCol[t] = parseInt( this.steps[t]['direction'] == 'up' ? this.col[t] + this.steps[t]['amount'] : this.col[t] - this.steps[t]['amount'] );
            
            
            for (var g in this.newCol) {
                if (this.newCol[g] > 255) this.newCol[g] = 255;
                if (this.newCol[g] < 0) this.newCol[g] = 0;
            }

            this.trigger.style.color = '#'+mlf.rgbToHex(this.newCol);

			} else {
            	clearInterval(this.intie);
            	//if this was an outward fade (i.e. not reverse) and mode is set to 1, automatically and immediately do fade back to orig colour
            	if (!this.reverse && mlf.mode == 1) mlf.init(this, true);
        	}

    }
    
    //start anim
    this.fadeInt_counter = 0;    
    this.intie = setInterval( (function(inst){return function(){inst.fade_do()}})(this), 80);
	
}



//onload
window.onload = function() {
    registerEvent(window, 'mouseover', function(evt) { mlf.init(evt); });
    if (mlf.mode == 0) registerEvent(window, 'mouseout', function(evt) { mlf.init(evt, true); });
}



//fade in prep
mlf.init = function(evtOrRes, reverse) {

	if (!evtOrRes.trigger)
    var trigger = document.all ? window.event.srcElement : evtOrRes.target; //what woke us up?
    else
    var trigger = evtOrRes.trigger;
    
    if (trigger.tagName == 'A') {//a link, was it? eh? EH? If so, do anim.
    	
    	//if we're reversing back to orig colour, what WAS orig colour? (set in global storer the first time this link is hovered over. See long comment in constructor.)
    	if (reverse) origCol = mlf.origColsStorer[trigger.toString()] ? mlf.origColsStorer[trigger.toString()] : mlf.objInst[trigger.toString()].origCol;
    	
    	try { //kill object if already eixsts (will always be true if this is called by mouse out, not over) so we can start a clean, new process on the object
        	clearInterval(mlf.objInst[trigger.toString()].intie);
            delete(mlf.objInst[trigger.toString()]);
    	} catch(e) {}
    	
    	//new animation session - off we go
    	mlf.objInst[trigger.toString()] = new mlf.obj(trigger, reverse ? origCol : null);
    	
	}
}



//rgb > hex
mlf.rgbToHex = function(rgb, returnAsStringNotArray) {

    //expects either a 3-part RGB array or one number from a 3-part RGB string. Exit if neither of these passed.
    if (!rgb)
    return false;
    else if (!(typeof rgb == "number" && rgb >= 0 && rgb <= 255) && !(typeof rgb == "object" && rgb.join('').match(/^[0-9]{3,9}$/gi) && parseInt(rgb.join('')) <= 255255255))
    return false;

    //since func expects number OR array, harmonise data type here so whichever passed, after this point script knows it's working with an array
    if (typeof rgb != "object") rgb = [rgb];

    var ret = [];

    //recursively convert
    for (var o in rgb) {
        var temp = "0123456789ABCDEF".charAt((rgb[o]-rgb[o]%16)/16)+"0123456789ABCDEF".charAt(rgb[o]%16);
        ret[o] = temp;
    }

    //and return, either as 3-part array or as string
    return ret.join("");

}// JavaScript Document