﻿function fade(sElemId, sRule, bBackward)
{
	if (!document.getElementById(sElemId)) return;
	var aRuleList = sRule.split(/\s*,\s*/);
	    //sRule - набір правил	
	for (var j	= 0; j < aRuleList.length; j++)
	{
		sRule = aRuleList[j];		
		if (!fade.aRules[sRule]) continue;//невизначене правило\
		var i=0;		
		if (!fade.aProc[sElemId])
		    //елемент ще не опрацьовувався
		    //готуємо список процесів
		{
			fade.aProc[sElemId] = {};
		}
		else 
		    if (fade.aProc[sElemId][sRule])
		        //якщо до елемента вже застосовувалося правило
		        //то запам'ятовуємо стан процесу і зупиняємо його
		    {
			    i = fade.aProc[sElemId][sRule].i;
			    clearInterval(fade.aProc[sElemId][sRule].tId);
		    }
		//Якщо досягнута межа то робити нічого не треба
		if ((i==0 && bBackward) || (i==fade.aRules[sRule][3] && !bBackward)) 
		    continue;
		//запускаємо фейдинг
		fade.aProc[sElemId][sRule] = 
		{
		    'i' : i, 
		    'tId':setInterval('fade.run("'+sElemId+'","'+sRule+'")', fade.aRules[sRule][4]),
		    'bBackward':Boolean(bBackward)
		};
	}
}

fade.aProc = {};
    //масив запущених процесів
fade.aRules = {};
    //масив правил, заповнюється fade.addRule
//Виконує один крок фейдингу
fade.run = function(sElemId, sRule)
{
	//всі дані містяться в fade.aRules
    fade.aProc[sElemId][sRule].i += fade.aProc[sElemId][sRule].bBackward ? -1 : 1;
 	var finishPercent = fade.aProc[sElemId][sRule].i / fade.aRules[sRule][3];
 	    //відсоток виконання правила змінюється від 0 (не включая 0) до 1 (1 = 100%)
	var startPercent = 1 - finishPercent; 
	var aValueStart = fade.aRules[sRule][0];
	var aValueFinish = fade.aRules[sRule][1];	
	var path = fade.aRules[sRule][2];
	var target = document.getElementById(sElemId);
	var obj = target;
	for (var i = 0; i < path.length-1; i++)
	    obj = obj[path[i]];
	if (fade.aRules[sRule][5] == false)
	{
	    //обчислюємо значення червоного, зеленого, синього кольорів
        obj[path[path.length-1]] = 'rgb('+ 
	        Math.floor( aValueStart['r'] * startPercent + aValueFinish['r'] * finishPercent ) + ','+
	        Math.floor( aValueStart['g'] * startPercent + aValueFinish['g'] * finishPercent ) + ','+
	        Math.floor( aValueStart['b'] * startPercent + aValueFinish['b'] * finishPercent ) +')';
	}
	else 
	{
	    var value = Math.round((aValueFinish - aValueStart) * finishPercent + aValueStart);
	    obj[path[path.length-1]] = value;
	}
	    //якщо вже перебрані всі проміжні знвчення, то зупиняємо виконання
	if ( fade.aProc[sElemId][sRule].i == fade.aRules[sRule][3] || fade.aProc[sElemId][sRule].i == 0) 
	    clearInterval(fade.aProc[sElemId][sRule].tId); 
}

fade.back = function (sElemId, sRule){fade(sElemId, sRule, true);};
fade.addRule = function (sRuleName, sFadeStartValue, sFadeFinishValue, sCSSProp, nSteps, nDelay, nSignProp)
{
	fade.aRules[sRuleName] = [
	    (nSignProp ? sFadeStartValue : fade.splitRGB(sFadeStartValue)),
	    (nSignProp ? sFadeFinishValue : fade.splitRGB(sFadeFinishValue)),
	    fade.ccs2js(sCSSProp),
	    nSteps || 50,
	    nDelay || 1,
	    nSignProp || false];
};

//функція для визначення ваги червоного, зеленого і синього кольорів, наприклад, 
//#FFFF00 у ['r':255, 'g':255, 'b':0]
fade.splitRGB = function (color)
{
    var rgb = color.replace(/[# ]/g,"").replace(/^(.)(.)(.)$/,'$1$1$2$2$3$3').match(/.{2}/g);
    for (var i=0;  i<3; i++)
        rgb[i] = parseInt(rgb[i], 16);
    return {
        'r':rgb[0],
        'g':rgb[1],
        'b':rgb[2]
    };
};
//функція для перетворення назв властивостей CSS у відповідні назви властивостей javascript 
//border-color у borderColor
fade.ccs2js = function(cssProperty)
{
    return cssProperty.replace(/\-(.)/g,function(){return arguments[1].toUpperCase();}).split(".");
};
