/**
 * @projectDescription
 * Скрипт управления движением на странице: фейд страницы при загрузке, показ флэшек при ховере, анимация скроллирования, управление лифтом.
 *
 * @author Vlad Yakovlev (scorpix@design.ru)
 * @copyright Art.Lebedev Studio (http://www.artlebedev.ru)
 * @requires jQuery 1.3
 * @requires SWFConnectorUtils
 * @requires SWFObject 2
 * @version 0.3.2 (05.02.2009)
 */
var mainAnimating = (function(options) {

	/**
	 * Элементы jQuery.
	 * @type {jQuery}
	 */
	var els;

	/**
	 * Флаг пребывания юзера в самом низу страницы.
	 */
	var bottom = true;

	/**
	 * Объект управления флэшками.
	 * @type {Object}
	 */
	var flashVideo;

	/**
	 * Объект управления анимации при инициализации страницы.
	 * @type {Object}
	 */
	var loadAnimating;

	/**
	 * Объект управления иконки лифта.
	 * @type {Object}
	 */
	var depth;

	/**
	 * Передает сообщение скроллирования объекту управления флэшками.
	 * @param {Number} id Идентификатор соединения (флэшки).
	 */
	function flashScroll(id) {
		flashVideo.scroll(id, fastScroll);
	}

	/**
	 * Инициализация параметров, переданных скрипту.
	 * @param {Object} inOptions Настройки:
	 * <ul>
	 *  <li><code>flash</code> - настройки для объекта управления флэшками.</li>
	 * </ul>
	 */
	function setOptions(inOptions) {
		flashVideo.setOptions(inOptions.flash);
	}

	/**
	 * Срабатывает при ресайзе.
	 */
	function windowResize() {
		// Скроллирует окно вниз при ресайзе окна, если юзер был внизу.
		/*if (bottom) {
			els.scroller.scrollTop(getDocumentHeight() - els.window.height());
		}*/
	}

	/**
	 * Cрабатывает при скролле окна.
	 */
	function windowScroll() {
		bottom = 10 > getDocumentHeight() - els.window.height() - els.scroller.scrollTop();
	}

	/**
	 * Анимирует скроллирование страницы вверх или вниз.
	 * @param {String} target Скроллировать вверх (<code>up</code>) или вниз (<code>under</code>).
	 */
	function fastScroll(target) {
		/** @type {Number} */
		var startPos = els.scroller.scrollTop();

		depth.setMove(false);

		var params = {
			time: 2,
			onComplete: function() {
				depth.setMove(true);
				depth.setPos(true);
			}
		};

		switch (target) {
			case 'under':
				var moveTo = getDocumentHeight() - els.window.height();
				params.moveX = function(value) {
					this.scrollTop = startPos + Math.ceil(value * (moveTo - startPos));
				};

				break;

			case 'up':
				params.moveX = function(value) {
					this.scrollTop = Math.ceil((1 - value) * startPos);
				};

				break;
		}

		depth.animate(target, 2);
		jTweener.addTween(els.scroller, params);
	}

	/**
	 * Возвращает высоту документа.
	 * @return {Number}
	 */
	function getDocumentHeight()
	{
		return els.back.outerHeight();
	}

	$(function() {
		els = {
			window: $(window),
			back: $('#back'),
			scroller: $('#scroller'),
			sectionUnder: $('#section_under'),
			backUp: $('#back_up'),
			imageUp: $('#back_up .image'),
			imageUnder: $('#back_under .image'),
			imageUnderGray: $('#back_under_gray .image'),
			backGray: $('#back_gray'),
			depth: $('#depth'),
			textBlock: $('#depth .number')
		};

		var hrefs = location.href.split('?');
		var hrefId = 'surface';

		if (!(hrefs[1] && hrefId == hrefs[1].substr(0, hrefId.length))) {
			els.scroller.scrollTop(getDocumentHeight() - els.window.height());
		}

		flashVideo.load();

		els.window.load(function() {
			loadAnimating.animate();

			//if ($.browser.mozilla) {
			//	CanvasShaper();
			//}
		});

		els.window.resize(windowResize);

		els.scroller.scroll(windowScroll);

		// Подергаем элементы в IE, чтоб они были видны в окне браузера.
		if ($.browser.msie) {
			els.window.load(function() {
				$('.section_link, .page_link, .navigation, .main_navigation_container').css('margin-left', 1).css('margin-left', '');
			});
		}

		$('.section_link a').click(function() {
			fastScroll($(this).attr('href').substr(1));

			return false;
		});

		$('.section .main_navigation .up div a, .section .main_navigation .under div a').click(function() {
			fastScroll($(this).attr('href').substr(1));

			return false;
		});
	});

	// В Safari почему-то глючит.
	if ($.browser.safari) {
		$(function() {
			paddingFix();

			els.window.resize(paddingFix);

			function paddingFix() {
				els.sectionUnder.css('margin-top', parseInt(els.back.css('padding-bottom')));
			}
		});
	}

	if ($.browser.msie && 6 >= parseInt($.browser.version)) {
		$(function() {
			var backImageSize = {
				height: 1190,
				width: 1203
			};

			imagesFix();

			els.window.resize(imagesFix);

			function imagesFix() {
				var backUpSize = {
					height: els.backUp.height(),
					width: Math.ceil(els.backUp.width() / 2)
				};

				if (backUpSize.height / backUpSize.width < backImageSize.height / backImageSize.width) {
					// Вычисляем размер по ширине
					var attrs = {
						height: 'auto',
						width: backUpSize.width
					};
				} else {
					// Вычисляем размер по высоте
					var attrs = {
						height: backUpSize.height,
						width: 'auto'
					};
				}

				els.imageUp.css(attrs);
				els.imageUnder.css(attrs);
				loadAnimating.ieFix(attrs);
			}
		});
	}

	flashVideo = (function() {

		/**
		 * Информация об объектах Flash. Индекс - тип флэша, значение - информация об изображении (image) и видео (video):
		 * <ul>
		 *  <li><code>connection</code> - номер соединения для "общения" с флэш-объектами,</li>
		 *  <li><code>inited</code> - флаг инициализации флэшки,</li>
		 *  <li><code>path</code> - путь к файлу флэша.</li>
		 * </ul>
		 */
		var objects = {};

		/**
		 * Соответствие идентификатора соединения и типа флэшки.
		 */
		var con2Types = {};

		/**
		 * Таймаут для ховера.
		 */
		var timeoutId = 0;

		/**
		 * Таймаут для ховера.
		 */
		var curTimeoutId = 0;

		/**
		 * Объект коннектора для обратной связи с флэшками.
		 * @type {SWFConnector}
		 */
		var connector;

		var isScroll = false;

		/**
		 * Настройки, переданные скрипту:
		 * <ul>
		 *  <li><code>debug</code> - флаг отладки,</li>
		 *  <li><code>connector</code> - путь к флэшке-коннектору,</li>
		 *  <li><code>objects</code> - пути к флэшкам:
		 *   <ul>
		 *    <li><code>up</code> - верхнее изображение (<code>image</code>) и видео (<code>video</code>),</li>
		 *    <li><code>under</code> - нижнее изображение (<code>image</code>) и видео (<code>video</code>),</li>
		 *   </ul>
		 *  </li>
		 * </ul>
		 * @type {Object}
		 */
		var options;

		var pathParts = location.href.split('/');

		var language = pathParts[3] && 'en' == pathParts[3] ? 'en' : 'ru';

		/**
		 * Загружает flash.
		 */
		function load() {
			var mt = (new Date()).getTime();
			var i = 0;

			connector = new SWFConnector(options.connector, 'flash_connector');

			for (var type in options.objects) {
				objects[type] = {
					showed: false,
					image: {
						connection: mt + i,
						inited: false,
						path: options.objects[type].image
					},
					video: {
						connection: mt + i + 1,
						inited: false,
						path: options.objects[type].video
					}
				};
				con2Types[objects[type].image.connection] = type;
				con2Types[objects[type].video.connection] = type;
				i += 2;
			}

			for (var type in objects) {
				init(type);
			}
		}

		/**
		 * Создает флэш-объекты изображения и видео.
		 * @param {String} type Тип объектов.
		 */
		function init(type) {
			$('#image_' + type + ', #video_' + type).css('top', -7);

			swfobject.embedSWF(objects[type].video.path, 'flash_video_' + type, '100%', '100%', '9.0.0', '', {
				connection_id: objects[type].video.connection,
				debug_mode: options.debug ? 1 : 0
			});
			swfobject.embedSWF(objects[type].image.path, 'flash_image_' + type, '100%', '100%', '9.0.0', '', { connection_id: objects[type].image.connection }, {
				bgcolor: '#000000',
				// Изображение должно быть с прозрачностью.
				wmode: 'transparent'
			});
		}

		/**
		 * Событие об инициализации флэшки.
		 * @param {Number} id Идентификатор соединения.
		 */
		function inited(id) {
			if (!con2Types[id]) {
				return;
			}

			/** Тип флэшки */
			var type = con2Types[id];
			/** Изображение или видео */
			var flashType = id == objects[type].image.connection ? 'image' : 'video';

			objects[type][flashType].inited = true;
			// Убираем с экрана флэшку.
			$('#' + flashType + '_' + type).removeClass('init').addClass('moved').css('top', '');

			// Нужно, чтоб проинициализировались и изображение, и видео.
			if (!objects[type].image.inited || !objects[type].video.inited) {
				return;
			}

			// "Вешаем" события для показа и скрытия флэшек.
			$('#section_' + type + ' .section_link').hover(function() {
				if (isScroll) {
					return false;
				}

				timeoutId++;
				curTimeoutId = timeoutId;
				setTimeout(function() {
					show(type);
				}, 100);

				var offset = $('#section_' + type + ' .section_link').offset();

				// Запускаем показ изображения.
				connector.sendCommand(objects[type].image.connection, 'setposition', [offset.left, offset.top]);
			}, function() {
				timeoutId++;
			});
			$('#section_' + type + ' .section_link a').click(function() {
				hide(type);
			});
		}

		/**
		 * Запускает процесс отображения флэшек.
		 * @param {String} type Тип флэшек.
		 */
		function show(type) {
			if (timeoutId == curTimeoutId) {
				timeoutId++;
			} else {
				return;
			}

			if (objects[type].showed) {
				return;
			}

			$('#section_' + type + ' .section_link a').addClass('hover');
			objects[type].showed = true;

			var offset = $('#section_' + type + ' .section_link').offset();

			if ($.browser.msie) {
				play(objects[type].video.connection);

				return;
			}

			// Запускаем показ изображения.
			connector
				.addCommand(objects[type].image.connection, 'setposition', [offset.left, offset.top])
				.addCommand(objects[type].image.connection, 'setlanguage', [language])
				.addCommand(objects[type].image.connection, 'show')
				.addCommand(objects[type].video.connection, 'setposition', [offset.left, offset.top, '2'])
				.addCommand(objects[type].video.connection, 'setlanguage', [language])
				.sendCommands();

			$('#image_' + type).removeClass('moved');
		}

		/**
		 * Событие готовности проигрывания видео.
		 * @params {Number} id Идентификатор соединения
		 */
		function play(id) {
			if (!con2Types[id]) {
				return;
			}

			var type = con2Types[id];

			if (!objects[type].showed) {
				return;
			}

			// Позиционируем видео для просмотра.
			$('#video_' + type).removeClass('moved');
			// Запускаем проигрывание.
			if ($.browser.msie) {
				var offset = $('#section_' + type + ' .section_link').offset();

				connector
					.addCommand(objects[type].video.connection, 'setposition', [offset.left, offset.top])
					.addCommand(objects[type].video.connection, 'setlanguage', [language])
					.addCommand(objects[type].video.connection, 'playVideo')
					.sendCommands();
			} else {
				connector
					.addCommand(objects[type].video.connection, 'playVideo')
					.addCommand(objects[type].image.connection, 'hide')
					.sendCommands();
			}

			setTimeout(function() {
				$('#image_' + type).addClass('moved');
			}, 500);
		}

		/**
		 * Событие скрытия видео.
		 * @params {Number} id Идентификатор соединения.
		 */
		function flashHide(id) {
			if (con2Types[id]) {
				hide(con2Types[id]);
			}
		}

		/**
		 * Скрывает флэшки.
		 * @param {String} type Тип флэшек.
		 */
		function hide(type) {
			if (!objects[type].showed) {
				return;
			}

			objects[type].showed = false;

			$('#section_' + type + ' .section_link a').removeClass('hover');
			// Останавливаем видео.
			connector.sendCommand(objects[type].video.connection, 'stopVideo');
			// Скрываем флэшки.
			$('#video_' + type + ', #image_' + type).addClass('moved');
		}

		/**
		 * Скроллирует окно при нажатии на ссылку.
		 * @type {Number} id Идентификатор соединения.
		 * @type {Function} releaseFunc Функция, выполняемая после скроллирования.
		 */
		function scroll(id, releaseFunc) {
			var type = con2Types[id];

			if (type) {
				isScroll = true;
				hide(type);
				releaseFunc('up' == type ? 'under' : 'up');

				setTimeout(function() {
					isScroll = false;
				}, 200);
			}
		}

		function setOptions(inOptions) {
			options = inOptions;
		}

		return {
			hide: flashHide,
			inited: inited,
			load: load,
			play: play,
			setOptions: setOptions,
			scroll: scroll
		};
	})();

	loadAnimating = (function() {

		/**
		 * Анимация скрытия черно-белого изображения.
		 */
		function animate() {
			var backImageGray = new Image();
			backImageGray.onload = function() {
				onLoadImageGray();
			};
			backImageGray.src = els.imageUnderGray.attr('src');
		}

		/**
		 * Фикс для IE 6.
		 */
		function ieFix(attrs) {
			if (els.backGray) {
				els.imageUnderGray.css(attrs);
			}
		}

		/**
		 * Событие загрузки черно-белого изображения.
		 */
		function onLoadImageGray() {
			els.scroller.removeClass('junvisible');
			var backImage = new Image();
			backImage.onload = onLoadImageUnder;
			backImage.src = els.imageUnder.attr('src');
		}

		/**
		 * Событие загрузки нижнего фонового изображения.
		 */
		function onLoadImageUnder() {
			jTweener.addTween(els.imageUnderGray, {
				transition: 'easeInCubic',
				opacity: 0,
				time: 2,
				onComplete: function() {
					els.backGray.remove();
					els.backGray = null;
				}
			});
		}

		return {
			animate: animate,
			ieFix: ieFix
		};
	})();

	depth = (function Depth() {

		/**
		 * Высота окна браузера.
		 * @type {Number}
		 */
		var winHeight;

		/**
		 * Высота документа.
		 * @type {Number}
		 */
		var docHeight;

		/**
		 * Высота скроллера.
		 * @type {Number}
		 */
		var scrollerHeight;

		/**
		 * Максимальное положение скроллера по высоте.
		 * @type {Number}
		 */
		var max;

		/**
		 * Максимальное положение скроллера по высоте.
		 * @type {Number}
		 */
		var min;

		/**
		 * Максимальный метраж под землю.
		 */
		var maxDepth = 42;

		/**
		 * Высота стрелок скроллера.
		 */
		var arrowHeight = 20;

		/**
		 * Последняя учтенная позиция вертикального скроллера.
		 */
		var lastScrollPos = 0;

		/**
		 * Направление движения скроллера.
		 */
		var scrollDirection = '';

		/**
		 * Флаг, можно ли перемещать.
		 */
		var mayMove = true;

		var isAnimate = false;

		$(function() {
			setBorders();
			setPos();

			els.window.resize(function() {
				setBorders();
				setPos();
			});
			els.scroller.scroll(function() {
				setPos(true);
			});
			$('#depth .arrow_lift').click(click);
		});

		/**
		 * Анимирует спуск под землю или подъем на воздух.
		 * @param {String} direction Анимировать вверх (<code>up</code>) или вниз (<code>under</code>).
		 * @param {Number} time Время анимации в секундах.
		 */
		function animate(direction, time) {
			/** @type {Number} */
			var scrollTo = 'up' == direction ? 0 : docHeight - winHeight;
			/** @type {Number} */
			var scrollPos = scrollTo * (winHeight - scrollerHeight - arrowHeight) / (docHeight - winHeight);
			/** @type {Number} */
			var realScrollTo = scrollPos + arrowHeight + scrollerHeight / 2 >= min - scrollTo ? scrollPos + arrowHeight + scrollerHeight / 2 : min - scrollTo;

			$('#depth .content').css('visibility', 'hidden');

			isAnimate = true;

			jTweener.removeTween(els.depth);
			jTweener.addTween(els.depth, {
				top: realScrollTo,
				time: time,
				transition: 'easeinoutcubic',
				onComplete: function() {
					isAnimate = false;
				}
			});
		}

		/**
		 * Событие клика по лифту - запуск анимации скролирования.
		 */
		function click() {
			if (isAnimate) {
				return;
			}

			/** @type {Number} */
			var scrollTop = els.scroller.scrollTop();
			/** @type {Number} */
			var direction = scrollDirection;

			if (scrollTop < winHeight / 2) {
				direction = 'under';
			} else if (scrollTop > docHeight - winHeight * 3 / 2) {
				direction = 'up';
			}

			fastScroll(direction);
		}

		/**
		 * Устанавливает границы, в которых может перемещаться скроллер.
		 */
		function setBorders() {
			winHeight = els.window.height();
			docHeight = getDocumentHeight();
			scrollerHeight = Math.round((winHeight - 2 * arrowHeight) * winHeight / docHeight);
			min = winHeight * 0.9;
			max = docHeight - scrollerHeight / 2 - arrowHeight;
		}

		/**
		 * Устанавливает флаг перемещения.
		 * @param {Boolean} isTrue Перемещать можно (<code>true</code>) или нельзя (<code>false</code>).
		 */
		function setMove(isTrue) {
			mayMove = isTrue;
		}

		/**
		 * Обновляет позицию скроллера.
		 * @type {Boolean} animate Анимировать (<code>true</code>) или нет (только для Fx).
		 */
		function setPos(animate) {
			if (!mayMove) {
				return;
			}

			/** @type {Number} */
			var scrollTop = els.scroller.scrollTop();
			/** @type {Number} */
			var scrollPos = scrollTop * (winHeight - scrollerHeight - arrowHeight) / (docHeight - winHeight);
			/**
			 * Позиция скроллинга в окне.
			 * @type {Number}
			 */
			var realScrollTop = scrollPos + arrowHeight + scrollerHeight / 2 >= min - scrollTop ? scrollPos + arrowHeight + scrollerHeight / 2 : min - scrollTop;
			/**
			 * Глубина в метрах.
			 * @type {Number}
			 */
			var number = Math.round(-(realScrollTop + scrollTop - min - arrowHeight) / (max - min) * maxDepth);

			scrollDirection = scrollTop > lastScrollPos ? 'under' : 'up';
			lastScrollPos = scrollTop;

			if (0 < number) {
				number = 0;
			}

			jTweener.removeTween(els.depth);

			if (animate && $.browser.firefox) {
				jTweener.addTween(els.depth, {
					top: realScrollTop,
					time: 0.5,
					transition: 'easeinoutcubic',
					onComplete: function() {
						els.textBlock.text(number);
						$('#depth .content').css('visibility', '');
					}
				});
			} else {
				els.depth.css('top', realScrollTop);

				var prefix = number ? '−' : '';
				els.textBlock.text(prefix + Math.abs(number));
				$('#depth .content').css('visibility', '');
			}
		}

		return {
			animate: animate,
			setMove: setMove,
			setPos: setPos
		}
	})();

	var CanvasShaper = (function() {
		var sections = [ {
			container: $('#back_up'),
			canvas: null,
			image: null
		}, {
			container: $('#back_under'),
			canvas: null,
			image: null
		}];

		var className = 'shape';

		init();

		function init() {
			for (var i = 0; i < sections.length; i++) {
				var image = new Image();
				image.onload = function() { }
				image.src = sections[i].container.find('.image').attr('src');

				var canvas = $('<canvas class="' + className + '"></canvas>').appendTo(sections[i].container);

				sections[i].container.find('.image').remove();
				sections[i].canvas = canvas;
				sections[i].image = image;
			}

			updateCanvases();

			$(window).resize(updateCanvases);
		}

		function updateCanvases() {
			for (var i = 0; i < sections.length; i++) {
				var canvas = sections[i].canvas;
				var image = sections[i].image;

				var containerSize = {
					height: sections[i].container.height(),
					width: sections[i].container.width() / 2
				};

				var sx = 0;
				var sy = 0;
				var sWidth = image.width;
				var sHeight = image.height;

				if (containerSize.width < image.width && containerSize.height < image.height) {
					sWidth = containerSize.width;
					sHeight = containerSize.height;
					sx = Math.round((image.width - containerSize.width) / 2);
				} else {
					if (containerSize.width / image.width > containerSize.height / image.height) {
						sHeight = Math.round(image.height * image.width / containerSize.width);
					} else {
						sWidth = Math.round(image.width * image.height / containerSize.height);
						sx = Math.round((image.width - sWidth) / 2);
					}
				}

				canvas.attr({
					height: containerSize.height,
					width: containerSize.width
				});

				if (0 < i) {
					canvas.css('left', Math.round((sections[i].container.width() - containerSize.width) / 2));
				}

				var ctx = canvas.get(0).getContext('2d');

				ctx.drawImage(image, sx, sy, sWidth, sHeight, 0, 0, containerSize.width, containerSize.height);
			}
		}
	});

	return {
		flashInited: flashVideo.inited,
		flashPlay: flashVideo.play,
		flashHide: flashVideo.hide,
		flashScroll: flashScroll,
		setOptions: setOptions
	}
})();

