var ThirdPartyAuthHandler = Class.create();
ThirdPartyAuthHandler.attributes = ["parent", "requestName"];
ThirdPartyAuthHandler.prototype = {
    initialize: function(parent, requestName, relativeURL) {
        this.parent = parent;
        this.requestName = requestName;
        ajaxEngine.registerRequest(requestName,
                                   this.parent._getBaseURL()+"/"+relativeURL);
        ajaxEngine.registerAjaxObject(requestName, this);
    },
    xmlToHash: function(response) {
        var attrs = response.getElementsByTagName("data")[0].attributes;
        var data = new Object();
        for (var i = 0; i < attrs.length; i++) {
            var value = attrs[i].nodeValue;
            if (value == 'false') {
                value = false;
            }
            data[attrs[i].nodeName] = value;
        }
        return data;
    },
    ajaxUpdate: function(ajaxResponse) {
        var camel = this.requestName.replace(/^[a-z]/,
            function (m) { return m.toUpperCase(); });
        var method = '_handle'+camel+'Response';
        this.parent[method](this.xmlToHash(ajaxResponse));
    }
}

var ThirdPartyAuth = Class.create();
ThirdPartyAuth.attributes = ["_baseURL", "_libURL", "_loginFormDiv", "passthru"];
ThirdPartyAuth.prototype = {
    initialize: function(properties) {
        this._baseURL = ("http://"+properties.stage
                         +"www.care2.com/passport/services/tpa");
        this._libURL = "http://"+properties.stage+"www.care2.com/js";
        this._npoID = properties.npoID;
        this.passthru = locationHandler.passthru;

        new ThirdPartyAuthHandler(this, 'doLogin', 'login.html');
        new ThirdPartyAuthHandler(this, 'renderLoginForm', 'login_form.html');
        new ThirdPartyAuthHandler(this, 'doForgotPassword', 'forgot.html');
        new ThirdPartyAuthHandler(this, 'renderProfileForm', 'edit.html');
        new ThirdPartyAuthHandler(this, 'renderSignUpForm', 'signup.html');
        new ThirdPartyAuthHandler(this, 'autoLogin', 'autologin.html');
    },
    // wrap passthru parameters
    sendRequest: function() {
        var param = [];
        var c = arguments.length;
        for(var i=0;i<c;++i) {
            param.push(arguments[i]);
        }
        param = param.concat(this.passthru.encoded(true));
        ajaxEngine.sendRequest.apply(ajaxEngine, param);

    },
    passthruGet: function(encoded) {
        if(this.passthru.clear(false).length == 0) {
            return '';
        }
        if(encoded) {
            return '&' + this.passthru.encoded(false).join('&');
        } else {
            return '&' + this.passthru.clear(false).join('&');
        }
    },
    checkLogin: function(targetDiv, tpaVariableName, closure) {
        if (!this.getSessionId()) {
            //location = "?do=login&pg="+encodeURIComponent(location);
            this.renderLoginForm(targetDiv, tpaVariableName, { pg: location });
            return false;
        }
        closure();
        return true; // is logged in
    },
    renderLoginForm: function(targetDiv, tpaVariableName, params) {
        if (this.getSessionId()) {
            location = "?";
        }
        this._loginFormDiv = targetDiv;
        this._loginReturnURL = params.pg?params.pg:locationHandler.getURL();
        var signUpUrl = locationHandler.parseLocation().baseURL
            +'?do=sign_up_form'
            +this.passthruGet()
            +'&pg='
            +encodeURIComponent(this._loginReturnURL);

        var onSubmit = tpaVariableName+".submitLoginForm('login_form')";
        var action = "javascript: void("+
            (window.navigator.appName=="Microsoft Internet Explorer"?
             onSubmit:'0')+")";
        // This shouldn't really be coupled to ddb...
        var forgotUrl =
            encodeURI('javascript:'+tpaVariableName
                      +".renderForgotPasswordForm($('ddb_content'), '"
                      +tpaVariableName+"')");
        if(!params.pg) {
            params.pg = this._loginReturnURL;
        }
        this.sendRequest('renderLoginForm',
                               { name: 'pg', value: params.pg },
                               { name: 'signup', value: signUpUrl },
                               { name: 'action', value: action },
                               { name: 'onclick', value: onSubmit },
                               { name: 'forgot', value: forgotUrl },
                               { name: 'npoID', value: this._npoID });
    },
    _handleRenderLoginFormResponse: function(data) {
        this._loginFormDiv.innerHTML = data.html;
        $('login_form').email.focus();
    },
    submitLoginForm: function(formId) {
        var form = $(formId);
        var status = $('login_status');

        // JSUpdate integration...
        var params = Form.getElements(form);
        params.unshift('doLogin');
        this.sendRequest.apply(this, params);

        with (html) replaceNodeChildren(status, span("Logging In... "));
        Form.disable(form);
        return false;
    },
    _handleDoLoginResponse: function(data) {
        if (data.status) {
            with (html) replaceNodeChildren(this._loginFormDiv, p(data.msg));
            this._setSessionId(data.session);
            window.location = this._loginReturnURL+this.passthruGet();
        } else {
            with (html) replaceNodeChildren($('login_status'),
                                            span(data.msg));
            var form = this._loginFormDiv.getElementsByTagName('form')[0];
            Form.enable(form);
        }
    },
    autoLogin: function(email, password, returnURL) {
        this.sendRequest('autoLogin',
                               { name: 'email', value: email },
                               { name: 'password', value: password },
                               { name: 'npoID', value: this._npoID },
                               { name: 'pg', value: returnURL });
    },
    _handleAutoLoginResponse: function(data) {
        this._setSessionId(data.session);
        window.location = data.pg;
    },
    renderForgotPasswordForm: function(targetDiv, tpaVariableName) {
        this._forgotFormDiv = targetDiv;
        var formId = 'forgot_form';
        var onSubmit = tpaVariableName+
            ".submitForgotPasswordForm('"+formId+"')";
        var action = "javascript: void("+
            (window.navigator.appName=="Microsoft Internet Explorer"?
             onSubmit:'0')+")";
        var msg = "Forgot your password?  We'll email it to you.  Just provide"
            +" the email address you used to create your account.";
        var first;
        with (html)
        var loginForm = form({action: action, id: formId, 'class': 'tpa_form'},
                             label({'for': 'email'}, "Email: "), br(),
                             first=input({type: 'text', name: 'email'}), br(),
                             span({id: 'forgot_status'}), br(),
                             input({type: 'hidden', name: 'npoID',
                                           value: this._npoID}),
                             input({type: 'submit', name: 'submit',
                                           onClick: onSubmit,
                                           value: 'Remind Me'}), br());
        with (html)
        replaceNodeChildren(targetDiv, div({ style: 'width: 40em' },
                                           p(msg), loginForm));
        first.focus();
    },
    submitForgotPasswordForm: function(formId) {
        var form = $(formId);
        var status = $('forgot_status');

        var params = Form.getElements(form);
        params.unshift('doForgotPassword');
        this.sendRequest.apply(this, params);

        with (html) replaceNodeChildren(status,
                                        span("Looking up your account..."));
        Form.disable(form);
        return false;
    },
    _handleDoForgotPasswordResponse: function(data) {
        if (data.status) {
            with (html)
            var response = div({ style: 'width: 40em' },
                               p(data.msg), p(a({ href: location }, "Back")));
            replaceNodeChildren(this._loginFormDiv, response);
        } else {
            with (html) replaceNodeChildren($('forgot_status'),
                                            span(data.msg));
            var form = this._loginFormDiv.getElementsByTagName('form')[0];
            Form.enable(form);
        }
    },
    renderProfileForm: function(targetDiv, tpaVariableName, params) {
        var returnURL = params['pg'] || '';
        var errors = params['err'] || '';
        this._profileFormDiv = targetDiv;
        if (!returnURL) {
            returnURL = locationHandler.getURL();
        }
        this.sendRequest('renderProfileForm',
                               {name: 'pg', value: returnURL },
                               {name: 'C2TPA', value: this.getSessionId() },
                               {name: 'err', value: errors});
    },
    _handleRenderProfileFormResponse: function(data) {
        this._profileFormDiv.innerHTML = data.html;
        this._appendLocationField('profile_form');
        this._changeAddressType();
    },
    _appendLocationField: function(formId) {
        with (html)
        var loc = input({ type: 'hidden', name: 'form_url', value: location });
        this.getElementById(formId).appendChild(loc);
    },
    renderSignUpForm: function(targetDiv, tpaVariableName,
                               params, autoLoginURL) {
        if (this.getSessionId()) {
            location = "?";
        }
        var returnURL = params['pg'] || '';
        var errors = params['err'] || '';
        this._signUpFormDiv = targetDiv;
        if (!returnURL) {
            returnURL = locationHandler.getURL();
        } else {
	        returnURL += this.passthruGet();
	    }
        var autoLogin = '';
        if (autoLoginURL) {
            autoLoginURL += (autoLoginURL.indexOf('?') > -1?'&':'?')
                +'pg='+encodeURIComponent(returnURL)
                +this.passthruGet();
        }

        this.sendRequest('renderSignUpForm',
                               {name: 'pg', value: returnURL },
                               {name: 'npoID', value: this._npoID },
                               {name: 'auto_login', value: autoLoginURL },
                               {name: 'err', value: errors});
    },
    _handleRenderSignUpFormResponse: function(data) {
        this._signUpFormDiv.innerHTML = data.html;
        this._appendLocationField('profile_form');
        this._changeAddressType();
    },
    _changeAddressType: function() {
        /* For some reason this JS embedded in the form will not get eval'ed */
        window.change_address_type = function(type) {
            if (type == "usps") {
                $("tpa_usps_address").style.display = "inline";
                $("tpa_i18n_address").style.display = "none";
            } else {
                $("tpa_usps_address").style.display = "none";
                $("tpa_i18n_address").style.display = "inline";
            }
        }
        change_address_type($('profile_form')['profile[address_type]'][0]
                            .checked?"usps":"i18n");
    },
    getSessionId: function() {
        var c = cookieJar.get('C2TPA');
        if (c == undefined) {
            c = '';
        }
        return c;
    },
    getNpoId: function() {
        return this._npoID;
    },

    _clearSessionId: function() {
        cookieJar.unset('C2TPA');
    },

    logout: function() {
        this._clearSessionId();
        window.location = window.location;
    },

    _setSessionId: function(sessionID) {
        var expires = new Date(new Date().getTime() + 24*60*60*1000);
        cookieJar.set('C2TPA', sessionID, "expires="+expires.toGMTString());
    },

    _getBaseURL: function() {
        return this._baseURL;
    },

    _getLibURL: function() {
        return this._libURL;
    },
    getElementById: function(id) {
        return getObj(id); // from rico_extentions.js
    }
}
var html = new HTML(document);


