var zoo = {};
zoo.version = "0.0.1";

zoo.dom = {
    popUp: function(aURL, aWidth, aHeight, aScroll, aName) {
        var zLeft = (screen.width - aWidth) / 2;
        var zTop = (screen.height - aHeight) / 2;
        var zWinProp = 'width='+aWidth+',height='+aHeight
                     + ',left='+zLeft+',top='+zTop+',scrollbars='+aScroll+',resizable';
        zWin = window.open(aURL, name, zWinProp);
        zWin.window.focus();
    },

    makeHoverable: function(elm) {
        elm.observe('mouseover', function() {
            this.addClassName('hover');
        });
        
        elm.observe('mouseout', function() {
            this.removeClassName('hover');
        });       
    },
    
    widgets: {
        ValuePrompt: function() {           
            var display = function(event) {
                var element = event.element(event);
                if (!element.value) {
                    element.addClassName('prompt');
                    element.value = '[' + element.getAttribute('prompt') + ']';
                }
            }
            
            var remove = function(event) {
                var element = event.element(event);
                var prompt = '[' + element.getAttribute('prompt') + ']';
                if (element.value == prompt) {
                    element.removeClassName('prompt');
                    element.value = '';
                }
            }
            
            return function() {
                $$('input[prompt]').each(function(input) {
                    input.observe('focus', remove);
                    input.observe('blur', display);
                    display({
                        element: function() {
                            return input;
                        }
                    });
                });
            }
        }(),
        
        Hoverable: function() {
            // elementype = elementype || 'tr';
            var elements = this.elements = $$('*[hoverable="Y"]');         
            var l = elements.length;
                       
            for (var i = 0; i < l ; i++) {
                var $elm = elements[i];
                
                $elm.observe('mouseover', function() {
                    this.addClassName('hover');
                });
                   
                $elm.observe('mouseout', function() {
                    this.removeClassName('hover');
                });
                
            }
            return true;
        },

        Select: function() {
            // elementype = elementype || 'tr';
            var elements = this.elements = $$('select[stylizedselect="Y"]');         
            var l = elements.length;
                       
            for (var i = 0; i < l ; i++) {
                var $elm = elements[i];
                zoo.form.StylizedSelect.createFromElement($elm);
            }
            return true;
        },
               
       
        Valign: function() {
            $$('img.valign').each(function(img) {
                img.style.position = 'relative';
                var h = img.getHeight();
                var w = img.getWidth();
                var max = h > w ? h : w;
                if (h < max) {
                    d = max - h;
                    img.style.top = d / 2 + 'px';
                }
            });
            return true;
        },
        
        Table: function() {
            $$('a.ico-remove').each(function(link) {
                link.observe('click', zoo.remove);
            })
            return true;
        },
        
        Mgr: function() {
            $$('a.ico-remove', 'input.action-remove').each(function(link) {
                link.observe('click', zoo.mgr.remove);
                if (link.getAttribute('onclick')) {
                    link.setAttribute('onclick', '');
                }                    
            })
            return true;
        }
    }
    
}

zoo.dom.widgets.anchorHijax = function() {
    var hijax = {
        request: function(anchor) {    
            // check if anchor has a container to update to
            var updateEl = anchor.id && $(anchor.id + '-container');
            // if not, update to parent node
            updateEl = updateEl ? updateEl : anchor.parentNode;
            var ajx = new Ajax.Updater(anchor.parentNode, anchor.href, {
                method: 'get',
                onComplete: function() {
                    return true;
                }
            });
        },
        init: function() {
            var hijax_list = $$('.hijax');
            if (hijax_list) {
                hijax_list.each(function(anchor){
                    $(anchor).observe('click', function(e) {
                        this.clickEvent = e;
                        hijax.request(this);
                        e.stop();
                        return false;
                    });
                });
            }
           return true;
        }
    }
    return function() {
        return hijax.init();
    }
}();

zoo.dom.widgets.headerBlinds = function() {

    var _blind = function() {
        var blind = this.blind;
        if (blind.down) {
            $(blind.areaId).blindDown();
            blind.down = false;
            blind.toggle.update('-');
        } else {
            $(blind.areaId).blindUp();
            blind.down = true;
            blind.toggle.update('+');
        }
    }

    return function() {
        $$('.blinds').each(function(header) {
            header.addClassName('pointer');
            
            var blinds = new Element('div', {
                'className': 'blind pointer',
                'title'    : 'click to toggle'
            }).update('-');
            
            header.blind = blinds.blind = {
                areaId: header.getAttribute('listid'),
                down: false,
                toggle: blinds
            }

            header.appendChild(blinds);
            header.observe('click', _blind);
            _blind.call(blinds);
            return true;
        });     
    }
}();

zoo.dom.widgets.TableHoverable = function() {
    var _observe = function(tables) {
        var self = this;
        tables.each(function(table) {
            table.observe('mouseover', _hover.bindAsEventListener(self));
            table.observe('mouseout', _out.bindAsEventListener(self));                
        });
    }
    var _hover = function(event) {
        var tr = Event.findElement(event, 'tr');
        if (tr) {
            tr.addClassName('hover');
        }
    }        
    var _out = function(event) {
        var tr = Event.findElement(event, 'tr');
        if (tr) {
            tr.removeClassName('hover');
        }            
    }
    return function() {
        var tables = $$('table[tablehoverable="Y"]');
        _observe.call(this, tables);
    }       
}();

