(function ($_) {
    function gid (id) {
        return document.getElementById(id);
    }
    function random (prefix) {
        return (prefix?prefix:"") + Math.random().toString(36).slice(2);
    }
    function Worker (_interval) {
        var self = {
            init: function () {
                return this;
            },
            regist: function (callback, bindObj) {
                this.tasks.push({
                    callback: callback,
                    bindObj: bindObj || this,
                    arguments: []
                });
                if ( this.task_id == null ) {
                    return this.start_worker();
                }
            },
            start_worker: function () {
                this.task_id = setInterval(function () {
                    if ( self.tasks.length && !self.lock ) {
                        self.lock = true;
                        var task = self.tasks.shift();
                        task.callback.apply(task.bindObj, task.arguments);
                        self.lock = false;
                    } else if ( self.tasks.length == 0 && self.lock ) {
                        clearInterval( self.task_id );
                        self.task_id = null;
                    } else {}
                }, this.interval);
            },
            setInterval: function (_interval) {
                this.interval = _interval;
            },
            tasks: [],
            task_id: null,
            lock: false,
            interval: _interval || 100
        };
        return self.init();
    };
    var worker = new Worker(100),
        loader = function (image, retry_count) {
            var retry = arguments.callee.caller,
                retry_count = retry_count || 0;
            worker.regist(function () {
                this.src     = this.getAttribute('rel');
                this.onerror = function () {
                    retry.count = !retry.count ? 1 : ++retry.count;
                    return retry.count <= retry_count ? retry.apply(image, [image, retry_count]) : ( image.onerror=function(){} );
                };
            }, image);
        },
        format = function (str, params) {
            var params = params || {};
            return ( str || "" ).replace(/(?:{([^}]+)})/g, function (a,vars) {
                return params[vars] ? params[vars] : "";
            });
        };
    $_.fn.extend({
        carouselSuperLite: function (_option) {
            var option = $_.extend({
                dataSource: "",
                params: {},
                image_width: 60,
                image_height: 60,
                count: 6,
                speed: 1000,
                easing: 'swing',
                position: function(){return true},
                format: '<a href="{link}" target="_blank"><img src="/img/no_image.gif" /></a>',
                disableClass: 'disable',
                selectClass: 'selected',
                retry_count: 0,
                load_interval: 100,
                data: []
            }, _option), targets = this;
            var images = $_.makeArray(option.data),
                image_list_array = $_.map(images, function (image, i) {
                    // fixed position
                    $_.isFunction( option.position ) && option.position.call(null, image, i) && ( option.position = i );
                    // format list tag
                    return format('<li id="{list_id}">' + option.format + '</li>', $_.extend(image, option, {
                        list_id:random('_')
                    }));
                });

            if ( $_.browser.msie && $_.browser.version >= 8 ) {
                var position    = $_.isFunction( option.position ) ? 0 : option.position,
                    count       = option.count > images.length ? images.length : option.count,
                    center      = Math.max( position - Math.floor(count/2), 0 ),
                    image_list  = image_list_array.slice(center, center+count).join(""),
                    images      = images.slice(center, center+count);
                option.position = Math.max(position-center, 0);
            } else {
                var image_list = image_list_array.join("");
            }

            worker.setInterval(option.load_interval);
            targets.each(function (target_count) {
                var ulbox       = $_(option.ulbox,   this).append( image_list ),
                    prevBtn     = $_(option.prevBtn, this),
                    nextBtn     = $_(option.nextBtn, this),
                    max         = Math.max(images.length - option.count,0),
                    count       = option.count > images.length ? images.length : option.count,
                    box_width   = ( option.image_width * count ) + ( count * 12 ),
                    position    = $_.isFunction( option.position ) ? 0 : option.position,
                    easing      = $_.easing.hasOwnProperty(option.easing) ? option.easing : 'swing',
                    retry_count = option.retry_count,
                    loaded      = {},
                    loadImage = function () {
                        $_.each(images.slice(position, position+count), function (i, image) {
                            if ( !loaded.hasOwnProperty( image.list_id ) ) {
                                try {
                                    var tag = gid( image.list_id ).getElementsByTagName('img')[0];
                                    loader(tag, retry_count);
                                } catch (e) {}
                                loaded[ image.list_id ] = true;
                            }
                        });
                    },
                    scrollTo  = function (is_static) {
                        loadImage();
                        ulbox.animate({
                            left: -( ( option.image_width * position ) + ( position * 4 ) ) + "px"
                        }, is_static ? 0 : option.speed, easing);
                        prevBtn[ ( position > 0   ? 'remove' : 'add' ) + 'Class' ]( option.disableClass );
                        nextBtn[ ( position < max ? 'remove' : 'add' ) + 'Class' ]( option.disableClass );
                    },
                    scrollToCenter = function () {
                        $_.className.add(gid(images[ position ].list_id), option.selectClass);
                        position = Math.max( Math.min( position - Math.floor( count / 2 ), max ), 0 );
                        scrollTo(true);
                    };
                /* set style sheet */
                // $_( this ).css('width', box_width + 54), ulbox.parent().css('width', box_width), ulbox.css('height', option.image_height);
                /* bind event listener */
                prevBtn.bind('mousedown', function () {
                    position = Math.max(0, position - count);
                    scrollTo();
                });
                nextBtn.bind('mousedown', function () {
                    position = ( position + count ) > max ? max : ( position + count );
                    scrollTo();
                });
                /* initialize */
                scrollToCenter();
            });
            return this;
        }
    });
})(jQuery);
