var _QL = Ext.DomQuery.select;
var _Q = Ext.DomQuery.selectNode;
var _QV = Ext.DomQuery.selectValue; 

var MK = {};
var Dom = YAHOO.util.Dom;
var Event = YAHOO.util.Event;

MK.config = {
    hijackFormErrorFn: function() {},
    loginFn: function(afterLoginFn) {}
};

MK.batch = function(el, method, o, override) {
    if (YAHOO.lang.isArray(el) && el.length==0) {
        return false;
    }

    return Dom.batch(el, method, o, override);
};

MK.findAncestor = function(el, ancestorTagName) {
    var node = el;
    ancestorTagName = ancestorTagName.toUpperCase();
    while(node) {
        if (node.tagName && node.tagName.toUpperCase()==ancestorTagName) {
            return node;
        }
        node = node.parentNode;
    }
    return null;
};

MK.forEach = function(collection, fn, obj, override) {
    var scope = window;
    if (override) {
        if (override === true) {
            scope = obj;
        } else {
            scope = override;
        }
    }
    for (var key in collection) {
        if (YAHOO.lang.hasOwnProperty(collection, key)) {
            fn.call(scope, key, collection[key], obj);
        }
    }
}

MK.setStyle = function(el, o) {
    var f = function(el) {
        for (prop in o) {
            if (YAHOO.lang.hasOwnProperty(o, prop)) {
                Dom.setStyle(el, prop, o[prop]);
            }
        }
    };

    MK.batch(el, f);
};

MK.setClass = function(el, className) {
    var f = function(el) {
        el.className = className;
    };

    MK.batch(el, f);
};

MK.set = function(el, o) {
    var f = function(el) {
        var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
        MK.forEach(o, function(prop, value) {
                if (prop==='content') {
                    el.innerHTML = value;
                } else if (prop==='style') {
                    MK.setStyle(el, value);
                } else if (prop==='class') {
                    MK.setClass(el, value);
                } else {
                    if (useSet) {
                        el.setAttribute(prop, value);
                    } else {
                        el[prop] = value;
                    }
                }
            });
    };

    MK.batch(el, f);
};

// from extjs
MK.insertHtml = function(where, el, html) {
    where = where.toLowerCase();
    if(el.insertAdjacentHTML){
        switch(where){
        case "beforebegin":
            el.insertAdjacentHTML(where, html);
            return el.previousSibling;
        case "afterbegin":
            el.insertAdjacentHTML(where, html);
            return el.firstChild;
        case "beforeend":
            el.insertAdjacentHTML(where, html);
            return el.lastChild;
        case "afterend":
            el.insertAdjacentHTML(where, html);
            return el.nextSibling;
        }
        throw 'Illegal insertion point -> "' + where + '"';
    }
    var range = el.ownerDocument.createRange();
    var frag;
    switch(where){
    case "beforebegin":
        range.setStartBefore(el);
        frag = range.createContextualFragment(html);
        el.parentNode.insertBefore(frag, el);
        return el.previousSibling;
    case "afterbegin":
        if(el.firstChild){
            range.setStartBefore(el.firstChild);
            frag = range.createContextualFragment(html);
            el.insertBefore(frag, el.firstChild);
            return el.firstChild;
        }else{
            el.innerHTML = html;
            return el.firstChild;
        }
    case "beforeend":
        if(el.lastChild){
            range.setStartAfter(el.lastChild);
            frag = range.createContextualFragment(html);
            el.appendChild(frag);
            return el.lastChild;
        }else{
            el.innerHTML = html;
            return el.lastChild;
        }
    case "afterend":
        range.setStartAfter(el);
        frag = range.createContextualFragment(html);
        el.parentNode.insertBefore(frag, el.nextSibling);
        return el.nextSibling;
    }
    throw 'Illegal insertion point -> "' + where + '"';
}

MK.create = function(tagName, o) {
    var el = document.createElement(tagName);
    MK.set(el, o);

    return el;
};

MK.append = function(parentEl, tagName, o) {
    var el = MK.create(tagName, o);
    parentEl.appendChild(el);
    return el;
};

MK.appendHtml = function(parentEl, html) {
    return MK.insertHtml('beforeend', parentEl, html);
}

MK.appendEl = function(parentEl, el) {
    parentEl.appendChild(el);
    return el;
};

MK.insertBefore = function(sibling, tagName, o) {
    var el = MK.create(tagName, o);
    sibling.parentNode.insertBefore(el, sibling);
    return el;
};