zoo.dom.widgets.AssetSelect = function() {
    var $assetSelectMgr;

    var _observe = function(assetFields) {
        var self = this;
        // for each asset field found create select widget and get em nodes!
        assetFields.each(function(sel) {
            var select = new AssetSelectField({
                id        : sel.getAttribute('id'),
                container : sel.parentNode,
                select    : sel,
                input     : $('inp-' + sel.getAttribute('id'))
            })
            select.getNodeElements();
        });        
        return;
    }
    
    var _getInstance = function(id) {
        return $assetSelectMgr.selectList['asset-select-' + id]; 
    }
    
    /**
     * asset select class
     */
    var AssetSelectField = function(opts) {
        this.id        = opts.id;
        this.container = opts.container;
        this.select    = opts.select;
        this.nodeList  = opts.nodeList;
        this.input     = opts.input;
        this.loading   = new Element('div', {className: 'loading hidden'}).update('Loading ...');
        this.select.appendChild(this.loading);
        
        // register instance w/ mgr
        $assetSelectMgr.selectList[this.id] = this;        
    }

    /**
     * asset select public methods:
     */    
    AssetSelectField.prototype = {
        getNodeValueFromEl: function(el) {
            var elId = el.getAttribute('id');
            return elId.replace('inp-node-', '');
        },
        appendToolBarEvent: function(toolbarIco) {
            toolbarIco.observe('click', this.toolbarClick.bindAsEventListener(this));
        },
        getNodeElements: function() {
            var sel = this;
            var listContainer = sel.select.select('ul')[0];
            
            // append toolbar options
            var upDirIco     = sel.select.select('.up-dir-24');     
            var parentDirIco = sel.select.select('.home-24');
            if (upDirIco.length)     this.appendToolBarEvent(upDirIco[0]);
            if (parentDirIco.length) this.appendToolBarEvent(parentDirIco[0]);

            // get folder nodes and set event handlers
            var folderNodes = sel.select.select('.item-tree');        
            folderNodes.each(function(node) {
                zoo.dom.makeHoverable(node);
                node.observe('click', sel.nodeClick.bindAsEventListener(sel));
            });

            // get file nodes and set event handlers
            var fileNodes = sel.select.select('.item-file');
            fileNodes.each(function(node) {
                zoo.dom.makeHoverable(node);
                if (sel.getNodeValueFromEl(node) == sel.input.value) {
                    sel.currentlySelectedFileEl = node;
                }
                node.observe('click', sel.fileClick.bindAsEventListener(sel));
            });
            this.listContainer = listContainer;
            this.fileList = fileNodes;
            this.nodeList = folderNodes;
        },
        nodeClick: function(event) {
            // get reference to element clicked
            var el = event.findElement('.item-tree');
            // get id for node to fetch children on
            var nodeId = this.getNodeValueFromEl(el);
            // create url
            this.fetchNodes(nodeId); 
        },
        fileClick: function(event) {
            // get reference to element clicked
            var el = event.findElement('.item-file');
            if (this.currentlySelectedFileEl) {
                this.currentlySelectedFileEl.removeClassName('selected');
            }
            el.addClassName('selected');
            this.currentlySelectedFileEl = el;
            var nodeId = this.getNodeValueFromEl(el);
            // create url
            this.input.value = nodeId;

            this.select.fire('wgt:select', {
                assetSel: this,
                img: el.select('img')[0]
            });
        },
        toolbarClick: function(event) {
            // get id for node to fetch children on
            var el = event.findElement('span.ico');            
            var nodeId = this.getNodeValueFromEl(el);
            this.fetchNodes(nodeId);            
        },
        fetchNodes: function(nodeId) {
            // create url
            var href = zoo.util.url.addQuery(this.id + '_nid', nodeId);            
            var self = this;
            this.select.addClassName('loading');
            new Ajax.Request(
                href,
                {
                    method: 'get', 
                    onSuccess: function(transport) {
                        self.select.removeClassName('loading');
                        self.refresh(transport.responseText)
                    }
                }
            );                
        },
        refresh: function(html) {
            if (html) {
                this.select.update(html);
            }
            this.loading   = new Element('div', {className: 'loading hidden'}).update('Loading ...');
            this.select.appendChild(this.loading);            
            this.getNodeElements();
        },
        getValue: function() {
            return this.input.value;
        }
    }

    return function() {
        $assetSelectMgr = zoo.dom.widgets.AssetSelect;
        $assetSelectMgr.selectList = {};
        $assetSelectMgr.get = _getInstance;
        var assetFields = $$('.asset-select');
        _observe.call($assetSelectMgr, assetFields);
    }       
}();

zoo.user = {
  
    save: function() {       
        var email   = $('inp-password');
        var confirm = $('inp-confirm-password');
        
        // console.log(email.value + ' ' + confirm.value);
        
        if (email.value == confirm.value) {
            
            return false;
            return zoo.form.save();
        }
        // console.log("password not confirmed!");
        return false;
    },
  
    widgets: {
        
        passwordUpdate: function() {
            
            var inpEmail = {}, inpConfirm = {}
            
            var init = function() {
                inpEmail.value = this.value;
                var confirm = inpConfirm.elm;
                confirm.removeClassName('disabled');
                confirm.disabled = false;                
                return true;
            }
            
            var update = function() {
/*                
                var confirm = inpConfirm.elm;                
                confirm.addClassName('disabled');
                confirm.disabled = true;                  
                return true;
*/
            }
            
            var enable = function() {
                
            }
            
            var confirm = function() {
                                
                
            }            
            
            return function() {
                var email   = $('inp-password');
                var confirm = $('inp-confirm-password');
                
                email.observe('focus', init);
                confirm.observe('blur', update);
                
                inpEmail.elm   = email;
                inpConfirm.elm = confirm;
                return true;
                
            }
            
        }()  
    
    }
    
}

