
function always() {
	return true;
}

function never() {
	return false;
}

/* DateFormat */
function TDateFormat() {
	if (!TDateFormat.prototype.tDateFormat) {
		TDateFormat.prototype.monthName = [ "января", "февраля", "марта", "апреля"
			, "мая", "июня", "июля", "августа"
			, "сентября", "октября", "ноября", "декабря"
		];
		TDateFormat.prototype.dayName = [
			"воскресенье", "понедельник", "вторник"
			, "среда", "четверг", "пятница", "суббота"
		];
		TDateFormat.prototype.fullDate = function (date) {
			return this.dayName[date.getDay()] + ", " + date.getDate()
				+ " " + this.monthName[date.getMonth()] + " " + date.getFullYear() + " года";
		};
		TDateFormat.prototype.tDateFormat = true;
	}
}

var dateFormat = null;
TDateFormat.getInstance = function() {
	if (dateFormat == null) dateFormat = new TDateFormat();
	return dateFormat;
};

/* UserAgent */
function TUserAgent() {
	if (!TUserAgent.prototype.tUserAgent) {
		TUserAgent.prototype.hasDOM = document.getElementById ? always : never;
		TUserAgent.prototype.hasVersion = function(minVersion) {
			return !minVersion || minVersion <= this.iAgentVersion;
		};
		var agentName = navigator.userAgent.toLowerCase(), at;
		var at;
		if ((at = agentName.indexOf('msie')) < 0) TUserAgent.prototype.isMSIE = never;
		else {
			TUserAgent.prototype.agentVersion = parseInt(agentName.charAt(at + 5));
			TUserAgent.prototype.isMSIE = TUserAgent.prototype.hasVersion;
		}
		if ((at = agentName.indexOf('opera')) < 0) TUserAgent.prototype.isOpera = never;
		else {
			TUserAgent.prototype.agentVersion = parseInt(agentName.charAt(at + 6));
			TUserAgent.prototype.isOpera = TUserAgent.prototype.hasVersion;
		}
		if (document.getElementById) TUserAgent.prototype.getElement = function(id) {
			return document.getElementById(id);
		}; else if (document.all) TUserAgent.prototype.getElement = function(id) {
			return document.all[id];
		}; else TUserAgent.prototype.getElement = function() {
			return null;
		};
		TUserAgent.prototype.tUserAgent = true;
	}
}

var userAgent = null;
TUserAgent.getInstance = function() {
	if (userAgent == null) userAgent = new TUserAgent();
	return userAgent;
};

function getElement(id) {
	var agent = TUserAgent.getInstance();
	return agent.getElement(id);
}

/* DOM tools */
function TDOMTools() {
	var prototype = this.constructor.prototype;
	if (!prototype.tDOMTools) {
		prototype.hasClassName = function (element, className) {
			var has = false;
			if (element.className) {
				if (element.className == className) has = true;
				else {
					var nameList = element.className.split(" "), listAt = 0;
					while (listAt < nameList.length && nameList[listAt] != className) listAt++;
					has = listAt < nameList.length;
				}
			}
			return has;
		};
		prototype.addClassName = function (element, className) {
			if (!element.className) element.className = className;
			else if (!this.hasClassName(element, className)) element.className += " " + className;
		};
		prototype.removeClassName = function (element, className) {
			if (element.className) {
				if (element.className == className) element.className = "";
				else {
					var nameList = element.className.split(" "), listAt = 0;
					while (listAt < nameList.length && nameList[listAt] != className) listAt++;
					if (listAt < nameList.length) {
						nameList.splice(listAt, 1);
						element.className = nameList.join(" ");
					}
				}
			}
		};
		prototype.tDOMTools = true;
	}
}
TDOMTools.getInstance = function () {
	if (!TDOMTools.instance) TDOMTools.instance = new TDOMTools();
	return TDOMTools.instance;
};
domTools = TDOMTools.getInstance();