MK.insertAfter = function(sibling, tagName, o) {
    var el = MK.create(tagName, o);
    sibling.parentNode.insertBefore(el, sibling['nextSibling']);
    return el;
};

MK.insertFirst = function(parentEl, tagName, o) {
    var el = MK.create(tagName, o);
    parentEl.insertBefore(el, parentEl.firstChild);
    return el;
};

MK.insertFirstHtml = function(parentEl, html) {
    return MK.insertHtml('afterBegin', parentEl, html);
}


MK.remove = function(el) {
    var f = function(el) {
        el.parentNode.removeChild(el);
    };

    MK.batch(el, f);
};

MK.decodeJSON = function(json) {
    return eval("(" + json + ')');
};

// o = {
//        disableForm: function(), enableForm: function(),
//        urlFn: function()
//        callback: function() ,obj: instance , override: boolean,
MK.ajaxFormSubmit = function(formEl, o) {
    var callback = o.callback;
    var obj = o.obj;
    var override = o.override;
    var urlFn = o.urlFn;

    var scope = formEl;

    if (override) {
        if (override === true) {
            scope = obj;
        } else {
            scope = override;
        }
    }

    var beforeSubmit = function() {
        for(var i=0; i<formEl.elements.length; i++) { 
            formEl.elements[i].disabled = true; 
        } 
        if (o.disableForm) {
            o.disableForm.call(scope, formEl, obj);
        }

        var submitButtonEl = _Q('input[type=submit]', formEl);

        if (submitButtonEl) {
            /*
            MK.insertAfter(submitButtonEl,
                'img', {
                    'src': '/img/loading.gif',
                    'class': 'ajax-loading'
                });
                */
        }
        MK.remove(_QL('.errorlist', formEl));
    };

    var handleGo = function(data) {
        window.location.pathname = data;
    };

    var handleFormError = function(data) {
        MK.forEach(data, function(id, error_list) {
                var ulEl = MK.insertAfter(_Q('#id_'+id, formEl), 'ul', {
                        'class': 'errorlist'});
                error_list.forEach(function(error) {
                        MK.append(ulEl, 'li', {
                                'content': error
                            });
                    });
            });

        var element = _Q('tr:contains(errorlist) label', formEl) || _Q('p:contains(errorlist) label', formEl);
        if (element) {
            element = document.getElementById(element.getAttribute('for') || element.getAttribute('htmlFor'));
            element.focus();
            element.select();
        }
    };

    var submitFn=null;

    var handleLoginRequired = function(data) {
        MK.config.loginFn(function() {
                submitFn();
            }, data);
    };

    var enableForm = function() {
        // MK.remove(_Q('.ajax-loading', formEl));
        for(var i=0; i<formEl.elements.length; i++) { 
            formEl.elements[i].disabled = false; 
        } 
        if (o.enableForm) {
            o.enableForm.call(scope, formEl, obj);
        }
    };

    var afterResponse = function(response) {
        var action = response.action || {};

        enableForm();

        if (action["go"]) {
            handleGo(action["go"]);
            return;
        }

        action["form-error"] && handleFormError(action["form-error"]);

        if (action["login-required"]) {
            handleLoginRequired(action["login-required"]);
            return;
        }

        if (callback) {
            callback.call(scope, response.result, action.callback, formEl, obj);
        }
    };

    submitFn = function() {
        var Connect = YAHOO.util.Connect;

        Connect.setForm(formEl);
        beforeSubmit();

        var url = formEl['action'];
        if (urlFn) {
            url = urlFn(url);
        }
        Connect.asyncRequest('POST', url, {
                success: function(response) {
                    var result = null;
                    try {
                        result = MK.decodeJSON(response.responseText);
                    } catch(e) { result = {'result': false}; }

                    afterResponse(result);
                },
                failure: function(resp) {
                    enableForm();
                    // TODO:
                },
                timeout: 20000
            });
    };

    submitFn();
};


MK.hijackForm = function(o) {
    Event.on(o.formEl, 'submit', function(ev) {
            Event.stopEvent(ev);
            var formEl = MK.findAncestor(Event.getTarget(ev), 'FORM');

            if (o.preFn) {
                var scope = formEl;
                if (o.override) {
                    if (o.override === true) {
                        scope = o.obj;
                    } else {
                        scope = o.override;
                    }
                }
                if (o.preFn.call(scope, formEl, o)===false) {
                    return;
                }
            }

            MK.ajaxFormSubmit(formEl, o);
        });
};

MK.hijackForm.jsonFormat = function(url) {
    return url+'?format=json';
};