zoo.mgr = function() {
    var $self = this;
    return {
        edit: function(id) {
            if (this.onEditFunc) {
                var result = $self.onEditFunc(id);
                if (!result) return true;
            }
            // console.log(id);
            location.href = '?action=edit&id=' + id;
            return true;
        },
        removeTxt: null,
        remove: function(event) {
            var element = event.element(event);
            // prevent event from bubbling
            Event.stop(event);

            var ajxRemove = function() {
                Modalbox.hide();
                /* this should use POST! */
                var href = this.getAttribute('href');
                var redirectHref = this.getAttribute('redirect-href'); 
                                
                new Ajax.Request(href, {
                    method: 'get', 
                    onSuccess: function(transport) {
                        setTimeout(function() {
                            // if we have redirect ur, go there, otherwise refresh page
                            if (redirectHref) {
                                location.href = redirectHref;
                                return;
                            }
                            location.reload(true);
                            return;
                        }, 500);
                    }
                });       
                return true;
            }
                   
            var removeTxt = zoo.mgr.removeTxt || element.getAttribute('removemsg') || 'Please confirm that you wish to delete this item.';

            var setHandler = function() {
                $('deleteBut').observe('click', ajxRemove.bindAsEventListener(element));
                $('cancelBut').observe('click', function() {
                    Modalbox.hide();
                    return true;
                });
                return true;
            }

            var node = new Element('div', {className: 'warning', style: 'display:none'}).update(
            new Element('p').update(removeTxt)
            ).insert(new Element('input', {type: 'button', value: 'Confirm', id: 'deleteBut'})).insert(
            new Element('span').update(' or ')
            ).insert(new Element('input', {
                type: 'button',
                value: 'Cancel',
                id: 'cancelBut'
            }));
                
            Modalbox.show(node, {title: element.title, width: 600, afterLoad: setHandler, href: element.href });   
            // removeBtn.observe('click', function() { Modalbox.hide() });
            
            Event.stop(event);
            return false;
        },
        
        confirm: {
            show: function(element, opts) {
                var title = opts.title
                var width = opts.width || 600;

                var ajxConfirm = function() {
                    var href = this.getAttribute('url');
                    Modalbox.show(href, {title: element.title, width: width});   
                    return true;
                }
                       
                var confirmTxt = element.getAttribute('msg') || 'Please confirm you would like to perform this operation.';
    
                var setHandler = function() {
                    $('deleteBut').observe('click', ajxConfirm.bindAsEventListener(element));
                    $('cancelBut').observe('click', function() {
                        Modalbox.hide();
                        return true;
                    });
                    return true;
                }
    
                var node = new Element('div', {className: 'warning', style: 'display:none'}).update(
                new Element('p').update(confirmTxt)
                ).insert(new Element('input', {type: 'button', value: 'Confirm', id: 'deleteBut'})).insert(
                new Element('span').update(' or ')
                ).insert(new Element('input', {
                    type: 'button',
                    value: 'Cancel',
                    id: 'cancelBut'
                }));
                    
                Modalbox.show(node, {title: element.title, width: width, afterLoad: setHandler, href: element.href });   
                return false;
            }                        
        }
    }   
}();