/* Observable */
function TObservable(constructor, object) {
	if (!constructor.prototype.tObservable) {
		constructor.prototype.addObserver = function(observer) {
			if (this.observerList == null) this.observerList = new Array();
			this.observerList[this.observerList.length] = observer;
		};
		constructor.prototype.notifyEvent = function(notify) {
			if (this.observerList != null) for (var index = 0; index < this.observerList.length; index++) {
				notify(this.observerList[index]);
			}
		};
		constructor.prototype.removeObserver = function(observer) {
			if (this.observerList != null) {
				var index = 0;
				while (index < this.observerList.length && this.observerList[index] != observer) index++;
				if (index < this.observerList.length) this.observerList.splice(index, 1);
			}
		};
		constructor.prototype.tObservable = true;
	}
	object.observerList = null;
}


/* Page */
function TPage() {
	TObservable(TPage, this);
	if (!TPage.prototype.tPage) {
		TPage.prototype.notifyLoad = function() {
			this.notifyEvent(function(observer) {
				if (observer.notifyLoad) observer.notifyLoad();
			});
		};
		TPage.prototype.notifyResize = function() {
			this.notifyEvent(function(observer) {
				if (observer.notifyResize) observer.notifyResize();
			});
		};
		TPage.prototype.notifyUnload = function() {
			this.notifyEvent(function(observer) {
				if (observer.notifyUnload) observer.notifyUnload();
			});
		};
		TPage.prototype.tPage = true;
	}
}

var page = null;
TPage.getInstance = function() {
	if (page == null) page = new TPage();
	return page;
};
window.onload = function() {
	TPage.getInstance().notifyLoad();
};
window.onresize = function() {
	TPage.getInstance().notifyResize();
};
window.onunload = function() {
	TPage.getInstance().notifyUnload();
};

/* MRef specifier */
function TMRefSpecifier() {
	if (!TMRefSpecifier.prototype.tMRefSpecifier) {
		TMRefSpecifier.prototype.add = function(refId) {
			if (this.refIdList == null) this.refIdList = new Array();
			this.refIdList[this.refIdList.length] = refId;
		}
		TMRefSpecifier.prototype.notifyLoad = function() {
			if (this.refIdList != null) for (refIdAt = 0; refIdAt < this.refIdList.length; refIdAt++) {
				var anchor = getElement(this.refIdList[refIdAt]);
				if (anchor != null) {
					mref = anchor.attributes['mref'] != null ? anchor.attributes['mref'].value : this.refIdList[refIdAt];
					mref += String.fromCharCode(0x20 + 0x20) + 'composyst' + String.fromCharCode(0x20 + 0x0e) + 'ru';
					if (anchor.innerHTML == '') anchor.innerHTML = mref;
					anchor.href = 'ma' + String.fromCharCode(0x69, 0x6c, 0x74, 111) + String.fromCharCode(0x20 + 0x1a) + mref;
					anchor.style.display = 'inline';
				}
			}
		}
		TMRefSpecifier.prototype.tMRefSpecifier = true;
	}
	this.refIdList = null;
	TPage.getInstance().addObserver(this);
}

var mrefSpecifier = null;
TMRefSpecifier.getInstance = function() {
	if (mrefSpecifier == null) mrefSpecifier = new TMRefSpecifier();
	return mrefSpecifier;
};

