/* Copyright 2009 Open Hospitality, Inc.  All rights reserved. */
(function() {
    var initializing = false, fnTest = /xyz/.test(function() { xyz; }) ? /\b_super\b/ : /.*/;
    
    this.Class = function() { };
    
    Class.extend = function(prop) {
        var _super = this.prototype;       
        initializing = true;
        var prototype = new this();
        initializing = false;
        
        for (var name in prop) {
            prototype[name] = typeof prop[name] == "function" && typeof _super[name] == "function" && fnTest.test(prop[name]) ?
            (function(name, fn) {
                return function() {
                    var tmp = this._super;
                    this._super = _super[name];
                    var ret = fn.apply(this, arguments);
                    this._super = tmp;
                    return ret;
                };
            })(name, prop[name]) : prop[name];
        }

        function Class() { if (!initializing && this.init) { this.init.apply(this, arguments); } }
        Class.prototype = prototype;
        Class.constructor = Class;
        Class.extend = arguments.callee;

        return Class;
    };
})();

/**
* This is the base class for ajax forms which reveal themselves upon clicking (or focusing, if text input) on a trigger.
* @param string wrapper(ex. '#someid') - Wraps the form
* @param string trigger(ex. '#sometrigger') - Triggers the form display
* @var body(jquery Obj) - The document's body element
* @var wrapper(jquery Obj) - The designated form wrapper
* @var error(jquery Obj) - Error message div
* @var success(jquery Obj) - Success message div(must be id of '#' + wrapperid + 'success').  This allows you to put the success message outside of the wrapper
* @var loader(jquery Obj) - Loading gif(must be class of '.ssloader')
* @var form(jquery Obj) - The form element (.ssform)
* @var close(jquery Obj) - Link to close the form (.ssclose)
* @var required(jquery Obj) - Fields that are required (.ssrequired)
* @var optional(jquery Obj) - Fields that are optional
* @var emails(jquery Obj) - Fields that are emails; will be validated (.ssemail)
* @var inputs(jquery Obj) - All inputs
* @var textInputs(jquery Obj) - All text inputs
* @var trig(jquery Obj) - Element that triggers the form
* @var string msg - Error or success message
* @var bool display - Tells whether form is currently displayed/expanded
* @var array initialVals - Stores the inital values of the text fields
*/

