TheCarbonAccount = window.TheCarbonAccount || {};

TheCarbonAccount.scripts = (function() {
    /* Adapted From Prototype 1.4 */
    var scriptFragment = '(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)';
    var matchAll = new RegExp(scriptFragment, 'img');
    var matchOne = new RegExp(scriptFragment, 'im');
    return {
        'strip': function(s) {
            return s.replace(matchAll, '');
        },
        'extract': function(s) {
            var matches = s.match(matchAll) || [];
            var scripts = [];
            for (var i = 0, j = matches.length; i < j; i++) {
                var scriptTag = matches[i];
                var script = (scriptTag.match(matchOne) || ['', ''])[1];
                scripts[scripts.length] = script;
            }
            return scripts;
        },
        'evalAll': function(s) {
            var scripts = TheCarbonAccount.scripts.extract(s);
            for (var i = 0, j = scripts.length; i < j; i++) {
                eval(scripts[i]);
            }
        }
    };
})();

TheCarbonAccount.modal = (function() {
    /* We need to construct this HTML:
    <div class="modal" id="modal">
        <img src="/static/img/modal_top.gif" class="modalTop">
        <div class="modalInner">
        ...
        </div>
    </div>
    */
    
    var $D = YAHOO.util.Dom;
    var $C = YAHOO.util.Connect;
    var $gS = document.getElementsBySelector;
    // http://dean.edwards.name/weblog/2007/03/sniff/
    var isMSIE = /*@cc_on!@*/false;

    function getDiv() {
        var div = document.getElementById('modal');
        if (!div) {
            div = document.createElement('div');
            div.id = 'modal';
            div.style.zIndex = 20;
            var img = document.createElement('img');
            img.src = '/static/img/modal_top.gif';
            img.className = 'modalTop';
            div.appendChild(img);
            var inner = document.createElement('div');
            inner.id = 'modalInner';
            div.appendChild(inner);
            div.style.display = 'none';
            document.body.appendChild(div);
        }
        return div;
    }
    
    function show() {
        //console.log('show() called');
        var div = getDiv();
        with(div.style) {
            width = '494px';
            position = 'absolute';
            left = ($D.getDocumentWidth() / 2 - (494 / 2)) + 'px';
            top = '30px' // ($D.getDocumentHeight() / 2 - (470 / 2)) + 'px';
            zIndex = 20;
            display = 'block';
        }
    }
    
    function hide() {
        var div = getDiv();
        div.style.display = 'none';
    }
    
    function close() {
        //console.log('close() called');
        var div = getDiv();
        div.style.display = 'none';
        var inner = $D.get('modalInner');
        // Clear contents
        while(inner.firstChild) {
            inner.removeChild(inner.firstChild);
        }
        TheCarbonAccount.hideAllCalendars();
        TheCarbonAccount.help.hideHelp();
        TheCarbonAccount.coverpage.hideLoading();
        TheCarbonAccount.coverpage.uncoverPage();
    }
    
    function fromUrl(url, callback) { // callback is optional
        /* Give this a URL and an optional callback. It will load the contents 
           of the URL in to a modal dialog. It will also check if there are any
           <script> blocks in the returned HTML; if there are, it will strip 
           them before inserting the HTML in to the page and then execute them
           shortly after the innerHTML has been updated. Finally, it will 
           execute the callback (if supplied).
        */
        $D.addClass(getDiv(), 'ajaxloading');
        callback = callback ? callback : function(){};
        TheCarbonAccount.coverpage.showLoading();
        $C.asyncRequest('GET', url, {
            'success': function(o) {
                var div = getDiv();
                $D.removeClass(div, 'ajaxloading');
                var html = o.responseText;
                var stripped = TheCarbonAccount.scripts.strip(html);
                var modalInner = $D.get('modalInner');
                while (modalInner.firstChild) {
                    modalInner.removeChild(modalInner.firstChild);
                }
                modalInner.innerHTML = stripped;
                TheCarbonAccount.coverpage.hideLoading();
                if (isMSIE) {
                    show(); // Everyone else gets pretty animations
                } else {
                    $D.setStyle(div, 'opacity', 0);
                    var anim = new YAHOO.util.Anim(div, {opacity: {to: 1}}, 0.5);
                    show();
                    anim.animate();
                }
                /* Insert a 100ms delay before executing callbacks, to give 
                   the DOM time to catch up (callbacks are likely to want to 
                   manipulate the modal's DOM) */
                setTimeout(function() {
                    TheCarbonAccount.scripts.evalAll(html);
                    if (callback) {
                        callback();
                    }
                    // Add handlers to any new help icons
                    TheCarbonAccount.help.addHandlers();
                    // Resize the coverpage, just in case dialog has grown
                    TheCarbonAccount.coverpage.expandCoverDiv();
                }, 100);
            },
            'failure': function(o) {
                $D.removeClass(getDiv(), 'ajaxloading');
                console.log('modal.fromUrl('+url+') failed: ' + o.statusText);
                TheCarbonAccount.coverpage.hideLoading();
                close();
            }
        });
    }

    function formFromUrl(url) {
        /* New, improved version of fromUrl; will eventually replace it 
           entirely.
           
           - Loads the url as an HTML fragment, bungs it in a modal dialog
           - evals() any <script> blocks found in that fragment
           - if the fragment contained "<form"...
             - That form needs the Ajax treatment:
             - Attach a submit handler to it
             - When the form is submitted, do an Ajax POST to the action of 
               the form with 'ajax/' added on the end.
             - Whatever comes back, bung in innerHTML and eval the script
           
           This should allow us to be completely unobtrusive. The fragments we 
           are using exist as standalone forms at the URL without the ajax/ 
           suffix, and we've entirely eliminated duplicate code.
        */
        TheCarbonAccount.coverpage.showLoading();
        $D.addClass(getDiv(), 'ajaxloading');
        $C.asyncRequest('GET', url, {
            'success': function(o) {
                var div = getDiv();
                $D.removeClass(div, 'ajaxloading');
                var html = o.responseText;
                var stripped = TheCarbonAccount.scripts.strip(html);
                var modalInner = $D.get('modalInner');
                while (modalInner.firstChild) {
                    modalInner.removeChild(modalInner.firstChild);
                }
                modalInner.innerHTML = stripped;
                TheCarbonAccount.coverpage.hideLoading();
                if (isMSIE) {
                    show(); // Everyone else gets pretty animations
                } else {
                    $D.setStyle(div, 'opacity', 0);
                    var anim = new YAHOO.util.Anim(div, {opacity: {to: 1}}, 0.5);
                    show();
                    anim.animate();
                }
                /* Insert a 100ms delay before executing scripts, to give 
                   the DOM time to catch up (scripts are likely to want to 
                   manipulate the modal's DOM) */
                setTimeout(function() {
                    TheCarbonAccount.scripts.evalAll(html);
                    if (/<form/.exec(html)) {
                        // Hook up that onsubmit Ajax
                        var forms = $D.get('modalInner').getElementsByTagName(
                            'form'
                        );
                        for (var i = 0, form; form = forms[i]; i++) {
                            ajaxifyForm(form);
                        }
                    }
                    // Add handlers to any new help icons
                    TheCarbonAccount.help.addHandlers();
                    // Resize the coverpage, just in case dialog has grown
                    TheCarbonAccount.coverpage.expandCoverDiv();
                }, 100);
            },
            'failure': function(o) {
                $D.removeClass(getDiv(), 'ajaxloading');
                console.log('modal.fromUrl('+url+') failed: ' + o.statusText);
                TheCarbonAccount.coverpage.hideLoading();
                close();
            }
        });
    }
    
    function ajaxifyForm(form) {
        /* The second half of formFromUrl */
        $E.on(form, 'submit', function(ev) {
            $E.stopEvent(ev);
            // URL should end in ajax/, if it doesn't already
            var url = form.action;
            if (!/ajax\/$/.exec(url)) {
                url += 'ajax/';
            }
            $C.setForm(form);
            $D.addClass(getDiv(), 'ajaxloading');
            $C.asyncRequest('POST', url, {
                'success': function(o) {
                    $D.removeClass(getDiv(), 'ajaxloading');
                    var html = o.responseText;
                    var stripped = TheCarbonAccount.scripts.strip(html);
                    var modalInner = $D.get('modalInner');
                    while (modalInner.firstChild) {
                        modalInner.removeChild(modalInner.firstChild);
                    }
                    modalInner.innerHTML = stripped;
                    setTimeout(function() {
                        TheCarbonAccount.scripts.evalAll(html);
                        // Add handlers to any new help icons
                        TheCarbonAccount.help.addHandlers();
                        TheCarbonAccount.coverpage.expandCoverDiv();
                        if (/<form/.exec(html)) {
                            // Hook up that onsubmit Ajax, again
                            var forms = $D.get('modalInner').getElementsByTagName(
                                'form'
                            );
                            for (var i = 0, form; form = forms[i]; i++) {
                                ajaxifyForm(form);
                            }
                        }
                    }, 100);
                },
                'failure': function(o) {
                    $D.removeClass(getDiv(), 'ajaxloading');
                    console.log('POST ('+url+') failed: ' + o.statusText);
                    TheCarbonAccount.coverpage.hideLoading();
                    close();
                }
            });
        });
    }

    function showErrors(errors) {
        /* First clean out all currently displayed errors */
        var lis = $gS('div#modal li.invalid');
        for (var li, i = 0; li = lis[i]; i++) {
            YAHOO.util.Dom.removeClass(li, 'invalid');
            li.title = '';
        }
        for (key in errors) {
            if (errors.hasOwnProperty(key)) {
                /* Sometimes we provide a hook for the error */
                if ($D.get(key + '_errorMsg')) {
                    $D.get(key + '_errorMsg').innerHTML = errors[key][0];
                } else {
                    var input = $gS(
                        'div#modal form input[name="' + key + '"]'
                    )[0];
                    if (input) {
                        var li = input.parentNode;
                        var p = li.getElementsByTagName('p')[0];
                        if (!p) {
                            p = document.createElement('p');
                            p.className = 'validError';
                            li.appendChild(p);
                        }
                        p.innerHTML = errors[key][0];
                        YAHOO.util.Dom.addClass(li, 'invalid');
                    }
                }
            }
        }
        TheCarbonAccount.coverpage.expandCoverDiv();
    }
    
    return {
        'fromUrl': fromUrl,
        'show': show,
        'hide': hide,
        'close': close,
        'getDiv': getDiv,
        'showErrors': showErrors,
        'formFromUrl': formFromUrl
    };
})();