/* photoManager for iPhone/jQuery
*
*  A plugin to mimic the native iPhone photoManager
*
*  version 0.1 - 10/02/2010 
*  author: Renato Formato - Roll Multimedia Design <renato@rollstudio.it>
*  
*  double released under GPL and MIT license
*  copyright 2010 
*
*/
;(function($){
  $.fn.photoManager = function(opts) {
    return this.each(function(){
      var $this = $(this),
          opt = $.extend({
             containerSelector:"ul",
             imgSelector:"li",
             width:320,
             margin:20
          },opts);
      var pM = new photoManager();
      pM.el = $this;
      pM.opt = opt;
      pM.imgs = $this.find(opt.imgSelector);
      pM.container = $this.find(opt.containerSelector);
      $this.data("photoManager",pM);
      //inizializzo contenitore
      $this.css({overflow:"hidden"});
      pM.container.pm_gestures(pM,{rotate:false});
      $this.pm_refresh(opt.width);
    });
  };
  
  var initWidths = function(pM) {
    var wt = 0;
    for(var i=0, imgs = pM.imgs, count=imgs.length;i<count;i++) {
      var wi = imgs.eq(i).outerWidth();
      pM.widths[i] = wi;
      pM.bounds[i] = {left:wt-30,right:wt+50};
      pM.totalWidths[i] = wt;
      wt += wi;
    }
  }
  
  var rescaleImg = function(img,width) {
    var $img = $(img),
        scale = $img.width()/img.naturalWidth;
    $img.data("pm_scale",{scale:scale});
    $img.css({marginLeft:img.naturalWidth*(scale-1)/2+"px",marginTop:img.naturalHeight*(scale-1)/2+"px"}).width("auto");
    img.style.webkitTransform = "translate3d(0,0,0) scale("+scale+") rotate(0)";
  }
  
  $.fn.pm_refresh = function(width) {
    var pM = this.data("photoManager"),
        opt = pM.opt,
        imgs = pM.imgs,
        length = imgs.length;
    opt.width = width;
    var wc = length*width+(length-1)*opt.margin;
    imgs.css({width:width+"px"}).slice(1).css({paddingLeft:opt.margin+"px"});
    imgs.find("img").each(function(){
      //devo prendere la larghezza delle immagini e memorizzarla
      //poi resettarla ed applicazione una trasfromazione con scale 
      //per riportarla alla dimensione voluta
      if(this.naturalWidth) {
        rescaleImg(this,width);
      } else {
        $(this).load(function(){
          rescaleImg(this,width);
        })
      }
    });
    initWidths(pM);    
    var data = pM.container.css({
      width:wc+"px",
      WebkitTransition:"-webkit-transform 100ms ease-out"
    }).data("pm_gestures");
    data.x = moveToIndex(pM,pM.currentIndex);
  }
  
  var moveToIndex = function(pM,index) {
    pM.currentIndex = index;  
    var wt = pM.totalWidths[index],
        wi = pM.widths[index],
        dx = -wt-(index==0?0:pM.opt.margin);
    pM.imgs.css("WebkitTransform","translate3d(0,0,0) scale(1)");
    pM.container.css({
      WebkitTransformOrigin: (wt+wi/2)+"px 50%",
      WebkitTransform : "translate3d("+dx+"px,0,0) scale(1) rotate(0)"
    });
    return dx;
  }
  
  var photoManager = function() {
    this.el = null;
    this.opt = null;
    this.widths = [];
    this.bounds = [];
    this.totalWidths = [];
    this.gestures = {
      inited:false,
      started: false
    };
    this.container = null;
    this.imgs = null;
    this.currentIndex = 0;
    this.next = function() {
      var data = this.container.data("pm_gestures");
      if(this.currentIndex<this.imgs.length-1) {
        this.currentIndex++;
        data.x = moveToIndex(this,this.currentIndex);
        data.scale = 1;
        this.el.trigger("pageChange.photoManager",{index:this.currentIndex});
      }
    }
    this.previous = function() {
      var data = this.container.data("pm_gestures");
      if(this.currentIndex>0) {
        this.currentIndex--;
        data.x = moveToIndex(this,this.currentIndex);
        data.scale = 1;
        this.el.trigger("pageChange.photoManager",{index:this.currentIndex});
      }    
    }
  };
  
  $.fn.pm_gestures = function(pM,opts) {
    var defopts = {pan:true,scale:true,rotate:true};
    opts = $.extend(defopts,opts||{});
    if(!pM.gestures.inited) {
      var init = function(e) {
        if(pM.gestures.started) {
          //console.log("touchmove prevent on document - gesture running...");
          e.preventDefault();
        }      
      };
      $(document).unbind("touchmove.photoManager",init).bind("touchmove.photoManager",init);
      pM.gestures.inited = true;
    };
    return this.each(function() {
      $(this).data("pm_gestures",{scale:1,rotation:0,x:0,y:0,tcount:0})
      .bind("touchstart",function(e){
        //console.log("touchstart");
        if(pM.gestures.started) 
          return false;
        var el = this;
        var data = $(el).data("pm_gestures");
        var ev = e.originalEvent;
        data.startX = ev.targetTouches[0].clientX;
        data.startY = ev.targetTouches[0].clientY;
        return false;
      }).bind("touchmove",function(e){
        //console.log("touchmove");
        e.preventDefault();
        var el = this;//e.target;
        var data = $(el).data("pm_gestures");
        if(pM.gestures.started || data.tcount>0) {
          //console.log("touchmove stopped - gesture running...");
        } else if(opts.pan) {
          //console.log("panning");
          var ev = e.originalEvent;
          var leftDelta = ev.targetTouches[0].clientX - data.startX;
          var topDelta = ev.targetTouches[0].clientY - data.startY;
          data.startX = ev.targetTouches[0].clientX;
          data.startY = ev.targetTouches[0].clientY;
          data.x += leftDelta;
          if(data.scale>1) {
            data.y += topDelta;
          } else 
            data.y = 0;
          el.style.webkitTransform = "translate3d("+data.x+"px,"+data.y+"px,0) scale("+data.scale+") rotate(" + ((data.rotation) % 360) + "deg)";
        }
        e.stopImmediatePropagation();
      }).bind("gesturestart",function(e){
        //console.log("gesturestart");
        if(!opts.rotate && !opts.scale)
          return false;
        var el = this;
        var data = $(el).data("pm_gestures");
        data.tcount = 2;
        data.startScale = data.scale;
        data.startRotation = data.rotation;
        pM.gestures.started = true;
      }).bind("gesturechange",function(e){
        var ev = e.originalEvent;
        var el = this;
        var data = $(el).data("pm_gestures");
        //translate3d(0,0,0) trick to fix a transform bug
        var newScale = data.startScale*(opts.scale?ev.scale:1);
        if(newScale<1) {
          newScale = 1;
          data.y = 0;
        }
        var newRotation = (data.startRotation + (opts.rotate?ev.rotation:0)) % 360; 
        el.style.webkitTransform = "translate3d("+data.x+"px,"+data.y+"px,0) scale("+newScale+") rotate(" + newRotation + "deg)";        
        var sx = 0, dx = 0;
        for(var i=pM.currentIndex-1;i>=0;i--) {
          var delta = pM.widths[i]*(1-1/newScale)/2;
          if(sx==0)
            sx += delta;
          else 
            sx += delta*2;
          pM.imgs.get(i).style.webkitTransform = "translate3d("+sx+"px,0,0) scale("+1/newScale+") rotate(0)";
        }
        for(var i=pM.currentIndex+1;i<pM.imgs.length;i++) {
          var delta = pM.widths[i]*(1-1/newScale)/2;
          if(dx==0)
            dx -= delta;
          else 
            dx -= delta*2;
          pM.imgs.get(i).style.webkitTransform = "translate3d("+dx+"px,0,0) scale("+1/newScale+") rotate(0)";
        }
        data.scale = newScale;
        data.rotation = newRotation;
      }).bind("gestureend",function(e){
        //console.log("gestureend");
        var el = this;
        var ev = e.originalEvent;
        pM.gestures.started = false;
      }).bind("touchend",function(e){
        //console.log("touchend");
        var el = this;
        var data = $(el).data("pm_gestures");
        //verifico se devo cambiare immagine
        var change = false;
        var delta = pM.widths[pM.currentIndex]*(data.scale-1)/2,
            deltay = pM.container.height()*(data.scale-1)/2,
            $img = pM.imgs.eq(pM.currentIndex).find("img"),
            deltayCenter = (pM.container.height()/2-$img.height()*$img.data("pm_scale").scale)*data.scale,
            deltaMargin = pM.currentIndex==0?0:pM.opt.margin;
        deltay = Math.max(deltay,deltayCenter);
        if(!data.tcount) {
          if(-data.x>pM.bounds[pM.currentIndex].right+delta) {
            if(pM.currentIndex<pM.imgs.length-1) {
              pM.currentIndex++;
              change = true;
            }
          } else if(-data.x<pM.bounds[pM.currentIndex].left-delta) {
            if(pM.currentIndex>0) {
              pM.currentIndex--;
              change = true;
            }
          }
          if(change) {
            data.x = moveToIndex(pM,pM.currentIndex);
            data.scale = 1;
            pM.el.trigger("pageChange.photoManager",{index:pM.currentIndex});
          }
        } 
        if(!change) {
        //torno in posizione base se non ci sono cambiamenti di immagine
          if(data.scale == 1) {
            var wt = pM.totalWidths[pM.currentIndex];
            data.x = -wt-deltaMargin;
            this.style.webkitTransform = "translate3d("+data.x+"px,0,0) scale(1) rotate(0)";
          } else {
            //verifico bounds immagine
            if(-data.x>pM.totalWidths[pM.currentIndex]+delta+deltaMargin)//destra
              data.x = -(pM.totalWidths[pM.currentIndex]+delta+deltaMargin);
            else if(-data.x<pM.totalWidths[pM.currentIndex]-delta)//sinistra
              data.x = -pM.totalWidths[pM.currentIndex]+delta;
            if(data.y>deltay)
              data.y = deltay;
            else if(data.y<0 && data.y<deltayCenter)
              data.y = deltayCenter;
            this.style.webkitTransform = "translate3d("+data.x+"px,"+data.y+"px,0) scale("+data.scale+") rotate(0)";
          }
        }
        if(data.tcount)
          data.tcount--;
        return false;
      });
    });
  }  
})(jQuery)

