/*  Starbox 1.2.2 - 11-01-2010
 *  Copyright (c) 2008-2011 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.6,                               // 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/starbox/',         // directory of images relative to this file
    stars: 5,                                    // the amount of stars
    total: 0                                     // amount of votes cast
  }
};

(function () {
    function d(b) {
        document.loaded ? b.call(document) : document.observe("dom:loaded", b);
    }
    Object.extend(Starboxes, {
        REQUIRED_Prototype: "1.7",
        REQUIRED_Scriptaculous: "1.8.3",
        load: function () {
            this.require("Prototype"), this.identify.counter = 1;
            if (/^(https?:\/\/|\/)/.test(this.options.overlayImages)) {
                this.imageSource = this.options.overlayImages
            } else {
                var b = /starbox(?:-[\w\d.]+)?\.js(.*)/;
                this.imageSource = (($$("script[src]").find(function (a) {
                    return a.src.match(b)
                }) || {}).src || "").replace(b, "") + this.options.overlayImages
            }
        },
        require: function (b) {
            if (typeof window[b] == "undefined" || this.convertVersionString(window[b].Version) < this.convertVersionString(this["REQUIRED_" + b])) {
                throw "Starbox requires " + b + " >= " + this["REQUIRED_" + b]
            }
        },
        convertVersionString: function (f) {
            var e = f.replace(/_.*|\./g, "");
            e = parseInt(e + "0".times(4 - e.length));
            return f.indexOf("_") > -1 ? e - 1 : e
        },
        fixIE: function (f) {
            var e = (new RegExp("MSIE ([\\d.]+)")).exec(f);
            return e ? parseFloat(e[1]) < 7 : !1
        }(navigator.userAgent),
        identify: function (f) {
            f = $(f);
            var e = f.readAttribute("id"),
                g = arguments.callee;
            if (e) {
                return e
            }
            do {
                e = "starbox_" + g.counter++
            } while ($(e));
            f.writeAttribute("id", e);
            return e
        },
        imagecache: [],
        cacheImage: function (b) {
            this.getCachedImage(b.src) || this.imagecache.push(b);
            return b
        },
        getCachedImage: function (b) {
            return this.imagecache.find(function (a) {
                return a.src == b
            })
        },
        buildQueue: [],
        queueBuild: function (b) {
            this.buildQueue.push(b)
        },
        processBuildQueue: function () {
            this.buildQueue[0] ? this.cacheBuildBatch(this.buildQueue[0]) : this.batchLoading = !1
        },
        cacheBuildBatch: function (g) {
            var f = [],
                j = g.options.overlay,
                i = this.getCachedImage(j);
            this.buildQueue.each(function (b) {
                b.options.overlay == j && (f.push(b), this.buildQueue = this.buildQueue.without(b))
            }.bind(this));
            if (i) {
                this.buildBatch(f, i)
            } else {
                var h = new Image;
                h.onload = function () {
                    this.buildBatch(f, {
                        src: j,
                        height: h.height,
                        width: h.width,
                        fullsrc: h.src
                    })
                }.bind(this), h.src = Starboxes.imageSource + j
            }
        },
        buildBatch: function (f, e) {
            f.each(function (b) {
                b.imageInfo = e, b.build()
            }), this.processBuildQueue()
        },
        useEvent: function (b) {
            return {
                click: "click",
                mouseover: "mouseover",
                mouseout: b ? "mouseleave" : "mouseout"
            }
        }(Prototype.Browser.IE),
        capture: function (b) {
            Prototype.Browser.IE || (b = b.wrap(function (f, e) {
                var h = Object.isElement(this) ? this : this.element,
                    g = e.relatedTarget;
                g != h && !$A(h.select("*")).member(g) && f(e)
            }));
            return b
        }
    }), Starboxes.load(), d(function () {
        Starboxes.processBuildQueue()
    });
    var c = Class.create({
        initialize: function (f, e) {
            this.element = $(f), this.average = e, this.options = Object.extend(Object.clone(Starboxes.options), arguments[2] || {}), $w("identity rated max total").each(function (b) {
                this[b] = this.options[b]
            }.bind(this)), this.locked = this.options.locked || this.rated && !this.options.rerate, this.identity || (this.identity = Starboxes.identify(this.element)), this.options.effect && (this.options.effect.mouseover || this.options.effect.mouseout) && Starboxes.require("Scriptaculous"), Starboxes.queueBuild(this), Starboxes.batchLoading && Starboxes.processBuildQueue()
        },
        enable: function () {
            $w("mouseout mouseover click").each(function (f) {
                var e = f.capitalize(),
                    g = this["on" + e].bindAsEventListener(this);
                this["on" + e + "_cached"] = f == "mouseout" && !Prototype.Browser.IE ? Starboxes.capture(g) : g, this.starbar.observe(Starboxes.useEvent[f], this["on" + e + "_cached"])
            }.bind(this)), this.buttons.invoke("setStyle", {
                cursor: "pointer"
            })
        },
        disable: function () {
            $w("mouseover mouseout click").each(function (b) {
                this.starbar.stopObserving(Starboxes.useEvent[b], this["on" + b.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, this.options.effect && (this.zeroPosition = this.getBarPosition(0), this.maxPosition = this.getBarPosition(this.options.max));
            var b = {
                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"
            }, b.base))))), this.rated && this.status.addClassName("rated"), this.locked && this.status.addClassName("locked"), this.options.ghosting && (this.wrapper.insert(this.ghost = (new Element("div", {
                className: "ghost"
            })).setStyle(b.absolute)), this.options.ghostColor && this.ghost.setStyle({
                background: this.options.ghostColor
            }), 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(b.absolute)).insert((new Element("div")).setStyle(b.absolute).insert(this.starbar = (new Element("div")).setStyle(b.base))), this.options.color && this.colorbar.setStyle({
                background: this.options.color
            }), this.options.effect && (this.colorbar.scope = this.colorbar.identify()), this.options.stars.times(function (a) {
                var e;
                this.starbar.insert(e = (new Element("div")).setStyle(Object.extend({
                    background: "url(" + this.starSrc + ") top left no-repeat",
                    left: this.starWidth * a + "px"
                }, b.star))), e.setStyle({
                    left: this.starWidth * a + "px"
                }), Starboxes.fixIE && e.setStyle({
                    background: "none",
                    filter: "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + this.starSrc + "'', sizingMethod='scale')"
                })
            }.bind(this)), this.buttons = [], this.options.buttons.times(function (f) {
                var e, g = this.options.inverse ? this.boxWidth - this.buttonWidth * (f + 1) : this.buttonWidth * f;
                this.starbar.insert(e = (new Element("div")).setStyle({
                    position: "absolute",
                    top: 0,
                    left: g + "px",
                    width: this.buttonWidth + (Prototype.Browser.IE ? 1 : 0) + "px",
                    height: this.starHeight + "px"
                })), e.rating = this.buttonRating * f + this.buttonRating, this.buttons.push(e)
            }.bind(this)), this.setBarPosition(this.colorbar, this.average), this.element.update(this.container), this.inputs = {}, $w("average max rated rerated total").each(function (e) {
                this.element.insert(this.inputs[e] = new Element("input", {
                    type: "hidden",
                    name: this.identity + "_" + e,
                    value: "" + (e == "rerated" ? !! this[e] : this[e])
                }))
            }.bind(this)), this.options.indicator && (this.hover.insert(this.indicator = new Element("div", {
                className: "indicator"
            })), this.updateIndicator()), this.locked || this.enable()
        },
        updateAverage: function (f) {
            this.rated && this.options.rerate && (this.average = (this.total * this.average - this.rated) / (this.total - 1 || 1));
            var e = this.rated ? this.total : this.total++;
            this.average = this.average == 0 ? f : (this.average * (this.rated ? e - 1 : e) + f) / (this.rated ? e : e + 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 (f) {
            var e = this.boxWidth - f / this.buttonRating * this.buttonWidth;
            return parseInt(this.options.inverse ? e.ceil() : -1 * e.floor())
        },
        setBarPosition: function (h, g) {
            this.options.effect && this["activeEffect_" + h.scope] && Effect.Queues.get(h.scope).remove(this["activeEffect_" + h.scope]);
            var l = this.getBarPosition(g);
            if (arguments[2]) {
                var k = parseInt(h.getStyle("left")),
                    j = this.getBarPosition(g);
                if (k == j) {
                    return
                }
                var i = ((this.maxPosition - (k - j).abs()).abs() / this.zeroPosition.abs()).toFixed(2);
                this["activeEffect_" + h.scope] = new Effect.Morph(h, {
                    style: {
                        left: l + "px"
                    },
                    queue: {
                        position: "end",
                        limit: 1,
                        scope: h.scope
                    },
                    duration: this.options.duration * i
                })
            } else {
                h.setStyle({
                    left: l + "px"
                })
            }
        },
        onClick: function (f) {
            var e = f.element();
            if (e.rating) {
                this.updateAverage(e.rating), this.options.indicator && this.updateIndicator(), this.options.ghosting && this.setBarPosition(this.ghost, this.average, window.Effect && Effect.Morph), this.rated || this.status.addClassName("rated"), this.rerated = !! this.rated, this.rated = e.rating, this.options.rerate || (this.disable(), this.status.addClassName("locked"), this.onMouseout(f));
                var g = {};
                $w("average identity max rated rerated total").each(function (b) {
                    b != "identity" && (this.inputs[b].value = this[b]), g[b] = this[b]
                }.bind(this)), this.options.onRate(this.element, g), this.element.fire("starbox:rated", g)
            }
        },
        onMouseout: function (b) {
            this.setBarPosition(this.colorbar, this.average, this.options.effect && this.options.effect.mouseout), this.hovered = !1, this.options.hoverClass && this.hover.removeClassName(this.options.hoverClass), this.options.hoverColor && this.colorbar.setStyle({
                background: this.options.color
            }), this.element.fire("starbox:left")
        },
        onMouseover: function (f) {
            var e = f.element();
            e.rating && (this.setBarPosition(this.colorbar, e.rating, this.options.effect && this.options.effect.mouseover), !this.hovered && this.options.hoverClass && this.hover.addClassName(this.options.hoverClass), this.hovered = !0, this.options.hoverColor && this.colorbar.setStyle({
                background: this.options.hoverColor
            }), this.element.fire("starbox:changed", {
                identify: this.options.identity,
                max: this.options.max,
                rating: e.rating,
                total: this.total
            }))
        }
    });
    window.Starbox = c
})();
