//------------------------------Misc utility---------------------------------------
var StringBuilder = function()
{
    var _buffer = new Array();

    var Constructor = function(text)
    {
        if (text || (typeof(text) == "string"))
        {
            _buffer.push(text);
        }
    }

    this.Append = function(text)
    {
        if (text)
        {
            _buffer.push(text);
        }
    }

    this.Clear = function()
    {
        _buffer.splice(0, _buffer.length);
    }

    this.getSize = function()
    {
        return _buffer.length;
    }

    this.IsEmpty = function()
    {
        return (_buffer.length == 0);
    }

    this.ToString = function()
    {
        return _buffer.join('');
    }

    this.getLength = function()
    {
        return _buffer.length;
    }

    Constructor.apply(this, arguments);
}

//------------------------------Validation-----------------------------------------

var Validator = Class.create();

Validator.prototype = {
    _controlID : null,
    _validatorID : null,
    _disabled : false,
    errorMessage : null,
    summaryMessage : null,

    initialize : function(controlID, validatorID, errorMessage, summaryMessage) {
        this._controlID = controlID;
        this._validatorID = validatorID;
        this.errorMessage = errorMessage;
        this.summaryMessage = summaryMessage;

        var validator = $(validatorID);
        if (validator) {
            validator.innerHTML = errorMessage;
            validator.hide();
        }

        $(this._controlID).observe("change", this._elementChanged.bind(this));
    },

    getIsValid : function() {
        if (!this._validatable()) return true;
        return $F(this._controlID) != "";
    },

    setDisabled : function(value) {
        this._disabled = value;
    },

    validate : function() {
        if (!this._validatable()) return true;

        var valid = false;

        if (!this.getIsValid()) {
            var validator = $(this._validatorID);
            if (validator) {
                validator.innerHTML = this.errorMessage;
                validator.show();
            }
            valid = false;
        } else {
            valid = true;
        }

        if (!valid) {
            if (typeof(Effect) != "undefined") {
                Effect.Pulsate(this._controlID, {duration: 0.5, pulses: 2, from: 0.3});
            }
//            Effect.Shake(this._controlID, 40);
            //            new Effect.Highlight(this._controlID);
        }

        return valid;
    },

    reset : function() {
        $(this._validatorID).hide();
    },

    _validatable : function() {
        var control = $(this._controlID);
        if (control.getAttribute("requiredField")) return control.getAttribute("requiredField") == "true";
        return true;
    },

    _elementChanged : function() {
        if (this.validate()) this.reset();
    }
}

var RegExValidator = Class.create();

RegExValidator.prototype = Object.extend(Object.extend(new Object(), Validator.prototype), {
    _regexp : null,
    _validateEmpty : false,

    setPattern : function(pattern) {
        this._regexp = RegExp(pattern);
    },

    setValidateEmpty : function(value) {
        this._validateEmpty = value;
    },

    getIsValid : function() {
        var value = $F(this._controlID);
        if (value == "" && !this._validateEmpty)return true;
        var matches = this._regexp.exec(value);
        return (matches != null && value == matches[0]);
    }
});

var CompareValidator = Class.create();

CompareValidator.prototype = Object.extend(Object.extend(new Object(), Validator.prototype), {
    _controlToCompare : null,

    setControlToCompare : function(control) {
        this._controlToCompare = control;
    },

    getIsValid : function() {
        return $F(this._controlID) == $F(this._controlToCompare);
    }
});

var ValidationSummary = Class.create();

ValidationSummary.prototype = {
    _validators : null,
    _controlID : null,

    initialize : function(validators, controlID) {
        this._validators = validators;
        this._controlID = controlID;
    },

    validate : function() {
        var result = true;
        this._validators.each(function(validator) {
            if (!validator.validate()) result = false;
        });

        if (!result) {
            $(this._controlID).innerHTML = this._generateSummary();
            $(this._controlID).show();
        } else {
            $(this._controlID).hide();
        }

        return result;
    },

    reset : function() {
        this._validators.reset(function(validator) {
            validator.reset();
        });
        $(this._controlID).hide();
    },

    _generateSummary : function() {
        var result = "<ul>";
        this._validators.each(function(validator) {
            if (!validator.getIsValid()) {
                var li = "<li>";
                li += validator.summaryMessage;
                li += "</li>";
                result += li;
            }
        });
        result += "</ul>";

        return result;
    }
}

//---------------------------------------------Popup----------------------------------------------

var Popup = Class.create();

Popup.prototype = {
    _elementID : null,
    _parentID : null,
    _width : null,

    initialize : function(elementID, parentID, width) {
        this._elementID = elementID;
        this._parentID = parentID;
        this._width = width;

        var element = $(elementID);
        var parent = $(parentID);                
        
        //For IE use focusout event to hide popup
        if (navigator.appName == 'Microsoft Internet Explorer') {
            element.observe("focusout", this.hide.bind(this));
        } else { //For Firefox and Opera observe parent clicks
            parent.observe("click", this.hide.bind(this), true);
        }

        element.addClassName("validationSummary");
        var popupStyle = {
            width: this._width,
        //                    height : "200px",
            textAlign : "left",
            zIndex : 1001
        };
        $(elementID).setStyle(popupStyle);
        $(elementID).hide();
    },

    show : function() {
        var element = $(this._elementID);
        var parent = $(this._parentID);

        var elementSize = element.getDimensions();
        var parentSize = parent.getDimensions();

        var elementLeft = parent.offsetLeft - elementSize.width / 2 + parentSize.width / 2;
        var elementTop = parent.offsetTop - elementSize.height / 2 + parentSize.height / 2;
        var h = elementSize.height
        Position.absolutize(element);
        element.setStyle({
            width: this._width,
            height : h + "px",
            left: elementLeft + "px",
            top: elementTop + "px"
        }
                );
        element.show();
        element.focus();
    },

    hide : function() {
        var element = $(this._elementID);
        element.hide();
        Position.relativize(element);
    }
}

//----------------Event routines---------------------
var EventManager = Class.create();

EventManager.prototype = {
    _events : null,

    initialize : function(target, eventNames) {
        this._events = new Hash();
        eventNames.each(function(name) {
            this._events[name] = new Array();
        }.bind(this));
        target.attachEvent = this.attachEvent.bind(this);
        target.raiseEvent = this.raiseEvent.bind(this);
    },

    attachEvent : function(eventName, eventHandler) {
        var handlers = this._events[eventName];
        if (handlers != null) {
            handlers.push(eventHandler);
        }
    },

    raiseEvent : function(eventName, args) {
        var handlers = this._events[eventName];
        handlers._each(function(handler) {
            handler.apply(null, args);
        });
    }
}

//------------Misc functions-------------------------
function AlertFeatureNotImplemented()
{
    alert('We are sorry but this feature is not implemented yet!');
}