/* Timer */
function TTimer() {
	if (!TTimer.prototype.tTimer) {
		TTimer.prototype.addObserver = function(observer, interval) {
			this.stop();
			var observerEntry = null;
			if (this.entryList == null) this.entryList = new Array();
			else {
				var index = 0;
				while (index < this.entryList.length && this.entryList[index].observer != observer) index++;
				if (index < this.entryList.length) observerEntry = this.entryList[index];
			}
			if (!observerEntry) {
				observerEntry = new Object();
				observerEntry.observer = observer;
				this.entryList[this.entryList.length] = observerEntry;
			}
			observerEntry.interval = 0 < interval ? interval : 15;
			observerEntry.nextAt = (new Date()).getTime() + observerEntry.interval;
			this.update();
		};
		TTimer.prototype.removeObserver = function(observer) {
			if (this.entryList != null) {
				this.stop();
				var index = 0;
				while (index < this.entryList.length && this.entryList[index].observer != observer) index++;
				if (index < this.entryList.length) this.entryList.splice(index, 1);
				this.update();
			}
		};
		TTimer.prototype.stop = function() {
			if (this.timeoutId) {
				window.clearTimeout(this.timeoutId);
				this.timeoutId = null;
			}
		};
		TTimer.prototype.update = function() {
			if (this.updateAt == null) {
				this.updateAt = (new Date()).getTime();
				var activeList = new Array();
				for (var index = 0; index < this.entryList.length; index++) {
					var listEntry = this.entryList[index];
					if (listEntry.nextAt <= this.updateAt) {
						listEntry.nextAt = this.updateAt + listEntry.interval;
						activeList[activeList.length] = listEntry;
					}
				}
				for (var index = 0; index < activeList.length; index++) activeList[index].observer.notifyInterval();
				var nextAt = null;
				for (var index = 0; index < this.entryList.length; index++) {
					var listEntry = this.entryList[index];
					if (nextAt == null || listEntry.nextAt < nextAt) nextAt = listEntry.nextAt;
				}
				if (this.updateAt < nextAt) this.timeoutId = window.setTimeout('TTimer.notifyInterval()', nextAt - this.updateAt);
				this.updateAt = null;
			}
		};
		TTimer.notifyInterval = function() {
			var timer = TTimer.getTimer();
			timer.timeoutId = null;
			timer.update();
		};
		TTimer.prototype.tTimer = true;
	}
	this.updateAt = null;
	this.timeoutId = null;
	this.entryList = null;
}

var timer = null;
TTimer.getTimer = function() {
	if (!timer) timer = new TTimer();
	return timer;
};


/* Rollover */
function TRollover(object) {
	TObservable(TRollover, this);
	if (!TRollover.prototype.tRollover) {
		TRollover.prototype.setRollover = function(rollover) {
			if (this.rollover != rollover) {
				if (rollover) this.notifyEvent(function(observer) {
					if (observer.notifyRollover) observer.notifyRollover();
				}); else this.notifyEvent(function(observer) {
					if (observer.notifyRollout) observer.notifyRollout();
				});
				this.rollover = rollover;
			}
		};
		TRollover.prototype.tRollover = true;
	}
	this.object = object;
	this.object.rolloverObject = this;
	this.rollover = null;
	for (var index = 1; index < arguments.length; index++) this.addObserver(arguments[index]);
	this.object.onmouseover = function() {
		this.rolloverObject.setRollover(true);
	};
	this.object.onmouseout = function() {
		this.rolloverObject.setRollover(false);
	};
}


/* Click */
function TClick(object) {
	TObservable(TClick, this);
	if (!TClick.prototype.tClick) {
		TClick.prototype.getObject = function () {
			return this.object;
		};
		TClick.prototype.click = function () {
			var self = this;
			this.notifyEvent(function (observer) {
				if (observer.notifyClick) observer.notifyClick(self);
			});
		};
		TClick.prototype.tClick = true;
	}
	this.object = object;
	for (var index = 1; index < arguments.length; index++) this.addObserver(arguments[index]);
	var self = this;
	this.object.onclick = function() {
		self.click();
		return false;
	};
}


