//  Starbox 1.1.0 - 01-04-2008
//  Copyright (c) 2008 Nick Stakenburg (http://www.nickstakenburg.com)
//
//  Licensed under a Creative Commons Attribution-Noncommercial-No Derivative Works 3.0 Unported License
//  http://creativecommons.org/licenses/by-nc-nd/3.0/

//  More information on this project:
//  http://www.nickstakenburg.com/projects/starbox/

var Starboxes = {
  options: {
    buttons: 5,                                  // amount of clickable areas
    className : 'default',                       // default class
    color: false,                                // would overwrite the css style to set color on the stars
    duration: 0.7,                               // the duration of the revert effect, when effects are used
    effect: {
      mouseover: false,                          // use effects on mouseover, default false
      mouseout: (window.Effect && Effect.Morph)  // use effects on mouseout, default when available
    },
    hoverColor: false,                           // overwrites the css hover color
    hoverClass: 'hover',                         // the css hover class color
    ghostColor: false,                           // the color of the ghost stars, if used
    ghosting: false,                             // ghosts the previous vote
    identity: false,                             // a unique value you can give each starbox
    indicator: false,                            // use an indicator, default false
    inverse: false,                              // inverse the stars, right to left
    locked: false,                               // lock the starbox to prevent voting
    max: 5,                                      // the maximum rating of the starbox
    onRate: Prototype.emptyFunction,             // default onRate, function(element, memo) {}
    rated: false,                                // or a rating to indicate a vote has been cast
    ratedClass: 'rated',                         // class when rated
    rerate: false,                               // allow rerating
    overlay: 'default.png',                      // default star overlay image
    overlayImages: '../../images/js_stars/',         // directory of images relative to this file ../images/starbox/
    stars: 5,                                    // the amount of stars
    total: 0                                     // amount of votes cast
  }
};

  Object.extend(Starboxes, { "REQUIRED_Prototype": "1.6.0.2", "REQUIRED_Scriptaculous": "1.8.1", 
  
  "load": function ()
  {
    this.require("Prototype");
    this.identify.counter = 1;
    var A = /starbox(?:-[\w\d.]+)?\.js(.*)/;
    this.imageSource = (($$("head script[src]").find(function (B)
    {
      return B.src.match(A);
    }) || { }).src || "").replace(A, "") + this.options.overlayImages;
  }, 
  
  "require": function (A)
  {
    if (typeof window[A] == "undefined" || this.convertVersionString(window[A].Version) < this.convertVersionString(this["REQUIRED_" + A]))
      {
        throw "Lightview requires " + A + " >= " + this["REQUIRED_" + A];
      }
  }, 
  
  "convertVersionString": function (A)
  {
    var B = A.replace(/_.*|\./g, "");
    B = parseInt(B + "0".times(4 - B.length));
    return A.indexOf("_") > -1 ? B - 1 : B;
  }, 
  
  "fixIE": function (B)
  {
    var A = (new RegExp("MSIE ([\\d.]+)")).exec(B);
    return A ? parseFloat(A[1]) < 7 : false;
  }(navigator.userAgent), "identify": function (B)
  {
    B = $(B);
    var C = B.readAttribute("id"), A = arguments.callee;
    if (C)
      {
        return C;
      }
    do 
      {
        C = "starbox_" + A.counter++;
      }
    while ($(C));
    B.writeAttribute("id", C);
    return C;
  }, 
  
  "imagecache": [], "cacheImage": function (A)
  {
    if (!this.getCachedImage(A.src))
      {
        this.imagecache.push(A);
      }
    return A;
  }, 
  
  "getCachedImage": function (A)
  {
    return this.imagecache.find(function (B)
    {
      return B.src == A;
    });
  }, 
  
  "buildQueue": [], "queueBuild": function (A)
  {
    this.buildQueue.push(A);
  }, 
  
  "processBuildQueue": function ()
  {
    if (!this.buildQueue[0])
      {
        this.batchLoading = true;
        return;
      }
    this.cacheBuildBatch(this.buildQueue[0]);
  }, 
  
  "cacheBuildBatch": function (C)
  {
    var E = [], B = C.options.overlay, A = this.getCachedImage(B);
    this.buildQueue.each(function (F)
    {
      if (F.options.overlay == B)
        {
          E.push(F);
          this.buildQueue = this.buildQueue.without(F);
        }
    }.bind(this));
    if (!A)
      {
        var D = new Image();
        D.onload = function ()
        {
          this.buildBatch(E, { "src": B, "height": D.height, "width": D.width, "fullsrc": D.src });
        }.bind(this);
        D.src = Starboxes.imageSource + B;
      }
    else
      {
        this.buildBatch(E, A);
      }
  }, 
  
  "buildBatch": function (B, A)
  {
    B.each(function (C)
    {
      C.imageInfo = A;
      C.build();
    });
    this.processBuildQueue();
  }, 
  
  "useEvent": function (A)
  {
    return { "click": "click", "mouseover": "mouseover", "mouseout": A ? "mouseleave" : "mouseout" };
  }(Prototype.Browser.IE), 
  
  "capture": function (A)
  {
    if (!Prototype.Browser.IE)
      {
        A = A.wrap(function (E, D)
        {
          var C = Object.isElement(this) ? this : this.element, B = D.relatedTarget;
          if (B != C && !$A(C.select("*")).member(B))
            {
              E(D);
            }
        });
      }
    return A;
  } 
 }
);



  Starboxes.load();
  document.observe("dom:loaded", Starboxes.processBuildQueue.bind(Starboxes));


  var Starbox = Class.create({ "initialize": function (A, B)
  {
    this.element = $(A);
    this.average = B;
    this.options = Object.extend(Object.clone(Starboxes.options), arguments[2] || { });
    $w("identity rated max total").each(function (C)
    {
      this[C] = this.options[C];
    }.bind(this));
    this.locked = this.options.locked || this.rated && !this.options.rerate;
    if (!this.identity)
      {
        this.identity = Starboxes.identify(this.element);
      }
    if (this.options.effect && (this.options.effect.mouseover || this.options.effect.mouseout))
      {
        Starboxes.require("Scriptaculous");
      }
    Starboxes.queueBuild(this);
    if (Starboxes.batchLoading)
      {
        Starboxes.processBuildQueue();
      }
  }
  
  , "enable": function ()
  {
    $w("mouseout mouseover click").each(function (C)
    {
      var B = C.capitalize(), A = this["on" + B].bindAsEventListener(this);
      this["on" + B + "_cached"] = C == "mouseout" && !Prototype.Browser.IE ? Starboxes.capture(A) : A;
      this.starbar.observe(Starboxes.useEvent[C], this["on" + B + "_cached"]);
    }.bind(this));
    this.buttons.invoke("setStyle", { "cursor": "pointer" });
  }
  
  , "disable": function ()
  {
    $w("mouseover mouseout click").each(function (A)
    {
      this.starbar.stopObserving(Starboxes.useEvent[A], this["on" + A.capitalize() + "_cached"]);
    }.bind(this));
    this.buttons.invoke("setStyle", { "cursor": "auto" });
  }
  
  , "build": function ()
  {
    this.starWidth = this.imageInfo.width;
    this.starHeight = this.imageInfo.height;
    this.starSrc = this.imageInfo.fullsrc;
    this.boxWidth = this.starWidth * this.options.stars;
    this.buttonWidth = this.boxWidth / this.options.buttons;
    this.buttonRating = this.options.max / this.options.buttons;
    if (this.options.effect)
      {
        this.zeroPosition = this.getBarPosition(0);
        this.maxPosition = this.getBarPosition(this.options.max);
      }
    var A = { "absolute": { "position": "absolute", "top": 0, "left": 0, "width": this.boxWidth + "px", "height": this.starHeight + "px" }, "base": { "position": "relative", "width": this.boxWidth + "px", "height": this.starHeight + "px" }, "star": { "position": "absolute", "top": 0, "left": 0, "width": this.starWidth + "px", "height": this.starHeight + "px" } };
    this.element.addClassName("starbox");
    this.container = (new Element("div", { "className": this.options.className || "" })).setStyle({ "position": "relative" }).insert(this.status = (new Element("div")).insert(this.hover = (new Element("div")).insert(this.wrapper = (new Element("div", { "className": "stars" })).setStyle(Object.extend({ "overflow": "hidden" }, A.base)))));
    if (this.rated)
      {
        this.status.addClassName("rated");
      }
    if (this.locked)
      {
        this.status.addClassName("locked");
      }
    if (this.options.ghosting)
      {
        this.wrapper.insert(this.ghost = (new Element("div", { "className": "ghost" })).setStyle(A.absolute));
        if (this.options.ghostColor)
          {
            this.ghost.setStyle({ "background": this.options.ghostColor });
          }
        if (this.options.effect)
          {
            this.ghost.scope = this.ghost.identify();
          }
        this.setBarPosition(this.ghost, this.average, window.Effect && Effect.Morph);
      }
    this.wrapper.insert(this.colorbar = (new Element("div", { "className": "colorbar" })).setStyle(A.absolute)).insert((new Element("div")).setStyle(A.absolute).insert(this.starbar = (new Element("div")).setStyle(A.base)));
    if (this.options.color)
      {
        this.colorbar.setStyle({ "background": this.options.color });
      }
    if (this.options.effect)
      {
        this.colorbar.scope = this.colorbar.identify();
      }
    this.options.stars.times(function (B)
    {
      var C;
      this.starbar.insert(C = (new Element("div")).setStyle(Object.extend({ "background": "url(" + this.starSrc + ") top left no-repeat", "left": this.starWidth * B + "px" }, A.star)));
      C.setStyle({ "left": this.starWidth * B + "px" });
      if (Starboxes.fixIE)
        {
          C.setStyle({ "background": "none", "filter": "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + this.starSrc + "'', sizingMethod='scale')" });
        }
    }.bind(this));
    this.buttons = [];
    this.options.buttons.times(function (D)
    {
      var C;
      var B = this.options.inverse ? this.boxWidth - this.buttonWidth * (D + 1) : this.buttonWidth * D;
      this.starbar.insert(C = (new Element("div")).setStyle({ "position": "absolute", "top": 0, "left": B + "px", "width": this.buttonWidth + (Prototype.Browser.IE ? 1 : 0) + "px", "height": this.starHeight + "px" }));
      C.rating = this.buttonRating * D + this.buttonRating;
      this.buttons.push(C);
    }.bind(this));
    this.setBarPosition(this.colorbar, this.average);
    this.element.update(this.container);
    this.inputs = { };
    $w("average max rated rerated total").each(function (B)
    {
      this.element.insert(this.inputs[B] = new Element("input", { "type": "hidden", "name": this.identity + "_" + B, "value": "" + (B == "rerated" ? !!this[B] : this[B]) }));
    }.bind(this));
    if (this.options.indicator)
      {
        this.hover.insert(this.indicator = new Element("div", { "className": "indicator" }));
        this.updateIndicator();
      }
    if (!this.locked)
      {
        this.enable();
      }
  }, 
  
  "updateAverage": function (A)
  {
    if (this.rated && this.options.rerate)
      {
        this.average = (this.total * this.average - this.rated) / (this.total - 1 || 1);
      }
    var B = this.rated ? this.total : this.total++;
    this.average = this.average == 0 ? A : (this.average * (this.rated ? B - 1 : B) + A) / (this.rated ? B : B + 1);
  }, 
  
  "updateIndicator": function ()
  {
    this.indicator.update((new Template(this.options.indicator)).evaluate({ "max": this.options.max, "total": this.total, "average": (this.average * 10).round() / 10 }));
  }, 
  
  "getBarPosition": function (B)
  {
    var A = this.boxWidth - B / this.buttonRating * this.buttonWidth;
    return parseInt(this.options.inverse ? A.ceil() : -1 * A.floor());
  }, 
  
  "setBarPosition": function (A, B)
  {
    if (this.options.effect && this["activeEffect_" + A.scope])
      {
        Effect.Queues.get(A.scope).remove(this["activeEffect_" + A.scope]);
      }
    var D = this.getBarPosition(B);
    if (arguments[2])
      {
        var C = parseInt(A.getStyle("left")), F = this.getBarPosition(B);
        if (C == F)
          {
            return;
          }
        var E = ((this.maxPosition - (C - F).abs()).abs() / this.zeroPosition.abs()).toFixed(2);
        this["activeEffect_" + A.scope] = new Effect.Morph(A, { "style": { "left": D + "px" }, "queue": { "position": "end", "limit": 1, "scope": A.scope }, "duration": this.options.duration * E });
      }
    else
      {
        A.setStyle({ "left": D + "px" });
      }
  }, 
  
  "onClick": function (C)
  {
    var B = C.element();
    if (!B.rating)
      {
        return;
      }
    this.updateAverage(B.rating);
    if (this.options.indicator)
      {
        this.updateIndicator();
      }
    if (this.options.ghosting)
      {
        this.setBarPosition(this.ghost, this.average, window.Effect && Effect.Morph);
      }
    if (!this.rated)
      {
        this.status.addClassName("rated");
      }
    this.rerated = !!this.rated;
    this.rated = B.rating;
    if (!this.options.rerate)
      {
        this.disable();
        this.status.addClassName("locked");
        this.onMouseout(C);
      }
    var A = { };
    $w("average identity max rated rerated total").each(function (D)
    {
      if (D != "identity")
        {
          this.inputs[D].value = this[D];
        }
      A[D] = this[D];
    }.bind(this));
    this.options.onRate(this.element, A);
    this.element.fire("starbox:rated", A);
  }, 
  
  "onMouseout": function (A)
  {
    this.setBarPosition(this.colorbar, this.average, this.options.effect && this.options.effect.mouseout);
    this.hovered = false;
    if (this.options.hoverClass)
      {
        this.hover.removeClassName(this.options.hoverClass);
      }
    if (this.options.hoverColor)
      {
        this.colorbar.setStyle({ "background": this.options.color });
      }
    this.element.fire("starbox:left");
  }, 
  
  "onMouseover": function (B)
  {
    var A = B.element();
    if (!A.rating)
      {
        return;
      }
    this.setBarPosition(this.colorbar, A.rating, this.options.effect && this.options.effect.mouseover);
    if (!this.hovered && this.options.hoverClass)
      {
        this.hover.addClassName(this.options.hoverClass);
      }
    this.hovered = true;
    if (this.options.hoverColor)
      {
        this.colorbar.setStyle({ "background": this.options.hoverColor });
      }
    this.element.fire("starbox:changed", { "identify": this.options.identity, "max": this.options.max, "rating": A.rating, "total": this.total });
  } });