var specialsignup = Class.extend({
    init: function(wrapper, trigger, position, transition, valhelper) {
        this.wrapper = $(wrapper);
        this.trig = $(trigger);
        this.position = position || 'top';
        this.transition = transition || 'slide';
        this.valhelper = valhelper;

        this.body = $('body');
        this.error = $(wrapper + ' .sserror');
        this.success = $('#' + this.wrapper.attr('id') + 'success');
        this.loader = $(wrapper + ' .ssloader');
        this.form = $(wrapper + ' .ssform');
        this.close = $(wrapper + ' .ssclose');
        this.required = $(wrapper + ' .ssrequired');
        this.optional = $(wrapper + ' :input:not(:hidden)').not(':submit').not('.ssrequired');
        this.emails = $(wrapper + ' .ssemail');
        this.inputs = this.form.find(':input');
        this.textInputs = this.form.find(':text');
        this.msg = '';
        this.display = 0;
        this.focuselement = $(wrapper + ' .ssfocus');
        this.errorFields = new Array();
        this.closeTimer = null;
        this.initialVals = [];
        this.activateTrigger();
        this.activateClose();
        this.activateSubmit();
        this.bindResize();
        this.bindScroll();
        if (this.valhelper == true) {
            this.getInitialValues();
            this.activateInputs();
        }
    },

    showLoader: function() { this.loader.show(); },

    hideLoader: function() { this.loader.hide(); },

    parseMessage: function(msg) { return msg.replace(/_/g, ' '); },

    updateDisplayStatus: function() {
        if (this.display == 0) { this.display = 1; }
        else { this.display = 0; }
    },

    getInitialValue: function(obj) { return this.initialVals[obj.attr('id')]; },

    getInitialValues: function() {
        var me = this;
        $.each(me.textInputs, function() { me.initialVals[$(this).attr('id')] = $(this).val(); });
    },

    resetInitialValue: function(obj) {
        var iv = this.getInitialValue(obj);
        obj.val(iv);
    },

    clearValue: function(obj) { obj.val(''); },

    checkInitialValue: function(obj) {
        var iv = this.getInitialValue(obj);
        if (obj.val() == iv) { this.clearValue(obj); }
        else if (obj.val() === '') { this.resetInitialValue(obj); }
    },

    setBlur: function(obj) {
        var me = this;
        obj.bind('blur', function() { me.checkInitialValue($(this)); });
    },

    setFocus: function(obj) {
        var me = this;
        obj.bind('focus', function() { me.checkInitialValue($(this)); });
    },

    bindScroll: function() {
        var me = this;
        $(window).bind('scroll', function() {
            if (me.display == 1) {
                clearTimeout(me.scrollTimer);
                var closure = function() { me.repositionElements(); }
                me.scrollTimer = setTimeout(closure, 200);
            }
        });
    },

    bindResize: function() {
        var me = this;
        $(window).bind('resize', function() { if (me.display == 1) { me.repositionElements(); } });
    },

    activateInputs: function() {
        var me = this;
        $.each(me.textInputs, function() {
            if ($(this).attr('id') != me.trig.attr('id')) {
                me.setFocus($(this));
                me.setBlur($(this));
            }
        });
    },

    activateTrigger: function() {
        var me = this;
        var bind = 'click';
        if (this.trig.is("INPUT")) {
            bind = 'focus';
            me.setBlur(me.trig);
        }
        this.trig.bind(bind, function() {
            if (bind == 'focus' && me.valhelper == true) { me.checkInitialValue($(this)); }
            if (me.display == 0) { me.displayForm(); }
            return false;
        });
    },

    activateSubmit: function() {
        var me = this;
        this.form.submit(function() {
            me.clearMessages();
            if (!me.validateFields()) { return false; }
            me.clearOptionalFields();
            me.showLoader();

            $.ajax({
                type: "POST",
                url: $(this).attr('action'),
                data: me.inputs.serialize(),
                success: function(ret) {
                    me.hideLoader();
                    me.resetOptionalFields();
                    if (me.isErrorResponse(ret)) {
                        me.msg = 'Your submission was not successful.  Please try again.';
                        me.displayErrorMessage();
                    }
                    else {
                        me.displaySuccessMessage();
                        me.resetAllFields();
                    }
                },
                error: function(XMLHttpRequest, textStatus, errorThrown) {
                    me.hideLoader();
                    me.msg = 'This request did not work ' + textStatus + errorThrown;
                    me.displayErrorMessage();
                }
            });

            return false;
        });
    },

    isErrorResponse: function(r) {
        var re = new RegExp("<!--ERROR-->");
        return re.exec(r);
    },

    activateClose: function() {
        var me = this;
        this.close.bind('click', function() {
            if (me.closeTimer != null) { clearTimeout(me.closeTimer); }
            me.closeForm();
        });
    },

    clearMessages: function() {
        this.msg = '';
        this.success.hide();
        this.loader.hide();
        this.error.empty();
        this.error.hide();
        this.removeErrorHighlights();
    },

    clearOptionalFields: function() {
        var me = this;
        $.each(this.optional, function() { if ($(this).val() == me.getInitialValue($(this))) { me.clearValue($(this)); } });
    },

    resetOptionalFields: function() {
        var me = this;
        $.each(this.optional, function() { if ($(this).val() == '') { me.resetInitialValue($(this)); } });
    },

    resetAllFields: function() {
        var me = this;
        $.each(this.textInputs, function() { me.resetInitialValue($(this)); });
    },

    //clearAllFields: function() {
    //var me = this;
    //$.each(this.textInputs, function() { me.clearValue($(this)); });
    //},

    validateEmail: function(email) {
        var myregex = new RegExp('^[_a-zA-Z0-9-]+(\.[_a-zA-Z0-9-]+)*@[a-zA-Z0-9-]+(\.[a-zA-Z0-9-]+)*\.(([0-9]{1,3})|([a-zA-Z]{2,3})|(aero|coop|info|museum|name))$');
        var result = email.match(myregex);
        if (result && result[0] == email) { return true; }
        else { return false; }
    },

    verifyEmail: function(obj) {
        var verifier = $("#verify_" + obj.attr('name'));
        if (verifier.id != undefined) {
            if (obj.val() == verifier.val()) { return true; }
            else { return false; }
        }
        return true;
    },

    validateFields: function() {
        var me = this;
        var error = false;
        $.each(this.required, function() {
            var iv = me.getInitialValue($(this));
            var trimval = $.trim($(this).val());
            if (trimval == '') {
                me.errorFields.push($(this));
                error = true;
            }
            else if ($(this).val() == iv && iv !== '') {
                me.errorFields.push($(this));
                error = true;
            }
        });
        if (error == true) { me.msg += "Please fill in the highlighted fields.<br />"; }
        $.each(this.emails, function() {
            if (!me.validateEmail($(this).val())) {
                me.msg += "Your email is invalid.<br />";
                me.errorFields.push($(this));
                error = true;
            }
            if (!me.verifyEmail($(this))) {
                me.msg += "Your emails do not match.";
                me.errorFields.push($(this));
                me.errorFields.push($("#verify_" + $(this).attr('name')));
                error = true;
            }

        });
        if (error) {
            me.displayErrorMessage();
            return false;
        }
        else { return true; }
    },

    displaySuccessMessage: function() {
        var me = this;
        this.success.show();
    },

    displayErrorMessage: function() {
        var msg = this.parseMessage(this.msg);
        this.error.append(msg);
        this.highlightErrorFields();
        this.error.show();
        this.repositionElements();
    },

    highlightErrorFields: function() {
        $.each(this.errorFields, function() { $(this).addClass("inputerror"); });
    },

    removeErrorHighlights: function() {
        $.each(this.errorFields, function() {
            $(this).removeClass("inputerror");
        });
        this.errorFields = new Array();
    },

    toggleForm: function() {
        switch (this.transition) {
            case 'slide':
                this.wrapper.animate({ height: 'toggle', opacity: 'toggle' }, 500, 'swing');
                break;
            case 'fade':
                this.wrapper.animate({ opacity: 'toggle' }, 150, 'swing');
                break;
            default:
                break;
        }
        this.updateDisplayStatus();
    },

    displayForm: function() {
        var me = this;        
        if (this.display == 0) {
            this.clearMessages();
            this.repositionElements();
            this.toggleForm();
            var closure = function() { me.focuselement.focus(); }
            setTimeout(closure, 500);
        }
    },

    closeForm: function() {
        var me = this;
        if (this.display == 1) {
            this.toggleForm();
            this.trig.unbind();
            this.clearMessages();
            this.activateTrigger();
            var closure = function() { me.form.show(); }
            setTimeout(closure, 500);
        }
    },

    addOpaqueLayerDiv: function() {
        this.body.append("<div id='opaquelayer'></div>");        
        this.ol = $('#opaquelayer');
        this.ol.css({
            minWidth: '100%',
            minHeight: '100%',
            height: '100%',
            opacity: '0.5',
            backgroundColor: '#000000',
            zIndex: '100',
            position: 'absolute',
            top: '0',
            left: '0',
            margin: '0',
            padding: '0',
            display: 'none'
        });
    },

    toggleOpaqueLayer: function() {
        this.ol.animate({ opacity: 'toggle' }, 50, 'linear');
    },

    repositionElements: function() {
        this.findWinHeight();
        this.findDocHeight();
        this.findWrapHeight();
        //this.findScrollTop();
        this.findDistFromTop();
        this.repositionOpaqueLayer();
        this.repositionWrapper();
    },

    findWinHeight: function() { this.winHeight = $(window).height(); },

    findDocHeight: function() { this.docHeight = $(document).height(); },

    //findScrollTop: function() { this.scrollTop = $(window).scrollTop(); },

    findWrapHeight: function() { this.wrapHeight = this.wrapper.height(); },

    repositionOpaqueLayer: function() {
        var h = this.docHeight;
        this.ol.css('height', h + 'px');
    },

    repositionWrapper: function() {        
        if (this.position == 'center') {
            this.wrapper.css({
                position: 'relative' //,
                //margin: this.fromTop + 'px auto 0 auto'
            });
        }
    },

    findDistFromTop: function() {
        var dist = 0;
        if (this.winHeight > this.wrapHeight && this.position != 'top') {
            var diff = this.winHeight - this.wrapHeight;
            dist = Math.floor((diff - 5) / 2);
        }
        this.fromTop = dist + this.scrollTop;
    }
});