/* Toggle */
function TToggle(object) {
	TObservable(TToggle, this);
	if (!TToggle.prototype.tToggle) {
		TToggle.prototype.addState = function(stateIndex, state) {
			this.stateList[stateIndex] = state;
		}
		TToggle.prototype.getState = function() {
			return this.stateList[this.stateAt];
		}
		TToggle.prototype.toggle = function() {
			var stateAt = 0;
			if (this.stateAt != null) {
				stateAt = this.stateAt + 1;
				while (stateAt < this.stateList.length && this.stateList[stateAt] == null) stateAt++;
				if (stateAt == this.stateList.length) stateAt = 0;
			}
			this.setStateIndex(stateAt);
		};
		TToggle.prototype.setState = function(state) {
			var stateIndex = 0;
			while (stateIndex < this.stateList.length && this.stateList[stateIndex] != state) stateIndex++;
			if (stateIndex < this.stateList.length) this.setStateIndex(stateIndex);
		}
		TToggle.prototype.setStateIndex = function(stateIndex) {
			if (this.stateAt != stateIndex) {
				this.stateAt = stateIndex;
				this.notifyEvent(function(observer, toggle) {
					if (observer.notifyToggle) observer.notifyToggle(toggle);
				});
			}
		}
		TToggle.prototype.tToggle = true;
	}
	this.object = object;
	this.object.toggleObject = this;
	this.stateList = Array(0, 1);
	this.stateAt = null;
	for (var index = 1; index < arguments.length; index++) this.addObserver(arguments[index]);
	this.object.onclick = function() {
		this.toggleObject.toggle();
		return false;
	};
}


/* State image */
function TStateImage(image) {
	if (!TStateImage.prototype.tStateImage) {
		TStateImage.prototype.addState = function(stateIndex, imageSrc) {
			var state = this.stateList[stateIndex];
			if (!state) this.stateList[stateIndex] = state = new Array();
			for (var index = 1; index < arguments.length; index++) this.addVariant(state, index - 1, arguments[index]);
			return state;
		};
		TStateImage.prototype.setState = function(stateIndex) {
			if (this.stateIndex != stateIndex) {
				this.stateIndex = stateIndex;
				this.update();
			}
		};
		TStateImage.prototype.getState = function() {
			var stateIndex = this.stateIndex != null ? this.stateIndex : 0;
			return stateIndex < this.stateList.length ? this.stateList[stateIndex] : null;
		}
		TStateImage.prototype.addVariant = function(state, variantIndex, imageSrc) {
			state[variantIndex] = new Image();
			state[variantIndex].src = imageSrc;
		};
		TStateImage.prototype.setVariant = function(variantIndex) {
			if (this.variantIndex != variantIndex) {
				this.variantIndex = variantIndex;
				this.update();
			}
		}
		TStateImage.prototype.getVariant = function(state) {
			var variantIndex = this.variantIndex != null ? this.variantIndex : 0;
			return variantIndex < state.length ? state[variantIndex] : null;
		}
		TStateImage.prototype.update = function() {
			var state = this.getState(), image = state ? this.getVariant(state) : null;
			if (image && this.stateImage != image) {
				this.image.src = image.src;
				this.stateImage = image;
			}
		}
		TStateImage.prototype.tStateImage = true;
	}
	this.stateList = new Array();
	this.stateIndex = this.variantIndex = null;
	this.image = image;
	this.stateImage = null;
	if (1 < arguments.length) {
		var index = 1, state = null, variantIndex = 0;
		do {
			if (typeof(arguments[index]) == 'number') state = this.addState(arguments[index]), variantIndex = 0;
			else if (state && typeof(arguments[index]) == 'string') this.addVariant(state, variantIndex++, arguments[index]);
		} while (++index < arguments.length);
	}
}


/* ImageRollover */
function TImageRollover(stateImage, idleVariant, overVariant) {
	if (!TImageRollover.prototype.tImageRollover) {
		TImageRollover.prototype.notifyRollover = function() {
			this.stateImage.setVariant(this.overVariant);
		}
		TImageRollover.prototype.notifyRollout = function() {
			this.stateImage.setVariant(this.idleVariant);
		}
		TImageRollover.prototype.tImageRollover = true;
	}
	this.stateImage = stateImage;
	this.idleVariant = idleVariant;
	this.overVariant = overVariant;
}


