/*
  This program is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License version 2 as
  published by the Free Software Foundation.
  
  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.
  
  You should have received a copy of the GNU General Public License
  along with this program; if not, write to the Free Software
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  
  Copyright 2011 Tamara Stephas Visual Arts
*/

// If the browser window is narrower than the document, the banner element
// will be sized to the window rather than the document. This means that
// when the user scrolls right the horizontal bar under the banner will
// appear truncated. This fixes that by making sure the banner is at least
// as wide as the document.
function fixBannerWidth() {
  if ($(window).width() < 1000) {
    $(".banner").width(1000);
  } else {
    $(".banner").width("100%");
  }
}

$(window).load(fixBannerWidth).resize(fixBannerWidth);

// If the left border of the image is more than 180px (onside class width +
// margin) from the edge of the <div> (at 220px), move the title beside the
// image. The title element gets reformatted so that the title, media, and
// size are on separate lines.
function checkTitlePlacement() {
  var img = $(".artwork img");
  if (img.length == 0)
    return;
  if (img.position().left >= 220 + 160 + 20) {
    $(".artwork .title .sep").replaceWith("<br />");
    var titleLeft = img.position().left + img.width() + 20;
    $(".artwork .title").addClass("onside").css("left", titleLeft);
  }
}

$(window).load(checkTitlePlacement);

