/*
 * JBoss, Home of Professional Open Source
 * Copyright 2013, Red Hat, Inc. and individual contributors
 * by the @authors tag. See the copyright.txt in the distribution for a
 * full listing of individual contributors.
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 */

(function ($, rf) {

    rf.ui = rf.ui || {};

    var defaultOptions = {
        interval: 1000,
        minValue: 0,
        maxValue: 100
    };

    var stateSelectors = {
        initial: '> .rf-pb-init',
        progress: '> .rf-pb-rmng',
        finish: '> .rf-pb-fin'
    };

    // Constructor definition
    rf.ui.ProgressBar = function(componentId, options) {
        // call constructor of parent class
        $super.constructor.call(this, componentId);
        this.__elt = this.attachToDom();
        this.options = $.extend(this.options, defaultOptions, options || {});
        this.enabled = this.options.enabled;
        this.minValue = this.options.minValue;
        this.maxValue = this.options.maxValue;

        this.__setValue(this.options.value || this.options.minValue /* TODO - check with Ilya */);

        if (this.options.resource) {
            this.__poll();
        } else if (this.options.submitFunction) {
            this.submitFunction = new Function("beforeUpdateHandler", "afterUpdateHandler", "params", "event", this.options.submitFunction);
            this.__poll();
        }

        if (this.options.onfinish) {
            rf.Event.bind(this.__elt, "finish", new Function("event", this.options.onfinish));
        }
    };

    // Extend component class and add protected methods from parent class to our container
    rf.BaseComponent.extend(rf.ui.ProgressBar);

    // define super class link
    var $super = rf.ui.ProgressBar.$super;

    $.extend(rf.ui.ProgressBar.prototype, (function() {
        return {
            name: "ProgressBar",

            __isInitialState: function() {
                return parseFloat(this.value) < parseFloat(this.getMinValue());
            },

            __isProgressState: function() {
                return !this.__isInitialState() && !this.__isFinishState();
            },

            __isFinishState: function() {
                return parseFloat(this.value) >= parseFloat(this.getMaxValue());
            },

            __beforeUpdate: function(event) {
                if (event.componentData && typeof event.componentData[this.id] != 'undefined') {
                    this.setValue(event.componentData[this.id]);
                }
            },

            __afterUpdate: function(event) {
                this.__poll();
            },

            __onResourceDataAvailable: function(data) {
                var parsedData = rf.parseJSON(data);
                if (parsedData instanceof Number || typeof parsedData == 'number') {
                    this.setValue(parsedData);
                }

                this.__poll();
            },

            __submit: function() {
                if (this.submitFunction) {
                    this.submitFunction.call(this, $.proxy(this.__beforeUpdate, this), $.proxy(this.__afterUpdate, this),
                        this.__params || {});
                } else {
                    $.get(this.options.resource, this.__params || {}, $.proxy(this.__onResourceDataAvailable, this), 'text');
                }
            },

            __poll: function(immediate) {
                if (this.enabled) {
                    if (immediate) {
                        this.__submit();
                    } else {
                        this.__pollTimer = setTimeout($.proxy(this.__submit, this), this.options.interval);
                    }
                }
            },

            __calculatePercent: function(v) {
                var min = parseFloat(this.getMinValue());
                var max = parseFloat(this.getMaxValue());
                var value = parseFloat(v);
                if (min < value && value < max) {
                    return (100 * (value - min)) / (max - min);
                } else if (value <= min) {
                    return 0;
                } else if (value >= max) {
                    return 100;
                }
            },

            __getPropertyOrObject: function(obj, propName) {
                if ($.isPlainObject(obj) && obj.propName) {
                    return obj.propName;
                }

                return obj;
            },

            getValue: function() {
                return this.value;
            },

            __showState: function (state) {
                var stateElt = $(stateSelectors[state], this.__elt);

                if (stateElt.length == 0 && (state == 'initial' || state == 'finish')) {
                    stateElt = $(stateSelectors['progress'], this.__elt)
                }

                stateElt.show().siblings().hide();
            },

            __setValue: function(val, initialStateSetup) {
                this.value = parseFloat(this.__getPropertyOrObject(val, "value"));

                if (this.__isFinishState() || this.__isInitialState()) {
                    this.disable();
                }
            },

            __updateVisualState: function() {
                if (this.__isInitialState()) {
                    this.__showState("initial");
                } else if (this.__isFinishState()) {
                    this.__showState("finish");
                } else {
                    this.__showState("progress");
                }

                var p = this.__calculatePercent(this.value);
                $(".rf-pb-prgs", this.__elt).css('width', p + "%");
            },

            setValue: function(val) {
                var wasInFinishState = this.__isFinishState();

                this.__setValue(val);
                this.__updateVisualState();

                if (!wasInFinishState && this.__isFinishState()) {
                    rf.Event.callHandler(this.__elt, "finish");
                }
            },

            getMaxValue: function() {
                return this.maxValue;
            },

            getMinValue: function() {
                return this.minValue;
            },

            isAjaxMode: function () {
                return !!this.submitFunction || !!this.options.resource;
            },

            disable: function () {
                this.__params = null;
                if (this.__pollTimer) {
                    clearTimeout(this.__pollTimer);
                    this.__pollTimer = null;
                }

                this.enabled = false;
            },

            enable: function (params) {
                if (this.isEnabled()) {
                    return;
                }

                this.__params = params;
                this.enabled = true;

                if (this.isAjaxMode()) {
                    this.__poll(true);
                }

            },

            isEnabled: function() {
                return this.enabled;
            },

            destroy: function() {
                this.disable();
                this.__elt = null;
                $super.destroy.call(this);
            }
        }
    }()));

})(RichFaces.jQuery, RichFaces);