var LightboxSignup = specialsignup.extend({
    init: function(wrapper, trigger, position, transition, valhelper) { //location is center or top,transition is slide or fade in/out
        this._super(wrapper, trigger, position, transition, valhelper);
        this.addExtraWrapper();
        this.addOpaqueLayerDiv();
        this.applyCss();		
    },

    addExtraWrapper: function() {
        this.wrapper.wrap("<div id='" + this.wrapper.attr('id') + "extrawrapper'></div>");
        this.extrawrapper = $("#" + this.wrapper.attr('id') + "extrawrapper");
        this.success.wrap("<div id='" + this.success.attr('id') + "extrawrapper'></div>");
        this.successwrapper = $("#" + this.success.attr('id') + "extrawrapper");
    },

    applyCss: function() {
        switch (this.position) {
            case 'center':
                this.wrapper.css({
                    position: 'relative'//,
                    //margin: this.fromTop + 'px auto'
                });
                this.success.css({
                    margin: 'auto'
                });
                break;
            case 'top':
                this.wrapper.css({
                    position: 'relative',
                    margin: '0px auto'
                });
                break;
        }
        this.extrawrapper.css({
            position: 'absolute',
            top: '0',
            left: '0',
            width: '100%',
            zIndex: '1000'
        });
    },

    displayForm: function() {
        if (this.display == 0) {
            this._super();
            this.toggleOpaqueLayer();
        }
    },

    closeForm: function() {
        if (this.display == 1) {
            this._super();
            this.toggleOpaqueLayer();
        }
    },

    displaySuccessMessage: function() {
        var me = this;
        var msg = this.parseMessage(this.msg);
        this.success.append(msg);
        this.form.hide();
        this.success.show();
        var closure = function() { me.closeForm(); }
        this.closeTimer = setTimeout(closure, 3000);
    }
});


var DropdownSignup = specialsignup.extend({
    init: function(wrapper, trigger, position, transition, valhelper) {
        this._super(wrapper, trigger, position, transition, valhelper);
        this.additional = $(wrapper + ' .ssadditional');
        this.additional.hide();
        this.addOpaqueLayerDiv();
    },
    toggleForm: function() {
        this.additional.animate({ height: 'toggle', opacity: 'toggle' }, 500, 'swing');
        if (this.close.css('display') == 'none') { this.close.css('display', 'block'); }
        else { this.close.css('display', 'none'); }
        this.updateDisplayStatus();
    }
});