function EstheticScroller () {
    this.options = {
                            /* Public */
        layerId:            false,
        crop: {
            x1:             10,
            x2:             10,
            y1:             10,
            y2:             50
        },
        z_pitch:            100000,
        ratio:              1,
        positioning:        1,
        animationSpeed:     250,
        playerSpeed:        5000,
        visiblityLevel:     3,
        scrollerWidth:      600,
        scrollerHeight:     20,
        pointerWidth:       20,
        pointerHeight:      20,
        overlayOpacity:     80,
        topBorderCorection: 10,
        scrollBarEnabled:   true,
                            /* Private */
        maxHeight:          0,
        maxWidth:           0,
        position:           0,
        viewport: {
            width:          0,
            height:         0
        },
        player_active:      true,
        bar:                false,
        pointer:            false,
        dialog: {
            overlay:        false,
            content:        false,
            image:          false
        }
    }
    
    var cs = this;

    /*
     * Инициализация класса
     **/
    this.init = function (custom) {
        /*
         * Установка параметров пользователя
         **/
		for(var name in cs.options) {
			this[name] = (custom !== undefined && custom[name] !== undefined) ? custom[name] : cs.options[name];
		}
        
        if (!$('#' + cs.layerId)) {
            return;
        }

        /*
         * Установка обработчиков событий
         **/
        $('#' + cs.layerId + ' img').live('click', function () {
            cs.click($(this));
        });
        $('#scroller-modal-overlay').live('click', function () {
            cs.removeModals();
        });
        $('#scroller-modal-close').live('click', function () {
            cs.removeModals();
        });
        $('#scroller-modal-forward').live('click', function () {
            cs.position++;
            cs.applyModalScroll();
        });
        $('#scroller-modal-backward').live('click', function () {
            cs.position--;
            cs.applyModalScroll();
        });
        $('#' + cs.layerId).scroll(function () {
            console.log('.');
        });
        
        this.jqEl = $('#' + cs.layerId);
        cs.jqEl.css('visibility', 'visible');
        
        cs.viewport.width = cs.jqEl.width();
        cs.viewport.height = cs.jqEl.height() - 30; /* Зазор 20px для полоски прокрутки*/
        
        cs.preloadImages();
        if (cs.scrollBarEnabled) {
            cs.initScroller();
        }
        
        cs.MouseWheel.init();
        
        return;
    }

    /*
     * Инициализация полосы прокрутки
     **/
    this.initScroller = function () {
        var sc_top = cs.viewport.height - cs.scrollerHeight,
            sc_left = Math.round((cs.viewport.width - cs.scrollerWidth) / 2),
            sc_id = 'est-scroller-bar-' + Math.round(Math.random() * 9999999);
        
        var embed = '<div id="' + sc_id + '" class="scroller-bar"></div>';
        cs.jqEl.append(embed);
        
        cs.bar = {
            position: {
                top: sc_top,
                left: sc_left,
                width: cs.scrollerWidth,
                height: cs.scrollerHeight,
                zIndex: 10 * cs.z_pitch
            },
            ctrl: $('#' + sc_id)
        }
        
        cs.bar.ctrl.css({
            top: sc_top,
            left: sc_left,
            width: cs.scrollerWidth,
            height: cs.scrollerHeight,
            zIndex: 10 * cs.z_pitch,
            opacity: 0
        });
        
        cs.bar.ctrl.animate({
            opacity: 1
        }, 500);
        
        var pt_top = cs.viewport.height - cs.pointerHeight,
            pt_left = Math.round(sc_left - (cs.pointerWidth / 2)),
            pt_id = 'est-scroller-pointer-' + Math.round(Math.random() * 9999999);
            
        embed = '<div id="' + pt_id + '" class="scroller-pointer"></div>';
        cs.jqEl.append(embed);
        
        cs.pointer = {
            position: {
                top: pt_top,
                left: pt_left,
                width: cs.pointerWidth,
                height: cs.pointerHeight,
                zIndex: 10 * cs.z_pitch + 1
            },
            ctrl: $('#' + pt_id)
        }
        
        cs.pointer.ctrl.css({
            top: pt_top,
            left: pt_left,
            width: cs.pointerWidth,
            height: cs.pointerHeight,
            zIndex: 10 * cs.z_pitch + 1
        });
        
        return;
    }
    
    /*
     * Загрузка графики
     **/
    this.preloadImages = function () {
        if (!cs.jqEl) return false;
        
        cs.images = new Array();
        var counter = 0;
        
        cs.jqEl.find('img').each(function () {
            cs.images[counter] = new Image();
            cs.images[counter].src = $(this).attr('src');
            counter++;
        });
        
        cs.checkImagesLoading();
        cs.jqEl.append('<div id="scroller-basic-loader">Images: <span id="scroller-basic-loaded">0</span>/' + cs.images.length + '</div>');
        
        $('#scroller-basic-loader').css({
            top: Math.round((cs.jqEl.height() - $('#scroller-basic-loader').height() - parseInt($('#scroller-basic-loader').css('padding-top'), 10) - parseInt($('#scroller-basic-loader').css('padding-bottom'), 10)) / 2),
            left: Math.round((cs.jqEl.width() - $('#scroller-basic-loader').width() - parseInt($('#scroller-basic-loader').css('padding-left'), 10) - parseInt($('#scroller-basic-loader').css('padding-right'), 10)) / 2)
        });
        
        return;
    }
    
    /*
     * Контроллер загрузки графики
     **/
    this.checkImagesLoading = function () {
        var counter = 0;
        for(var i in cs.images) {
            if (!cs.images[i].complete) {
                setTimeout(cs.checkImagesLoading, 10);
                return;
            }
            counter++;
            if ($('#scroller-basic-loaded')) {
                $('#scroller-basic-loaded').text(counter);
            }
        }
        
        try {
            $('#scroller-basic-loader').remove();
        } catch (e) { }
        
        var counter = 0;
        cs.jqEl.find('img').each(function () {
            var i_src = cs.images[counter].src;
            cs.images[parseInt(counter, 10)] = {
                ctrl: $(this),
                height: $(this).height(),
                width: $(this).width(),
                title: $(this).attr('alt'),
                src: i_src,
                params: {
                    visible: false,
                    x: 0,
                    y: 0,
                    z: 0
                }
            }
            if ($(this).height() > cs.maxHeight) cs.maxHeight = $(this).height();
            if ($(this).width() > cs.maxWidth) cs.maxWidth = $(this).width();
            counter++;
        });
        
        cs.build();
        return;
    }
    
    /*
     * Построение визуальнойчасти контента
     **/
    this.build = function () {
        /*
         * Создание матрици позиционирования
         **/
        var w_width = cs.viewport.width - (cs.crop.x1 + cs.crop.x2),
            w_height = cs.viewport.height - (cs.crop.y1 + cs.crop.y2),
            w_elements = cs.images.length,
            w_radius = w_width / 2;
            
        var matrix = new Array ();

        for (var i = 0; i < w_elements; i++) {
            var angle = (360 / w_elements) * i;
            matrix[i] = {
                z: w_width + Math.round(w_radius * Math.cos(angle * 2 * Math.PI / 360)),
                x: cs.crop.x1 + Math.round(w_width / 2) + Math.round(w_radius * Math.sin(angle * 2 * Math.PI / 360)),
                y: cs.crop.y1 + Math.round(w_height / 2),
                ratio: Math.pow((w_width + w_radius * Math.cos(angle * 2 * Math.PI / 360)) / (w_width + w_radius), cs.positioning)
            }
        }
        
        this.matrix = matrix;
        cs.draw(250);
        
        return;
    }
    
    /*
     * Расстановка изображений по указанным координатам
     **/
    this.draw = function (speed) {
        if (!cs.images || !cs.matrix) {
            return;
        }
        var count = cs.images.length;
        var top_image = false;
        
        $('.scroller-top-image').each(function () {
            $(this).removeClass('scroller-top-image');
        });
        
        cs.checkPosition();
        
        for (var i in cs.matrix) {
            var image_id = parseInt(i, 10) + parseInt(cs.position, 10);
            if (image_id >= count) {
                image_id = image_id - count;
            }
            
            var image = cs.images[image_id];
            var matrix = cs.matrix[i];
            
            var z = matrix.z + cs.z_pitch,
                w = Math.round(matrix.ratio * cs.ratio * image.width),
                h = Math.round(matrix.ratio * cs.ratio * image.height),
                op = matrix.ratio;
            var x = matrix.x - Math.round(w / 2),
                y = matrix.y - Math.round(h / 2),
                v = false;
                
            if (
                parseInt(i, 10) == 0 || 
                parseInt(i, 10) < cs.visiblityLevel || 
                parseInt(i, 10) > cs.matrix.length - cs.visiblityLevel
            ) {
                v = true;
            }
            
            if (v) {
                image.ctrl.stop(true, true);
                image.ctrl.css('visibility', 'visible');
                image.ctrl.attr('id', 'ctrl-image-' + image_id);
                image.ctrl.css('z-index', z);
                
                if (i == 0) {
                    image.ctrl.addClass('scroller-top-image');
                    x = x - cs.topBorderCorection;
                    top_image = {
                        ctrl: image.ctrl,
                        left: x,
                        top: y,
                        width: w,
                        height: h,
                        zIndex: z
                    }
                }

                image.ctrl.animate({
                    left: x,
                    top: y,
                    width: w,
                    height: h,
                    opacity: op
                }, speed);
            } else {
                image.ctrl.css('visibility', 'hidden');
                image.ctrl.attr('id', 'ctrl-image-' + image_id);
                image.ctrl.css({
                    left: x,
                    top: y,
                    width: w,
                    height: h,
                    zIndex: z
                });
            }
        }
        
        if (top_image != false) {
            cs.showInfo(top_image, speed);
        }
        
        if (cs.bar !== false && cs.scrollBarEnabled !== false) {
            var pt_left = Math.round((cs.bar.position.width / (cs.images.length - 1) * cs.position) + cs.bar.position.left - cs.pointer.position.width / 2);
            cs.pointer.ctrl.stop(true, true);
            cs.pointer.ctrl.animate({
                left: pt_left
            }, speed);
        }
        return;
    }

    /*
     * Отображение информационной строки
     **/
    this.showInfo = function (image, speed) {
        if ($('#scroller-info-block').attr('id')) {
            $('#scroller-info-block').stop(true, true);
            $('#scroller-info-block').css({
                visibility:'hidden',
                opacity: 0
            });
        } else {
            var embed = '<div id="scroller-info-block" style="visibility:hidden;"><p>Название сайта - <a href="#" title=""></a></p><p><span></span></p></div>';
            cs.jqEl.append(embed);
        }
        
        var info = $('#scroller-info-block'),
            link = '#', title = '', desc = '';
        
        if (!image.ctrl.attr('title')) {
            return;
        }
        title = image.ctrl.attr('title');

        if (!image.ctrl.attr('description')) {
            return;
        }
        desc = image.ctrl.attr('description');

        if (image.ctrl.attr('link')) {
            link = image.ctrl.attr('link');
        }

        info.find('a').attr('href', link);
        info.find('a').attr('title', title);
        info.find('a').text(title);
        info.find('span').text(desc);
        
        info.css({
            zIndex: image.zIndex + 1,
            visibility: 'visible',
            left: image.left,
            top: image.top + image.height - 20 - info.height(),
            opacity: 0
        });
        
        info.animate({
            opacity:0
        }, speed).animate({
            opacity:0.8
        }, speed);
        
        return;
    }

    /*
     * Исправление значения позиции элемента
     **/
    this.checkPosition = function () {
        var count = cs.images.length;
        if (cs.position >= count) {
            var floor = parseInt(cs.position / count, 10);
            cs.position = cs.position - (floor * count);
        }
        if (cs.position < 0) {
            cs.position = count + cs.position;
        }
        return;
    }
    
    /*
     * Обработка клика по элементу
     **/
    this.click = function (image) {
        
        cs.player_active = false;
        
        var id = parseInt(image.attr('id').replace(/[^0-9]+/, ''), 10);
        
        cs.checkPosition();
        
        if (id == cs.position) {
            cs.showModal();
            return;
        }

        var x = Math.floor(image.width() / 2 + parseInt(image.css('left').replace(/[^0-9\.]+/, ''), 10)),
            center = Math.floor(cs.viewport.width / 2);
        if (x > center) {
            cs.position++;
        } else {
            cs.position--;
        }
        
        cs.scroll();
        return;
    }

    /*
     * Обработка прокрутки
     **/
    this.scroll = function () {
        cs.checkPosition();
        cs.draw(cs.animationSpeed);
    }
    
    /*
     * Автоматическая прокрутка изображений
     **/
    this.play = function () {
        if (cs.player_active === false) {
            return;
        }
        cs.position++;
        cs.scroll();
        return;
    }

    /*
     * Отображение модального диалога рисунка
     **/
    this.showModal = function () {
        cs.player_active = false;

        /*
         * 1.Overlay
         **/
        $('body').append('<div id="scroller-modal-overlay" class="scroller-modals"></div>');
        cs.dialog.overlay = {
            ctrl: $('#scroller-modal-overlay')
        };
        
        cs.dialog.overlay.ctrl.css({
            opacity: 0,
            left: 0,
            top: 0,
            width: $(document).width(),
            height: $(document).height(),
            zIndex: 10 * cs.z_pitch + 100
        });
        cs.dialog.overlay.ctrl.animate({
            opacity: cs.overlayOpacity / 100
        }, 500);
        
        /*
         * 2. Preview
         **/
        $('body').append('<div id="scroller-modal-content" class="scroller-modals scroller-modal-preloading"></div>');
        
        var mc_top = $(document).scrollTop() + ($(window).height() / 2 - 28),
            mc_left = $(document).scrollLeft() + ($(window).width() / 2 - 28);
        
        cs.dialog.content = {
            ctrl: $('#scroller-modal-content'),
            position: {
                top: mc_top,
                left: mc_left,
                zIndex: 10 * cs.z_pitch + 101
            }
        };
        
        cs.dialog.content.ctrl.css(cs.dialog.content.position);
        cs.dialog.content.ctrl.css({opacity:0});
        cs.dialog.content.ctrl.animate({
            opacity: 1
        }, 500);
        cs.loadModal();
        
        return;
    }
    
    /*
     * Удаление элементов модального диалога
     **/
    this.removeModals = function () {
        cs.checkPosition();
        cs.draw(0);
        $('.scroller-modals').each(function () {
            $(this).animate({
                opacity: 0
            }, 500, function () {
                $(this).remove();
            });
        });
        cs.dialog = {
            overlay: false,
            content: false,
            image: false
        };
        return;
    }

    /*
     * Старт процедуры загрузки отображаемого изображения
     **/
    this.loadModal = function () {
        var image = cs.images[cs.position];
        if (image == undefined) {
            cs.removeModals();
            return;
        }
        var source = image.ctrl.attr('longdesc');
        if (source == undefined || source == '') {
            source = image.ctrl.attr('src');
        }
        
        if (source == undefined || source == '') {
            cs.removeModals();
            return;
        }
        
        cs.dialog.image = new Image();
        cs.dialog.image.id = 'scroller-modal-image';
        cs.dialog.image.src = source;
        
        cs.checkModalLoading();
        
        return;
    }

    /*
     * Контроль процедуры загрузки отображаемого изображения
     **/
    this.checkModalLoading = function () {
        if (!cs.dialog.image) {
            cs.removeModals();
            return;
        }
        if (!cs.dialog.image.complete) {
            setTimeout(cs.checkModalLoading, 1000);
            return;
        }

        /*
         * Вставка изображения
         **/
        var im_width = parseInt(cs.dialog.image.width, 10),
            im_height = parseInt(cs.dialog.image.height, 10),
            padding = parseInt($('#scroller-modal-content').css('padding-top'), 10),
            cl_w = $(window).width(),
            cl_h = $(window).height();

        $('#scroller-modal-content').removeClass('scroller-modal-preloading ');
        $('#scroller-modal-content').css({
            width: im_width,
            height: im_height,
            left: Math.round($(document).scrollLeft() + (cl_w / 2) - (padding + im_width / 2)),
            top: Math.round($(document).scrollTop() + (cl_h / 2) - (padding + im_height / 2))
        });
        $('#scroller-modal-content').append(cs.dialog.image);
        
        /*
         * Вставка элементов управления
         **/
        var m_close = '<div id="scroller-modal-close" class="scroller-modals scroller-modal-buttons"></div>';
        $('body').append(m_close);
        $('#scroller-modal-close').css({
            left: Math.round($(document).scrollLeft() + (cl_w / 2) + (padding + im_width / 2)) - 16,
            top: Math.round($(document).scrollTop() + (cl_h / 2) - (padding + im_height / 2)) - 16,
            zIndex: 10 * cs.z_pitch + 102
        });
        
        var m_forward = '<div id="scroller-modal-forward" class="scroller-modals scroller-modal-buttons"></div>';
        $('body').append(m_forward);
        var fb_left = Math.round($(document).scrollLeft() + (cl_w / 2) + (padding + im_width / 2)) - $('#scroller-modal-forward').width(),
            fb_top = Math.round($(document).scrollTop() + (cl_h / 2) - (padding / 2));
        $('#scroller-modal-forward').css({
            left: fb_left,
            top: fb_top,
            zIndex: 10 * cs.z_pitch + 102
        });
        
        var m_backward = '<div id="scroller-modal-backward" class="scroller-modals scroller-modal-buttons"></div>';
        $('body').append(m_backward);
        var bb_left = Math.round($(document).scrollLeft() + (cl_w / 2) - (padding + im_width / 2)) + $('#scroller-modal-backward').width() - 28,
            bb_top = Math.round($(document).scrollTop() + (cl_h / 2) - (padding / 2));
        $('#scroller-modal-backward').css({
            left: bb_left,
            top: bb_top,
            zIndex: 10 * cs.z_pitch + 102
        });
    }

    /*
     * Приминение параметров прокрутки
     **/
    this.applyModalScroll = function () {
        cs.checkPosition();
        $('.scroller-modal-buttons').each(function () {
            $(this).remove();
        });
        $('#scroller-modal-content').attr('style', '');
        $('#scroller-modal-content').html('');
        $('#scroller-modal-content').addClass('scroller-modal-preloading');
        
        var mc_top = $(document).scrollTop() + ($(window).height() / 2 - 28),
            mc_left = $(document).scrollLeft() + ($(window).width() / 2 - 28);
        
        cs.dialog.content = {
            ctrl: $('#scroller-modal-content'),
            position: {
                top: mc_top,
                left: mc_left,
                zIndex: 10 * cs.z_pitch + 101
            }
        };
        
        cs.dialog.content.ctrl.css(cs.dialog.content.position);
        cs.dialog.content.ctrl.css({opacity:0});
        cs.dialog.content.ctrl.animate({
            opacity: 1
        }, 500);
        cs.loadModal();
        
        return;
    }

    /*
     * Контроллер ролика мыши
     **/
	this.MouseWheel = {
		init: function() {
			if(window.addEventListener) {
				cs.jqEl.get(0).addEventListener('DOMMouseScroll', cs.MouseWheel.get, false);
			}
			cs.MouseWheel.addEvent(cs.jqEl.get(0),'mousewheel',cs.MouseWheel.get);
		},
		addEvent: function(obj, type, fn) {
			if(obj.addEventListener) {
				obj.addEventListener(type, fn, false);
			}
			else if(obj.attachEvent) {
				obj["e"+type+fn] = fn;
				obj[type+fn] = function() { obj["e"+type+fn]( window.event ); };
				obj.attachEvent( "on"+type, obj[type+fn] );
			}
		},
		get: function(event) {
			var delta = 0;
			if (!event) {
				event = window.event;
			}
			if (event.wheelDelta) {
				delta = event.wheelDelta / 120;
			} else if (event.detail) {
				delta = -event.detail / 3;
			}
			if (delta) {
				cs.MouseWheel.handle(delta);
			}
			cs.MouseWheel.suppressBrowserDefault(event);
		},
		suppressBrowserDefault: function(e) {
			if(e.preventDefault) {
				e.preventDefault();
			} else {
				e.returnValue = false;
			}
			return false;
		},
		handle: function(delta) {
			var change = false;
			var newImageID = 0;
            cs.player_active = false;
			if(delta > 0) {
                cs.position++;
			} else {
                cs.position--;
			}
            cs.scroll();
		}
	};
}