(function ($) {
  $.fn.spinner = function(method) {
    var methods = {
      init: function(spritesrc) {
        return this.each(function () {
          var $this = $(this);
          var data = {
            sprites: $("<img />")
          };
          data.sprites.load(function () {
            data.step = 0;
            data.stepCount = this.width / this.height;
            data.size = this.height;
            $this.css({
              width: this.height,
              height: this.height,
              "background-image": "url(" + spritesrc + ")",
              "background-repeat": "no-repeat"
            });
            delete data.sprites;
            $this.trigger("resize.spinner");
          });
          data.sprites.attr("src", spritesrc);
          $this.addClass("spinner");
          $this.data("spinner", data);
        });
      },

      start: function() {
        return this.each(function () {
          var $this = $(this);
          var data = $this.data("spinner");
          if (data.stepper) {
            return;
          }
          data.stepper = window.setInterval(function () {
            var pos = -data.size * data.step;
            $this.css("background-position", pos + "px top");
            data.step = (data.step + 1) % data.stepCount;
          }, 1000 / data.stepCount);
        });
      },

      stop: function() {
        return this.each(function () {
          var $this = $(this);
          var data = $this.data("spinner");
          if (! data.stepper) {
            return;
          }
          window.clearInterval(data.stepper);
          delete data.stepper;
        });
      }
    };

    if (methods[method]) {
      // Execute a command on the element.
      var args = Array.prototype.slice.call(arguments, 1);
      return methods[method].apply(this, args);
    } else if (method) {
      // Initialize the element with the given sprite.
      return methods.init.apply(this, arguments);
    } else {
      $.error("Missing method '" + method + "' on jQuery.spinner");
      return this;
    }
  };

  $.fn.slide = function(method) {
    var methods = {
      init: function(options) {
        return this.each(function () {
          var $this = $(this);
          var data = {
            imagesrc: options.imagesrc
          };

          data.spinner = $("<div />").spinner(options.loader);
          data.image = $("<img />");
          var caption = $(options.caption).addClass("caption");
          var controls = helpers.createControls.apply($this);
          $this.mouseenter(function (evt) {
            controls.fadeIn("fast");
          }).mouseleave(function (evt) {
            controls.fadeOut("fast");
          });
          $this.append(data.spinner, data.image, caption, controls);

          $this.addClass("slide");
          $this.data("slide", data);
        });
      },

      show: function (callback) {
        return this.each(function () {
          var $this = $(this);
          var data = $this.data("slide");
          if ($this.css("display") != "none") {
            return;
          }
          if (! data.image[0].src) {
            data.image.load(function () {
              if (data.image.css("display") == "none") {
                $this.slide("hide", function () {
                  $this.slide("show");
                });
              }
            });
            data.image[0].src = data.imagesrc;
          }
          if (! data.image[0].complete) {
            data.spinner.show();
            data.spinner.spinner("start");
            data.image.hide();
          } else {
            data.spinner.hide();
            data.spinner.spinner("stop");
            data.image.show();
          }
          helpers.updatePosition.apply($this);
          $this.fadeIn("slow", function () {
            if (callback) {
              callback.apply($this[0]);
            }
          });
        });
      },

      hide: function (callback) {
        return this.each(function () {
          var $this = $(this);
          var data = $this.data("slide");
          if ($this.css("display") == "none") {
            return;
          }
          $this.fadeOut("slow", function () {
            data.spinner.spinner("stop");
            if (callback) {
              callback.apply($this[0]);
            }
          });
        });
      }
    };

    var helpers = {
      createControls: function () {
        var $this = this;
        var controls = $("<div />").addClass("controls").hide();
        controls.append($("<a />", {
          text: "\u00ab",
          "class": "previous",
          href: "#",
          click: function (evt) {
            evt.stopPropagation();
            $this.trigger("previous.slide");
            return false;
          }
        }));
        controls.append($("<a />", {
          text: "\u00bb",
          "class": "next",
          href: "#",
          click: function (evt) {
            evt.stopPropagation();
            $this.trigger("next.slide");
            return false;
          }
        }));
        controls.append($("<a />", {
          text: "\u00d7",
          "class": "close",
          href: "#",
          click: function (evt) {
            evt.stopPropagation();
            $this.trigger("close.slide");
            return false;
          }
        }));
        return controls;
      },

      updatePosition: function () {
        var $window = $(window);
        var $document = $(document);
        this.css({
          left: "",
          top: "",
          width: "",
          height: ""
        });
        var docWidth = $document.width();
        var docHeight = $document.height();
        var winHeight = $window.height();
        var width = this.width();
        var height = this.height();
        var slideWidth = this.outerWidth();
        var slideHeight = this.outerHeight();
        var left = (docWidth - slideWidth) / 2;
        if (left < 0) {
          left = 0;
        }
        var top = ((winHeight - slideHeight) / 2) + $window.scrollTop();
        if (slideHeight <= docHeight) {
          if (top < 0) {
            top = 0;
          } else if (top + slideHeight > docHeight) {
            top = docHeight - slideHeight
          }
        } else {
          if (top < 0) {
            top = 0;
          }
        }
        this.css({
          left: left,
          top: top,
          width: width,
          height: height
        });
      }
    }

    if (methods[method]) {
      // Execute a command on the element.
      var args = Array.prototype.slice.call(arguments, 1);
      return methods[method].apply(this, args);
    } else if (typeof method === 'object' || !method) {
      // Initialize the element with the given options.
      return methods.init.apply(this, arguments);
    } else {
      $.error("Missing method '" + method + "' on jQuery.slide");
      return this;
    }
  };

  $.fn.background = function(method) {
    var methods = {
      init: function(opacity) {
        return this.each(function () {
          var $this = $(this);
          var data = {
            opacity: opacity
          };
          // Update the background size when the window gets resized.
          $(window).resize(function () {
            helpers.resize.apply($this);
          });
          $this.addClass("background");
          $this.data("background", data);
        });
      },

      show: function(callback) {
        return this.each(function () {
          var $this = $(this);
          var data = $this.data("background");
          helpers.resize.apply($this);
          $this.fadeTo("slow", data.opacity, function () {
            if (callback) {
              callback.apply($this[0]);
            }
          });
        });
      },

      hide: function(callback) {
        return this.each(function () {
          var $this = $(this);
          $this.fadeOut("slow", function () {
            if (callback) {
              callback.apply($this[0]);
            }
          });
        });
      }
    };

    var helpers = {
      resize: function () {
        var $window = $(window);
        this.css({
          width: $window.width(),
          height: $window.height()
        });
      }
    };

    if (methods[method]) {
      // Execute a command on the element.
      var args = Array.prototype.slice.call(arguments, 1);
      return methods[method].apply(this, args);
    } else if (method) {
      // Initialize the element with the given opacity.
      return methods.init.apply(this, arguments);
    } else {
      $.error("Missing method '" + method + "' on jQuery.background");
      return this;
    }
  };

  $.fn.slideshow = function(method) {
    var methods = {
      init: function (options) {
        return this.each(function () {
          var $this = $(this);
          // Initialize the slideshow element with the given options.
          var data = {
            target: $this,
            slides: $()
          };
          $this.data("slideshow", data);
          // Create the slides for the slideshow from the slide data provided.
          if (options.slides) {
            for (var i = 0; i < options.slides.length; i++) {
              var slideData = options.slides[i];
              var slide = $("<div />").slide({
                imagesrc: slideData.src,
                caption: slideData.caption,
                loader: options.loader
              });
              slide.bind("close.slide", function () {
                $this.slideshow("close");
              }).bind("next.slide", function () {
                $this.slideshow("next", $(this));
              }).bind("previous.slide", function () {
                $this.slideshow("previous", $(this));
              });
              slide.slide("hide");
              data.slides = data.slides.add(slide);
            }
          }
          // Create a background image for the slideshow, and close the
          // slideshow when it is clicked.
          data.background = $("<div />").background(0.8).click(function (evt) {
            $this.slideshow("close");
          });
          // Set the class and hide the slideshow, and add the slides and
          // background objects to it.
          $this.addClass("slideshow").hide();
          $this.append(data.slides);
          $this.append(data.background);
        });
      },

      open: function (index) {
        return this.each(function () {
          var $this = $(this);
          var data = $this.data("slideshow");
          var slide = $(data.slides[index]);
          if ($this.css("display") != "none" || !slide) {
            return;
          }
          $this.show();
          data.background.background("show", function () {
            slide.slide("show");
          });
        });
      },

      close: function () {
        return this.each(function () {
          var $this = $(this);
          var data = $this.data("slideshow");
          data.slides.slide("hide", function () {
            data.background.background("hide", function () {
              $this.hide();
            });
          });
        });
      },

      next: function (slide) {
        return this.each(function () {
          var $this = $(this);
          var data = $this.data("slideshow");
          slide.slide("hide", function () {
            var index = data.slides.index(slide);
            slide = data.slides[index + 1];
            if (slide == undefined) {
              slide = data.slides[0];
            }
            $(slide).slide("show");
          });
        });
      },

      previous: function (slide) {
        return this.each(function () {
          var $this = $(this);
          var data = $this.data("slideshow");
          slide.slide("hide", function () {
            var index = data.slides.index(slide);
            slide = data.slides[index - 1];
            if (slide == undefined) {
              slide = data.slides[data.slides.length - 1];
            }
            $(slide).slide("show");
          });
        });
      }
    };

    if (methods[method]) {
      // Execute a command on the element.
      var args = Array.prototype.slice.call(arguments, 1);
      return methods[method].apply(this, args);
    } else if (typeof method === 'object' || !method) {
      // Initialize the element with the given options.
      return methods.init.apply(this, arguments);
    } else {
      $.error("Missing method '" + method + "' on jQuery.slideshow");
      return this;
    }
  }
})(jQuery);

$(document).ready(function () {
  // Don't even try to run our slideshow in IE6 and lower. Just use the
  // scriptless alternative.
  if ($.browser.msie && $.browser.version < 7) {
    return;
  }
  var slideList;
  try {
    slideList = artworkList;
  }
  catch (e) {
  }
  if (slideList != undefined) {
    var slideshow = $("<div />").appendTo($("body")).slideshow({
      slides: slideList,
      loader: "/images/spinner.png"
    });
    $(".gallery .thumbnail a").click(function () {
      slideshow.slideshow("open", $(this).index(".gallery .thumbnail a"));
      return false;
    });
  }
});

