//
//                                                           скрипт движения слоя
//                                                           разработка: A.St.
//                                                           май 2009
//
// подключение:
//      - подключить скрипт в хэде
//      - после определения всех элементов, участвующих в процессе (слои, кнопки) прописать инициализацию объекта ( z.b. currentMotion = new motion.load( "moutingDiv", "holdDiv", 300);)
//      - написать привязки к событиям, в которых указать ссылку на init с указанием направления (currentMotion.init( direction);)
//      - проверить стили у слоёв
//      - читать консоль ошибок в случае неудачи

function $( id) {
    return document.getElementById( id);
}

Motion = function( mDiv, hDiv, delta, cycle, element, beginFunc, endFunc, processFunc) {
/*
    конструктор( что_двигать( id), рамка( id),  на_сколько_двигать( px))
    нажатие на левую кнопку    ->  движение вправо  ->  1
    нажатие на правую кнопку  ->  движение влево    -> -1
*/
    this.moutingDiv = mDiv;               			// id двигающегося слоя
    this.holdDiv = hDiv;                     			// id слоя-рамки
	this.autoWidth = false;							// автоподгон размеров дивов?
    this.pixelWidth = true;							// пересчитать размеры дивов через пиксели?
    this.constantStep = 0;							   // использовать постоянную скорость движения?
    this.finalPosition = null;             		      	// финальная позиция слоя после окончания движения
    this.currentPosition = 0;     		          	// текущая позиция
    this.time = 0;                                			// переменная времени
    this.direction = 0;                       			   	// направление движения
    this.step = 0;                                  			// шаг текущего цикла
    this.condition = 0;                     			    // условие остановки
    this.timeOut = 15;                           		// время задержки м/д циклами
    this.cycle = 0;                                         // надо ли зациклить 
    this.dynamicDelta = false;                     // надо ли определять динамически дельту
    this.allWidth = (document.body.scrollWidth) ? document.body.scrollWidth : document.documentElement.scrollWidth;
    this.load( delta, cycle, element, beginFunc, endFunc, processFunc);
}