/* Creates an object whose methods produce HTML elements.
 *
 * If the first argument doesn't look like a node or string,
 * it will be treated as an object from which to grab properties.
 * Other arguments will be child nodes.
 *
 * Example:
 * html = new HTML(document);
 * with (html) document.body.appendChild(p("Hello World"));
 *
 * Like Perl's CGI module.
 */
function HTML(doc) {
    doc.write; // generates slightly more informative error if no doc
    elements = ['a', 'p', 'input', 'form', 'br', 'label', 'span', 'div',
                'li', 'strong'];

    this._isNodeOrStr = function(thing) {
        // duck typing works better than instanceof w/ IE
        // if it quacks like a duck, it's a duck.
        if (thing.setAttribute) {
            return true;
        }
        if (typeof(thing) == 'string') {
            return true;
        }
        return false;
    }
    this._makeElementMethod = function(elem) {
        this[elem] = function () {
            var e = doc.createElement(elem);
            var i = 0;
            if (arguments.length > 0 && !this._isNodeOrStr(arguments[0])) {
                i++;
                var attrs = arguments[0];
                for (var attr in attrs) {
                    /* Filter out Prototype's Object method(s) */
                    if (typeof(attrs[attr]) != 'function') {
                        e.setAttribute(attr, attrs[attr]);
                    }
                }
            }
            for (; i < arguments.length; i++) {
                var node = arguments[i];
                if (typeof(node) == 'string') {
                    node = document.createTextNode(node);
                }
                e.appendChild(node);
            }
            return e;
        }
    }
    for (var i = 0; i < elements.length; i++) {
        this._makeElementMethod(elements[i]);
    }
}