zoo.form = function() {
        
    var _displayError = function(form, emptyfields) {
        var errorNode = form.errorMsg || $(form.getAttribute('name') + '-err');

        if (!errorNode) {
            var errorNode = new Element('div', {className: 'form-err', id: form.getAttribute('name') + '-err' });
            form.errorMsg = errorNode;
        }
        errorNode.update();
        errorNode.insert(
            new Element('h3').update(zoo.form.copy.errorTitle)
        );
        if (zoo.form.showReEnterIntroElement) {
            errorNode.insert(new Element('p').update('Please re-enter the fields in red:'));
        }

        var errorList = new Element('ul');            

        emptyfields.each(function(field) {
            var parentEl = $(field.parentNode);
            var label = parentEl.select('label')[0];            
            // check if field has its own error label
            if (field.getAttribute('errorName')) {
                var errorLabel = field.getAttribute('errorName');
            } else {
                var errorLabel = label.innerHTML.replace(':', '');
            }
            
            if (label) {
                label.addClassName('error');
            } else {
                field.addClassName('error');
            }
            var errorReason = field.invalidElement ? ': <span class="error">' + field.invalidElement : '</span>';
            errorList.insert(new Element('li').update(
                errorLabel + errorReason
            ));
        });

        errorNode.insert(errorList);

        form.parentNode.insertBefore(errorNode, form);

        if (window.Modalbox) {
            Modalbox.MBcontent.scrollTop = 0;
        } else {
            errorNode.scrollTo();
        }

        if (window.Modalbox) {
            zoo.Modalbox.resizeToContent();
        }
        // if(window.Modalbox) Modalbox.MBwindow.shake(
        errorNode.highlight();
        return true;
    }
    var _validateForm = function(form) {
        form = $(form);
        var inputs = form.getElements();
        // var inputs = form.getInputs();
        var emptyFields = [];
        var invalidFields = [];
        var validateType, rte, hasPrompt;
        
        inputs.each(function(field) {
            // reset label if previously errored on.
            field = $(field);
            
            isRTE = field.getAttribute('rte');           
            if (isRTE) {
                var rte = tinyMCE.get(field.id);
                field.value = rte.getContent();
            }
            
            if (field.error) {
                var parentEl = $(field.parentNode);
                var label = parentEl.select('label')[0];
                if (label) {
                    label.removeClassName('error');
                } else {
                    field.removeClassName('error');
                }
                field.error = null;
                if (field.invalidElement) field.invalidElement = null;
            }
            // check if required
            if (field.getAttribute('required') == "Y" && !field.getValue()) {
                field.error = true;
                if (field.getAttribute('requiredMsg')) {
                    field.invalidElement = field.getAttribute('requiredMsg');
                } else {
                    if (zoo.form.copy.fieldRequiredMessage) {
                        field.invalidElement = zoo.form.copy.fieldRequiredMessage;
                    }
                }
                emptyFields.push(field);
                return;
            }
            
            // check if we need to validate
            var validateType = field.getAttribute('validate')
            if (validateType) {
                // check if validate type has params embedded in it
                var validRegEx = /\[.*/;
                var match = validateType.match(validRegEx);
                var validateParam = '';
                // if it does, then strip them out and pass to validator                
                if (match) {
                    validateType = validateType.replace(validRegEx, '');
                    validateParam = match[0].replace(/^\[|\]$/g, '');
                    
                    // create params for validate function
                    var validateParams = validateParam.split(',');
                    var i = 0;
                    validateParams.each(function(param) {
                        validateParams[i] = param.replace(/^\s+|\s+$/g,"");
                        i++;
                    });
                    
                    validateParams = [field, form].concat(validateParams);
                } else {
                    var validateParams = [field, form];
                }
                var validResult = _validationHandler[validateType].apply(form, validateParams);
                if (validResult.error) {
                    field.error = true;
                    field.invalidElement = validResult.error;
                    invalidFields.push(field);             
                }
                return;
            }
  
            
            /* don't save/submit prompts */
            hasPrompt = field.getAttribute('prompt');
            if (hasPrompt && field.getValue() == '[' + hasPrompt + ']') {
                field.value = '';                
            }
        })
               
        return {
            emptyFields   : emptyFields,
            invalidFields : invalidFields               
        }       

    }
    
    var _validationHandler = function() {
        
        return {
            
            email: function(field) {
                var str = field.getValue();
                var error="";
         
                var emailFilter = /^[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}$/;
                if (!(emailFilter.test(str))) {
                    return {
                        error: "Please enter a valid email address.\n"
                    }
                    return false;
                }
                else {
                    //test email for illegal characters
                    var illegalChars= /[\(\)\<\>\,\;\:\\\"\[\]]/
                    if (str.match(illegalChars)) {

                        return {
                            error: "The email address contains illegal characters.\n"
                        }
                   }
                }
                return {
                    error: false    
                }
            },
            
            length: function(field, form, minlength, maxlength) {
                var str = field.getValue();

                minlength = parseInt(minlength);
                maxlength = parseInt(maxlength);

                if (minlength) {
                    if (str.length < minlength) {
                        return {
                            error: "Must be at least " + minlength + " characters long.\n"
                        }
                    }
                }

                if (maxlength) {
                    if (str.length < maxlength) {
                        return {
                            error: "May not be greater than " + minlength + " characters long.\n"
                        }
                    }
                }

                return true;                
            },
            
            /**
             * checks for valid password
             * @todo check for reason of error
             */
            password: function(field) {
                var str = field.getValue();
                
                var illegalChars = /[\W_]/; // allow only letters and numbers
                // if ((str.length < 6) || (str.length > 10)){
                if (str.length < 6){
                    return {
                        error: "Must be greater than 6 characters.\n"
                    }
                }
                else if (illegalChars.test(str)) {
                    return {
                        error: "Contains illegal characters.\n"
                    }
                }
                
                else if (!((str.search(/[a-z]+/) > -1)
                    && (str.search(/[A-Z]+/) > -1)
                    && (str.search(/[0-9]+/) > -1))) {
                    return {
                        error: "Must contain at least one uppercase letter, one lowercase letter, and one numeral.\n"
                    }
                    return false;
                }
                return true;
            },
            
            confirmPassword: function(field, form, checkAgainstFieldName) {
                if (!form[checkAgainstFieldName]) throw new Error('confirm password does not have a valid password field to check against! - ' + checkAgainstFieldName);
                if (field.getValue() !== form[checkAgainstFieldName].getValue()) {
                    // reset field
                    field.value = '';
                    return {
                        error: 'does not match password'
                    }
                }
                return {
                    error: false
                }
                
                return false;                
            },
            
            confirmEmail: function(field, form, checkAgainstFieldName) {
                if (!form[checkAgainstFieldName]) throw new Error('confirm email does not have a valid email field to check against! - ' + checkAgainstFieldName);
                if (field.getValue() !== form[checkAgainstFieldName].getValue()) {
                    // reset field
                    field.value = '';
                    return {
                        error: 'does not match email'
                    }
                }
                return {
                    error: false
                }
                
                return false;                
            },
            
            verify: function(field, form, checkAgainstFieldName) {
                if (!form[checkAgainstFieldName]) throw new Error('verify field does not have a valid field to check against! - ' + checkAgainstFieldName);
                if (field.getValue() !== form[checkAgainstFieldName].getValue()) {
                    // reset field
                    field.value = '';
                    
                    var verifyToLabel = $$('label[for=' + checkAgainstFieldName +']');
                    if (verifyToLabel && verifyToLabel.length) {
                        var fieldName = verifyToLabel[0].innerHTML;
                    } else {
                        var fieldName = '';
                    }
                    return {
                        error: 'does not match ' + fieldName
                    }
                }
                return {
                    error: false
                }
                
                return false;                
            },
            
            username: function(field) {
                var str = field.getValue();
                var illegalChars = /\W/; // allow letters, numbers, and underscores
                if ((str.length < 4) || (str.length > 10)) {
                    return {
                        error: "The username is the wrong length.\n"
                    }
                }
                else if (illegalChars.test(strng)) {
                    return {
                        error: "The username contains illegal characters.\n"
                    }
                } 
                return false;   
            },
            
            number: function(field, digits) {
                var number = field.getValue();
                
                if(isNaN(number)) {
                    return {
                        error: "Must only contain numbers."
                    }
                }
                /*
                if (digits && number.length > digits) {
                    return {
                        error: "Must contain only " + digits + " dgits."
                    }                    
                }
                */
                return false;   
            }
            
        }
        
    }();
    
    
    return {
        showReEnterIntroElement: true,
        copy: {
            errorTitle: 'Sorry your form had a few problems'            
        },
        init: function() {},
    
        loading: function(form) {
            if (window.Modalbox) {
                form.style.display = "none";
                Modalbox.MBcontent.insert(new Element('p', {className: 'form-save-msg'}).update('Saving, please be patient...'));
                Modalbox.MBcontent.insert(Modalbox.MBloading);

                // Modalbox.MBcontent.update(new Element('p', {className: 'form-save-msg'}).update('Saving, please be patient...'));
                // Modalbox.MBcontent.appendChild(Modalbox.MBloading);
                Modalbox.resizeToContent();
            }
            return true;
        },
        
        success: function(transport) {
            if (window.Modalbox) {
                // Modalbox.show("<p>Form Has Been Saved Successfully</p>");
                // Modalbox.resizeToContent();
                Modalbox.hide(); 
            }
            if (zoo.isAdmin) {
                setTimeout(function() {
                   location.reload(true);
                }, 500);
            }
            return true;
        },
       
        save: function(form) {
            
            // wrap save in try catch so that we never submit bad form
            try {
                var results = _validateForm(form);
     
                /* remove shaking of modalbox... for now. */
                var errorFields = [];
                errorFields = errorFields.concat(results.emptyFields, results.invalidFields);
                
                if (errorFields.length) {
                    _displayError(form, errorFields);
                    return false;
                }
                // useful when we need to debug
                // return true;   
                // check if we hijack form save and use ajax
                if ((window.Modalbox && window.Modalbox.MBcontent) || form.getAttribute("ajax") == "Y") {
                    this.loading(form);
                    
                    if (form.getAttribute("enctype") && form.getAttribute("enctype") == 'multipart/form-data') {
                        form.hasFiles = true;
                        // if we have a file post to an iframe and do not use
                        // ajax method
                        AIM.submit(form, {
                            'onStart'   : Prototype.emptyFunction,
                            'onComplete': this.success
                        });
                        return true;
                    }
                    
                    var url = form.action;                   
                    var successFunc = form.onSuccess || this.success;
                    
                    new Ajax.Request(url, {
                        method: 'post',
                        parameters: form.serialize(true),   
                        // onSuccess: Prototype.emptyFunction
                        onSuccess: successFunc
                    });
                    return false;
                }
                
                return true;

            } catch(e) {
                // @todo need sys email here
                if (window.console) {
                    console.dir(e);
                }
                return false;
            }           
        },
        
        /* date input class */
        Date: function(element) {
            this.ico    = element;
            var dateId  = element.getAttribute('date-id');
            this.input  = $(dateId);
            zoo.form.Date.instances[dateId] = this;
            zoo.form.Date.instanceArray.push(this);
        }
      
    }
  
}();

/* ########################################################################## */
/*   date formfield widget                                                    */
/* ########################################################################## */
zoo.form.Date.instanceArray = [];
zoo.form.Date.instances = {};
zoo.form.Date.show = function(el) {
    
    var scalCalendar = $('scal-calendar');
    if (!scalCalendar) {

        scalCalendar = new Element('div', {
            className: 'scal tinyscal zscal',
            id: 'scal-calendar'
        });
        var modalBox = $('XXXXMB_window');
        if (modalBox) {
            modalBox.appendChild(scalCalendar);
            
        } else {
            
            document.body.insertBefore(scalCalendar, document.body.firstChild);    
        }
        
    }
    
    // get id of date input
    var dateId = el.getAttribute('date-id');
    // do we have a js instance of this?
    var dateInput = zoo.form.Date.instances[dateId];
    // if no, create one first
    if (!dateInput) {
        dateInput = new zoo.form.Date(el);
    }
    dateInput.calElement = scalCalendar;
    // display calendar
    dateInput.show();
    return true;
}

zoo.form.Date.prototype = {
    
    show: function() {
        if (!this.scal) {
            var self = this;
            this.scal = new scal('scal-calendar', this.update, {
                updateformat: 'mm/dd/yyyy',
                closebutton: '<img src="/img/close-ico.jpg" />'              
            });
            this.scal.zooDate = this;
            
            var onSelChange = function(){
                var updateElement = self.zooDate.input;
                updateElement[updateElement.tagName == 'INPUT' ? 'setValue' : 'update'](this.currentdate.format(this.options.updateformat));
                self.scal.closeCalendar();
            };
            this.input.observe('keypress', this.hide.bindAsEventListener(this));            
        } else {
            this.scal.zooDate.open = false;
        }
        var date = new Date($F(this.input));
        this.scal.setCurrentDate(isNaN(date) ? new Date() : date);
        var dim = $(this.ico).cumulativeOffset();
        this.calElement.style.top  = dim.top + 'px';
        this.calElement.style.left = dim.left + 30 + 'px';
        this.calElement.style.display = "block";       
    },
    
    hide: function() {
        if(this.scal.isOpen()) {
            this.scal.closeCalendar();
            this.open = false;
        }
        return true;        
    },
    
    update: function() {
        this.zooDate.input.value = this.currentdate.format('mm/dd/yyyy');
        if (this.zooDate.opened) {
            this.closeCalendar();
            this.zooDate.opened = false;
        } else {
            this.zooDate.opened = true;
        }
        return true;
    }
}

/* ########################################################################## */
/*   multi entry formfield widget                                             */
/* ########################################################################## */
zoo.form.MultiEntry = function(entryId, fields) {
    this.multiEntryContainer = $(entryId);

    this.addButton = this.multiEntryContainer.select('button.btn-entry')[0];

    this.id = 'multi-entry-' + Math.floor(Math.random() * 99999);
    this.addButton.setAttribute('multi-entry-id', this.id);
    this._fields = fields;
    zoo.form.MultiEntry.instance[this.id]= this;
}
zoo.form.MultiEntry.prototype = function() { 
    var _getEntryInputs = function() {
        this.addContainer = $(this.addButton.parentNode);
        this.entryFields = this.addContainer.select('.text, select');
    }
    
    var _getValueContaines = function() {
        var formFieldContainer = $(this.addContainer.parentNode);
        this.entryTable    = formFieldContainer.select('table.multi-entry')[0];
        this.hiddenEntries = formFieldContainer.select('div.hidden-entries')[0];
    }
    
    var _getValues = function() {
        var values = {};
        this.entryFields.each(function(input) {
            var field = input.getAttribute('name').replace('-entry', '');
            var display = input.tagName == 'SELECT' ? input.options[input.selectedIndex].text : input.getValue();
            values[field] = { value: input.getValue(), display: display };
            input.value = '';
        });
        return values;
    }
    
    var _addValuesToHiddenInputs = function(values) {
        var inputElement;
        for (field in values) {
            inputElement = new Element('textarea', {
                'class': 'hidden',
                name: field + '[]',
                value: values[field].value
            }).update(values[field].value);
            // ie no likey this.. class hidden hides it for us
            // inputElement.setAttribute('type', 'hidden');
            this.hiddenEntries.appendChild(inputElement);
        }
        return true;
    }
    
    var _getTBody = function() {
        if (this.entryTBody) return this.entryTBody;
        var els  = this.entryTable.select('tbody');
        if (els) {
            var tBody = els[0];
        } else {
            var tBody = document.createElement();
            this.entryTable.appendChild(tBody);
        }
        this.entryTBody = tBody;
        return tBody;            
    }
    
    var _addValuesToEntryTable = function(values) {
        var tBody = _getTBody.call(this);
        var cell;
        var row = new Element('tr');

        var items = tBody.select('cell');
  
        var className = items.length % 2 == 0 ? 'even' : 'odd';
        row.addClassName(className);
        
        row.observe('mouseover', function() {
            this.addClassName('hover');
        });
           
        row.observe('mouseout', function() {
            this.removeClassName('hover');
        });

        for (field in this._fields) {
            if (!values[field]) continue;
            cell = new Element('td', { 'class': 'item-' + field }).update(values[field].display);
            row.appendChild(cell);
        }
                    
        var removeLink = new Element('a', {
            'class': 'button-anchor remove'
        }).update('remove')

        removeLink.observe('click', this.removeEntry.bindAsEventListener(this, row));
                         
        cell = new Element('td', { 'class': 'item-remove' }).update(removeLink);

        row.appendChild(cell);

        tBody.appendChild(row);
        
        return true;
    }
    
    var _updateRemoveLinks = function() {
        var self = this;
        this.multiEntryContainer.select('table.multi-entry a.remove').each(function(removeLink) {
            var row = removeLink.parentNode.parentNode;
            removeLink.observe('click', self.removeEntry.bindAsEventListener(self, row));
        })            
    }
    
    return {
        init: function() {
            _getEntryInputs.call(this);
            _getValueContaines.call(this);
            _updateRemoveLinks.call(this);
        },
        add: function(values) {
            _addValuesToHiddenInputs.call(this, values);
            _addValuesToEntryTable.call(this, values);
        },
        addEntry: function() {
            var values = _getValues.call(this);
            this.add(values);
            return true;
        },
        removeEntry: function(e, row) {
            var tBody = _getTBody.call(this);
            var valueRows = tBody.select('tr');
            var killRow   = valueRows.indexOf(row);
            var hiddenFields;
            for (field in this._fields) {              
                hiddenFields = this.hiddenEntries.select('textarea[name="' + field + '[]"]');
                if (hiddenFields[killRow]) {
                    this.hiddenEntries.removeChild(hiddenFields[killRow]);
                }
            }
            row.parentNode.removeChild(row);
        },
        getId: function() {
            return this.id;
        }
    }
}();

zoo.form.MultiEntry.instance= {};
zoo.form.MultiEntry.init = function(entryId, fields) {
    multiEntry = new zoo.form.MultiEntry(entryId, fields);
    multiEntryId = multiEntry.getId();
    multiEntry.init();
}
zoo.form.MultiEntry.add = function(btn, fieldName) {
    var multiEntryId = btn.getAttribute('multi-entry-id')
    if (!multiEntryId) {
        multiEntry = new zoo.form.MultiEntry(btn, window[fieldName]);
        multiEntryId = multiEntry.getId();
        multiEntry.init();
    } else {
        multiEntry = zoo.form.MultiEntry.instance[multiEntryId];
    }
    multiEntry.addEntry();
    return true;
}

zoo.remove = function(e) {
    e = e || window.event;
    var ajxRemove = function() {
        Modalbox.hide();                                 
        new Ajax.Request(this.href, {
            method: 'get', 
            onSuccess: function(transport) {
                setTimeout(function() {
                    location.reload(true);
                    return;
                }, 500);
            }
        });       
        return true;
    }

    var setHandler = function() {
	$('deleteBut').observe('click', ajxRemove.bindAsEventListener(this));
        $('cancelBut').observe('click', function() {
            Modalbox.hide();
            return true;
        });
        return true;
    }
    
    var removeBtn = new Element('input', {
        type: 'button',
        value: 'Cancel',
        id: 'cancelBut'
    });
    
    var node = new Element('div', {className: 'warning', style: 'display:none'}).update(
    new Element('p').update('Please confirm that you wish to delete this item.')
    ).insert(new Element('input', {type: 'button', value: 'Confirm', id: 'deleteBut'})).insert(
    new Element('span').update(' or ')
    ).insert(new Element('input', {
        type: 'button',
        value: 'Cancel',
        id: 'cancelBut'
    }));
        
    Modalbox.show(node, {title: this.title, width: 600, afterLoad: setHandler, href: this.href });   
    removeBtn.observe('click', function() { Modalbox.hide() });
    
    Event.stop(e);
    return false;
}

zoo.Modalbox = function() {
    var bakAfterLoad, bakBeforeHide; 
    return {
        fitToScreen: function() {
            var modal_h = Modalbox.MBwindow.getHeight();
            var viewport_h = document.viewport.getHeight();
            /*
            var el = window.debugDiv || document.createElement('div');
            window.debugDiv = el;
            window.debugDiv.style.position = 'absolute';
            window.debugDiv.style.top = '10px';
            window.debugDiv.style.left = '0px';
            window.debugDiv.textAlign = 'left';
            window.debugDiv.width = '300px';
            window.debugDiv.border = '2px red solid';
            window.debugDiv.style.backgroundColor = 'white';            
            window.debugDiv.style.fontSize = '12px';             
            el.innerHTML += '<p>modal_h = ' + modal_h +  ' and viewport_h = ' + viewport_h + '</p>';
            */
            if (modal_h > viewport_h) {
                Modalbox.MBwindow.style.height = viewport_h - 20 + 'px';
                Modalbox.MBcontent.style.height = viewport_h - 40 - Modalbox.MBheader.getHeight() + 'px';
                
            }
            if (bakAfterLoad) {
                backAfterLoad();
            }
            if (!zoo.Modalbox.height) {
                // zoo.Modalbox.height = Modalbox.MBwindow.getHeight();
                zoo.Modalbox.height = 0;
                // check modal for any changes to modal size and fit to screen if changes
                zoo.Modalbox.listener = setInterval(zoo.Modalbox.checkIfHeightChanged, 500);
            }

            backAfterLoad = null;
        },
        
        checkIfHeightChanged: function() {
            /*
            var el = window.debugDiv || document.createElement('div');
        
            window.debugDiv = el;
            window.debugDiv.style.position = 'absolute';
            window.debugDiv.style.top = '10px';
            window.debugDiv.style.left = '0px';
            window.debugDiv.textAlign = 'left';
            window.debugDiv.width = '300px';
            window.debugDiv.border = '2px red solid';
            window.debugDiv.style.backgroundColor = 'white';            
            window.debugDiv.style.fontSize = '12px';            
            el.innerHTML += '<p>check if height</p>';
            */
            var h = Modalbox.MBwindow.getHeight();
            if (zoo.Modalbox.height != h) {
                // el.innerHTML += '<p style="color: red">height changed</p>';
                zoo.Modalbox.height = h;
                zoo.Modalbox.fitToScreen();
            }
            // document.body.appendChild(el);
            return true;
        },
        
        show: function() {
    
            if (arguments[1].afterLoad) {
                var bakAfterLoad = arguments[1].afterLoad;
            }
            
            if (arguments[1].beforeHide) {
                var bakBeforeHide = arguments[1].beforeHide;
            }

            // fit modal to screen on window resize
            Event.observe(window, 'resize', zoo.Modalbox.fitToScreen);

            arguments[1].afterLoad = zoo.Modalbox.fitToScreen;
            arguments[1].beforeHide = zoo.Modalbox.cleanUp;
            
            Modalbox.show.apply(Modalbox, arguments);

        },
        
        resizeToContent: function() {
            var opts = { afterResize: zoo.Modalbox.fitToScreen };
            Modalbox.resizeToContent.apply(Modalbox, [opts]);
        },
        
        cleanUp: function() {
            // remove listener for height and for resize changes
            if (zoo.Modalbox.listener) clearInterval(zoo.Modalbox.listener);
            Event.stopObserving(window, 'resize', zoo.Modalbox.fitToScreen);
            
            if (zoo.form.Date.instanceArray.length) {
                zoo.form.Date.instanceArray.each(function(dateInput) {
                   dateInput.scal.closeCalendar();
                   dateInput.opened = false;
                });
                var scalCalendar = $('scal-calendar');
                if (scalCalendar) {
                    document.body.removeChild(scalCalendar);
                }
            }
            if (bakBeforeHide) {
                bakBeforeHide();
            }
            bakBeforeHide = null;
        }
    }
}();

/**
*
*  AJAX IFRAME METHOD (AIM)
*  http://www.webtoolkit.info/
*
**/
var AIM = {

    frame : function(c) {

        var n = 'f' + Math.floor(Math.random() * 99999);
        var d = document.createElement('DIV');
        d.innerHTML = '<iframe width="100%" style="display:none" src="about:blank" id="'+n+'" name="'+n+'" onload="AIM.loaded(\''+n+'\')"></iframe>';
        document.body.appendChild(d);

        var i = document.getElementById(n);
        if (c && typeof(c.onComplete) == 'function') {
            i.onComplete = c.onComplete;
        }

        return n;
    },

    form : function(f, name) {
        f.setAttribute('target', name);
    },

    submit : function(f, c) {
        AIM.form(f, AIM.frame(c));
        if (c && typeof(c.onStart) == 'function') {
            return c.onStart();
        } else {
            return true;
        }
    },

    loaded : function(id) {
        var i = document.getElementById(id);
        if (i.contentDocument) {
            var d = i.contentDocument;
        } else if (i.contentWindow) {
            var d = i.contentWindow.document;
        } else {
            var d = window.frames[id].document;
        }
        if (d.location.href == "about:blank") {
            return;
        }

        if (typeof(i.onComplete) == 'function') {
            i.onComplete(d.body.innerHTML);
        }
    }

}

zoo.Math = {
    random: function(min, max) {
        return (Math.floor(Math.random() * (max+1 - min)) + min);
    }
}

zoo.util = {
    url: {
        addQuery: function(field, val) {
            var qry = location.search;
            if (qry) {
                qry = '&' + qry.slice(1);
            }
            return location.protocol + '//' +
                   location.hostname +
                   location.pathname +
                   '?' + field + '=' + val +
                   qry;
        }
    }
    
};

/* cookie methods */
zoo.util.setCookie = function(cookieName, aValue, aExpires, aPath, aDomain, aSecure ) {
    var zToday = new Date();
    zToday.setTime( zToday.getTime() );
    if ( aExpires ) aExpires = aExpires * 1000 * 60 * 60 * 24;
    var zExpiresDate = new Date( zToday.getTime() + ( aExpires ) );
    document.cookie = cookieName + "=" + escape( aValue ) +
    ( ( aExpires ) ? ";expires=" + zExpiresDate.toGMTString() : "" ) + 
    ( ( aPath )    ? ";path="    + aPath                      : "" ) + 
    ( ( aDomain )  ? ";domain="  + aDomain                    : "" ) +
    ( ( aSecure )  ? ";secure"                                : "" );
}
zoo.util.getCookie = function(cookieName) {
    var zCurrentCookie, zCookieName, zCookieValue,	zCookieFound = false;
    var zCookieArray = document.cookie.split(";");
    for ( var i = 0; i < zCookieArray.length; i++ )	{
            zCurrentCookie = zCookieArray[i].split("=");
            zCookieName = zCurrentCookie[0].replace(/^\s+|\s+$/g, "");
            if ( zCookieName == cookieName ) {
                    zCookieFound = true;
                    if ( zCurrentCookie.length > 1 ) zCookieValue = unescape( zCurrentCookie[1].replace(/^\s+|\s+$/g, "") );
                    return zCookieValue;
                    break;
            }
            zCurrentCookie = null;
            zCookieName = "";
    }
    return null;
}
zoo.util.removeCookie = function(cookieName, path, domain) {
    if (zoo.util.getCookie(cookieName)) document.cookie = cookieName + "=" +
    ((path)   ? ";path="   + path   : "") +
    ((domain) ? ";domain=" + domain : "") +
     ";expires=Thu, 01-Jan-1970 00:00:01 GMT";
    return true;
}

// standard widgets to invoke on dom load
document.observe("dom:loaded", zoo.dom.widgets.Hoverable);
document.observe("dom:loaded", zoo.dom.widgets.TableHoverable);
document.observe("dom:loaded", zoo.dom.widgets.ValuePrompt);
document.observe("dom:loaded", function() {
    zoo.isAdmin = Boolean(zoo.isAdmin || location.href.match(/\.admin\./) || location.href.match(/portals\/admin\//));
});

// these events must rely on all images and objects being completly ready
Event.observe(window, 'load', function() {
    // if images come from cdn, this wont work in dom:loaded
    zoo.dom.widgets.Valign();
});

/* crap.. this needs to move under DOM */
function toggleEditor(id) {
    if (!tinyMCE.get(id))   
        tinyMCE.execCommand('mceAddControl', false, id);
    else    
        tinyMCE.execCommand('mceRemoveControl', false, id);
}
