function Banner(args) 
{
    this.instanceId = Banner.instances.length;
    Banner.instances.push(this);
    $('#'+args.slideId).html('<div id="' + args.divId + '"></div>');
    this.hostId = args.divId;
    this.slideId = args.slideId;
    this.slideShowControlsId = args.slideShowControlsId;
    this.host =  jQuery('#' + args.divId);
    this.host.width(args.width).height(args.height);
    this.width = args.width;
    this.height = args.height;
    this.slides = args.slides;
    this.nextDelay = args.nextDelay;
    this.fadeDelay = args.fadeDelay;
    this.loaded = [];
    var out = '';
    
    for (var i = 0, max = this.slides.length; i < max; i++) {
            this.loaded[i] = false;
            onclickImg = '';
            useMap = '';
            mapHtml = '';
            if(this.slides[i].link!=""){
                onclickImg = 'onclick="window.location=\''+this.slides[i].link+'\'"';
            }else{
                nameMap = 'useMap'+(i);
                useMap = 'usemap="#'+nameMap+'"';
                mapHtml = '<map name="'+nameMap+'">';
                mapHtml += this.slides[i].map;
                mapHtml += '</map>';
            }
            content = '<a id="' + this.hostId + i + '"><img '+onclickImg+' src="' + this.slides[i].image + '" onload="Banner.instances[' + this.instanceId + '].onLoad(' + i + ')" '+useMap+'>'+mapHtml+'</a>';
            var slide = jQuery(content).css({'width': 0, 'height': args.height, 'display': 'none'});
            this.host.append(slide);
            out += '<div id="slide-ctrl' + i + '" onclick="Banner.instances[0].next('+i+')"></div>';
    }
    $('#'+this.slideShowControlsId).html(out);
    this.next();
}

// used for soft references to a banner instance
Banner.instances = [];

Banner.prototype = {
    instanceId: null,
    width: null,
    height: null,
    nextDelay: null,
    fadeDelay: null,
    slides: null,
    hostId: null,
    host: null,
    current: 0,
    last: 0,
    zIndex: 0,
    timer: null,
    resumeTimerId: null,
    pending: false, // image is pending but not loaded yet
    loaded: null, // array of: int (slide index) => bool (loaded or not)
    onLoad: function (id) {
        this.loaded[id] = true;
        if (this.pending && id == this.current) {
            this.pending = false;
            this.next();
        }
    },
    stop: function (resume) {
        var that = this;
        if (this.timer != 'off')
            clearInterval(this.timer);
        this.timer = 'off';
        if (this.resumeTimerId !== null) {
            clearTimeout(this.resumeTimerId);
            this.resumeTimerId = null;
        }
        if (resume) {
            this.resumeTimerId = setTimeout(function () { that.next() }, this.nextDelay);
        }
    },
    next: function (current) {
        var that = this;
        if (typeof current != "undefined") {
            last = this.last;
            this.current = current;
            this.stop(true);
        } else {
            last = (this.current > 0 ? this.current - 1 : this.slides.length - 1) % this.slides.length;
        }
        if (this.loaded[this.current]) {
            var slide = jQuery('#' + this.hostId + this.current);
            slide
                .css({ 'width': 0, 'margin-left': 0, 'display': 'none', 'zIndex': this.zIndex++ })
                .css({ 'display': 'block' })
                .animate({ 'margin-left': this.width }, {
                    'duration': this.fadeDelay,
                    'callback': function (current) {
                        slide.css('margin-left', 0);
                    },
                    'step': function (current) {
                        // avoid IE6 jitter by using only even widths (rounding error)
                        slide.css('width', 2 * Math.ceil(current / 2));
                    }
                });
            $('#'+this.slideShowControlsId).css({ 'zIndex': this.zIndex });
            $('#slide-ctrl' + this.current).css('backgroundPosition', 'left top');
            if (last != this.current) {
                $('#slide-ctrl' + last).css('backgroundPosition', 'left -8px');
            }
            this.last = this.current;
            this.current = (this.current + 1) % this.slides.length;
            this.stop();
            this.timer = setInterval(function () { that.next() }, this.nextDelay);
        } else {
            this.pending = true;
        }
    }
};
