/**
* jQuery photoslider
* @author R.Lisin
*/
(function($){
  var l=window, photoindex=new Array(), ns=new Array(),
  isset=function(e){return('undefined'==typeof(e))?false:true},
  sprintf=function(s){
    var c=s.match(/(%s)/gm).length,a=arguments
    for(var i=1;i<=c;i++) {s=s.replace("%s",isset(a[i])?a[i]:'')}
    return s
  },
  alias=function(o,m) {return function(){return m.apply(o, arguments)}}, // ~$.proxy
  noop=function(){return false},
  strim=function(s){return s.replace(/^\/+|\/+$/gi,'')}, // ~php "slash" trim
  setmwheel=function(el, o, m) {
    if(el.addEventListener && !window.opera) el.addEventListener('DOMMouseScroll', alias(o,m), false);
    el.onmousewheel=alias(o,m);
  },
  settings = {
    slider_dia: 600, slider_margin: 27, picture_width: 91, button_width: 44,
    path: 'photo/all', urlparam: '', count: 0, offset: 0,
    mode: 'all', id: 0, // SQL
    href: '/%s/%s/%s', // s.path + image.id + s.urlparam
    container: 'inline', // 'inline'|object
    slideSpeed: 250,
    noLinks: false,
    show_one: false,  // draw the slider even if there is only one image
    fading: false // static fade-out left and right sides
  },

  Ps=function(xParams) {
    this.s = $.extend(true, {}, settings); // clone the default settings
    if('object'==typeof(xParams)) for(var i in xParams) this.s[i]=xParams[i];
    this.images=new Array()
    this.picsvisible=Math.round((this.s.button_width+this.s.slider_dia)/this.s.picture_width)
    this.selnode=this.current=this.currentDefault=this.scrollChecking=this.generated=this.loadingNext=false
    this.index=ns.length; ns.push(this)
    this.url="/ajx/photosliderm.php"
  }

  Ps.prototype.template1=function(current){
    var html='<div id="photo-container-'+this.index+'" class="image-slider" unselectable="on">'+
    '<a class="arrow back" id="lSC-'+this.index+'" href="#backward" title="листать назад"></a>'+
    '<a class="arrow forw" id="rSC-'+this.index+'" href="#forward" title="листать вперед"></a>'+
    (this.s.fading
      ? '<img src="/i/spacer.gif" alt="" class="fade-left"/><img src="/i/spacer.gif" alt="" class="fade-right"/>'
      : '')+
    '<div class="slider-outer" id="pScroll-'+this.index+'" class="noselect">'+
    '<ul id="photo-link-'+this.index+'" style="width:'+(this.images.length*this.s.picture_width)+'px">'
    for(var i=0;i<this.images.length;i++) {
      html+='<li'+(this.images[i].id==current?' class="active"':'')+'></li>'
      if (this.images[i].id==current) this.currentDefault = this.current = i + parseInt(this.s.offset,10); // =absolute offset in result sequence
    }
    html+='</ul></div></div><br/>';
    return html;
  }
  Ps.prototype.template2=function(d){
    return '<a href="'
    + sprintf(this.s.href, strim(this.s.path), d.id, strim(this.s.urlparam))
    + '"'+ (this.s.noLinks ? ' onclick="return false"':'') +'><img src="'+d.src5+'" alt=""></a>'
  }
  Ps.prototype.push=function(d){ photoindex[d.id]=[this.index, d]; this.images.push(d);
    if(this.generated) this.pL.append($("<li>"+this.template2(d)+"</li>"));
  }
  Ps.prototype.lpush=function(d){ photoindex[d.id]=[this.index, d]; this.images.splice(0,0,d);
    if(this.generated) this.pL.prepend($("<li>"+this.template2(d)+"</li>"));
  }
  Ps.prototype.show=function(d){
    if (!this.generated && (this.images.length>1 || this.s.show_one)) {
      if ('inline'==this.s.container) document.write(this.template1(d.id))
      else this.s.container.html($(this.template1(d.id)))
      this.generated=true
      this.bS  = $("#pScroll-"+this.index)
      var time = this.s.slideSpeed, sl=alias(this,this.sl), sr=alias(this,this.sr),
      mu=function(){l.clearInterval($(this).attr('ii'))}

      this.lSC = $('#lSC-'+this.index).bind('mouseup mouseout',mu).click(noop)
      .mousedown(function(){sl();$(this).attr('ii',l.setInterval(sl, time))})

      this.rSC = $('#rSC-'+this.index).bind('mouseup mouseout',mu).click(noop)
      .mousedown(function(){sr();$(this).attr('ii',l.setInterval(sr, time))})

      this.pL = $('#photo-link-'+this.index); this.pC=$('#photo-container-'+this.index)
      if (this.images.length<this.picsvisible && this.s.show_one==0) {
        this.pC.css('width',this.images.length*this.s.picture_width);
        this.lSC.hide(); this.rSC.hide();
      }
      this.s.offset=parseInt(this.s.offset,10)
      this.s.count=parseInt(this.s.count,10)
      this.scroll({data:{offset:$.inArray(d, this.images)}})
      setmwheel(this.bS[0], this, this.mwheel)
    }
  }
  Ps.prototype.sl=function(){this.scroll({data:{sign:'-'}})}
  Ps.prototype.sr=function(){this.scroll({data:{sign:'+'}})}
  Ps.prototype.mwheel=function(event){
    var delta=0
    if (!event) event=window.event
    if (event.wheelDelta) delta=event.wheelDelta/120
    if (window.opera); else if (event.detail) delta=-event.detail/3
    if (delta) this.scroll({ data:{sign: delta<0 ? '+' : '-'} })
    if (event.preventDefault) event.preventDefault()
    event.returnValue=false
  }
  Ps.prototype.anchor=function(){
    if (!isset(this.pC)) return
    var d=this.pC.offset().top
    $('html,body').scrollTop(d)
  }
  Ps.prototype.anchorMe=function(id){
    if (isset(l.scrolled) || !isset(photoindex[id])) return;
    l.scrolled=true
    var a=ns[photoindex[id][0]];
    $(document).ready(alias(a, this.anchor));
  }
  // set slider to a given position or scroll with a given direction; e.data={sign:'+', offset:24}
  Ps.prototype.scroll=function(e){
    if (this.bS.queue().length > 2) return;
    var scrollOffset = isset(e.data.offset) ? parseInt(e.data.offset,10) : this.picsvisible;
    if (isset(e.data.sign)) { this.bS.animate(
      {scrollLeft: e.data.sign+"="+this.s.picture_width*scrollOffset},
      this.s.slideSpeed, 'linear', alias(this, this.scrollCheck)
    )}
    else {
      scrollOffset-=Math.floor(this.picsvisible/2)
      this.bS.scrollLeft(this.s.picture_width*scrollOffset)
      this.scrollCheck()
    }
  }
  // 1. set src's for viewable imgs; 2. run ajx browsing if needed
  Ps.prototype.scrollCheck=function(){
    if(this.scrollChecking)return; this.scrollChecking=true;
    this.selnode=Math.round(this.bS.scrollLeft() / this.s.picture_width)
    var Middle=Math.round(this.picsvisible/2), e
    var StartNode=(this.selnode-Middle<0)?0:this.selnode-Middle
    var FinishNode=(this.selnode+this.picsvisible+3>this.images.length)?this.images.length:this.selnode+this.picsvisible+3
    for(var i=StartNode;i<FinishNode;i++) if (!isset(this.images[i].loaded)) {
      this.images[i].loaded=1
      this.pL.children("li:eq("+i+")").html(this.template2(this.images[i]))
    }
    if(this.selnode<this.picsvisible*2) this.loadNext(-1)
    else if(this.selnode>this.images.length-this.picsvisible*2) this.loadNext(1)

    this.scrollChecking=false;
  }
  Ps.prototype.loadNext=function(dir){
    if ((dir>0&&this.s.count==this.images.length+this.s.offset) || (dir<0&&0==this.s.offset) || this.loadingNext) return;
    // prevent multiple execution
    this.loadingNext=true
    var o = (dir>0) ? (this.s.offset + this.images.length) : (this.s.offset - 24), // @fix limit
    order = this.s.urlparam.match(/&o=([a-z])/)
    if(order) order=order[1]
    $.getJSON(this.url, {ac:'browse', mode:this.s.mode, id:this.s.id, offset:o, dir:dir, order:order},
      alias(this,this.loadedNext))
  }
  // Kaboom Kaboom Kaboom!
  Ps.prototype.loadedNext=function(r){
    r.dir=parseInt(r.dir,10)
    this.pL.css({width:(this.images.length+r.result.length)*this.s.picture_width})
    if (r.dir<0) {
      this.s.offset=parseInt(r.offset,10)
      // fix animation jerking by queuing prepend function
      var prepend=(function(ps,r){return function(){
        for(var i=r.result.length;i>0;i--) ps.lpush(r.result[i-1])
        ps.bS.scrollLeft(ps.bS.scrollLeft()+ps.s.picture_width*r.result.length)
        ps.loadingNext=false
        $(this).dequeue()
      }})(this,r)
      this.bS.queue(prepend)
    }
    else {
      for(var i=0;i<r.result.length;i++) this.push(r.result[i])
      this.loadingNext=false
    }
  }

  /**
   * Lightbox integration
   - next/prev buttons avail-detection (hasNext,hasPrev)
   - next/prev buttons (loadNextBig)
   - direct-update lightbox content (via cb)
   */
  Ps.prototype.hasNext=function(){ return this.current < this.s.count-1 }
  Ps.prototype.hasPrev=function(){ return this.current > 0 }
  Ps.prototype.loadNextBig=function(dir, lightbox){
    if ((dir>0&&this.current==this.s.count-1) || (dir<0&&0==this.current) || this.loadingNext) return;
    // prevent multiple execution
    this.loadingNext=true
    var o = dir>0 ? this.current+1 : this.current-1, // load 1 next/prev item from the current one
    order = this.s.urlparam.match(/&o=([a-z])/)
    if(order) order=order[1]
    $.getJSON(this.url, {ac:'browse', mode:this.s.mode, id:this.s.id, offset:o, dir:dir, order:order, full:true},
      (function(lightbox,slider){return function(r){slider.loadedNextBig(r,lightbox)}})(lightbox,this)
    )
  }
  Ps.prototype.loadedNextBig=function(r,lightbox){
    this.current = r.offset;
    this.loadingNext=false;
    // take data to lightbox
    lightbox(r.result);
  }
  // onClose lightbox
  Ps.prototype._finish=function() {
    // reset current image offset
    this.current = this.currentDefault;
  }

  /**
   * window's functions
   */
  // show slider and scrolls to a given image `id`
  l.photoslider=function(id){
    var returnInstance = arguments[1] ? 1 : 0;
    if(isset(photoindex[id])){
      if (returnInstance) return ns[photoindex[id][0]];
      else ns[photoindex[id][0]].show(photoindex[id][1]);
    }
    return false
  }
  l.Photoslider=Ps;
  l.ns=ns; // debug
  $(document).ready(function(){
    // all lightboxes; @fixme: split anchors with rel="lightbox[title1]" and rel="lightbox[title2]"
    $('a[rel*=lightbox]').lightBox();
    // @fix for opera - swfobject scrolls `overflow` to zero position
    /**
    if (window.opera) { for(var i in ns) {
      if ('object'==typeof(ns[i])) ns[i].scroll({data:{offset:ns[i].selnode+3}})
    }}
    */
  });
})(jQuery)