function removeAllChildNodes(element) {
    while (element.hasChildNodes()) {
        element.removeChild(element.lastChild);
    }
}

function replaceNodeChildren(element, newChild) {
    removeAllChildNodes(element);
    element.appendChild(newChild);
}

function getFormFields(form) {
    var fields = new Array();
    var elements = form.getElementsByTagName('input');
    for (var i = 0; i < elements.length; i++) {
        field = elements[i];
        if (field.name) {
            fields.push(field);
        }
    }
    return fields;
}

function urlEncodeForm(form) {
    var params = new Object();
    var fields = getFormFields(form);
    for (var i = 0; i < fields.length; i++) {
        field = fields[i];
        if (field.name) {
            params[field.name] = field.value;
        }
    }
    return urlEncode(params);
}

function urlEncode(objectAsHashOfParams) {
    var params = objectAsHashOfParams;
    var paramStrings = new Array();
    for (var param in params) {
        paramStrings.push(encodeURIComponent(param)+"="
                          +encodeURIComponent(params[param]));
    }
    return paramStrings.join("&");
}

function escapeHTML(html) {
    return html.toString()
        .replace(/&/gi, '&amp;')
        .replace(/</gi, '&lt;')
        .replace(/>/gi, '&gt;')
        .replace(/"/gi /*"*/, '&quot;')
        .replace(/'/gi /*'*/, '&apos;');
}