Motion.prototype = {
    load: function( delta, cycle, element, beginFunc, endFunc, processFunc) {
        this.delta = parseInt( delta);       			// на сколько двигаться
		if ( !this.delta || this.delta == "auto") {
			this.delta = parseInt( $( this.holdDiv).offsetWidth);
			this.autoWidth = true;
		}
		this.begin_func = this.defaultEventFunc;
		this.end_func = this.defaultEventFunc;
		this.process_func = this.defaultEventFunc;
		if ( beginFunc) {
			this.begin_func = beginFunc;
		}
		if ( endFunc) {
			this.end_func = endFunc;
		}
		if ( processFunc) {
		    this.process_func = processFunc;
		}
		if ( cycle) {
			this.cycle = true;                                   // нужно перемещать элементы или нет
		}
		if ( element) {
			this.cycleElementType = element;
			this.elementArray = this.getElementsArray();
			this.currentElement = 0;
			if ( this.autoWidth) {
				if ( this.pixelWidth) {						// выставляем размер вложенных в див элементов по пикселям
					for ( var i in this.elementArray) {
						this.elementArray[i].style.width = this.delta  + "px";
					}
					this.mDivWidth = this.elementArray.length * this.delta + "px";
				} else {										// выставляем размер вложенных в див элементов по процентам
					for ( var i in this.elementArray) {
						this.elementArray[i].style.width = Math.floor( 100 / this.elementArray.length) + "%";
					}
					this.mDivWidth = ((this.elementArray.length * this.delta) / 1016) * 102 + "%";
					
					// переопределяем дельту
					tempDelta = Math.ceil( Math.ceil( this.allWidth * ( parseInt( this.mDivWidth) / 100))  / this.elementArray.length);
					if ( this.delta < tempDelta) {
						this.delta = tempDelta;
 					}
				}
			}
			if ( this.mDivWidth ) {
				$( this.moutingDiv).style.width = this.mDivWidth;
			}
		}
    },

    reload: function() {
        this.load( this.delta, this.cycle, this.cycleElementType, this.begin_func, this.end_func, this.process_func);
    },
    
	getElementsArray: function() {
        this.elementArray = $( this.moutingDiv).getElementsByTagName( this.cycleElementType);
        this.tempArray = new Array();
        for ( var i in this.elementArray) {
			if ( this.elementArray[i].parentNode && this.elementArray[i].parentNode.id == this.moutingDiv) {
				this.isNodeFlag = 0;
				for ( var j in this.tempArray) {
					if ( this.tempArray[j] == this.elementArray[i]) {
						this.isNodeFlag = 1;
						break;
					}
				}
				if ( !this.isNodeFlag) {
					this.tempArray.push( this.elementArray[i]);
				}
			}
        }
	     return this.tempArray;
	},
	
    init: function( direct, currentFinal) {
         // определяем направление движения
        this.direction = direct;
		this.insertElement();
        // если движение не идет (финальная координата не определена) - прибавляем к кэшу смещения текущее положение
        if ( this.finalPosition == null) {
            this.temp = parseInt( $( this.moutingDiv).style.left);
         }
        // прибавляем к кэшу смещения прирост, равный заранее определённой величине delta ( размер дива, картинки)
        this.temp += this.direction * this.delta;
		// отчищаем ссылку на таймаут, определяем финальную координату и начинаем движение
		clearTimeout( this.time);
        if ( currentFinal) {
	        // если финальная координата задается
            if ( currentFinal > ( parseInt( $( this.moutingDiv).style.width) - Math.floor( $( this.holdDiv).offsetWidth / this.delta) * this.delta)) {
                currentFinal = parseInt( $( this.moutingDiv).style.width) - Math.floor( $( this.holdDiv).offsetWidth / this.delta) * this.delta;
            }
            this.finalPosition = currentFinal;
        } else if ( ( this.direction > 0 && this.temp <= 0) || ( this.direction < 0 && ( Math.abs( this.temp) <= Math.abs( parseInt( $( this.moutingDiv).offsetWidth) - Math.floor( $( this.holdDiv).offsetWidth / this.delta) * this.delta)))) {
             // условие присутствия реакции на нажатие кнопок-активаторов
            this.finalPosition = this.temp;
        }
		// поехали
		this.move();
    },
    
    move: function() {
        // присваем this переменной для функции setTimeout, которая просто this не понимает
        thisObj = this;
        // определяем currentPosition
        this.currentPosition = parseInt( $( this.moutingDiv).style.left);
		// если шаг не задан явно
        if ( !this.constantStep) {
			// определяем прирост для данного цикла ( описание закона движения)
			this.step = this.direction * Math.round (Math.abs( this.finalPosition - this.currentPosition) / 7);
			if ( Math.abs (this.step) < 2) {
				this.step = this.direction * 1;
			}
        } else {
        	// выполняем прирост на заданое значение
        	this.step = this.direction* this.constantStep;
        }
        // определяем условие повторного вызова этой функции ( достигается ли за этот цикл финальная позиция)
        if ( this.direction > 0) {
             this.condition = (this.currentPosition < this.finalPosition);
        } else {
            this.condition = (this.currentPosition > this.finalPosition);
        }
        if ( this.condition) {
            // передвигаем слой и перезапускаем функцию
            $( this.moutingDiv).style.left = (this.currentPosition + this.step) + "px";
            this.process_func.call( this);
            this.time = window.setTimeout( function() { thisObj.move() }, thisObj.timeOut);
        } else {
            // чистим таймаут и обнуляем переменные
            clearTimeout( this.time);
            this.finalPosition = null;
            this.time = null;
            this.step = 0;
            // вызываем внешнюю функцию
            this.end_func.call( this);
        }
    },
    
    insertElement: function() {
		if ( this.cycle == 1) {
			this.elementArray = this.getElementsArray();
			if ( this.currentElement == (this.elementArray.length - 1) && this.direction < 0) {
				if ( this.finalPosition != null) {
					this.temp += this.delta;
				}
				$( this.moutingDiv).style.left = ($( this.moutingDiv).offsetLeft + this.delta) + "px";
				this.tempChild = $( this.moutingDiv).removeChild( this.elementArray[0]);
				$( this.moutingDiv).appendChild( this.tempChild);
				this.currentElement = this.elementArray.length - 1;
			} else if ( this.currentElement == 0 && this.direction > 0) {
				if ( this.finalPosition != null) {
					this.temp -= this.delta;
				}
 				$( this.moutingDiv).style.left = ( $( this.moutingDiv).offsetLeft - this.delta) + "px";
				this.lastElement = this.elementArray.length - 1;
				this.firstElement = 0;
				$( this.moutingDiv).insertBefore( this.elementArray[this.lastElement],  this.elementArray[0]);
				this.currentElement = 0;
			} else {
				this.currentElement += (-1) * this.direction;
			}
		}
		// вызываем внешнюю функцию
		this.begin_func.call( this);
    },
	defaultEventFunc: function() {
    }

}
