/*---------------------------------------------------------------------------
 * File:        $RCSfile: pup_extensions.js,v $
 * Revision:    $Revision: 1.10 $
 * Author:      $Author: aelliott $
 * Date:        $Date: 2010-04-09 16:10:17 $
 *------------------------------------------------------------------------ */

Object.extend(Function.prototype, {
    iteratorize: function () {
        var __method = this, args = $A(arguments);

        return function () {
            var __args = $A(arguments);
            var e = __args.shift();
            __args = args.concat(__args);

            return __method.apply(this, [e].concat(__args));
        };
    }
});

Element.addMethods({
    setVisible: function (element, visibility) {
        return ((visibility) ? Element.show : Element.hide)(element);
    },

    twiddleClassName: function (element, className, present) {
        return ((present) ? Element.addClassName : Element.removeClassName)(
            element, className);
    },

    showErrorBalloon: function (element) {
        element = $(element);
        if (element.errors && element.errors.length > 0) {
            Tip(element._formatErrors(),
                BALLOON, true,
                ABOVE, true,
                FIX, [element, 20, -3],
                WIDTH, -300,
                DELAY, 200,
                DURATION, -1,
                FADEIN, 100,
                FADEOUT, 100,
                STICKY, true,
                FOLLOWMOUSE, false,
                BALLOONSTEMOFFSET, -10000);
        }

        return element;
    },

    hideErrorBalloon: function (element) {
        UnTip();

        return $(element);
    },

    _formatErrors: function (element) {
        element = $(element);

        if (element.errors.length == 0) {
            return null;
        }

        if (element.errors.length == 1) {
            return element.errors[0];
        }

        return "<ul>" + $A(element.errors).inject("", function (s, error) {
            return s + "<li>" + error + "</li>";
        }) + "</ul>";
    }
});

Element.addMethods("form", {
    submitWithEvents: function (element) {
        element = $(element);

        // There's a bug with event dispatching in Safari
        if (Prototype.Browser.WebKit) {
            element.submit();
            return element;
        }

        var event;
        if (document.createEvent) {
            event = document.createEvent("HTMLEvents");
            event.initEvent("submit", true, true);
        } else {
            event = document.createEventObject();
            event.eventType = "onsubmit";
        }

        if (document.createEvent) {
            element.dispatchEvent(event);
        } else {
            if (element.fireEvent(event.eventType, event)) {
                element.submit();
            }
        }

        return element;
    },

    getValue: function (element, control) {
        element = $(element);
        control = $(element[control]);

        if (!control) {
            return null;
        }

        if (!control.length) {
            return $F(control);
        }

        var values = $A(control).collect(
            function (e) {return e.checked ? e.value : null;})
            .compact();

        return values.length > 1 ? values : values[0];
    },

    setValue: function (element, control, value) {
        element = $(element);
        control = $(element[control]);

        if (!control) {
            return element;
        }

        if (!control.length) {
            control.value = value;
            return element;
        }

        if (!Object.isArray(value)) {
            value = $A([value]);
        }

        $A(control).each(function (e) {
            e.checked = value.member(e.value);
        });

        return element;
    },

    prepErrors: function (form) {
        $(form).getElements().each(function (el) {
            el.observe("focus", el.showErrorBalloon.bindAsEventListener(el));
            el.observe("blur", el.hideErrorBalloon.bindAsEventListener(el));
        });

        return $(form);
    },

    setErrors: function (form, errors) {
        form = $(form);
        form.setGlobalErrors(errors.globalErrors);
        var fieldError = form.setFieldErrors(errors.fieldErrors);

        if (!fieldError && form.errors) {
            form.showErrorBalloon();
        } else if (fieldError) {
            if (fieldError.type == "file") {
                fieldError.showErrorBalloon();
            } else {
                fieldError.activate();
            }
        }

        return form;
    },

    setGlobalErrors: function (form, globalErrors) {
        form = $(form);
        form.errors = globalErrors;
        return form;
    },

    setFieldErrors: function (form, fieldErrors) {
        if (!fieldErrors) {
            return null;
        }

        var firstError = null;

        $(form).getElements().each(function (el) {
            var errors = fieldErrors[el.name];
            if (errors) {
                if (!firstError) {
                    firstError = el;
                }
                el.addClassName("error");
                el.errors = errors;
            } else {
                el.removeClassName("error");
                el.errors = null;
            }
        });

        return firstError;
    }
});

Element.addMethods("input", {
    booleanValue: function (element) {
        element = $(element);
        return "true" == element.value;
    }
});

Element.addMethods("button", {
    disable: function (element) {
        element = $(element);
        element.disabled = true;
        return element;
    },

    enable: function (element) {
        element = $(element);
        element.disabled = false;
        return element;
    }
});

Element.addMethods("a", {
    disable: function (element, message) {
        element = $(element);
        element.enable();
        element.addClassName("disabled");
        element._disableFunc = function (e) {Event.stop(e);};
        element.observe("click", element._disableFunc);
        if (message) {
            element._title = element.title;
            element.title = message;
        }

        return element;
    },

    enable: function (element) {
        element = $(element);
        element.removeClassName("disabled");
        if (element._disableFunc) {
            element.stopObserving("click", element._disableFunc);
            element._disableFunc = null;
        }
        if (element._title) {
            element.title = element._title;
        }

        return element;
    }
});

