
// Inspired by base2 and Prototype
(function(){
  var initializing = false, fnTest = /xyz/.test(function(){xyz;}) ? /\b_super\b/ : /.*/;

  // The base Class implementation (does nothing)
  this.Class = function(){};
 
  // Create a new Class that inherits from this class
  Class.extend = function(prop) {
    var _super = this.prototype;
   
    // Instantiate a base class (but only create the instance,
    // don't run the init constructor)
    initializing = true;
    var prototype = new this();
    initializing = false;
   
    // Copy the properties over onto the new prototype
    for (var name in prop) {
      // Check if we're overwriting an existing function
      prototype[name] = typeof prop[name] == "function" &&
        typeof _super[name] == "function" && fnTest.test(prop[name]) ?
        (function(name, fn){
          return function() {
            var tmp = this._super;
           
            // Add a new ._super() method that is the same method
            // but on the super-class
            this._super = _super[name];
           
            // The method only need to be bound temporarily, so we
            // remove it when we're done executing
            var ret = fn.apply(this, arguments);       
            this._super = tmp;
           
            return ret;
          };
        })(name, prop[name]) :
        prop[name];
    }
   
    // The dummy class constructor
    function Class() {
      // All construction is actually done in the init method
      if ( !initializing && this.init )
        this.init.apply(this, arguments);
    }
   
    // Populate our constructed prototype object
    Class.prototype = prototype;
   
    // Enforce the constructor to be what we expect
    Class.constructor = Class;

    // And make this class extendable
    Class.extend = arguments.callee;
   
    return Class;
  };
})();

// Simple JavaScript Templating
// John Resig - http://ejohn.org/ - MIT Licensed
(function(){
  var cache = {};
 
  this.tmpl = function tmpl(str, data){
    // Figure out if we're getting a template, or if we need to
    // load the template - and be sure to cache the result.
    var fn = !/\W/.test(str) ?
      cache[str] = cache[str] ||
        tmpl(document.getElementById(str).innerHTML) :
     
      // Generate a reusable function that will serve as a template
      // generator (and which will be cached).
      new Function("obj",
        "var p=[],print=function(){p.push.apply(p,arguments);};" +
       
        // Introduce the data as local variables using with(){}
        "with(obj){p.push('" +
       
        // Convert the template into pure JavaScript
        str
          .replace(/[\r\t\n]/g, " ")
          .split("<%").join("\t")
          .replace(/((^|%>)[^\t]*)'/g, "$1\r")
          .replace(/\t=(.*?)%>/g, "',$1,'")
          .split("\t").join("');")
          .split("%>").join("p.push('")
          .split("\r").join("\\'")
      + "');}return p.join('');");
   
    // Provide some basic currying to the user
    return data ? fn( data ) : fn;
  };
})();

(function($){
    var options = {
        template : tmpl(
        '<div class="controls">' + 
            '<div class="prev"></div>' +
            '<div class="status"><%=status%></div>' +
            '<div class="next"></div>' +
        '</div>' +
        '<div class="photos"></div>'
        ),
        statusTemplate : tmpl("<%=current%> / <%=total%>"),
        changeEffect : "fade",
        speed: 300,
        fx: {}
    };

    options.fx.none = function(prev, next){
        prev.hide();
        next.show();
    };

    options.fx.fade = function(prev, next){
        var self = this;
        next.show().css({ position: "absolute", left: "0", top: "0", opacity: "0" });
        this.photosNode.css({ height: Math.max(prev.outerHeight(), next.outerHeight()) })
        prev.animate({ opacity: 0 }, options.speed);
        next.animate({ opacity: 1 }, options.speed, function(){
            self.photosNode.css({ height: next.outerHeight() })
            prev.hide();
            next.removeAttr("style");
        });
    }


    var dpSlideshow = Class.extend({
        init: function(obj, options)
        {
            this.node = $(obj);
            this.options = $.extend(true, {}, options);

            this.createui();
            this.bindui();
        },

        createui: function ()
        {

            this.photos = this.node.children().hide().eq(0).show().end();
            this.status = {
                current: 1,
                total: this.photos.length
            }

            var tpl = $(this.options.template({ status: this.options.statusTemplate(this.status)}));
            tpl.appendTo(this.node);
            this.photos.appendTo(tpl.filter(".photos"));
            this.controlsNode = this.node.find(".controls");
            this.photosNode = this.node.find(".photos");

            if(this.photos.length <= 1)
            {
                this.controlsNode.hide();
            }
        },

        bindui: function ()
        {
            var me = this;

            var prev = this.controlsNode.find(".prev");
            var next = this.controlsNode.find(".next");

            prev.click(function()
            {
                me.changePhoto(-1);
                return false;
            });

            next.click(function()
            {
                me.changePhoto(1);
                return false;
            });
            
        },

        setPhoto: function( newStatus ) {
            while(newStatus > this.status.total) newStatus -= this.status.total;
            while(newStatus < 1) newStatus += this.status.total;

            var oldPhoto = this.photos.eq(this.status.current - 1);
            var newPhoto = this.photos.eq(newStatus - 1);

            this.status.current = newStatus;

            var statusLine = this.controlsNode.find(".status");
            statusLine.html(this.options.statusTemplate(this.status));

            this.options.fx[ this.options.changeEffect && $.isFunction(this.options.fx[this.options.changeEffect]) ? this.options.changeEffect : "none" ].call(this, oldPhoto, newPhoto);
        },

        changePhoto: function(num)
        {
            this.setPhoto( this.status.current + parseInt(num, 10) );
        }
    });

    function initLinks( base ) {
        var slideshow = $( '.' + base ).data( 'b-slideshow' );

        $( '.' + base + '-link' ).click( function( ev ) {
                var photo_num = this.href.split('#')[1];
                slideshow.setPhoto( photo_num );
                ev.preventDefault();
        } );
    }

    $(document).ready(function()
    {
        $(".b-slideshow").each(function()
        {
            return $( this ).data( "b-slideshow", new dpSlideshow(this, options) );
        });

        initLinks( 'withbuttons' );


    });

})(jQuery);
