Shifter = {
  config: {
    changeAnimationTime: 1000,
    autoTimeoutDelay: 5000,
    list: [
      {
        img: 'http://server/image.jpg',
        url: 'http://server/link/'
      },
    ],
    bannerSize: { w: 1920, h: 1080 },
    buttonSize: { w: 20, h: 20 },
    buttonContainerPosition: 'relative',
    mode: 'move'
  },
  lock: true,
  current: null,
  loadNext: null,
  autoTimeout: null,
  mainElem: null,
  
  init: function(mainElemId, config) {
    if (typeof config == "object")
      for (var key in config)
        this.config[key] = config[key];
        
    this.mainElem = $('#' + mainElemId);
        
    /* css */
    this.mainElem.css('overflow', 'hidden');
    $('.shifter_root', this.mainElem).css('overflow', 'hidden');
    $('.shifter_root', this.mainElem).css('position', 'relative');
    $('.shifter_root', this.mainElem).css('width', this.config.bannerSize.w + 'px');
    $('.shifter_root', this.mainElem).css('height', this.config.bannerSize.h + 'px');
    $('.shifter_root', this.mainElem).css('margin-left', (-1 * Math.floor(this.config.bannerSize.w/2)) + 'px');
    $('.shifter_root', this.mainElem).css('left', '50%');
    $('.shifter_container', this.mainElem).css('position', 'absolute');
    $('.shifter_container', this.mainElem).css('left', '0');
    $('.shifter_container', this.mainElem).css('top', '0');
    $('.shifter_container', this.mainElem).css('width', (3 * this.config.bannerSize.w) + 'px');
    $('.shifter_container', this.mainElem).css('height', this.config.bannerSize.h + 'px');
    $('.shifter_buttons', this.mainElem).css('position', this.config.buttonContainerPosition);
    $('.shifter_buttons', this.mainElem).css('width', (this.config.list.length * this.config.buttonSize.w) + 'px');
    $('.shifter_buttons', this.mainElem).css('height', this.config.buttonSize.h + 'px');
    if (this.config.mode == 'fade') {
      $('.shifter_buttons', this.mainElem).css('z-index', 13);
    }
    
    $('.shifter_container', this.mainElem).append(this.getElement('left'));
    $('.shifter_container', this.mainElem).append(this.getElement('center'));
    $('.shifter_container', this.mainElem).append(this.getElement('right'));
    
    var cache = $(document.createElement('div')).attr('id', 'shifter_image_cache_4895795738475');
    cache.hide();
    cache.appendTo('body');
    
    for (var i=0; i<this.config.list.length; i++) {      
      $('.shifter_buttons', this.mainElem).append(this.getButton(i));
      var img = $(document.createElement('img'));
      img.attr('src', this.config.list[i].img);
      img.appendTo(cache);
    }
    
    this.select(0);
  },
  
  getElement: function(type) {
    var elem = $(document.createElement('div'));
    elem.addClass('elem');
    
    /* css */
    if (this.config.mode == 'fade') {
      elem.css('display', 'block');
      elem.css('position', 'absolute');
      elem.css('top', '0');
      elem.css('left', this.config.bannerSize.w + 'px');
    }
    else { // this.config.mode == 'move'
      elem.css('float', 'left');
    }
    elem.css('width', this.config.bannerSize.w + 'px');
    elem.css('height', this.config.bannerSize.h + 'px');
    
    var elemLnk = $(document.createElement('a'));
    elemLnk.addClass('shifter_' + type);
    elemLnk.append(elem);
    return elemLnk;
  },
  
  getButton: function(id) {
    var elem = $(document.createElement('div'));
    elem.addClass('butt');
    
    /* css */
    elem.css('float', 'left');
    elem.css('width', this.config.buttonSize.w + 'px');
    elem.css('height', this.config.buttonSize.h + 'px');
    
    elem.addClass('shifter_button_' + id);
    elem.click(function(){
      Shifter.change(id);
    });
    
    var elemDesc = $(document.createElement('span'));
    elemDesc.addClass('num');
    elemDesc.text("" + (id+1));
    elem.append(elemDesc);
    
    return elem;
  },
  
  loadItem: function(type, id, callback) {
    $('.shifter_' + type, this.mainElem).attr('href', this.config.list[id].url);
    $('.shifter_' + type + ' div.elem', this.mainElem).css('background-image', 'url("' + this.config.list[id].img + '")');
    
    this.prepareImage = new Image();
    this.prepareImage.src = this.config.list[id].img;
    
    if (!this.prepareImage.complete) {
      this.prepareCallback = callback;
      this.prepareInterval = setInterval(function(){
        Shifter.prepare();
      }, 50);
    }
    else
      callback();
  },
  
  prepareImage: null,
  prepareCallback: null,
  prepareInterval: null,
  
  prepare: function() {
    if (this.prepareImage.complete) {
      this.prepareCallback();
      try {
        clearInterval(this.prepareInterval);
        this.prepareInterval = null;
      }
      catch (e) {}
    }
  },
  
  select: function(id) {
    this.select1(id);
    // this.loadItem('center', id);
    // $('.shifter_container', this.mainElem).css('left', (-1 * this.config.bannerSize.w) + 'px');
//     
    // if (this.config.mode == 'fade') {
      // $('.shifter_left div.elem', this.mainElem).css('opacity', '0');
      // $('.shifter_left div.elem', this.mainElem).css('z-index', 11);
      // $('.shifter_left', this.mainElem).hide();
      // $('.shifter_center div.elem', this.mainElem).css('opacity', '1');
      // $('.shifter_center div.elem', this.mainElem).css('z-index', 11);
      // $('.shifter_center', this.mainElem).show();
      // $('.shifter_right div.elem', this.mainElem).css('opacity', '0');
      // $('.shifter_right div.elem', this.mainElem).css('z-index', 11);
      // $('.shifter_right', this.mainElem).hide();
    // }
    // $('.shifter_buttons .butt', this.mainElem).removeClass('selected');
    // $('.shifter_button_' + id, this.mainElem).addClass('selected');
    // this.current = id;
    // this.lock = false;
    // if (this.loadNext !== null) {
      // var queuedId = this.loadNext;
      // this.loadNext = null;
      // this.change(queuedId);
    // }
    // else {
      // this.autoTimeout = setInterval(function() { Shifter.auto(); }, this.config.autoTimeoutDelay);
    // }
  },
  
  select1: function(id) {
    this.loadItem('center', id, function() {
      Shifter.select2(id);
    });
  },
  
  select2: function(id) {
    $('.shifter_container', this.mainElem).css('left', (-1 * this.config.bannerSize.w) + 'px');
    
    if (this.config.mode == 'fade') {
      $('.shifter_left div.elem', this.mainElem).css('opacity', '0');
      $('.shifter_left div.elem', this.mainElem).css('z-index', 11);
      $('.shifter_left', this.mainElem).hide();
      $('.shifter_center div.elem', this.mainElem).css('opacity', '1');
      $('.shifter_center div.elem', this.mainElem).css('z-index', 11);
      $('.shifter_center', this.mainElem).show();
      $('.shifter_right div.elem', this.mainElem).css('opacity', '0');
      $('.shifter_right div.elem', this.mainElem).css('z-index', 11);
      $('.shifter_right', this.mainElem).hide();
    }
    $('.shifter_buttons .butt', this.mainElem).removeClass('selected');
    $('.shifter_button_' + id, this.mainElem).addClass('selected');
    this.current = id;
    this.lock = false;
    if (this.loadNext !== null) {
      var queuedId = this.loadNext;
      this.loadNext = null;
      this.change(queuedId);
    }
    else {
      this.autoTimeout = setInterval(function() { Shifter.auto(); }, this.config.autoTimeoutDelay);
    }
  },
  
  change: function(id) {
    this.change1(id);
    // if (id == this.current)
      // return;
    // if (this.lock) {
      // this.loadNext = id;
      // return;
    // }
    // this.lock = true;
    // try {
      // clearInterval(this.autoTimeout);
      // this.autoTimeout = null;
    // }
    // catch (e) {}
    // var direction = (id < this.current) ? 'left' : 'right';
    // this.loadItem(direction, id);
//     
    // if (this.config.mode == 'fade') {
      // $('.shifter_' + direction + ' div.elem', this.mainElem).css('z-index', 10);
      // $('.shifter_center div.elem', this.mainElem).animate(
        // {opacity: '0'},
        // {
          // queue: false,
          // duration: this.config.changeAnimationTime,
          // complete: function(){
            // $('.shifter_center', Shifter.mainElem).hide();
          // }
        // }
      // );
      // $('.shifter_' + direction, this.mainElem).show();
      // $('.shifter_' + direction + ' div.elem', this.mainElem).animate(
        // {opacity: '1'},
        // {
          // queue: false,
          // duration: this.config.changeAnimationTime,
          // complete: function(){
            // Shifter.select(id);
          // }
        // }
      // );
    // }
    // else { // this.config.mode == 'move'
      // $('.shifter_container', this.mainElem).animate(
        // {left: (direction=='left' ? 0 : (-2 * this.config.bannerSize.w))},
        // this.config.changeAnimationTime,
        // function(){
          // Shifter.select(id);
        // }
      // );
    // }
  },
  
  change1: function(id) {
    if (id == this.current)
      return;
    if (this.lock) {
      this.loadNext = id;
      return;
    }
    this.lock = true;
    try {
      clearInterval(this.autoTimeout);
      this.autoTimeout = null;
    }
    catch (e) {}
    var direction = (id < this.current) ? 'left' : 'right';
    
    this.loadItem(direction, id, function(){
      Shifter.change2(id);
    });
  },
  
  change2: function(id) {
    var direction = (id < this.current) ? 'left' : 'right';
    
    if (this.config.mode == 'fade') {
      $('.shifter_' + direction + ' div.elem', this.mainElem).css('z-index', 10);
      $('.shifter_center div.elem', this.mainElem).animate(
        {opacity: '0'},
        {
          queue: false,
          duration: this.config.changeAnimationTime,
          complete: function(){
            $('.shifter_center', Shifter.mainElem).hide();
          }
        }
      );
      $('.shifter_' + direction, this.mainElem).show();
      $('.shifter_' + direction + ' div.elem', this.mainElem).animate(
        {opacity: '1'},
        {
          queue: false,
          duration: this.config.changeAnimationTime,
          complete: function(){
            Shifter.select(id);
          }
        }
      );
    }
    else { // this.config.mode == 'move'
      $('.shifter_container', this.mainElem).animate(
        {left: (direction=='left' ? 0 : (-2 * this.config.bannerSize.w))},
        this.config.changeAnimationTime,
        function(){
          Shifter.select(id);
        }
      );
    }
  },
  
  auto: function() {
    this.change((this.current + 1) % this.config.list.length);
  }
}