/* Box */
function TBox(object) {
	if (!TBox.prototype.tBox) {
		TBox.prototype.getObject = function() {
			return this.object;
		};
		TBox.prototype.getStyle = function() {
			return this.object.style;
		};
		TBox.prototype.getStyleClass = function() {
			return this.object.className;
		}
		TBox.prototype.setStyleClass = function(className) {
			this.object.className = className;
		}
		TBox.prototype.show = function(visible) {
			var object = this.object;
			if (visible == null) visible = true;
			object.style.visibility = visible ? 'visible' : 'hidden';
		};
		TBox.prototype.hide = function() {
			this.show(false);
		};
		TBox.prototype.getAbsoluteAt = function(pointAt) {
			var object = this.object;
			var left = 0, top = 0;
			while (object) {
				left += object.offsetLeft;
				top += object.offsetTop;
				object = object.offsetParent;
			}
			if (!pointAt) pointAt = [left, top];
			else pointAt[0] = left, pointAt[1] = top;
			return pointAt;
		};
		TBox.prototype.getTargetAt = function(target, pointAt) {
			var targetAt = this.getAt(pointAt);
			var object = this.object, targetObject = target.object;
			if (object.offsetParent != targetObject.offsetParent) {
				var parent = object.offsetParent;
				while (parent) {
					targetAt[0] += parent.offsetLeft;
					targetAt[1] += parent.offsetTop;
					parent = parent.offsetParent;
				}
				parent = target.offsetParent;
				while (parent) {
					targetAt[0] -= parent.offsetLeft;
					targetAt[1] -= parent.offsetTop;
					parent = parent.offsetParent;
				}
			}
			return targetAt;
		}
		TBox.prototype.getAt = function(pointAt) {
			var object = this.object;
			if (!pointAt) pointAt = [object.offsetLeft, object.offsetTop];
			else pointAt[0] = object.offsetLeft, pointAt[1] = object.offsetTop;
			return pointAt;
		};
		TBox.prototype.setTo = function(point) {
			var object = this.object;
			object.style.left = point[0] + 'px';
			object.style.top = point[1] + 'px';
		};
		TBox.prototype.moveTo = function(point) {
			if (!this.flight) this.setTo(point);
			else this.flight.setTo(point);
		}
		TBox.prototype.hasFlight = function() {
			return this.flight ? true : false;
		}
		TBox.prototype.setFlight = function(flight) {
			this.flight = flight;
		};
		TBox.prototype.getFlight = function() {
			return this.flight;
		};
		TBox.prototype.clearFlight = function() {
			this.flight = null;
		};
		TBox.prototype.getWidth = function() {
			return this.object.offsetWidth;
		}
		TBox.prototype.getHeight = function() {
			return this.object.offsetHeight;
		}
		TBox.prototype.tBox = true;
	}
	this.object = object;
	this.flight = null;
}

function getBox(id) {
	var userAgent = TUserAgent.getInstance();
	var object = userAgent.getElement(id);
	return object ? new TBox(object) : null;
}


/* BoxShowRollover */
function TBoxShowRollover(box) {
	if (!TBoxShowRollover.prototype.tBoxShowRollover) {
		TBoxShowRollover.prototype.notifyRollover = function() {
			this.box.show();
		}
		TBoxShowRollover.prototype.notifyRollout = function() {
			this.box.hide();
		}
		TBoxShowRollover.prototype.tBoxShowRollover = true;
	}
	this.box = box;
}



