/*
 * Star rating object.  Requires jquery.
 * Copyright (c) 2008 by Paste Media Group.  All rights reserved.
 * Written by Philip Garrett.
**
Usage:
    var star = new StarRating({ id:yourID, rating:startingRating });
    star.onRatingDisplay = function(rating) { ... };    // user is picking a rating
    star.onRatingChange = function(rating) { ... };     // user picked a rating
**
*/

function StarRating(initializer) {
    // disambiguate 'this' from event callees
    var self = jQuery.extend(
        this,
        {
            rating: null,
            disabled: 0,
            disabledTitle: "",

            // callbacks
            onRatingDisplay: function(rating) {},
            onRatingChange:  function(rating) {},
            onHover:         function(rating) {},
            onLeave:         function(rating) {}
        },
        initializer
    );

    self.initialize = function() {
        self.selector = "#" + self.id;

        self.bg_id = self.id + "_bg";
        self.bg_selector = "#" + self.bg_id;

        self.fg_id = self.id + "_fg";
        self.fg_selector = "#" + self.fg_id;

        $(self.selector).html(
            '<div id="' + self.bg_id + '" ' +
                ((self.disabled && self.disabledTitle) ? ('title="' + self.disabledTitle + '"') : '') +
                '>' +
            '<div id="' + self.fg_id + '"></div>' +
            '</div>'
        );

        // precalc
        self.bg_node = $(self.bg_selector);
        self.fg_node = $(self.fg_selector);

        self.bg_node.css({ margin: 0, padding: '0 0 4px 0', width: '85px', height: '20px', background: 'url(/images/ratings/stars.gif) repeat-x', position: 'relative', left: '10px', top: '-5px', zIndex: 21, cursor: 'pointer' });
        self.fg_node.css({ margin: 0, padding: 0, width: '0', height: '20px', background: 'url(/images/ratings/stars.gif) left 25px', zIndex: 22 });

        // initial draw
        self.refresh();

        // set up event handlers
        self.bg_node.hover(
            function() {
                if (!self.disabled) {
                    self.onHover();
                }
            },
            function() {
                if (!self.disabled) {
                    self.onLeave();
                }
                self.refresh();
            }
        );

        self.bg_node.click(function(e) {
            if (!self.disabled) {
                self.setRating(self.getPosition(e).rating);
            }
        });

        self.bg_node.mousemove(function(e) {
            if (!self.disabled) {
                var ofs = self.bg_node.offset();
                var pos = self.getPosition(e);
                self.setMeter(pos.percent);
                self.onRatingDisplay(pos.rating);
            }
        });
    }

    // a rating was clicked
    self.setRating = function(newRating) {
        self.rating = newRating;
        self.onRatingDisplay(newRating);
        self.onRatingChange(newRating);
    };

    self.getPosition = function(event) {
        var ofs = self.bg_node.offset(),
            xofs = event.pageX - ofs.left;

        xofs = xofs < 0  ? 0
             : xofs > 84 ? 84
             : xofs;

        // this is percentage of stars filled, not actual rating (yet)
        var pct = Math.round(xofs * 100/85);
        pct = pct < 0   ? 0
            : pct > 100 ? 100
            : pct;

        var rating = self.percentToRating(pct);
        var label  = self.translateRating(rating);

        //$("#debug").html(label);

        return { x:xofs, percent:pct, rating:rating, label:label };
    };

    self.percentToRating = function(pct) {
        var pct_ofs, rofs, rrange;
        // which star?
        if      (pct < 20) { pct_ofs =  0; rofs = 0;  rrange =   25-0; } // (0-19,0-25)
        else if (pct < 40) { pct_ofs = 20; rofs = 26; rrange =  49-26; } // (20-39,26-49)
        else if (pct < 60) { pct_ofs = 40; rofs = 50; rrange =  74-50; } // (40-59,50-74)
        else if (pct < 80) { pct_ofs = 60; rofs = 75; rrange =  90-75; } // (60-79,75-90)
        else               { pct_ofs = 80; rofs = 91; rrange = 100-91; } // (80-99,91-100)
        
        // treat the rating as a percentage of the rating range and add it to
        // the base rating for this range
        var scalepct = (pct - pct_ofs) * 5;
        return Math.round(rofs + (rrange * (scalepct/100)));
    };

    self.ratingToPercent = function(rating) {
        // reversed algortihm in percentToRating
        var pct_ofs, rofs, rrange;
        if      (rating < 26) { pct_ofs =  0; rofs = 0;  rrange =   25-0; } // (0-19,0-25)
        else if (rating < 50) { pct_ofs = 20; rofs = 26; rrange =  49-26; } // (20-39,26-49)
        else if (rating < 75) { pct_ofs = 40; rofs = 50; rrange =  74-50; } // (40-59,50-74)
        else if (rating < 91) { pct_ofs = 60; rofs = 75; rrange =  90-75; } // (60-79,75-90)
        else                  { pct_ofs = 80; rofs = 91; rrange = 100-91; } // (80-99,91-100)
        return Math.round(100*(rating - rofs)/rrange/5 + pct_ofs);
    };

    self.translateRating = function(rating) {
        return rating < 26 ? 'Regrettable' :
               rating < 50 ? 'Forgettable' :
               rating < 75 ? 'Respectable' :
               rating < 91 ? 'Commendable' :
                             'Phenomenal';
    };

    self.setMeter = function(pct) {
        var w = Math.round(84*(pct/100));
        self.fg_node.css({width: w+"px"});
    };

    self.refresh = function() {
        if (self.rating)
            self.setMeter(self.ratingToPercent(self.rating));
        else
            self.setMeter(0);
        self.onRatingDisplay(self.rating);
    };

    self.initialize();

    return self;
}