MK.subtraction = function(a,b) {
    var result = [];
    var ai, bi=0;
    var i;
    var found;

    for (ai=0; ai<a.length; ai++) {
        found=false;
        for (i=0; i<b.length; i++) {
            if (a[ai]===b[bi]) {
                found=true;
                bi += (bi>=b.length-1) ? -bi : 1;
                break;
            }

            bi += (bi>=b.length-1) ? -bi : 1;
        }

        if (!found) {
            result[result.length] = a[ai];
        }
    }

    return result;
};

MK.Joiner = function(joinFn, o, override) {
    this.size = 0;
    this.active = 0;
    this.thread = [];

    this.init(joinFn, o, override);
};

MK.Joiner.prototype = {
    init: function(joinFn, o, override) {
        var scope = window;
        if (override) {
            if (override === true) {
                scope = obj;
            } else {
                scope = override;
            }
        }
        this.join = {
            'fn': joinFn,
            'obj': o,
            'scope': scope
        };
    },
    create: function(callback, o, override) {
        var scope = window;
        if (override) {
            if (override === true) {
                scope = obj;
            } else {
                scope = override;
            }
        }
        this.thread[this.size] = {
            'fn': callback,
            'obj': o,
            'scope': scope
        };

        this.size++;
    },
    start: function() {
        for (var i=0; i<this.size; i++) {
            var f = this.thread[i];
            f.fn.call(f.scope, f.obj);
        }
        this.active = this.size;

        if (this.size==0) {
            if (this.active==0) {
                var f = this.join;
                f.fn.call(f.scope, f.obj);
            }
        }
    },
    stop: function() {
        this.active--;

        if (this.active==0) {
            var f = this.join;
            f.fn.call(f.scope, f.obj);
        }
    }
};

//
MK.AjaxDialog = function(el, userConfig) {
	YAHOO.widget.Dialog.superclass.constructor.call(this, el, userConfig);
};

YAHOO.extend(MK.AjaxDialog, YAHOO.widget.Dialog);

MK.AjaxDialog.prototype.initDefaultConfig = function() {
	MK.AjaxDialog.superclass.initDefaultConfig.call(this);

    this.cfg.addProperty("destroyOnHide", { suppressEvent:true } );
};

MK.AjaxDialog.prototype.init = function(el, userConfig) {
    MK.AjaxDialog.superclass.init.call(this, el);

	this.beforeInitEvent.fire(MK.AjaxDialog);

	this.cfg.queueProperty("fixedcenter", true);
	this.cfg.queueProperty("visible", false);
	this.cfg.queueProperty("constraintoviewport", true);
	this.cfg.queueProperty("draggable", false);
	this.cfg.queueProperty("modal", true);

    var kl = new YAHOO.util.KeyListener(document, { keys:27 }, {
            fn: this.cancel, 
            scope: this, 
            correctScope: true 
        } ); 

    this.cfg.queueProperty("keylisteners", kl); 

	if (userConfig) {
		this.cfg.applyConfig(userConfig, true);
	}

    if (this.cfg.getProperty("destroyOnHide")) {
        this.hideEvent.subscribe(this.destroy, this, true);
    }

	this.initEvent.fire(MK.AjaxDialog);

};

MK.AjaxDialog.prototype.setFormConfig = function(o) {
    this.formConfig = o;

    o.orgConfig = {
        callback: o.callback,
        obj : o.obj,
        override: o.override
    };
    o.obj = this;
    o.override = true;

    o.disableForm = function(formEl) {
        var buttons = _QL('.button-group button', this.element);
        buttons.forEach(function(q) {
                q.disabled = true;
            });
    };
    o.enableForm = function(formEl) {
        var buttons = _QL('.button-group button', this.element);
        buttons.forEach(function(q) {
                q.disabled = false;
            });
    };
    o.callback = function(response, data, formEl) {
        if (o.orgConfig.callback) {
            var scope = formEl;
            if (o.orgConfig.override) {
                if (o.orgConfig.override === true) {
                    scope = o.orgConfig.obj;
                } else {
                    scope = o.orgConfig.override;
                }
            }
            o.orgConfig.callback.call(scope, response, data, formEl, o.orgConfig.obj);
        }
        if (response) {
            this.hide();
        }
    };
};

MK.AjaxDialog.prototype.submit = function() {
	if (this.validate()) {
		this.beforeSubmitEvent.fire();
        
        MK.ajaxFormSubmit(this.form, this.formConfig);
		
        this.submitEvent.fire();
		return true;
	} else {
		return false;
	}
};