/* Flight */
function TFlight(box) {
	TObservable(TFlight, this);
	if (!TFlight.prototype.tFlight) {
		TFlight.prototype.setVelocity = function(velocity) {
			this.velocity = 0 < velocity ? velocity : 100;
			this.advance = TFlight.prototype.velocityAdvance;
		};
		TFlight.prototype.setDuration = function(duration, originAt) {
			this.duration = 0 <= duration ? duration : 0;
			this.originAt = originAt;
			this.advance = TFlight.prototype.durationAdvance;
		};
		TFlight.prototype.setTo = function(point) {
			if (this.pointTo[0] != point[0] || this.pointTo[1] != point[1]) {
				this.pointTo[0] = point[0]; this.pointTo[1] = point[1];
				this.distance = null;
				this.startTime = null;
				this.update();
			}
		};
		TFlight.prototype.start = function(boxAt, updateTime) {
			this.startTime = updateTime;
			this.startAt[0] = boxAt[0]; this.startAt[1] = boxAt[1];
			this.notifyEvent(function(observer) {
				if (observer.notifyStart) observer.notifyStart();
			});
			TTimer.getTimer().addObserver(this, 10);
		};
		TFlight.prototype.update = function() {
			this.box.getAt(this.pointAt);
			if (this.pointTo[0] == this.pointAt[0] && this.pointTo[1] == this.pointAt[1]) this.complete();
			else {
				var updateTime = (new Date()).getTime();
				if (!this.startTime) this.start(this.pointAt, updateTime);
				else {
					var factor = this.advance(this.pointAt, updateTime);
					if (1 <= factor) this.box.setTo(this.pointTo);
					else {
						this.pointAt[0] = this.startAt[0] + (this.pointTo[0] - this.startAt[0]) * factor;
						this.pointAt[1] = this.startAt[1] + (this.pointTo[1] - this.startAt[1]) * factor;
						this.box.setTo(this.pointAt);
					}
				}
			}
		};
		TFlight.prototype.notifyInterval = function() {
			this.update();
		};
		TFlight.prototype.evaluateDistance = function(pointAt, pointTo) {
			return Math.sqrt(Math.pow(pointTo[0] - pointAt[0], 2) + Math.pow(pointTo[1] - pointAt[1], 2));
		}
		TFlight.prototype.getDistance = function() {
			if (this.distance == null) this.distance = this.evaluateDistance(this.startAt, this.pointTo);
			return this.distance;

		};
		TFlight.prototype.getDuration = function() {
			if (this.originAt) {
				if (this.originAt[0] != this.startAt[0] | this.originAt[1] != this.startAt[1]) {
					var originDistance = this.evaluateDistance(this.originAt, this.pointTo);
					if (originDistance == 0) this.duration = 0;
					else this.duration = this.duration * this.getDistance() / originDistance;
				}
				this.originAt = null;
			}
			return this.duration;
		};
		TFlight.prototype.durationAdvance = function(boxAt, updateTime) {
			return (updateTime - this.startTime) / (this.getDuration() * 1000);
		};
		TFlight.prototype.velocityAdvance = function(boxAt, updateTime) {
			return this.velocity * (updateTime - this.startTime) / 1000 / this.getDistance();
		};
		TFlight.prototype.complete = function() {
			TTimer.getTimer().removeObserver(this);
			this.box.setTo(this.pointTo);
			this.box.clearFlight();
			this.notifyEvent(function(observer) {
				if (observer.notifyComplete) observer.notifyComplete();
			});
		};
		TFlight.prototype.tFlight = true;
	}
	this.box = box;
	this.box.setFlight(this);
	this.velocity = null;
	this.duration = null;
	this.originAt = null;
	this.pointTo = [null, null];
	this.pointAt = [null, null];
	this.startTime = null;
	this.startAt = [null, null];
	this.distance = null;
}


/**/
function TInsetSwitcher(prefix, quantity) {
	var prototype = this.constructor.prototype;
	if (!prototype.tInsetSwitcher) {
		prototype.notifyLoad = function () {
			this.titleList = new Array();
			this.insetList = new Array();
			for (var itemAt = 0; itemAt < this.quantity; itemAt++) {
				var title = getElement(this.prefix + "title-" + itemAt);
				var inset = getElement(this.prefix + "inset-" + itemAt);
				if (title && inset) {
					this.titleList.push(title);
					this.insetList.push(inset);
					new TClick(title, this);
				}
			}
		};
		prototype.notifyClick = function (click) {
			for (var itemAt = 0; itemAt < this.titleList.length; itemAt++) {
				if (this.titleList[itemAt] == click.getObject()) {
					domTools.addClassName(this.titleList[itemAt], "active");
					domTools.addClassName(this.insetList[itemAt], "active");
				} else {
					domTools.removeClassName(this.titleList[itemAt], "active");
					domTools.removeClassName(this.insetList[itemAt], "active");
				}
			}
		};
		prototype.tInsetSwitcher = true;
	}
	this.prefix = prefix;
	this.quantity = quantity;
	TPage.getInstance().addObserver(this);
}
