/**
 * @author Ryan Johnson <http://saucytiger.com/>
 * @copyright 2008 PersonalGrid Corporation <http://personalgrid.com/>
 * @package LivePipe UI
 * @license MIT
 * @url http://livepipe.net/control/rating
 * @require prototype.js, livepipe.js
 */

if(typeof(Prototype) == "undefined")
	throw "Control.Rating requires Prototype to be loaded.";
if(typeof(Object.Event) == "undefined")
	throw "Control.Rating requires Object.Event to be loaded.";

Control.Rating = Class.create({
    initialize: function (container, options) {
        Control.Rating.instances.push(this);
        this.value = false;
        this.links = [];
        this.container = $(container);
        this.container.update('');
        this.options = {
            min: 1,
            max: 5,
            rated: false,
            input: false,
            reverse: false,
            capture: true,
            multiple: false,
            classNames: {
                off: 'rating_off',
                half: 'rating_half',
                on: 'rating_on',
                selected: 'rating_selected'
            },
            updateUrl: false,
            updateParameterName: 'value',
            afterChange: Prototype.emptyFunction
        };
        Object.extend(this.options, options || {});
        if (this.options.value) {
            this.value = this.options.value;
            delete this.options.value;
        }
        if (this.options.input) {
            this.options.input = $(this.options.input);
            this.options.input.observe('change', function (input) {
                this.setValueFromInput(input);
            } .bind(this, this.options.input));
            this.setValueFromInput(this.options.input, true);
        }
        var range = $R(this.options.min, this.options.max);
        (this.options.reverse ? $A(range).reverse() : range).each(function (i) {
            var link = this.buildLink(i);
            this.container.appendChild(link);
            this.links.push(link);
        } .bind(this));
        this.setValue(this.value || this.options.min - 1, false, true);
    },
    buildLink: function (rating) {
        var link = $(document.createElement('a'));
        link.value = rating;
        if (this.options.multiple || (!this.options.rated && !this.options.multiple)) {
            link.href = '';
            link.onmouseover = this.mouseOver.bind(this, link);
            link.onmouseout = this.mouseOut.bind(this, link);
            link.onclick = this.click.bindAsEventListener(this, link);
        } else {
            link.style.cursor = 'default';
            link.observe('click', function (event) {
                Event.stop(event);
                return false;
            } .bindAsEventListener(this));
        }
        link.addClassName(this.options.classNames.off);
        return link;
    },
    disable: function () {
        this.links.each(function (link) {
            link.onmouseover = Prototype.emptyFunction;
            link.onmouseout = Prototype.emptyFunction;
            link.onclick = Prototype.emptyFunction;
            link.observe('click', function (event) {
                Event.stop(event);
                return false;
            } .bindAsEventListener(this));
            link.style.cursor = 'default';
        } .bind(this));
    },
    setValueFromInput: function (input, prevent_callbacks) {
        this.setValue((input.options ? input.options[input.options.selectedIndex].value : input.value), true, prevent_callbacks);
    },
    setValue: function (value, force_selected, prevent_callbacks) {
        this.value = value;
        if (this.options.input) {
            if (this.options.input.options) {
                $A(this.options.input.options).each(function (option, i) {
                    if (option.value == this.value) {
                        this.options.input.options.selectedIndex = i;
                        throw $break;
                    }
                } .bind(this));
            } else
                this.options.input.value = this.value;
        }
        this.render(this.value, force_selected);
        if (!prevent_callbacks) {
            if (this.options.updateUrl) {
                var params = {};
                params[this.options.updateParameterName] = this.value;
                new Ajax.Request(this.options.updateUrl, {
                    parameters: params
                });
            }
            this.notify('afterChange', this.value);
        }
    },
    render: function (rating, force_selected) {
        (this.options.reverse ? this.links.reverse() : this.links).each(function (link, i) {
            if (rating >= link.value-0.75 && rating < link.value-0.25) {
                link.className = this.options.classNames['half'];
                if (this.options.rated || force_selected)
                    link.addClassName(this.options.classNames.selected);
            } else if (rating >= link.value - 0.25) {
                link.className = this.options.classNames['on'];
                if (this.options.rated || force_selected)
                    link.addClassName(this.options.classNames.selected);
            } else
                link.className = this.options.classNames.off;
        } .bind(this));
    },
    mouseOver: function (link) {
        this.render(link.value, true);
    },
    mouseOut: function (link) {
        this.render(this.value);
    },
    click: function (event, link) {
        this.options.rated = true;
        this.setValue((link.value ? link.value : link), true);
        if (!this.options.multiple)
            this.disable();
        if (this.options.capture) {
            Event.stop(event);
            return false;
        }
    }
});
Object.extend(Control.Rating,{
	instances: [],
	findByElementId: function(id){
		return Control.Rating.instances.find(function(instance){
			return (instance.container.id && instance.container.id == id);
		});
	}
});
Object.Event.extend(Control.Rating);