Ajax.Response = Class.create(Ajax.Response, {
    _getResponseJSON: function($super) {
        var json = $super();

        if (json && json._error) {
            this.errorJSON = json._error;
        }

        return json;
    }
});

var PupAjax = {};

PupAjax.JSONRequest = Class.create(Ajax.Request, {
    initialize: function ($super, url, options) {
        var onSuccess = options.onSuccess || Prototype.emptyFunction;
        var onError = options.onError || Prototype.emptyFunction;

        options.onSuccess = function (response) {
            if (Object.isUndefined(response.errorJSON)) {
                onSuccess(response.responseJSON);
            } else {
                onError(response.errorJSON);
            }
        };

        options.sanitizeJSON = true;

        $super(url, options);
    }
});

PupAjax.Errors = Class.create({
    initialize: function (errors) {
        this.fieldErrors = errors.fieldErrors || {};
        this.globalErrors = $A(errors.globalErrors);
    },

    hasFieldErrors: function () {
        return $H(this.fieldErrors).keys().any();
    },

    hasGlobalErrors: function () {
        return this.globalErrors.any();
    },

    hasErrors: function () {
        return this.hasFieldErrors() || this.hasGlobalErrors();
    }
});

PupAjax.AnchorMonitor = Class.create({
    initialize: function (target, url, options) {
        this.oldAnchor = this.trimAnchor(window.location.hash);

        this.target = target;
        this.url = url;

        var options = Object.extend({
            period: 0.3,
            onUpdateText: function () {return true;}
        }, options);

        this.translations =
            (options.translations) ? $H(options.translations) : null;
        this.period = options.period;
        this.onAjaxLoading = options.onAjaxLoading;
        this.onAjaxComplete = options.onAjaxComplete;

        this.onChange = options.onChange;
        this.onUpdateText = options.onUpdateText;
        this.passThroughQueryParams = options.passThroughQueryParams;

        this.skipNextChangingEvent = false;
    },

    onLoading: function () {
        if (!this.onAjaxLoading) {
            return;
        }

        this.loadingComplete = false;

        this.onAjaxLoading(
            function () {this.loadingComplete = true;}.bind(this));
    },

    doUpdate: function (response) {
        if (!this.onUpdateText(response.responseText)) {
            return;
        }

        this.target.update(response.responseText);
        if (this.onAjaxComplete) {
            this.onAjaxComplete();
        }

        document.fire.bind(document, "fragment:loaded").defer();
        document.fire.bind(document, "fragment:changed").defer();
    },

    onSuccess: function (response) {
        while (!this.loadingComplete) {
            this.onSuccess.bind(this, response).delay(0.1);
            return;
        }

        this.doUpdate(response);
    },

    executeRequest: function (method) {
        document.stopObserving("fragment:loaded");

        if (this.skipNextChangingEvent) {
            this.skipNextChangingEvent = false;
        } else {
            document.fire("fragment:changing");
        }

        this.loadingComplete = true;

        new Ajax.Request(this.url, {
            method: method,
            evalScripts: true,
            onLoading: this.onLoading.bind(this),
            onSuccess: this.onSuccess.bind(this),
            parameters: this.passThroughParams()
        });
    },

    translateAnchor: function (anchor) {
        if (!this.translations) {
            return anchor;
        }

        return this.translations.get(anchor);
    },

    startMonitoring: function () {
        this.target = $(this.target);

        new PeriodicalExecuter(this.checkAnchor.bind(this), this.period);

        document.fire("fragment:loaded");
    },

    forceInitialChange: function () {
        this.oldAnchor = null;
        this.skipNextChangingEvent = true;
    },

    trimAnchor: function(anchor) {
        if (anchor && anchor.indexOf("#") == 0) {
            anchor = anchor.substring(1);
        }

        return anchor;
    },

    checkAnchor: function () {
        var currentAnchor = this.trimAnchor(window.location.hash);

        if (currentAnchor != this.oldAnchor) {
            this.triggerUpdate(currentAnchor);
            this.oldAnchor = currentAnchor;
        }
    },

    triggerUpdate: function (anchor) {
        var method = this.translateAnchor(anchor);
        if (!method) {
            return;
        }

        if (this.onChange) {
            this.onChange(anchor);
        }

        this.executeRequest(method);
    },

    passThroughParams: function () {
        var query = window.location.search;
        if (!query) {
            return null;
        }

        var params = query.toQueryParams();
        if (this.passThroughQueryParams == null) {
            return params;
        }

        params = $H(params);
        filteredParams = $H();

        params.each(function (kv) {
            if (this.passThroughQueryParams.member(kv.key)) {
                filteredParams.set(kv.key, kv.value);
            }
        }, this);

        return filteredParams;
    }

});

var styleTask = function (el) {
    if (el._styled) {
        return;
    }

    el.insert({top: "<span style='padding-right: 0.5em;'>\u25a0</span>"});
    el._styled = true;
};

var styleAllTasks = function () {
    $$("ul.tasks > li").each(styleTask);
};

document.observe("dom:loaded", styleAllTasks);
document.observe("fragment:changed", styleAllTasks);