/**
 * Событие инициализации флэшки, отправляемое коннектором.
 * @param {Number} id Идентификатор соединения (флэшки).
 */
function onFlashObjectInitialized(id) {
	mainAnimating.flashInited(id);
}

/**
 * Событие показа флэшки-изображения, отправляемое коннектором.
 * @param {Number} id Идентификатор соединения (флэшки).
 */
function onFlashImageShown(id) {
	mainAnimating.flashPlay(id);
}

/**
 * Событие прекращения видео, отправляемое коннектором.
 * @param {Number} id Идентификатор соединения (флэшки).
 */
function onFlashMouseOut(id) {
	mainAnimating.flashHide(id);
}

/**
 * Событие прекращения видео и скроллирования страницы, отправляемое коннектором.
 * @param {Number} id Идентификатор соединения (флэшки).
 */
function onFlashMouseDown(id) {
	mainAnimating.flashScroll(id);
}

if ($.browser.msie) {
	$(function() {
		link = $('#section_up .page_link a');

		$('#section_up .page_link').hover(function() {
			link.css('top', -44);
		}, function() {
			link.css('top', '');
		});
	});
}

$(function() {
	var isCanvas = true;

	var className = 'shape';

	var objects = [];

	init();

	function init() {
		checkCanvas();

		$('.projects li').each(function(index) {
			var el = $(this);
			objects.push({
				root: el,
				width: 0,
				height: 0,
				canvas: null,
				radius: null,
				backColor: el.css('background-color'),
				borderColor: el.css('border-top-color'),
				borderWidth: parseInt(el.css('border-top-width'))
			});
		});

		updateSizes();

		for (var i = 0; i < objects.length; i++) {
			objects[i].root.css({
				background: 'none',
				border: 0,
				paddingTop: parseInt(objects[i].root.css('padding-top')) + objects[i].borderWidth,
				paddingLeft: parseInt(objects[i].root.css('padding-left')) + objects[i].borderWidth,
				paddingRight: parseInt(objects[i].root.css('padding-right')) + objects[i].borderWidth,
				paddingBottom: parseInt(objects[i].root.css('padding-bottom')) + objects[i].borderWidth
			});

			if (isCanvas) {
				createCanvas(i);
			} else {
				createVml(i);
			}
		}

		Common.Measurer.setFunc(update);
	}

	function checkCanvas() {
		var testCanvas = $('<canvas></canvas>').appendTo('body');

		if (!(testCanvas && testCanvas.get && testCanvas.get(0).getContext)) {
			isCanvas = false;
		}

		testCanvas && testCanvas.remove();
	}

	function createVml(index) {
		var section = objects[index];

		var canvas = document.createElement('v:shape');
		$(canvas).addClass(className + ' vml');
		canvas.style.width = section.width + 'px';
		canvas.style.height = section.height + 'px';
		canvas.style.left = '0px';
		canvas.style.top = '0px';
		canvas.coordsize = section.width + ' ' + section.height;
		canvas.fillcolor = section.backColor;
		canvas.path = 'm ' + section.radius + ',0 l ' + (section.width - section.radius) + ',0 qx ' + section.width + ',' + section.radius + ' l ' + section.width + ',' + (section.height - section.radius) + ' qy ' + (section.width - section.radius) + ',' + section.height + ' l ' + section.radius + ',' + section.height + ' qx 0,' + (section.height - section.radius) + ' l 0,' + section.radius + ' qy ' + section.radius + ',0';

		var fillShape = document.createElement('v:fill');
		$(fillShape).addClass('vml');
		fillShape.color = section.backColor;
		fillShape.type = 'frame';
		$(fillShape).appendTo(canvas);

		if (section.borderWidth) {
			var strokeShape = document.createElement('v:stroke');
			$(strokeShape).addClass('vml');
			strokeShape.color = section.borderColor;
			strokeShape.weight = section.borderWidth + 'pt';
			$(strokeShape).appendTo(canvas);
		} else {
			canvas.stroked = 'False';
		}

		section.canvas = $(canvas).prependTo(section.root);
	}

	function updateVml(index) {
		var radius = objects[index].radius;
		var height = objects[index].height;
		var width = objects[index].width;

		objects[index].canvas.get(0).path = 'm ' + radius + ',0 l ' + (width - radius) + ',0 qx ' + width + ',' + radius + ' l ' + width + ',' + (height - radius) + ' qy ' + (width - radius) + ',' + height + ' l ' + radius + ',' + height + ' qx 0,' + (height - radius) + ' l 0,' + radius + ' qy ' + radius + ',0';
	}

	function createCanvas(index) {
		var section = objects[index];

		objects[index].canvas = $('<canvas class="' + className + '"></canvas>').prependTo(section.root);
		objects[index].ctx = section.canvas.get(0).getContext('2d');
		updateCanvas(index);
	}

	function updateCanvas(index) {
		var section = objects[index];

		section.canvas.attr({
			height: section.height,
			width: section.width
		});
		section.ctx.fillStyle = section.backColor;
		drawShapeCanvas(index, section.borderWidth);
/*
		if ($.browser.opera) {
			section.ctx.globalCompositeOperation = 'destination-over';
			section.ctx.fillStyle = section.backColor;
			drawShapeCanvas(index, section.borderWidth);
		}
*/
		if (section.borderWidth) {
			section.ctx.globalCompositeOperation = 'destination-over';
			section.ctx.fillStyle = section.borderColor;
			drawShapeCanvas(index, 0);
		}
	}

	function drawShapeCanvas(index, border) {
		var ctx = objects[index].ctx;
		var radius = objects[index].radius;
		var width = objects[index].width;
		var height = objects[index].height;

		ctx.beginPath();
		ctx.moveTo(radius + border, border);
		ctx.lineTo(width - radius - border, border);
		ctx.arc(width - radius, radius, radius - border, -Math.PI / 2, 0, false);
		ctx.lineTo(width - border, height - radius - border);
		ctx.arc(width - radius, height - radius, radius - border, 0, Math.PI / 2, false);
		ctx.lineTo(radius + border, height - border);
		ctx.arc(radius, height - radius, radius - border, Math.PI / 2, Math.PI, false);
		ctx.lineTo(border ,radius + border);
		ctx.arc(radius, radius, radius - border, Math.PI, Math.PI * 3 / 2, false);
		ctx.fill();
		ctx.closePath();
	}

	function updateSizes() {
		for (var i = 0; i < objects.length; i++) {
			var width = objects[i].root.outerWidth();
			var height = objects[i].root.outerHeight();

			if (!isCanvas) {
				width -= objects[i].borderWidth * 2;
				height -= objects[i].borderWidth * 2;
			}

			var radius = Math.round(width > height ? width / 2 : height / 2);

			objects[i].radius = radius;
			objects[i].height = radius * 2;
			objects[i].width = radius * 2;
		}
	}

	function update() {
		updateSizes();

		if (isCanvas) {
			for (var i = 0; i < objects.length; i++) {
				updateCanvas(i);
			}
		} else {
			for (var i = 0; i < objects.length; i++) {
				updateVml(i);
			}
		}
	}
});
