/*
 * MethodChain Framwork
 * Copyright(c) 2008-2009, 김영보(YoungBo Kim). All rights reserved.
 * licensed under the MIT-style License.
 * http://www.MethodChain.com
 * version: 2.0.0
 */
var MethodChain = function(){
    version = '2.0.0';
};

MethodChain.prototype = {
    language: 'kr',    //'en','jp'
    chain: null,
    chainNode: null,
    dup: [],
    own: null,
    idNumber: 1,

    lineCount: 0,
    dataMapNumber: 100,

    emptyFn: function(){ },

    get: function(el){
        this.chain = typeof el === 'string' ? document.getElementById(el) : (el ? el : null);
        return this;
    },

    gets: function(els){
        els = els || [];
        if (typeof els == 'string'){
            els = [els];
        }
        var i = 0,
             len = els.length,
             rt = [];
        for (; i < len; i++){
            rt[rt.length] = this.get(els[i]).chain;
        }
        this.chain = rt;
        return this;
    },

    setOwn: function(el){
        this.own = null;
        if (typeof el == 'string' || el.tagName){
            if (!(el = this.get(el).chain)) {
                return this;
            }
        }
        if (!el.id) {
            el.id = this.id(false, 'mc_own_').chain;
        }
        this.own = el, this.chain = el;
        return this;
    },

    set: function(pty, type, vl){
        vl = vl || this.chain;
        if (type === undefined || type === ''){
            this[pty] = vl;
            return this;
        }
        var tp,
            fn = function(typ){
                return typeof typ.pop == 'function' && typ.constructor == Array;
            }

        if (typeof type === 'number'){
            tp = typeof pty === 'string' ? tp = this[pty] : pty;
            if (!tp || !(fn(tp))){
                this[pty] = [];
                tp = this[pty];
            }
            tp[type] = vl;
            return this;
        }

        if (typeof type === 'string'){
            if (typeof pty === 'string'){
                tp = this[pty];
                if (!tp || typeof tp == 'string' || fn(tp)){
                    this[pty] = {};
                    tp = this[pty];
                }
                tp[type] = vl;
            } else {
                if (typeof tp == 'string' || fn(pty)){
                    this[pty] = {};
                    tp = this[pty];
                    tp[type] = vl;
                } else {
                    pty[type] = vl;
                }
            }
        }
        return this;
    },

    removeSet: function(pty){
        delete mc[pty];
        return this;
    },

    setThis: function(that, pty, chn){
        chn = chn || this.chain;
        if (pty){
            that[pty] = chn;
        }
        return this;
    },

    setChain: function(value){
        this.chain = value;
        return this;
    },

    chainDup: function(){
        this.dup = this.chain;
        return this;
    },

    allocate : function(target, source, replace){
        if (target && source && typeof source == 'object') {
            for (var pty in source) {
                if (replace !== true) {
                    target[pty] = source[pty];
                } else if (target[pty] === undefined) {
                    target[pty] = source[pty];
                }
            }
        }
        this.chain = target;
        return this;
    },

    setPrototype: function(target, source){
        if (target && source) {
            var tpt = target.prototype;
            for (var pt in source) {
                tpt[pt] = source[pt];
            }
        }
        this.chain = target;
        return this;
    },

    // based on work by Alex Arnell
    extend: function(ch, pt, sup){
        var fn = function(){ },
             spt = pt.prototype;
        fn.prototype = spt;

        ch.prototype = new fn();
        ch.prototype.constructor = ch;
        ch.superclass = spt;

        if (spt.constructor == Object.prototype.constructor) {
            spt.constructor = pt;
        }
        if (sup) {
            if (!ch.prototype) {
                ch.prototype = new mc.emptyFn();
            }
            this.setPrototype(ch, sup);
        }
        return this;
    },

    each: function(obj, fn, scope, type){
        fn = fn || mc.emptyFn;
        scope = scope || this;
        type = (type || this.getType(obj).chain).toLowerCase();

        switch (type){
            case 'array':
            case 'nodelist':
                this.eachArray(obj, fn, scope);
                return this;
            case 'hash':
                this.eachHash(obj, fn, scope);
                return this;
        }
        fn.call(scope, obj, '');
        return this;
    },

    eachChain: function(fn, scope){
        this.each(this.chain, fn, (scope || this));
        return this;
    },

    getType: function(obj){
        if (this.isEmpty(obj).chain) {
            this.chain = 'empty';
            return this;
        }

        var type = typeof obj;
        if (type == 'object' && obj.nodeType) {
            this.chain = obj.nodeType == 2 ? 'attribute' : 'element';
            if (obj.nodeType == 3){
                this.chain = (/\S/).test(obj.nodeValue) ? 'textNode' : 'whitespace';
            }
            return this;
        }

        if (type == 'object'){
            if (typeof obj.length == 'number' && (typeof obj.item == 'function' || typeof obj.item == 'string')){
                this.chain = 'nodelist';
                return this;
            }
            if (typeof obj.pop == 'function' && obj.constructor == Array){
                this.chain = 'array';
                return this;
            }
            if (obj.constructor == Date){
                this.chain = 'date';
                return this;
            }
            for (var pty in obj){
                if (obj.hasOwnProperty(pty)){
                    this.chain = 'hash';
                    return this;
                }
                break;
            }
        }

        if (type == 'function'){
            if (obj.constructor == RegExp){
                this.chain = 'regexp';
                return this;
            }
        }

        this.chain = type;
        return this;
    },

    call: function() {
        var args = arguments, 
             fn = args[0], 
             scope = args[1];
        fn = fn || mc.emptyFn;
        scope = scope || this;
        this.chain = fn.apply(scope, Array.prototype.slice.call(arguments, 2));

        return this;
    },

    returnCall: function(fn, scope, args) {
        var sfn = fn, 
             sscope = scope, 
             sargs = args;
        return function(){
            mc.call(sfn, sscope, sargs);
        }
        return this;
    },

    custom: function(fn) {
        (fn || mc.emptyFn).apply(this, arguments);
        return this;
    },

    getBody: function(){
        this.chain = document.body || document.documentElement;
        return this;
    },

    createElement: function(tag, id, prefix) {
        tag = tag || 'div';
        var el = document.createElement(tag);
        el.id = id || mc.id(false, prefix).chain;

        this.chain = el;
        return this;
    },

    id: function(el, prefix){
        if (typeof el == 'object' && el.id){
            this.chain = el.id;
            return this;
        }

        prefix = prefix || 'mc_id_';
        this.chain = (prefix + (mc.idNumber++));
        return this;
    },

    select: function(selector, root){
        if (document.querySelectorAll){
            root = root || document;
            this.chain = root.querySelectorAll(selector);
        } else {
            this.Selector = mc.Selector.select(selector, root);
            this.chain = this.Selector.chain;
        }
        return this;
    },

    getClassFor: function(pty){
        if (mc.IE){
            this.chain = pty == 'className' ? 'class' : pty == 'htmlFor' ? 'for' : pty;
        } else {
            this.chain = pty == 'class' ? 'className' : pty == 'for' ? 'htmlFor' : pty;
        }
        return this;
    },

    setClassFor: function(pty){
        this.chain = pty == 'className' ? 'class' : pty == 'htmlFor' ? 'for' : pty;
        return this;
    },

	delay: function(){
        return function(){
            var args = arguments, 
                 fn = args[0], 
                 delay = args[1], 
                 scope = args[2];
            var params = Array.prototype.slice.call(arguments, 3);
            return setTimeout(function(){
                return fn.apply(scope || null, params);
            }, delay);
        };
	}(),

	periodical: function(){
        return function(){
            var args = arguments, 
                 fn = args[0], 
                 interval = args[1], 
                 scope = args[2];
            var params = Array.prototype.slice.call(arguments, 3);
            return setInterval(function(){
                return fn.apply(scope || null, params);
            }, interval);
        };
	}(),

	clearTimer: function(timer){
        clearTimeout(timer);
        clearInterval(timer);
        return this;
	},

    convertPixel: function(el, value){
        el = !el ? this.own : typeof el === 'string' ? this.get(el).chain : el;
        if (el.currentStyle){
            var sr = el.currentStyle.right;
            el.style.right = value || 0;
            value = el.style.pixelRight;
            el.style.right = sr;

            this.chain = value + 'px';
        }
        return this;
    },

    splitNumAlpha: function(value){
        if (!value) {
            this.chain = null;
            return this;
        }
        var dist = value.toString().match(mc.numericAlphaExp), 
             num;
        if (dist){
            num = parseInt(dist[2], 10);
            if (dist[1]) {
                num = num * -1;
            }
        }
        this.chain = dist ? ([num, dist[3] ? dist[3] : mc.DEFAULT_UNITS]) : null;
        return this;
    },

    newTemplate: function(){
        var tem = [], 
            args = arguments, 
            len = args.length, 
            i = 0;
        for (; i < len; i++) {
            tem.push(args[i]);
        }
        this.Template = new mc.TemplateClass(tem.join(''));
        return this;
    },

    eachJson: function(json, fn, that){
        that = that || this;
        var inFn = function(json, fn, that, pl){
            pl.eachArray(json, function(ary){
                pl.eachHash(ary, function(k, vl){
                    mc.isArray(vl).chain ? inFn(vl, fn, that, pl) : fn.call(that, k, vl);
                }, pl);
            }, pl);
        }
        inFn(json, fn, that, this);
        return this;
	},

    evalJson: function(json, st) {
        try {
            this.chain = eval('(' + json + ')');
        } catch (e){
            throw 'JSON convert Error';
        };
        if (st == true) {
            this.JsonData = this.chain;
        }
        return this;
    },

    namespace: function(){
        var i,
            arg = arguments,
            len = arg.length;
        for (i = 0; i < len; i++){
            sp = arg[i].split('.');
            pt = window[sp[0]] = window[sp[0]] = window[sp[0]] || {};
            pt[sp[1]] = pt[sp[1]] || {};
        }
    },

    resultShow: function(value, el){   // for test
        mc.lineCount++;
        var ch = document.createElement('div');
        ch.id = 'mc_result_' + mc.lineCount;
        document.getElementById(el || 'showArea').appendChild(ch);

        var result = document.createTextNode(mc.lineCount + '. ' + value);
        document.getElementById(ch.id).appendChild(result);
        return this;
    },

    //------Compare ------
    isNull: function(obj){
        this.chain = obj === null;
        return this;
    },

    isUndefined: function(obj){
        this.chain = typeof obj === 'undefined';
        return this;
    },

    isBoolean: function(obj){
        this.chain = typeof obj === 'boolean';
        return this;
    },

    isString: function(obj){
        this.chain = typeof obj === 'string';
        return this;
    },

    isNumber: function(obj){
        if (obj) {
            var ck = obj * 1;
            this.chain = (isNaN(ck) || typeof ck != 'number') ? false : true;
        } else {
            this.chain = false;
        }
        return this;
    },

    isFunction: function(obj){
        this.chain = typeof obj === 'function';
        return this;
    },

    isArray: function(obj){
        mc.chain = !obj ? false : typeof obj === 'object' && typeof obj.pop === 'function' && obj.constructor == Array;
        return this;
    },

    isObject: function(obj, type){
        this.chain = (obj && (typeof obj === 'object' || (!type && this.isFunction(obj).chain))) || false;
        return this;
    },

    isDate: function(obj){
        this.chain = (obj instanceof Date);
        return this;
    },

    isEmpty : function(obj){
        this.chain = (obj === null || obj === undefined || obj === '');
        return this;
    },

    isValue : function(obj){
        this.chain = (obj !== null && obj !== undefined && obj !== '');
        return this;
    },

    isElement : function(obj){
        if (typeof obj === 'string'){
            obj = mc.get(obj).chain;
        }
        this.chain = obj ? (obj.own ? obj.own.nodeType == 1 : obj.nodeType == 1) : false;
        return this;
    },

    isBlank : function(vl){
        this.chain = mc.allSpaceExp.test(vl);
        return this;
    },

    isBodyHtml : function(el){
        this.chain = (/^(?:body|html)$/i).test(el.tagName);
        return this;
    },

    isCssUnit: function(unit){
        this.chain = mc.unitCheckExp.test(unit);
        return this;
    },

    isInstance: function(ist, obj){
        this.chain = ist instanceof obj;
        return this;
    },

    isInput: function(el){
        el = !el ? this.own : typeof el === 'string' ? this.get(el).chain : el;
        this.chain = false;
        if (el && el.tagName){
            var tn = el.tagName.toUpperCase();
            this.chain = (tn == 'INPUT' || tn == 'TEXTAREA' || tn == 'SELECT') ? true : false;
        }
        return this;
    },

    //-----String-----
    defineValue: '',
    outScripts: '',

    trim: function(base){
        this.chain = String(base).replace(mc.trimExp, '');
        return this;
    },

    truncate: function(base, len, rp){
        len = len || 20;
        rp = this.isEmpty(rp).chain ? '...' : rp;
        this.chain = base.length > len ? base.slice(0, len - rp.length) + rp : String(base);
        return this;
    },

    defaultValue: function(value){
        this.chain = value ? this.defineValue = value : this.defineValue;
        return this;
    },

    encodeHTML: function(base){
        this.chain = base.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/"/g, '&quot;');
        return this;
    },

    decodeHTML: function(base) {
        this.chain = base.replace(/&amp;/g,'&').replace(/&lt;/g,'<').replace(/&gt;/g,'>').replace(/&quot;/g, '"');
        return this;
    },

    firstLetter: function(base) {
        this.chain = base.charAt(0).toUpperCase() + base.substring(1).toLowerCase();
        return this;
    },

    stripTags: function(base) {
        this.chain = String(base).replace(mc.stripTagsExp, '');
        return this;
    },

    stripScripts: function(base) {
        this.chain = String(base).replace(mc.stripScriptsExp, '');
        return this;
    },

    splitScripts: function(base) {
        var inScripts = this.outScripts = '';
        this.outScripts = base.replace(mc.stripScriptsExp, function(){
            inScripts = arguments[1] + '\n';
            return '';
        });
        this.chain = inScripts;
        return this;
    },

    camelCase: function(base){
        this.chain = base || '';
        if (base){
            this.chain = base.replace(mc.camelCaseExp, function(ep, cvt){
                    return cvt.charAt(1).toUpperCase();
                }
            )
        };
        return this;
    },

    underBar: function(base){
        this.chain = base || '';
        if (base){
            this.chain = base.replace(mc.dasherizeExp, function(ep, cvt){
                    return cvt.charAt(1).toUpperCase();
                }
            )
        };
        return this;
    },

    colorToHex: function(base){
        if (mc.rgb17Colors[base]){
            this.chain = '#' + mc.rgb17Colors[base];
            return this;
        }

        var first = base.charAt(0),
             sep, 
             i, 
             hex, 
             rrggbb = '';
        if (first == 'r') { //rgb(255, 255, 255)
            sep = base.match(mc.rgbValueExp);
            if (sep) {
                for (i = 1; i < 4; i++) {
                    hex = parseInt(sep[i], 10).toString(16);
                    rrggbb += hex.length == 1 ? '0' + hex : hex;
                }
            }
            this.chain = rrggbb ? '#' + rrggbb.toLowerCase() : null;
            return this;
        };

        if (first == '#') {
            if (base.length == 4){     //#abc
                for (i = 1; i < 4; i++){
                    rrggbb +=  base.charAt(i) + base.charAt(i);
                }
            } else if (base.length == 7){
                rrggbb = base.substr(1);
            }
            this.chain = rrggbb ? '#' + rrggbb.toLowerCase() : null;
            return this;
        }

        if (base.length == 6) {  //000000
            this.chain = '#' + base;
            return this;
        };
        this.chain = rrggbb ? rrggbb.toLowerCase() : null;
        return this;
    },

    matchText: function(base, value){
        if (this.isNumber(value).chain){
            value = value.toString();
        }
        if (this.isString(value).chain){
            value = [value];
        }

        this.chain = base.replace(mc.templateExp, function(src, key){
                return value[key] ? value[key] : '';
        });
        return this;
    },

    escapeExp: function(str) {
        this.chain = String(str).replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1');
        return this;
    } ,

    leftPad: function(tg, len, ch) {
        var rs = new String(tg);
        if (rs.length >= len){
            this.chain = tg;
            return this;
        }
        if (ch == null) {
            ch = ' ';
        }
        while (rs.length < len) {
            rs = ch + rs;
        };
        this.chain = rs;
        return this;
    },

    isInclude: function(bs, cp, dt){
        if (!dt){dt = '';}
        this.chain = (dt) ? (dt + bs + dt).indexOf(dt + cp + dt) > -1 : bs.indexOf(cp) > -1;
        return this;
	},

    splitTbody: function(base, attach){
        var sbd = base.split(/<\/tbody>/ig);
        if (!sbd[1]){
            sbd = base.split(/<\/table>/ig);
            sbd[0] += '<tbody>';
        }
        this.chain = sbd[0] + attach + '</tbody>' + (sbd[1] || '</table>');;
        return this;
	} ,

    nonSpace: function(vl){
        if (mc.isEmpty(vl).chain || (typeof vl == 'string' && vl.length == 0)){
            this.chain = '&#160;';
        } else {
            this.chain = vl;
        }
        return this;
    },

    isLocalChar: function(ch){
        if (ch){
            var uniCode = ch.charCodeAt(0);
            this.chain = (uniCode > 12592 && uniCode < 55204) ? true : false;
        } else {
            this.chain = false;
        }
        return this;
    },

    isLocalChars: function(chrs){
        if (chrs){
            var len = chrs.length,
                i;
            for (i = 0; i < len; i++){
                if (this.chain = this.isLocalChar(chrs.charAt(i)).chain){
                    return this;
                };
            }
        }
        this.chain = false;
        return this;
    },

    zeroToValue: function(value){
        this.chain = value || '';
        if (value == 0){
            this.chain = '0';
        }
        return this;
    },

    insertComma: function(value, len){
        if (value){
            len = len ? len : 3;
            if (len != this.commaLength){
                this.commaRegExp = new RegExp('(^[+-]?\\d+)(\\d{' + len + '})');
            }
            value = value.toString();
            while (this.commaRegExp.test(value)){
                value = value.replace(this.commaRegExp, '$1' + ',' + '$2');
            }
            this.commaLength = len;
        }
        this.chain = value;
        return this;
    },

    removeComma: function(value){
        if (value){
            value = value.toString();
        }
        this.chain = value && /,/.test(value) ? value.replace(/,/g, '') : value;
        return this;
    },

    //------ document -----
    getHtmlBody : function(){
        this.chain = mc.Strict ? document.documentElement : document.body;
        return this;
    },

    getDocWidth: function() {
        var sw = this.getHtmlBody().chain['scrollWidth'];
        this.chain = Math.max(sw, this.getViewportWidth().chain);
        return this;
    },

    getDocHeight: function() {
        var sh = this.getHtmlBody().chain['scrollHeight'];
        this.chain = Math.max(sh, this.getViewportHeight().chain);
        return this;
    },

    getDocWH: function() {
        this.chain = [this.getDocWidth().chain, this.getDocHeight().chain];
        return this;
    },

    getViewportWidth: function() {
        this.chain = mc.IE ? this.getHtmlBody().chain['clientWidth'] : self.innerWidth;
        return this;
    },

    getViewportHeight: function() {
        this.chain = mc.IE ? this.getHtmlBody().chain['clientHeight'] : self.innerHeight;
        return this;
    },

    getViewportWH: function(){
        this.chain = [this.getViewportWidth().chain, this.getViewportHeight().chain];
        return this;
    },

    getDocScrollLeft: function() {
        this.chain = window.pageXOffset || this.getHtmlBody().chain['scrollLeft'];
        return this;
    },

    getDocScrollTop: function() {
        this.chain = window.pageYOffset || this.getHtmlBody().chain['scrollTop'];
        return this;
    },

    getDocScrollLT: function() {
        this.chain = [this.getDocScrollLeft().chain, this.getDocScrollTop().chain];
        return this;
    },

    //----- Array -----
    stringToArray: function(base) {
        this.chain = mc.isArray(base).chain ? base : !base ? [] : base.split('');
        return this;
    },

    toArray: function(base) {
        if (!base){
            this.chain = [];
        } else {
            this.chain = mc.isArray(base).chain ? base : [base];
        }
        return this;
    },

    commaSplit: function(base) {
        if (/,/.test(base)) {
            var comma = base.split(','), 
                len = comma.length, 
                results = [], 
                i;
            for (i = 0; i < len; i++){
                results[i] = this.trim(comma[i]).chain;
            }
            this.chain = results;
        } else {
            this.chain = mc.isArray(base).chain ? base : [base];
        }
        return this;
    },

	isContains: function(base, cp){
        this.chain = this.indexOfArray(base, cp).chain != -1;
        return this;
	},

	indexOfArray: function(base, cp){
        if (mc.isArray(base).chain) {
            for (var i = 0, len = base.length; i < len; i++){
                if (base[i] == cp){
                    this.chain = i;
                    return this;
                }
            }
        }
        this.chain = -1;
        return this;
	},

    eachArray: function(ary, fn, scope) {
        scope = scope || this;
        if (!ary){
            ary = [];
        }
        if (typeof ary === 'string'){
            ary = [ary];
        }

        var i,
            len =  ary.length;
        for (i = 0; i < len; i++) {
            fn.call(scope, ary[i], i);
        }
        return this;
    },

    collectArray : function(ary, fn, scope) {
        scope = scope || this;
        if (!ary){
            ary = [];
        }

        var results = [], 
             i, 
             len = ary.length;
        for (i = 0; i < len; i++){
            results.push(fn.call(scope, ary[i], i));
        };

        this.chain = results;
        return this;
    },

    appendInit: function(init, base, fn, scope) {
        scope = scope || this;
        this.collectArray(base, function(value, index) {
            init = fn.call(scope, init, value, index);
        });

        this.chain = init;
        return this;
    },

    collectExp : function(re, base, fn, scope) {
        if (!this.isString(re).chain && this.isArray(base).chain) {
            scope = scope || this;
            var exp = new RegExp(re);
            var results = [], 
                 i, 
                 len = base.length;
            for (i = 0; i < len; i++) {
                if (base[i].match(exp)) {
                    results.push(fn.call(scope, base[i], i));
                }
            };
            this.chain = results;
            return this;
        };
        this.chain = false;
        return this;
    },

    _collectValue : function(op, base, fn, scope) {
        scope = scope || this;
        var result = [],
             i,
             len = base.length,
             value,
             cmp;

        var set = function(value, i){
            result[0] = value;
            result[1] = i;
            cmp = value;
        };

        var fnUse = this.isFunction(fn).chain;
        for (i = 0; i < len; i++) {
            value = fnUse ? fn.call(scope, base[i], i) : base[i];
            if (!cmp){
                set(value, i);
                continue;
            }
            if (op == 'Max' && value > cmp) {
                set(value, i);
            } else if (op == 'Min' && value < cmp) {
                set(value, i);
            } else if (op == 'Eq' && value == cmp){
                result.push(value);
                result.push(i);
            }
        };
        return result;
    },

    collectMax : function(base, fn, scope) {
        this.chain = this._collectValue('Max', base, fn, scope);
        return this;
    },

    collectMin : function(base, fn, scope) {
        this.chain = this._collectValue('Min', base, fn, scope);
        return this;
    },

    collectEq : function(base, fn, scope) {
        this.chain = this._collectValue('Eq', base, fn, scope);
        return this;
    },

    compactArray: function(base) {
        var results = [],
             i,
             len = base.length;

        for (i = 0; i < len; i++){
            if (!this.isEmpty(base[i]).chain){
                results.push(base[i]);
            }
        };
        this.chain = results;
        return this;
    },

    sortArray: function(data, ad, fn) {
        var dsc = (ad || 'A').toUpperCase() == 'A' ? 1 : -1;
        var rst = [],
             i = 0,
             len = data.length;

        for (; i < len; i++){
            rst[i] = data[i];
        }

        fn = fn || function(a, b){
            return a < b ? -1 : (a > b ? 1 : 0);
        };
        rst.sort(function(a, b){
            return fn(a, b) * dsc;
        });

        this.chain = rst;
        return this;
    },

    mergeArray: function() {
        var args = arguments,
             results = [],
             i,
             len = args.length,
             ag,
             j,
             nxt;

        for (i = 0; i < len; i++){
            if (ag = args[i]){
                if (typeof ag == 'string'){
                    ag = mc.commaSplit(ag).chain;
                }
                for (j = 0, nxt = ag.length; j < nxt; j++){
                    results.push(ag[j]);
                }
            };
        };
        this.chain = results;
        return this;
    },

    getTotal: function(base) {
        var total = 0,
             i,
             len = base.length;

        for (i = 0; i < len; i++){
            total += base[i];
        };
        this.chain = total;
        return this;
    },

    setStartEnd: function(base, start, end){
        var s,
             len = base.length - 1;

        start = mc.isEmpty(start).chain ? 0 : parseInt(start, 10);
        end = mc.isEmpty(end).chain ? len : parseInt(end, 10);

        if (end > len){
            end = len;
        }
        if (start > end){
            s = start, start = end, end = s;
        }
        this.chain = [start, end];
        return this;
    },

    getScope: function(base, start, end){
        if (!base || base.length < 1){
            this.chain = [];
            return this;
        }
        var result = [];
        mc.setStartEnd(base, start, end);
        start = this.chain[0], end = this.chain[1];

        for (; start <= end; start++){
            result[result.length] = base[start];
        }
        this.chain = result;
        return this;
    },

    getScopeDesc: function(base, end, start){
        if (!base || base.length < 1){
            this.chain = [];
            return this;
        }
        var result = [];
        mc.setStartEnd(base, start, end);
        start = this.chain[0], end = this.chain[1];

        for (; end >= start; end--){
            result[result.length] = base[end];
        }
        this.chain = result;
        return this;
    },

    addIndex: function(base, index, value){
        this.chain = [];
        var i, 
             len = base.length;
        if (index >= len){
            this.chain = base;
            this.chain[len] = value;
            return this;
        }
        for (i = 0; i < len; i++){
            if (index == i){
                this.chain.push(value);
            }
            this.chain.push(base[i]);
        }
        return this;
    },

    removeIndex: function(base, index){
        this.chain = [];
        var i,
             len = base.length;

        for (i = 0; i < len; i++){
            if (index != i){
                this.chain.push(base[i]);
            }
        }
        return this;
    },

    appendArray: function(base, target, exist){
        var rst = exist ? false : this.isContains(base, target).chain;
        if (!rst){
            base[base.length] = target;
        }
        this.chain = base;
        return this;
    },

    //----- Hash -----
    setHash: function(){
        this.Hash = {};
        var results = {}, 
             args = arguments;

        this.eachArray(args, function(plus){
            this.addHash(this.Hash, plus, false);
            this.eachHash(mc.chain, function(key, value){
                results[key] = value;
            })
        }, this)

        this.chain = results;
        return this;
    },

    addHash: function(target, hash, rp){
        var result = {}, 
             exist;
        this.eachHash(hash, function(key, value){
            exist = target.hasOwnProperty(key);
            if (!exist || exist && rp != true){
                target[key] = value;
                result[key] = value;
            };
        }, this);

        this.chain = result;
        return this;
    },

    addKeyValue: function(target, key, value, replace){
        this.chain = {};
        var exist = target.hasOwnProperty(key);
        if (!exist || exist && replace != true){
            target[key] = value;
            this.chain[key] = value;
        };
        return this;
    },

    getKeyOf: function(target, key) {
        this.chain = null;
        if (key) {
            this.chain = (target.hasOwnProperty(key)) ? target[key] : null;
        }
        return this;
    },

    getValueOf: function(target, value, all) {
        var results = [], 
             key;
        for (key in target){
            if (target.hasOwnProperty(key) && target[key] == value){
                results.push(key);
                if (!all) {break;}
            }
        }
        this.chain = results[0] ? results : null;
        return this;
    },

    getKeyValueOf: function(target, key, value) {
        this.chain = null;
        if (key) {
            this.chain = target[key] == value ? target : null;
        }
        return this;
    },

    getHashList: function(target, list) {
        var rtnList = [];
        this.eachHash(target, function(key, value){
            list ? rtnList.push(value) : rtnList.push(key);
        })
        this.chain = rtnList;
        return this;
    },

    getCount: function(target) {
        var count = 0, 
             key;
        this.eachHash(target, function(){
            count++;
        });
        this.chain = count;
        return this;
    },

    getRange: function(target, start, end) {
        start = start || 0;
        end = end || Number.MAX_VALUE;
        var results = { }, 
             key, 
             count = 0;

        this.eachHash(target, function(key){
            if (count >= start && count <= end) {
                results[key] = target[key];
            }
            count++;
        });

        this.chain = results;
        return this;
    },

    removeKey: function(target, keys, option) {
        var results = { };
        this.commaSplit(keys)
            .eachArray(mc.chain, function(key, index){
                if (target[key]){
                    results[key] = target[key];
                    option ? target[key] = '' : delete target[key];
                }
            })

        this.chain = results;
        return this;
    },

    removeValue: function(target, values, option){
        var results = { };
        this.commaSplit(values)
            .eachArray(mc.chain, function(rmv){
                this.eachHash(target, function(key, value){
                    if (rmv == value){
                        results[key] = value;
                        option ? delete target[key] : target[key] = '';
                    }
                })
            })
        this.chain = results;
        return this;
    },

    clearHash: function(){
        this.Hash = {};
        return this;
    },

    eachHash: function(target, fn, that){
        that = that || this;
        for (var key in target){
            if (target.hasOwnProperty(key)){
                fn.call(that, key, target[key]);
            }
        }
        return this;
    },

    hashToString: function(tg, deli, ap) {
        var rtn = '',
            key;

        for (key in tg){
            rtn += (key + (deli || '') + tg[key] + (ap || ''));
        }
        this.chain = rtn;
        return this;
    },

    //----- DOM Element -----
    relativeChange: false,
    overflowClip: false,

    focus: function(el){
        el = !el ? this.own : typeof el === 'string' ? this.get(el).chain : el;
        el.focus();
        this.chain = el;
        return this;
    },

    blur: function(el){
        el = !el ? this.own : typeof el === 'string' ? this.get(el).chain : el;
        el.blur();
        this.chain = el;
        return this;
    },

    selected: function(el){
        el = !el ? this.own : typeof el === 'string' ? this.get(el).chain : el;
        el.select();
        this.chain = el;
        return this;
    },

    selectedRange: function(sp, ep, el){
        el = !el ? this.own : typeof el === 'string' ? this.get(el).chain : el;
        var vl = mc.getValue(el).chain, 
             tr;
        if (vl){
            sp = mc.isNumber(sp).chain ? sp : 0;
            ep = mc.isNumber(ep).chain ? ep : vl.length;

            if (el.setSelectionRange){
                el.setSelectionRange(sp, ep);
            } else if (el.createTextRange){
                tr = el.createTextRange();
                tr.moveStart('character', sp);
                tr.moveEnd('character', ep - vl.length);
                tr.select();
            }
        }
        this.chain = [sp, ep];
        return this;
    },

    isVisible: function(ancestor, el){
        el = !el ? this.own : typeof el === 'string' ? this.get(el).chain : el;
        if (!(this.chainNode = el)){
            this.chain = false;
            return this;
        };

        var result = true;
        if (this.getStyle('visibility', el).chain == 'hidden' || this.getStyle('display', el).chain == 'none') {
            result = false;
        }
        if (!ancestor || !result){
            this.chain = result;
            return this;
        }

        while ((el = el.parentNode) && !this.isBodyHtml(el).chain){
            if (this.getStyle('visibility', el).chain == 'hidden' || this.getStyle('display', el).chain == 'none') {
                this.chain = false;
                return this;
            }
        }
        this.chain = true;
        return this;
    },

    setDisplay: function(show, el){
        el = !el ? this.own : typeof el === 'string' ? this.get(el).chain : el;
        show = (show === false ? 'none' : '');
        this.setStyle({display: show}, el);
        return this;
    },

    setVisibility: function(show, el){
        el = !el ? this.own : typeof el === 'string' ? this.get(el).chain : el;
        show = show == false ? 'hidden' : 'visible';
        this.setStyle({visibility: show}, el);
        return this;
    },

    insertAhead: function(target, el){
        target = !target ? this.own : typeof target === 'string' ? this.get(target).chain : target;
        el = !el ? this.own : typeof el === 'string' ? this.get(el).chain : el;
        if (el) {
            el.parentNode.insertBefore(target, el);
        }
        this.chain = target;
        return this;
    },

    insertAfter: function(target, el){
        target = !target ? this.own : typeof target === 'string' ? this.get(target).chain : target;
        el = !el ? this.own : typeof el === 'string' ? this.get(el).chain : el;
        if (el) {
             el.parentNode.insertBefore(target, el.nextSibling);
        }
        this.chain = target;
        return this;
    },

    appendEnd: function(target, el){
        target = !target ? this.own : typeof target === 'string' ? this.get(target).chain : target;
        el = !el ? this.own : typeof el === 'string' ? this.get(el).chain : el;
        if (el) {
             el.appendChild(target);
        }
        this.chain = target;
        return this;
    },

    insertBegin: function(target, el){
        target = !target ? this.own : typeof target === 'string' ? this.get(target).chain : target;
        el = !el ? this.own : typeof el === 'string' ? this.get(el).chain : el;
        if (el)  {
             el.insertBefore(target, el.firstChild);
        }
        this.chain = target;
        return this;
    },

    insertElement: function(adj, target, el){
        adj = adj.toLowerCase();
        switch(adj){
            case 'beforebegin':
                this.insertAhead(target, el);
                return this;
            case 'afterend':
                this.insertAfter(target, el);
                return this;
            case 'beforeend':
                this.appendEnd(target, el);
                return this;
            case 'afterbegin':
                this.insertBegin(target, el);
                return this;
        }
        this.chain = '';
        return this;
    },

    createAppend: function(tag, id, prefix, pt){
        this.createElement(tag, id, prefix)
            .appendEnd(mc.chain, pt);
        return this;
    },

    _setFragment: function(el, content, ab, ch){
        var cr = el.ownerDocument.createRange();
        ab == 'b' ? (ch ? cr.setStartBefore(el.firstChild) : cr.setStartBefore(el))
                  : (ch ? cr.setStartAfter(el.lastChild) : cr.setStartAfter(el));
        return cr.createContextualFragment(content);
    },

    beforeBegin: function(content, el){
        el = !el ? this.own : typeof el === 'string' ? this.get(el).chain : el;
        if (el.insertAdjacentHTML) {
            el.insertAdjacentHTML('BeforeBegin', content);
        } else {
            el.parentNode.insertBefore(this._setFragment(el, content, 'b'), el);
        };
        this.chain = el.previousSibling;
        return this;
    },

    afterEnd: function(content, el){
        el = !el ? this.own : typeof el === 'string' ? this.get(el).chain : el;
        if (el.insertAdjacentHTML) {
            el.insertAdjacentHTML('AfterEnd', content);
        } else {
            el.parentNode.insertBefore(this._setFragment(el, content, 'a'), el.nextSibling);
        };
        this.chain = el.nextSibling;
        return this;
    },

    beforeEnd: function(content, el, cn){
        el = !el ? this.own : typeof el === 'string' ? this.get(el).chain : el;
        if (el.insertAdjacentHTML) {
            el.insertAdjacentHTML('BeforeEnd', content);
        } else {
            if (el.lastChild){
                el.appendChild(this._setFragment(el, content, 'a', 'c'));
            } else {
                el.innerHTML = content;
            }
        };
        this.chain = cn ? mc.getDescendants(false, 'last', el).chain : el.lastChild;
        return this;
    },

    afterBegin: function(content, el){
        el = !el ? this.own : typeof el === 'string' ? this.get(el).chain : el;
        if (el.insertAdjacentHTML) {
            el.insertAdjacentHTML('AfterBegin', content);
        } else {
            if (el.firstChild){
                el.insertBefore((this._setFragment(el, content, 'b', 'c')), el.firstChild);
            } else {
                el.innerHTML = content;
            }
        };
        this.chain = el.firstChild;
        return this;
    },

    insertHTML: function(adj, content, el){
        adj = adj.toLowerCase();
        switch(adj){
            case 'beforebegin':
                this.beforeBegin(content, el);
                return this;
            case 'afterend':
                this.afterEnd(content, el);
                return this;
            case 'beforeend':
                this.beforeEnd(content, el);
                return this;
            case 'afterbegin':
                this.afterBegin(content, el);
                return this;
        }
        this.chain = '';
        return this;
    },

    removeElement: function(el, child){
        el = !el ? this.own : typeof el === 'string' ? this.get(el).chain : el;
        if (child === true){
            var count = el.childNodes || el.children;
            if (count.length > 0) {
                this.chain = '';
                return this;
            }
        };

        if (el && el.parentNode && el.tagName != 'BODY')  {
            el.parentNode.removeChild(el);
        }
        this.chain = el;
        return this;
    },

    removeChild: function(el){
        el = !el ? this.own : typeof el === 'string' ? this.get(el).chain : el;
        var nodes = this.getChildNodes(null, el).chain;
        for (var i = 0, ch; ch = nodes[i]; i++) {
            el.removeChild(ch);
        }

        this.chain = el;
        return this;
    },

    replaceElement: function(target, el){
        el = !el ? this.own : typeof el === 'string' ? this.get(el).chain : el;
        target = this.isElement(target).chain ? this.insertAhead(target, el).chain : this.beforeBegin(target, el).chain;

        this.removeElement(el);
        if (el) {
            this.own = target;
        }

        if (this.own && this.own.id == '') {
            this.own.id = this.id(target).chain;
        }
        this.chain = this.own;
        return this;
    },

    replaceChild: function(target, el){
        el = !el ? this.own : typeof el === 'string' ? this.get(el).chain : el;
        if (this.isElement(target).chain){
            el.innerHTML = '';
            el.appendChild(this.get(target).chain);
        } else {
            el.innerHTML = target;
        }

        this.chain = this.firstChild(false, el).chain;
        return this;
    },

    createChild: function(html, el){
        el = !el ? this.own : typeof el === 'string' ? this.get(el).chain : el;
        if (!html){
            this.chain = '';
            return this;
        }
        var tp = typeof html == 'string' ? 's' : mc.isArray(html).chain ? 'j' : 'h';

        if (tp == 's'){
            this.beforeEnd(html, el);
        } else if (tp == 'h'){
            this.newTemplate(html.template).Template.apply(el, 'beforeEnd', html.mapping);
        } else {
            this.Json.apply(html, el, 'beforeEnd', true);
        }
        return this;
    },

    getSelected: function(type, el, count){
        el = !el ? this.own : typeof el === 'string' ? this.get(el).chain : el;
        this.chain = [];

        if (count == 'all') {
            this.chain = el.options;
            return this;
        };

        var i,
            len = el.options.length,
            opt;

        for (i = 0; i < len; i++){
            opt = el.options[i];
            if (opt.selected) {
                if (type == 'selected') {
                    this.chain.push(opt);
                } else if (type == 'value') {
                    this.chain.push(opt.getAttribute('value') || opt.value || '');
                } else if (type == 'text') {
                    this.chain.push(opt.getAttribute('text') || opt.text);
                } else {
                    this.chain.push(opt.index);
                }

                if (count == 'first') {
                    break;
                };
            }
        }
        return this;
    },

    getOpts: function(el){
        el = !el ? this.own : typeof el === 'string' ? this.get(el).chain : el;

        var results = [],
            len = el.options.length,
            rst,
            i,
            opt;

        for (i = 0; i < len; i++){
            opt = el.options[i],
            rst = {};

            rst['id'] = opt.id || '';
            rst['value'] = opt.getAttribute('value') || opt.value || opt.text || '';
            rst['text'] = opt.text || '';
            rst['selected'] = opt.selected ? true : false;
            results[i] = rst;
        }
        this.chain = results;
        return this;
    },

    addSelect: function(index, hash, el){
        el = !el ? this.own : typeof el === 'string' ? this.get(el).chain : el;
        var opt = document.createElement('option');

        this.eachHash(hash, function(key, value){
            opt[key] = value;
        });

        index == null ? (mc.IE ? el.add(opt) : el.add(opt, null))
                          : (mc.IE ? el.add(opt, index) : el.add(opt, el.options.item(index)));

        this.chain = hash;
        return this;
    },

    removeSelect: function(index, el){
        el = !el ? this.own : typeof el === 'string' ? this.get(el).chain : el;
        var cnt = typeof index == 'string' ? this.commaSplit(index).chain : index;
        var opts = [], 
             i = 0, 
             len = el.options.length;
        for (; i < len; i++){
            opts[i] = el.options[i];
        }

        this.sortArray(cnt, 'D')
            .appendInit([], mc.chain, function(init, vl, ix){
                init.push(opts[vl]);
                el.remove(vl);
                return init;
            });

        return this;
    },

    getRadio: function(attr, check){
        var els = this.select('*[name=' + attr + ']', 'body').chain;
        this.chain = check ? [] : '';
        var i, 
             len, 
             el;

        for (i = 0, len = els.length; i < len; i++){
            el = els[i];
            if (check && !el.checked) {
                this.chain.push(el);
            }
            if (!check && el.checked) {
                this.chain = el;
                break;
            };
        }
        return this;
    },

    execScripts: function(scr){
        var el = document.createElement('script'), 
             scid;
        el.type = 'text/javascript';
        el.text = scr;
        el.id = scid = this.id(false, 'mc-script-id').chain;

        var list = document.getElementsByTagName('script');
        this.insertAfter(el, list[list.length - 1]);
        this.delay(this.removeElement, 70, this, scid);

        this.chain = scr;
        return this;
    },

    //----- DOM Node -----
    cleanNode: function(el){
        el = !el ? this.own : typeof el === 'string' ? this.get(el).chain : el;
        var child = el.firstChild, 
             white = /\S/, 
             next;

        while (child){
            next = child.nextSibling;
            if (child.nodeType == 3 && !white.test(child.nodeValue)) {
                el.removeChild(child);
            }
            child = next;
        }

        this.chain = el.childNodes;
        return this;
    },

    eachNodeList: function(list, pty, fn, scope){
        var nodes = this.isElement(list).chain ? [list] : list;
        var ptys = this.commaSplit(pty).chain,
             len = ptys.length,
             i,
             j,
             el,
             value;

        fn = fn || mc.emptyFn;
        scope = scope || this;

        if (nodes){
            for (i = 0; el = nodes[i]; i++){
                if (el.nodeType == 1){
                    for (j = 0; j < len; j++){
                        value = this.getClassFor(ptys[j]).chain;
                        fn.call(scope, value, el.getAttribute(value) || el[value], el);
                    }
                }
            }
        }
        return this;
    },

    isEmptyText: function(el){
        el = !el ? this.own : typeof el === 'string' ? this.get(el).chain : el;
        this.chain = this.getText(el)
                         .isBlank(mc.chain).chain;
        return this;
    },

    _getNode: function(base, next, el){
        el = !el ? this.own : typeof el === 'string' ? this.get(el).chain : el;
        var node = el[base];
        while (node && node.nodeType != 1) {
            node = node[next];
        };
        return this.chain = node;
    },

    _getNodes: function(base, next, el){
        el = !el ? this.own : typeof el === 'string' ? this.get(el).chain : el;
        var node = el[base],
             nodes = [];
        while (node) {
            if (node.nodeType == 1) {
                nodes.push(node);
            };
            node = node[next];
        }
        return this.chain = nodes;
    },

    _nodeSelect: function(selector, nodes, many){
        if (nodes[0]){
            var results = mc.Selector.arraySelect(selector, nodes).chain;
            if (results) {
                return this.chain = many === true ? results : results[0];
            }
        };
        return this.chain = null;
    },

    getChildNodes: function(selector, el){
        el = !el ? this.own : typeof el === 'string' ? this.get(el).chain : el;
        this._getNodes('firstChild', 'nextSibling', el);
        if (selector) {
            this._nodeSelect(selector, this.chain);
        }
        return this;
    },

    firstChild: function(selector, el){
        el = !el ? this.own : typeof el === 'string' ? this.get(el).chain : el;
        if (selector) {
            this._getNodes('firstChild', 'nextSibling', el);
            this._nodeSelect(selector, this.chain, false);
            return this;
        };

        this._getNode('firstChild', 'nextSibling', el);
        return this;
    },

    lastChild: function(selector, el){
        el = !el ? this.own : typeof el === 'string' ? this.get(el).chain : el;
        if (selector) {
            this._getNodes('lastChild', 'previousSibling', el);
            this._nodeSelect(selector, this.chain, false);
            return this;
        };

        this._getNode('lastChild', 'previousSibling', el);
        return this;
    },

    nextSibling: function(selector, el){
        el = !el ? this.own : typeof el === 'string' ? this.get(el).chain : el;
        if (selector) {
            this._getNodes('nextSibling', 'nextSibling', el);
            this._nodeSelect(selector, this.chain, false);
            return this;
        };

        this._getNode('nextSibling', 'nextSibling', el);
        return this;
    },

    nextSiblingAll: function(selector, el){
        el = !el ? this.own : typeof el === 'string' ? this.get(el).chain : el;
        this._getNodes('nextSibling', 'nextSibling', el);
        if (selector) {
            this._nodeSelect(selector, this.chain);
        }
        return this;
    },

    prevSibling: function(selector, el){
        el = !el ? this.own : typeof el === 'string' ? this.get(el).chain : el;
        if (selector){
            this._getNodes('previousSibling', 'previousSibling', el);
            this._nodeSelect(selector, this.chain, false);
            return this;
        };

        this._getNode('previousSibling', 'previousSibling', el);
        return this;
    },

    prevSiblingAll: function(selector, el){
        el = !el ? this.own : typeof el === 'string' ? this.get(el).chain : el;
        this._getNodes('previousSibling', 'previousSibling', el);
        if (selector) {
            this._nodeSelect(selector, this.chain);
        }
        return this;
    },

    siblingAll: function(selector, el){
        el = !el ? this.own : typeof el === 'string' ? this.get(el).chain : el;
        this.getChildNodes(selector, el['parentNode']);
        return this;
    },

    getDescendants: function(selector, index, el){
        selector = selector || '*';
        el = !el ? this.own : typeof el === 'string' ? this.get(el).chain : el;

        var nodes = this.select(selector, el.id).chain;
        if (index == 'last' && nodes){
            index = nodes.length - 1;
        }

        if (this.isNumber(index).chain){
            this.chain = nodes[index] ? nodes[index] : null;
            return this;
        };

        this.chain = nodes;
        return this;
    },

    isDescendant: function(node, el){
        if (!(node = this.get(node).chain)) {
            this.chain = false;
            return this;
        }
        el = !el ? this.own : typeof el === 'string' ? this.get(el).chain : el;

        if (el.compareDocumentPosition) {
            this.chain = !!(el.compareDocumentPosition(node) & 16);
            return this;
        }

        while (node = node.parentNode){
            if (el == node){
                this.chain = true;
                return this;
            };
        }

        this.chain = false;
        return this;
    },

    getParent: function(selector, el){
        el = !el ? this.own : typeof el === 'string' ? this.get(el).chain : el;
        this._getNode('parentNode', 'parentNode', el);
        if (selector) {
            this._nodeSelect(selector, [this.chain], false);
        }
        return this;
    },

    getAncestors: function(selector, index, el){
        el = !el ? this.own : typeof el === 'string' ? this.get(el).chain : el;
        this._getNodes('parentNode', 'parentNode', el);
        if (selector){
            this._nodeSelect(selector, this.chain);
        }

        var nodes = this.chain;
        if (this.isNumber(index).chain && this.isArray(nodes).chain){
            this.chain = nodes[index] ? nodes[index] : null;
            return this;
        };

        this.chain = nodes;
        return this;
    },

    isAncestor: function(node, el){
        if (!(node = this.get(node).chain)) {
            this.chain = false;
            return this;
        }
        el = !el ? this.own : typeof el === 'string' ? this.get(el).chain : el;

        if (node.compareDocumentPosition) {
            this.chain = !!(node.compareDocumentPosition(el) & 16);
            return this;
        }

        if (node.contains && !mc.Safari){
            this.chain = node.contains(el);
            return this;
        }

        while (el = el.parentNode){
            if (node == el){
                this.chain = true;
                return this;
            };
        }

        this.chain = false;
        return this;
    },

    sameAncestors: function(pty, value, el){
        var nodes = [];
        if (!value){
            this.chain = nodes;
            return this;
        }
        value = value.toUpperCase();

        el = !el ? this.own : typeof el === 'string' ? this.get(el).chain : el;
        this.getAncestors(false, false, el)
            .eachNodeList(mc.chain, pty, function(key, vl, node){
                if (vl && vl.toUpperCase() == value){
                    nodes.push(node);
                }
            });

        this.chain = nodes;
        return this;
    },

    querySelector: function(selector, el){
        el = !el ? this.own : typeof el === 'string' ? this.get(el).chain : el;
        this.chain = el.querySelector(selector);
        return this;
    },

    querySelector: function(selector, el){
        el = !el ? this.own : typeof el === 'string' ? this.get(el).chain : el;
        this.chain = el.querySelectorAll(selector);
        return this;
    },

    //------ DOM Attribute ------
    getAttr: function(attr, el, one){
        el = !el ? this.own : typeof el === 'string' ? this.get(el).chain : el;
        if (typeof attr === 'string'){
            attr = this.commaSplit(attr).chain;
        }
        if (!(mc.isArray(attr).chain)){
            attr = mc.getHashList(attr).chain;
        }

        var len = attr.length,
             i,
             pty = { },
             cv;

        for (i = 0; i < len; i++){
            cv = this.getClassFor(attr[i]).chain;
            pty[attr[i]] = el.getAttribute(cv) || el[cv] || '';
        }

        this.chain = one ? pty[attr[0]] : pty;
        this.chainNode = el;
        return this;
    },

    setAttr: function(hash, el){
        el = !el ? this.own : typeof el === 'string' ? this.get(el).chain : el;
        var pty = { }, 
             attr, 
             cv;
        for (attr in hash){
            cv = this.setClassFor(attr).chain;
            el.setAttribute(cv, hash[attr]);
        }
        this.chain = hash;
        this.chainNode = el;
        return this;
    },

    removeAttr: function(attr, el){
        el = !el ? this.own : typeof el === 'string' ? this.get(el).chain : el;
        if (typeof attr === 'string'){
            attr = this.commaSplit(attr).chain;
        }
        if (!(mc.isArray(attr).chain)){
            attr = mc.getHashList(attr).chain;
        }

        var len = attr.length, 
             i, 
             pty = { }, 
             cv;
        for (i = 0; i < len; i++){
            cv = this.getClassFor(attr[i]).chain;
            pty[attr[i]] = el.getAttribute(cv) || el[cv] || '';
            el.removeAttribute(cv);
        }
        this.chain = pty;
        this.chainNode = el;
        return this;
    },

    getValue: function(el, rv){
        el = !el ? this.own : typeof el === 'string' ? this.get(el).chain : el;
        this.chain = (rv === true && mc.isEmpty(el.value).chain) ? '' : el.value;
        this.chainNode = el;
        return this;
    },

    setValue: function(vl, el){
        el = !el ? this.own : typeof el === 'string' ? this.get(el).chain : el;
        el.value = (vl === undefined || vl === null) ? '' : vl;
        this.chain = el.value;
        this.chainNode = el;
        return this;
    },

    getText: function(el){
        el = !el ? this.own : typeof el === 'string' ? this.get(el).chain : el;
        if (el ){
            this.chain = el.innerText === undefined ? el.textContent : el.innerText;
            this.chainNode = el;
        } else {
            var er;
        }
        return this;
    },

    setText: function(text, el){
        el = !el ? this.own : typeof el === 'string' ? this.get(el).chain : el;
        el.innerText === undefined ? el.textContent = text : el.innerText = text;
        this.chain = el.textContent || el.innerText;
        this.chainNode = el;
        return this;
    },

    hasClass: function(cn, el){
        el = !el ? this.own : typeof el === 'string' ? this.get(el).chain : el;
        mc.isInclude(el.className, cn, ' ');
        return this;
    },

    addClass: function(cn, el){
        el = !el ? this.own : typeof el === 'string' ? this.get(el).chain : el;
        if (!cn){
            this.chain = '', this.chainNode = el;
            return this;
        }

        if (typeof cn == 'string'){
            cn = [cn];
        }
        var i,
             len = cn.length,
             nm,
             ac = [];

        for (i = 0; i < len; i++){
            if ((nm = cn[i]) && !(mc.isInclude(el.className, nm, ' ').chain)){
                el.className += (el.className ? ' ' : '') + nm;
                ac.push(nm);
            };
        }
        this.chain = ac, this.chainNode = el;
        return this;
    },

    removeClass: function(cn, el){
        el = !el ? this.own : typeof el === 'string' ? this.get(el).chain : el;
        if (!cn){
            this.chain = '', this.chainNode = el;
            return this;
        }

        if (!el.className){
            this.chain = [];
            return this;
        }
        if (typeof cn === 'string'){
            cn = [cn];
        }
        var i, 
             len = cn.length, 
             nm, 
             re, 
             rc = [];

        for (i = 0; i < len; i++){
            if ((nm = cn[i]) && mc.isInclude(el.className, nm, ' ').chain){
                if (el.className == nm){
                    el.className = '';
                } else {
                    re = new RegExp('(?:^|\\s+)' + nm + '(?:\\s+|$)', 'g');
                    el.className = el.className.replace(re, ' ');
                }
                rc.push(nm);
            };
        }
        this.chain = rc, this.chainNode = el;
        return this;
    },

    toggleClass: function(cn, el){
        el = !el ? this.own : typeof el === 'string' ? this.get(el).chain : el;
        this.hasClass(cn, el).chain ? this.removeClass(cn, el) : this.addClass(cn, el);
        return this;
    },

    replaceClass: function(bs, rp, el){
        el = !el ? this.own : typeof el === 'string' ? this.get(el).chain : el;
        this.removeClass(bs, el);
        this.addClass(rp, el);
        this.chainNode = el;
        return this;
    },

    eachAttr: function(el, pty, fn, scope){
        if (el == 'own' || this.isEmpty(el).chain) {
            el = this.own;
        }
        el = this.get(el).chain;
        fn = fn || mc.emptyFn;
        scope = scope || this;

        if (typeof pty === 'string'){
            pty = this.commaSplit(pty).chain;
        }
        var len = pty.length, 
             i, 
             cv;
        for (i = 0; i < len; i++){
            cv = this.getClassFor(pty[i]).chain;
            fn.call(scope, pty[i], el.getAttribute(cv) || el[cv] || '', el);
        }
        this.chain = [el, pty, fn, scope];
        this.chainNode = el;
        return this;
    },

    getAttrNodes: function(attr, el){
        el = !el ? this.own : typeof el === 'string' ? this.get(el).chain : el;
        mc.getChildNodes(false, el)
            .collectArray(mc.chain, function(nd){ return nd[attr]; }, this);

        this.chain = mc.chain.concat([el[attr]]);
        this.chainNode = el;
        return this;
    },

    getChecked: function(el){
        el = !el ? this.own : typeof el === 'string' ? this.get(el).chain : el;
        this.chain = el.checked;
        this.chainNode = el;
        return this;
    },

    setChecked: function(check, el){
        el = !el ? this.own : typeof el === 'string' ? this.get(el).chain : el;
        el.checked = check ? true : '';
        this.chain = check;
        this.chainNode = el;
        return this;
    },

    //----- DOM Style -----
    getStyle: function(pty, el){
        el = !el ? this.own : typeof el === 'string' ? this.get(el).chain : el;
        var dom = el.currentStyle ? false : true;
        pty = pty == 'float' ? (dom ? 'cssFloat' : 'styleFloat') : this.camelCase(pty).chain;
        var value = el.style[pty];

        if (!value || value == 'auto') {
            value = dom ? this._computedStyle(el, pty) : el.currentStyle[pty];
        }
        if (dom){
            this.chain = pty == 'opacity' ? (value ? parseFloat(value) : 1.0) : (value ? value : null);
            return this;
        }

        if (pty == 'opacity') {
            value = (el.style.filter.indexOf('opacity') >= 0) ?
                    el.style.filter.match(/alpha\(opacity=(.*)\)/i) : null;
            this.chain = value ? parseFloat(value[1]) / 100 : 1.0;
            return this;
        }

        if (value == 'auto'){
            value = (mc.widthHeightExp.test(pty) && el.style['display'] != 'none') ?
                el['offset' + mc.firstLetter(pty)] + 'px' : null;
        }

        if (value && !(String(value).indexOf('px') > -1) && this.isCssUnit(value).chain) {
            value = this.convertPixel(el, value).chain;
        }

        this.chain = value ? value : null;
        this.chainNode = el;
        return this;
    },

    getStyles: function(pty, el){
        el = !el ? this.own : typeof el === 'string' ? this.get(el).chain : el;
        if (typeof pty === 'string'){
            pty = this.commaSplit(pty).chain
        }
        var rtn = {}, 
             i, 
             len = pty.length;

        for (i = 0; i < len; i++) {
            rtn[pty[i]] = this.getStyle(pty[i], el).chain;
        }

        this.chain = rtn, this.chainNode = el;
        return this;
    },

    getTrblStyle: function(el){
        el = !el ? this.own : typeof el === 'string' ? this.get(el).chain : el;

        var rtn = {};
        rtn.top = this.getStyle('top', el).chain;
        rtn.bottom = rtn.top ? '' : this.getStyle('bottom', el).chain;
        rtn.left = this.getStyle('left', el).chain;
        rtn.right = rtn.left ? '' : this.getStyle('right', el).chain;

        this.chain = rtn, this.chainNode = el;
        return this;
    },

    setTrblStyle: function(t, r, b, l, el){
        el = !el ? this.own : typeof el === 'string' ? this.get(el).chain : el;
        var rtn = {};
        rtn.top = t, rtn.right = r, rtn.bottom = b, rtn.left = l;

        this.setStyle(rtn, el);
        this.chain = rtn, this.chainNode = el;
        return this;
    },

    setUnits: function(vl){
        this.chain = mc.numCheckExp.test(vl) ? vl + mc.DEFAULT_UNITS : vl;
        return this;
    },

    _computedStyle: function(el, pty){
        return (pty in el.style) ? document.defaultView.getComputedStyle(el, null)[pty] : null;
    },

    setStyle: function(hash, el){
        if (!hash){
            this.chain = {};
            return this;
        }
        el = !el ? this.own : typeof el === 'string' ? this.get(el).chain : el;
        var ptyValue = { }, 
             camel, 
             pty, 
             hvl;

        var cFn = function(hash, that) {
            var i, 
                 len, 
                 hs, 
                 ky, 
                 key, 
                 vl, 
                 value, 
                 stHash = { }, 
                 j;
            var csKeys = that.commaSplit(hash).chain, 
                 len = csKeys.length;

            for (i = 0; i < len; i++){
                hs = hash.split(':');
                ky = hs[0].match(/(\d+|\D+)?/);
                key = that.trim(ky[0]).chain;

                var con = [];
                for (j = 1; j < hs.length; j++){
                    con.push(hs[j]);
                }
                value = that.trim(con.join(':')).chain;

                if (value.charAt(0) == "'"){
                    vl = value.split("'");
                    value = that.trim(vl[1]).chain;
                }
                stHash[key] = value;
            }
            if (len > 0) {
                hash = stHash;
            }
            return hash;
        };

        if (typeof hash === 'string') {
            hash = cFn(hash, this);
        }
        if (typeof hash === 'array') {
            hash = cFn(hash[0], this);
        }

        for (pty in hash){
            hvl = hash[pty];
            if (pty == 'opacity'){
                ptyValue[pty] = this.setOpacity(hvl, el).chain;
                continue;
            }
            if (pty == 'width' || pty == 'height'){
                hvl = mc.setUnits(hvl).chain;
            }
            camel = pty == 'float' ? (el.currentStyle ? 'styleFloat' : 'cssFloat') : this.camelCase(pty).chain;

            el.style[camel] = hvl;
            ptyValue[camel] = hvl;
        }

        this.chain = ptyValue, this.chainNode = el;
        return this;
    },

    removeStyle: function(stn, el){
        if (!stn){
            this.chain = '';
            return this;
        }
        el = !el ? this.own : typeof el === 'string' ? this.get(el).chain : el;
        if (typeof stn === 'string') {
            stn = [stn];
        }
        var i,
            len = stn.length,
            sn;

        for (i = 0; i < len; i++){
            sn = stn[i];
            sn = sn == 'float' ? (el.currentStyle ? 'styleFloat' : 'cssFloat') : this.camelCase(sn).chain;
            el.style[sn] = '';
        }

        this.chain = stn;
        this.chainNode = el;
        return this;
    },

    setColor: function(color, el){
        el = !el ? this.own : typeof el === 'string' ? this.get(el).chain : el;
        if (el && color){
            el.style['color'] = color;
        }

        this.chain = color;
        this.chainNode = el;
        return this;
    },

    minusColor: function(minus, el){
        el = !el ? this.own : typeof el === 'string' ? this.get(el).chain : el;

        if (el && minus){
            mc.isInput(el).chain ? mc.getValue(el) : mc.getText(el);
            var vl = mc.chain.replace(/,/g, '');

            if (isFinite(vl)){
                if (parseInt(vl, 10) < 0){
                    el.style['color'] = minus;
                } else {
                    var clr = el.style['color'];
                    if (clr && clr == minus){
                        el.style['color'] = '';
                    }
                }
            }
        }
        this.chain = [minus];
        this.chainNode = el;
        return this;
    },

    _boxModelValue : function(model, ltrb, type, el){
        el = !el ? this.own : typeof el === 'string' ? this.get(el).chain : el;
        if (!ltrb) {
            ltrb = 'LTRB';
        }
        ltrb = (ltrb || 'LTRB').toUpperCase();

        var sta = this.stringToArray(ltrb).chain, 
             len = sta.length, 
             hash = { }, 
             value = 0, 
             i, 
             vl;
        for (i = 0; i < len; i++){
            vl = parseInt(this.getStyle(model[sta[i]], el).chain, 10) || 0;
            type ? hash[sta[i]] = vl : value += vl;
        }

        return type ? hash : value;
    },

    getBorder : function(ltrb, el){
        el = !el ? this.own : typeof el === 'string' ? this.get(el).chain : el;
        this.chain = this._boxModelValue(mc._boxModel.border, ltrb, true, el);
        return this;
    },

    getBorderValue : function(ltrb, el){
        el = !el ? this.own : typeof el === 'string' ? this.get(el).chain : el;
        this.chain = this._boxModelValue(mc._boxModel.border, ltrb, false, el);
        return this;
    },

    getPadding : function(ltrb, el){
        el = !el ? this.own : typeof el === 'string' ? this.get(el).chain : el;
        this.chain = this._boxModelValue(mc._boxModel.padding, ltrb, true, el);
        return this;
    },

    getPaddingValue : function(ltrb, el){
        el = !el ? this.own : typeof el === 'string' ? this.get(el).chain : el;
        this.chain = this._boxModelValue(mc._boxModel.padding, ltrb, false, el);
        return this;
    },

    getMargin : function(ltrb, el){
        el = !el ? this.own : typeof el === 'string' ? this.get(el).chain : el;
        this.chain = this._boxModelValue(mc._boxModel.margin, ltrb, true, el);
        return this;
    },

    getMarginValue: function(ltrb, el){
        el = !el ? this.own : typeof el === 'string' ? this.get(el).chain : el;
        this.chain = this._boxModelValue(mc._boxModel.margin, ltrb, false, el);
        return this;
    },

    getBPValue: function(ltrb, el){
        el = !el ? this.own : typeof el === 'string' ? this.get(el).chain : el;
        this.chain = mc.isNotStrictAndIE ? 0 :
            this.getBorderValue(ltrb, el).chain + this.getPaddingValue(ltrb, el).chain;
        return this;
    },

    getWidth: function(ex, el){
        el = !el ? this.own : typeof el === 'string' ? this.get(el).chain : el;
        if (!(this.chain = el.offsetWidth)) {
            return this;
        }

        var ec = ex ? ex.toUpperCase() : null;
        var ow = this.chain;

        if (ec == 'B'){
            this.chain = ow - this.getBorderValue('LR', el).chain;
        } else if (ec == 'P'){
            this.chain = ow - this.getPaddingValue('LR', el).chain;
        } else if (ec == 'BP'){
            this.chain = ow - this.getBorderValue('LR', el).chain - this.getPaddingValue('LR', el).chain;
        }
        return this;
    },

    setWidth: function(value, ex, el){
        el = !el ? this.own : typeof el === 'string' ? this.get(el).chain : el;
        if (!value){
            this.chain = '';
            this.chainNode = el;
            return this;
        }

        if (typeof value == 'string' && value.toLowerCase() == 'auto'){
            this.setStyle({width: 'auto'}, el);
            this.chain = 'auto', this.chainNode = el;
            return this;
        }

        var dist = this.splitNumAlpha(this.setUnits(value).chain).chain;
        var ec = ex ? ex.toUpperCase() : null;

        if (dist){
            if (ec == 'B'){
                dist[0] -= this.getBorderValue('LR', el).chain;
            } else if (ec == 'P'){
                dist[0] -= this.getPaddingValue('LR', el).chain;
            } else if (ec == 'BP'){
                dist[0] -= (this.getBorderValue('LR', el).chain + this.getPaddingValue('LR', el).chain);
            }
            this.setStyle({width: dist[0] + dist[1]}, el);
        } else {
            this.chain = value;
        }

        this.chainNode = el;
        return this;
    },

    setChildWidth: function(tg, el){
        tg = !tg ? this.own : typeof tg === 'string' ? this.get(tg).chain : tg;
        mc.getWidth('BP', el || mc.getParent(false, tg).chain)
           .setWidth(mc.chain, 'BP', tg);
        return this;
    },

    getHeight: function(ex, el){
        el = !el ? this.own : typeof el === 'string' ? this.get(el).chain : el;
        if (!(this.chain = el.offsetHeight)) {
            return this;
        }
        var ec = ex ? ex.toUpperCase() : null;
        var oh = this.chain;

        if (ec == 'B'){
            this.chain = oh - this.getBorderValue('TB', el).chain;
        } else if (ec == 'P'){
            this.chain = oh - this.getPaddingValue('TB', el).chain;
        } else if (ec == 'BP'){
            this.chain = oh - this.getBorderValue('TB', el).chain - this.getPaddingValue('TB', el).chain;
        }

        return this;
    },

    setHeight: function(value, ex, el){
        el = !el ? this.own : typeof el === 'string' ? this.get(el).chain : el;
        if (!value){
            this.chain = '';
            this.chainNode = el;
            return this;
        }

        if (typeof value == 'string' && value.toLowerCase() == 'auto'){
            this.setStyle({height: 'auto'}, el);
            this.chain = ['auto', 'auto'], this.chainNode = el;
            return this;
        }

        var dist = this.splitNumAlpha(this.setUnits(value).chain).chain;
        var ec = ex ? ex.toUpperCase() : null;

        if (dist){
            if (ec == 'B'){
                dist[0] -= this.getBorderValue('TB', el).chain;
            } else if (ec == 'P'){
                dist[0] -= this.getPaddingValue('TB', el).chain;
            } else if (ec == 'BP'){
                dist[0] -= (this.getBorderValue('TB', el).chain + this.getPaddingValue('TB', el).chain);
            }
            this.setStyle({height: dist[0] + dist[1]}, el);
        } else {
            this.chain = value;
        }

        this.chainNode = el;
        return this;
    },

    setChildHeight: function(tg, el){
        tg = !tg ? this.own : typeof tg === 'string' ? this.get(tg).chain : tg;
        mc.getHeight('BP', el || mc.getParent(false, tg).chain)
          .setHeight(mc.chain, 'BP', tg);
        return this;
    },

    getWH: function(ex, el){
        el = !el ? this.own : typeof el === 'string' ? this.get(el).chain : el;
        var wh = [];
        wh[0] = this.getWidth(ex, el).chain;
        wh[1] = this.getHeight(ex, el).chain;

        this.chain = wh;
        return this;
    },

    setWH: function(w, h, ex, el){
        if (!w && !h){this.chain = []; return this;}
        el = !el ? this.own : typeof el === 'string' ? this.get(el).chain : el;

        var wh = [];
        wh[0] = this.setWidth(w, ex, el).chain.width;
        wh[1] = this.setHeight(h, ex, el).chain.height;
        this.chain = wh;
        return this;
    },

    getXY: function(el){
        el = !el ? this.own : typeof el === 'string' ? this.get(el).chain : el;
        if (!el || el == document.body || el == document.documentElement) {
            this.chain = [];
            return this;
        }

        var doc = el.ownerDocument,
             parent = el.parentNode;
        var obj,
             left = 0,
             top = 0,
             offParent,
             acum = el,
             adjLeft = 2,
             adjTop = 2,
             tc;

        var dsLeft = this.getDocScrollLeft().chain,
             dsTop = this.getDocScrollTop().chain,
             x,
             y;

        if (el.getBoundingClientRect){
            tc = [0, 0];
            obj = el.getBoundingClientRect();
            tc[0] = Math.round(obj.left + dsLeft);
            tc[1] = Math.round(obj.top + dsTop);

            if (mc.IE6 && !mc.Strict){
                adjLeft = adjTop = 0;
                tc[0] -= adjLeft;
                tc[1] -= adjTop;
            }
            this.chain = tc;
            return this;
        }

        if (document.getBoxObjectFor){
            obj = document.getBoxObjectFor(el);
            x = parseInt(this._computedStyle(el, 'borderLeftWidth'), 10) || 0;
            y = parseInt(this._computedStyle(el, 'borderTopWidth'), 10) || 0;
            this.chain = [obj.x - x, obj.y - y];
            return this;
        }

        while (acum){
            left += acum.offsetLeft || 0;
            top += acum.offsetTop || 0;
            if (mc.Safari2){
                left += parseInt(this.getStyle(borderLeftWidth, acum).chain, 10) || 0;
                top += parseInt(this.getStyle(borderTopWidth, acum).chain, 10) || 0;
            }
            acum = acum.offsetParent;
        }

        if (this.getStyle('position', el).chain == 'fixed'){
            if (mc.Opera){
                left -= dsLeft;
                top -= dsTop;
            } else if (mc.Safari){
                left += dsLeft;
                top += dsTop;
            }
        } else {
            while (parent){
                left -= parseInt(parent.scrollLeft, 10) || 0;
                top -= parseInt(parent.scrollTop, 10) || 0;
                parent = parent.parentNode;
            }
            left += dsLeft;
            top += dsTop;
        }

        this.chain = [left, top];
        return this;
    },

    getX: function(el){
        this.chain = this.getXY(el).chain[0];
        return this;
    },

    getY: function(el){
        this.chain = this.getXY(el).chain[1];
        return this;
    },

    setPos: function(pos, el){
        el = !el ? this.own : typeof el === 'string' ? this.get(el).chain : el;

        if (pos){
            this.chain = this.setStyle({position: pos}, el).chain;
        } else {
            var ps = this.getStyle('position', el).chain;
            if (ps == 'static'){
                this.relativeChange = el;
                this.setStyle({position: 'relative'}, el);
                this.chain = 'relative';
            } else if (ps == 'relative'){
                this.chain = 'relative';
            } else {
                this.chain = '';
            }
        }
        return this;
    },

    setXY: function(x, y, el){
        if (!x && !y){
            this.chain = ['', ''];
            return this;
        }
        el = !el ? this.own : typeof el === 'string' ? this.get(el).chain : el;

        var xna = null,
             yna = null,
             left = null,
             right = null,
             pos, 
             ctXY,
             xyPos = ['', ''];

        var xtf = x ? true : false,
             ytf = y ? true : false;

        if (xtf){
            xna = this.splitNumAlpha(this.setUnits(x).chain).chain;
            left = parseInt(this.getStyle('left', el).chain, 10);
        }
        if (ytf){
            yna = this.splitNumAlpha(this.setUnits(y).chain).chain;
            right = parseInt(this.getStyle('top', el).chain, 10);
        }

        this.relativeChange = false;
        pos = this.setPos(null, el).chain;
        ctXY = this.getXY(el).chain;

        if (xtf){
            if (isNaN(left)) {
                left = (pos == 'relative') ? 0 : el.offsetLeft;
            }
            xyPos[0] = this.setStyle({left: xna[0] - ctXY[0] + left + xna[1]}, el).chain['left'];
        }
        if (ytf){
            if (isNaN(right)){
                right = (pos == 'relative') ? 0 : el.offsetTop;
            }
            xyPos[1] = this.setStyle({top: yna[0] - ctXY[1] + right + yna[1]}, el).chain['top'];
        }

        this.chain = xyPos;
        return this;
    },

    setX: function(x, el){
        if (!x){this.chain = []; return this;}
        this.chain = this.setXY(x, '', el).chain[0];
        return this;
    },

    setY: function(y, el){
        if (!y){this.chain = []; return this;}
        this.chain = this.setXY('', y, el).chain[1];
        return this;
    },

    setWHXY: function(w, h, x, y, ex, el){
        el = !el ? this.own : typeof el === 'string' ? this.get(el).chain : el;
        var rtn = [], 
             pty, 
             vl;

        rtn[0] = this.setWidth(w, ex, el).chain.width;
        rtn[1] = this.setHeight(h, ex, el).chain.height;

        this.setXY(x, y, el);
        rtn[2] = this.chain[0];
        rtn[3] = this.chain[1];

        this.chain = rtn;
        return this;
    },

    getWHXY: function(ex, el){
        el = !el ? this.own : typeof el === 'string' ? this.get(el).chain : el;
        var wh = this.getWH(ex, el).chain;
        this.chain = wh.concat(this.getXY(el).chain);
        return this;
    },

    getLeft: function(el){
        el = !el ? this.own : typeof el === 'string' ? this.get(el).chain : el;
        this.chain = this.getX(el).chain + this.getPaddingValue('L', el).chain
                                                 + this.getBorderValue('L', el).chain;
        return this;
    },

    getTop: function(el){
        el = !el ? this.own : typeof el === 'string' ? this.get(el).chain : el;
        this.chain = this.getY(el).chain + this.getPaddingValue('T', el).chain
                                                 + this.getBorderValue('T', el).chain;
        return this;
    },

    getRight: function(part, el){
        el = !el ? this.own : typeof el === 'string' ? this.get(el).chain : el;
        if (part) {
            part = part.toUpperCase();
        }

        var left = this.getLeft(el).chain;
        var wd = parseInt(this.getStyle('width', el).chain, 10) || 0;
        this.chain = left + wd;   // part=='W'

        if (part == 'P') {
            this.chain = left + wd + this.getPaddingValue('R', el).chain;
        }
        if (part == 'B') {
            this.chain = left + wd + this.getPaddingValue('R', el).chain +
                            this.getBorderValue('R', el).chain;
        }
        if (part == 'M') {
            this.chain = left + wd + this.getPaddingValue('R', el).chain +
                            this.getBorderValue('R', el).chain +
                            this.getMarginValue('R', el).chain;
        }
        return this;
    },

    getBottom: function(part, el){
        el = !el ? this.own : typeof el === 'string' ? this.get(el).chain : el;
        if (part) {
            part = part.toUpperCase();
        }

        var pv, 
             topht = this.getTop(el).chain + parseInt(this.getStyle('height', el).chain, 10) || 0;
        this.chain = topht;   // part=='W'

        if (part != 'W') {
            pv = topht + this.getPaddingValue('B', el).chain;
        };
        if (part == 'P') this.chain = pv;
        if (part == 'B') {
            this.chain = pv + this.getBorderValue('B', el).chain;
        }
        if (part == 'M') {
            this.chain = pv + this.getBorderValue('B', el).chain + this.getMarginValue('B', el).chain;
        }
        return this;
    },

    getOffsetParent: function(el){
        el = !el ? this.own : typeof el === 'string' ? this.get(el).chain : el;
        if (el.offsetParent){
            this.chain = el.offsetParent;
            return this;
        }
        if (this.isBodyHtml(el).chain){
            this.chain = el;
            return this;
        }

        while ((el = el.parentNode) && !this.isBodyHtml(el).chain){
            if (this.getStyle('position', el).chain != 'static'){
                this.chain = el;
                return this;
            };
        };

        this.chain = document.body;
        return this;
    },

    getOffsetNodes: function(el, base, absolute){
        el = !el ? this.own : typeof el === 'string' ? this.get(el).chain : el;
        base = !base ? this.own : typeof base === 'string' ? this.get(base).chain : base;

        var i, 
             baseXY = this.getXY(base).chain,
             compareXY = this.getXY(el).chain;

        for (i = 0; i < 2; i++){
            baseXY[i] -= compareXY[i];
            if (absolute && baseXY[i] < 0) {
                baseXY[i] *= -1;
            }
        }

        this.chain = baseXY;
        return this;
    },

    moveTo: function(hash, el){
        el = !el ? this.own : typeof el === 'string' ? this.get(el).chain : el;
        var to,
             touc,
             df = { };

        for (to in hash){
            touc = to.toUpperCase();
            if (touc == 'L') {
                df['L'] = this.setX(hash[to], el).chain;
            } else if (touc == 'R') {
                df['R'] = this.setX(hash[to], el).chain;
            } else if (touc == 'T') {
                df['T'] = this.setY(hash[to], el).chain;
            } else if (touc == 'B') {
                df['B'] = this.setY(hash[to], el).chain;
            }
        }
        this.chain = df;
        return this;
    },

    setOpacity: function(value, el){
        el = !el ? this.own : typeof el === 'string' ? this.get(el).chain : el;
        if (!el.currentStyle){
            this.chain = el.style.opacity = value;
            return this;
        }
        el.style.zoom = 1;
        el.style.filter = (value == 1 || !value) ? this.getStyle('filter', el).chain : 'alpha(opacity=' + (value * 100) + ')';

        this.chain = value;
        return this;
    },

    setOverflow : function(value, el){
        el = !el ? this.own : typeof el === 'string' ? this.get(el).chain : el;
        if (value == 'auto' && mc.Gecko2){
            el.style.overflow = 'hidden';
            mc.delay(function(){
                el.style.overflow = value;
            }, 2, this);
        } else {
            el.style.overflow = value;
        }
        this.chain = value, this.chainNode = el;
        return this;
    },

    makeClip: function(el){
        el = !el ? this.own : typeof el === 'string' ? this.get(el).chain : el;
        this.chain = '';
        if (!this.overflowClip){
            this.overflowClip = this.getStyle('overflow', el).chain;
            this.setOverflow('hidden', el);
        }
        return this;
    },

    unDoClip: function(el){
        el = !el ? this.own : typeof el === 'string' ? this.get(el).chain : el;
        this.chain = '';
        if (this.overflowClip) {
            this.setOverflow(this.overflowClip, el);
        }
        this.overflowClip = false;
        return this;
    },

    isWidthScroll: function(el){
        el = !el ? this.own : typeof el === 'string' ? this.get(el).chain : el;
        this.chain = el.scrollWidth > el.clientWidth;
        this.chainNode = el;
        return this;
    },

    isHeightScroll: function(el){
        el = !el ? this.own : typeof el === 'string' ? this.get(el).chain : el;
        this.chain = el.scrollHeight > el.clientHeight;
        this.chainNode = el;
        return this;
    },

    getClient: function(ct, el){
        el = !el ? mc.own : typeof el === 'string' ? this.get(el).chain : el;
        if (!ct){
            ct = 'HW';
        }
        ct = ct.toUpperCase();
        var rt = [], 
             ar = mc.stringToArray(ct).chain;

        for (i = 0; i < ar.length; i++){
            ar[i] == 'H' ? rt[i] = parseInt(el.clientHeight, 10) || 0 :
                              rt[i] = parseInt(el.clientWidth, 10) || 0;
        }
        this.chain = rt.length > 1 ? rt : rt[0];
        this.chainNode = el;
        return this;

    },

    getScroll: function(sc, el){
        el = !el ? mc.own : typeof el === 'string' ? this.get(el).chain : el;
        if (!sc){
            sc = 'HLTW';
        }
        sc = sc.toUpperCase();

        var rt = [], 
             i, 
             idx, 
             ar = mc.stringToArray(sc).chain,
             hltw = 'HLTW',
             sl;
        sl = ['scrollHeight', 'scrollLeft', 'scrollTop', 'scrollWidth'];

        for (i = 0; i < ar.length; i++){
            if ((idx = hltw.indexOf(ar[i])) != -1) {
                rt[i] = parseInt(el[sl[idx]], 10) || 0;
            }
        }

        this.chain = rt.length > 1 ? rt : rt[0];
        this.chainNode = el;
        return this;
    },

    getScrollSum: function(acum, el){
        el = !el ? this.own : typeof el === 'string' ? this.get(el).chain : el;
        var doc = this.getHtmlBody().chain,
             left = 0,
             top = 0;

        while (el){
            left += el.scrollLeft || 0;
            top += el.scrollTop || 0;
            el = el.parentNode;

            if (!acum && el.tagName == doc.tagName) {
                break;
            }
        }
        this.chain = [left, top], this.chainNode = el;
        return this;
    },

    clearScroll: function(st, sl, el){
        el = !el ? this.own : typeof el === 'string' ? this.get(el).chain : el;
        this.chain = { };
        this.chain['top'] = el['scrollTop'];
        this.chain['left'] = el['scrollLeft'];

        if (st){
            el['scrollTop'] = 0;
        }
        if (sl){
            el['scrollLeft'] = 0;
        }
        this.chainNode = el;
        return this;
    },

    scrollElement: function(aj, el){
        el = !el ? this.own : typeof el === 'string' ? this.get(el).chain : el;
        this.chain = {};
        var pty,
            uc,
            bar,
            vl;

        for (pty in aj){
            uc = pty.toUpperCase();
            bar = (uc == 'T' || uc == 'B') ? 'scrollTop' : 'scrollLeft';

            vl = aj[pty] ? parseInt(aj[pty], 10) : 0;
            el[bar] = vl;
            el[bar] = el[bar];

            this.chain[uc] = el[bar];
        }
        this.chainNode = el;
        return this;
    },

    scrollAdjust: function(aj, el){
        el = !el ? this.own : typeof el === 'string' ? this.get(el).chain : el;
        var left = el.scrollLeft, 
             top = el.scrollTop, 
             pty, 
             vl, 
             bar;
        for (pty in aj){
            vl = aj[pty] < 0 ? aj[pty] * -1 : aj[pty];
            bar = pty.toUpperCase();
            if ((bar == 'L' || bar == 'R') && !(this.isWidthScroll(el).chain)){
                continue;
            }
            if ((bar == 'T' || bar == 'B') && !(this.isHeightScroll(el).chain)){
                continue;
            }
            bar == 'L' ? left -= vl : bar == 'T' ? top -= vl : bar == 'R' ? left += vl : top += vl;
        }

        el['scrollLeft'] = left, el['scrollTop'] = top;
        this.chain = [left, top], this.chainNode = el;
        return this;
    },

    scrollTo: function(aj, el){
        el = !el ? this.own : typeof el === 'string' ? this.get(el).chain : el;
        var xy = this.getXY(el).chain, 
             pty, 
             vl, 
             bar;
        for (pty in aj){
            bar = pty.toUpperCase();
            if ((bar == 'L' || bar == 'R') && !(this.isWidthScroll(el).chain)){
                continue;
            }
            if ((bar == 'T' || bar == 'B') && !(this.isHeightScroll(el).chain)){
                continue;
            }
            vl = aj[pty] < 0 ? aj[pty] * -1 : aj[pty];
            bar == 'L' ? xy[0] -= vl : bar == 'T' ? xy[1] -= vl : bar == 'R' ? xy[0] += vl : xy[1] += vl;
        }

        window.scrollTo(xy[0], xy[1]);
        this.chain = xy, this.chainNode = el;
        return this;
    },

    getOffsetX : function(el){
        el = !el ? mc.own : typeof el === 'string' ? this.get(el).chain : el;
        this.chain = mc.getX(el).chain + mc.getWidth(false, el).chain;
        this.chainNode = el;
        return this;
    },

    getOffsetY : function(el){
        el = !el ? mc.own : typeof el === 'string' ? this.get(el).chain : el;
        this.chain = mc.getY(el).chain + mc.getHeight(false, el).chain;
        this.chainNode = el;
        return this;
    },

    getOffsetXY : function(el){
        el = !el ? mc.own : typeof el === 'string' ? this.get(el).chain : el;
        this.chain = [this.getOffsetX(el).chain, this.getOffsetY(el).chain];
        this.chainNode = el;
        return this;
    },

    setUnselectable : function(el){
        el = !el ? this.own : typeof el === 'string' ? this.get(el).chain : el;
        mc.setAttr({unselectable: 'on'}, el);
        mc.setStyle({'-moz-user-select': 'none', '-khtml-user-select': 'none'}, el);
        this.chain = el;
        this.chainNode = el;
        return this;
    },

    getColor: function(color, el){
        el = !el ? this.own : typeof el === 'string' ? this.get(el).chain : el;
        var gc = this.getStyle(color, el).chain, 
             pNode = el;

        while((gc == 'transparent' || gc == 'inherit') && pNode){
            pNode = this.getParent('', pNode).chain;
            gc = this.getStyle(color, pNode).chain;
        }

        this.chain = gc ? this.colorToHex(gc).chain : null;
        return this;
    },

    //----- Event -----
    on: function(){
        this.chain = mc.EventListener.addListener(this, Array.prototype.slice.call(arguments));
        return this;
    },

    onOwn: function(){
        this.chain = mc.EventListener.onOwn(this, Array.prototype.slice.call(arguments));
        return this;
    },

    off: function(){
        this.chain = mc.EventListener.removeListener(this, Array.prototype.slice.call(arguments));
        return this;
    },

    offOwn: function(){
        this.chain = mc.EventListener.offOwn(this, Array.prototype.slice.call(arguments));
        return this;
    },

    getControlKey: function(e){
        var key = false;
        if (e.keyCode > 7 && e.keyCode < 47 && e.keyCode != 44){
            if (mc.controlKeys.hasOwnProperty(e.keyCode)) {
                key = mc.controlKeys[e.keyCode];
            }
        }
        this.chain = key;
        return this;
    },

    getFnKey: function(e){
        var fnKey = false, 
             calc;
        if (e.type = 'keyup'){
            calc = e.keyCode - 111;
            if (calc > 0 && calc < 13) {
                fnKey = 'F' + calc;
            }
        }
        this.chain = fnKey;
        return this;
    },

    getKeyValue: function(e){
        var value = this.getControlKey(e).chain || this.getFnKey(e).chain;
        this.chain = value ? value : String.fromCharCode(e.keyCode);
        return this;
    },

    isBlurKey : function(e){
        var kc = e.keyCode;
        this.chain = (kc > 32 && kc < 41) || kc == 9 || kc == 13;
        return this;
    },

    isValueKey: function(e, space){
        if (!(this.chain = this.getControlKey(e).chain)){
            return this;
        };
        if (mc.Gecko){
            if ((this.chain == 'Delete' || this.chain == 'Insert') && e.NativeEvent['keyCode'] == 0){
                this.chain = false;
                return this;
            }
        }
        if (mc.IE && e.keyCode == 45){
            this.chain = false;
            return this;
        }
        if (space && (this.chain == 'Space')){
            this.chain = false;
            return this;
        }
        this.chain = true;
        return this;
    },

    isSizeKey : function(e){
        this.chain = (e.keyCode > 15 && e.keyCode < 46 && e.keyCode != 32);
        return this;
    },

    isPressKey: function(e){
        var cd = e.keyCode;
        if (mc.Gecko) {
            this.chain = cd == 8 || cd == 9 || cd == 13 || cd == 27 || (cd > 32 && cd < 41) || cd == 46;
            if ((cd == 45 || cd == 46) && e.NativeEvent['keyCode'] == 0){
                this.chain = false;
            }
            if (cd == 39 && e.NativeEvent['keyCode'] == 0){
                this.chain = false;
            }
        } else if (cd == 8 || cd == 45 ||cd == 46){
            this.chain = false;
        } else {
            this.chain = mc.controlKeys[cd] ? true : false;
        }
        return this;
    }

};  // MethodChain.prototype

// create mc object
var mc = new MethodChain();

mc.namespace('mc.combo', 'mc.component', 'mc.data', 'mc.dataquery', 'mc.dragdrop',
                     'mc.form',  'mc.grid',  'mc.guide','mc.panel', 'mc.types', 'mc.widget'
);
mc.namespace('mc.siteGuide');

//----- user Agent -----
(function(){
    mc.allocate(mc, {
        ua: navigator.userAgent.toLowerCase()
    });
})();

mc.allocate(mc, {
    Strict: document.compatMode == "CSS1Compat",
    Https: window.location.href.toLowerCase().indexOf("https") === 0,

    Version: (mc.ua.match( /.+(?:rv|it|ra|ie)[\/: ]([\d.]+)/ ) || [])[1],

    Gecko: /gecko/.test(mc.ua) && !/webkit|khtml|chrome/.test(mc.ua),
    IE: /msie/.test(mc.ua) && !/opera/.test(mc.ua),

    Opera: /opera/.test(mc.ua),
    Safari: /webkit|khtml/.test(mc.ua) && !/chrome/.test(mc.ua),
    Chrome: /chrome/.test(mc.ua),
    Webkit: /webkit/.test(mc.ua),

    Mac: /macintosh/.test(mc.ua) || /mac os x/.test(mc.ua),
    Windows: /windows/.test(mc.ua),
    Linux: /linux/.test(mc.ua)
});

(function(){
    mc.allocate(mc, {
        IE7: mc.IE && /msie 7/.test(mc.ua),
        IE8: mc.IE && /msie 8/.test(mc.ua),
        Safari2: mc.Safari && parseInt(mc.Version, 10) < 522 && !/adobeair/i.test(mc.ua),
        Safari3: mc.Safari && mc.ua.indexOf('wedkit/5') != -1,
        Gecko3: mc.Gecko && /rv:1.9/.test(mc.ua),
        isNotStrictIE: mc.IE && !mc.Strict
    });
})();
(function(){
    mc.allocate(mc, {
        IE6: mc.IE && !mc.IE7 && !mc.IE8,
        Gecko2: mc.Gecko && !mc.Gecko3
    });
})();
(function(){
    mc.unCalcTag = ['select'];
    if (!(mc.Strict)){ mc.unCalcTag.push('input', 'textarea'); }
    if (mc.IE || mc.Gecko){ mc.unCalcTag.push('button'); };
})();

//user agent class
(function(){
    var ht,
        cn,
        lg = mc.language;

    ht = document.getElementsByTagName('html')[0];
    cn = ht.className ? ht.className + ' ' : '';

    cn += mc.IE ? 'mc-IE ' + (mc.IE7 ? 'mc-IE7' : 'mc-IE6')
                : mc.Gecko ? 'mc-Gecko ' + (mc.Gecko3 ? 'mc-Gecko3' : 'mc-Gecko2')
                : mc.Opera ? 'mc-Opera'
                : mc.Safari ? 'mc-Safari'
                : mc.Chrome ? 'mc-Chrome' : '';
    ht.className = cn;
})();

mc.allocate(mc, {
    contentLoaded: false,
    DEFAULT_UNITS: 'px',

    _boxModel: {
        border: {
            'L': 'border-left-width', 'R': 'border-right-width',
            'T': 'border-top-width', 'B': 'border-bottom-width'
        },
        padding: {
            'L': 'padding-left', 'R': 'padding-right',
            'T': 'padding-top', 'B': 'padding-bottom'
        },
        margin: {
            'L': 'margin-left', 'R': 'margin-right',
            'T': 'margin-top', 'B': 'margin-bottom'
        }
    },

    rgb17Colors: {
        aqua: '00ffff', black: '000000', blue: '0000ff', fuchsia: 'ff00ff',
        gray: '808080', green: '008000', lime: '00ff00', maroon: '800000',
        navy: '000080', olive: '808000', orange: 'ffa500', purple: '800080',
        red: 'ff0000', silver: 'c0c0c0', teal: '008080', white: 'ffffff', yellow: 'ffff00'
    },

    controlKeys: {
    	8: 'BackSpace', 9: 'Tab', 13: 'Enter', 16: 'Shift', 17: 'Ctrl',
        18: 'Alt', 19: 'Pause', 20: 'CapsLock', 27: 'Esc', 32: 'Space',
        33: 'PageUp', 34: 'PageDown', 35: 'End', 36: 'Home', 37: 'Left',
    	38: 'Up', 39: 'Right', 40: 'Down',
        44: 'PrintScreen', 45: 'Insert', 46: 'Delete'
    },

    keyValues: {
        BACKSPACE: 8, TAB: 9, ENTER: 13, SHIFT: 16, CTRL: 17,
        ALT: 18, PAUSE: 19, CAPSLOCK: 20, ESC: 27, SPACE: 32,
        PAGEUP: 33, PAGEDOWN: 34, END: 35, HOME: 36, LEFT: 37,
        UP: 38, RIGHT: 39, DOWN: 40, PRINTSCREEN: 44, INSERT: 45, DELETE: 46
    }
});

//----- mc.RegExp -----

mc.allocate(mc, {
    trimExp: /^\s+|\s+$/g,
    allSpaceExp: /^\s*$/,

    stripTagsExp : /<\/?[^>]+>/img,
    stripScriptsExp: /<script[^>]*>((\n|\r|.)*?)<\/script>/img,

    camelCaseExp: /(-[a-z])/ig,
    dasherizeExp: /(_[a-z])/ig,
    templateExp: /\{([\w-]+)?\}/g,

    closeTagExp: /^(?:area|base|br|col|frame|hr|img|input|link|map|meta|param|range|spacer|wbr|)$/i,
    unitCheckExp: /^(\d[.\d]*)+(%|ch|cm|deg|em|ex|gd|hz|in|khz|ms|mm|pc|pt|px|rad|rem|s|vh|vm|vw){1}?/i,
    widthHeightExp: /^width|height$/,

    numericAlphaExp: /(^\-)?(\d+)(\D+)?/,
    rgbValueExp: /rgba?\(([\d]+),\s*([\d]+),\s*([\d]+)\)$/i,

    numCheckExp: /^\d+$/,
    numericExp: /\{(\d+)\}/g,
    moreExp: /^tag|text|child/
});

//----- mc.EventListener -----

mc.EventListener = function(){

    execFuncion = [];
    docReady = '';

    return {

        documentFired: false,
        removeBrowser: false,
        Events: { },

        _addAttach: function(){
            if (window.addEventListener) {
                return function(el, type, fn){
                    el.addEventListener(type, fn, false)
                }
            } else {
                if (window.attachEvent) {
                    return function(el, type, fn){
                        el.attachEvent('on' + type, fn)
                    }
                } else {
                    return mc.emptyFn;
                }
            }
        }(),

        _removeDetach: function(){
            if (window.removeEventListener) {
                return function(el, type, fn){
                    el.removeEventListener(type, fn, false)
                }
            } else {
                if (window.detachEvent) {
                    return function(el, type, fn){
                        el.detachEvent('on' + type, fn)
                    }
                } else {
                    return mc.emptyFn;
                }
            }
        }(),

        _deleteOn: function(type){
            return type.replace(/^on([A-Z])/, function(all, cap){
                return cap.toLowerCase();
            });
        },

        isExist : function(base, fn){
            if (mc.isEmpty(base).chain){
                return this.chain = -1;
            }
            var lsn = base,
                len = lsn.length,
                i,
                fnTo = fn.toString();

            for (i = 0; i < len; i++){
                if (lsn[i].fn.toString() == fnTo) {
                    this.chain = lsn[i].fn;
                    return i;
                }
            }
            return this.chain = -1;
        },

        _setFormat: function(that, event){
            var el, 
                 type, 
                 fn, 
                 scope;

            if (typeof event[1] === 'string') {
                el = event[0], type = event[1], fn = event[2], scope = event[3], opts = event[4];
            } else {
                el = that.own.id;
                type = event[0], fn = event[1], scope = event[2], opts = event[3];
            }

            return [el, type, fn, scope || that, opts || {}];
        },

        addListener: function(){
            var args = arguments,
                 ev = args[1],
                 evs = [],
                 i,
                 len,
                 el,
                 est,
                 row;

            if (typeof ev[0] === 'string' || ev[0].tagName || ev[0].nodeType == 9 || ev[0] == window) {
                ev = [mc.EventListener._setFormat(args[0], ev)];
            }

            len = ev.length;
            for (i = 0; i < len; i++){
                row = ev[i];
                if (!(el = mc.get(row[0]).chain)) {
                    throw 'Error : ' + row[0] + ' does not exist.';
                };
                if (est = mc.EventListener._addListener(el, row[1], row[2], row[3] || args[0], row[4] || {})) {
                    evs.push(est);
                }
            };
            return this.chain = evs;
        },

        _addListener: function(el, type, fn, scope, opts){
            type = /^on/.test(type) ? mc.EventListener._deleteOn(type) : type;
            type = type.toLowerCase();

            var listener = function(e){
                e = new mc.Event(e);
                if (opts.prevent == true) {
                    e.preventDefault();
                }
                if (opts.stop == true) {
                    e.stopBubble();
                }
                if (opts.bubble == true) {
                    e.bubbleDefault();
                }
                fn.call(scope, e, e._getTarget(), opts);
            };

            var id = el.id,
                 evs = mc.EventListener.Events,
                 est = false, 
                 chType;

            if (!evs[id]) {
                evs[id] = { };
            }
            chType = evs[id];
            if (!chType[type]) {
                chType[type] = [];
            }
            if (this.isExist(chType[type], fn) < 0) {
                chType[type].push({fn: fn, scope: scope, ls: listener, op: opts});
                mc.EventListener._addAttach(el, type, listener);
                est = [el, type, fn, scope, opts];
            };
            return est;
        },

        onOwn: function(){
            var args = arguments, 
                 ev = args[1], 
                 evs = [], 
                 i, 
                 len, 
                 row, 
                 est;
            if (typeof ev[0] === 'string'){
                ev = [ev];
            }
            for (i = 0, len = ev.length; i < len; i++){
                row = ev[i];
                if (est = mc.EventListener._addListener(mc.own, row[0], row[1], row[2] || args[0], row[3] || {})) {
                    evs.push(est);
                }
            };
            return this.chain = evs;
        },

        removeListener: function(){
            var args = arguments, 
                 ev = args[1], 
                 evs = [], 
                 i, 
                 len, 
                 el, 
                 est, 
                 row;
            if (typeof ev[0] === 'string' || ev[0].tagName || ev[0].nodeType == 9 || ev[0] == window) {
                ev = [mc.EventListener._setFormat(args[0], ev)];
            }
            for (i = 0, len = ev.length; i < len; i++){
                row = ev[i];
                if (!(el = mc.get(row[0]).chain)) {
                    throw 'Error : ' + row[0] + ' does not exist.';
                };
                if (est = mc.EventListener._removeListener(el, row[1], row[2])) {
                    evs.push(est);
                }
            };
            return this.chain = evs;
        },

        _removeListener: function(el, type, fn){
            type = /^on/.test(type) ? mc.EventListener._deleteOn(type) : type;
            type = type.toLowerCase();

            var id = el.id, 
                 evsEl = mc.EventListener.Events[id], 
                 est = false, 
                 index, 
                 tgls, 
                 nc;
            if (mc.isObject(evsEl).chain){

                if ((index = this.isExist(evsEl[type], fn)) > -1) {
                    tgls = evsEl[type][index]['ls'];
                    mc.EventListener._removeDetach(el, type, tgls);
                    evsEl[type].splice(index, 1);
                    nc = mc.EventListener.Events[id][type];
                    if (!nc || !nc[0]){
                        delete mc.EventListener.Events[id][type];
                    }
                    est = [el, type, fn];
                }
            }
            return est;
        },

        offOwn: function(){
            var args = arguments, 
                 event = args[1], 
                 events = [], 
                 i, 
                 len, 
                 row, 
                 est;
            for (i = 0, len = event.length; i < len; i++){
                row = event[i];
                if (est = mc.EventListener._removeListener(mc.own, row[0], row[1])) {
                    events.push(est);
                }
            };
            return this.chain = events;
        },

        clearListener: function(){
            var evs = mc.EventListener.Events, 
                 id, 
                 ccType, 
                 type, 
                 ccLs, 
                 len, 
                 i;
            for (id in evs){
                ccType = evs[id];
                for (type in ccType){
                    ccLs = ccType[type] || [], len = ccLs.length;
                    for (i = 0; i < len; i++){
                        mc.EventListener._removeDetach(mc.get(id).chain, type, ccLs[i].ls);
                    }
                }
            }

            mc.EventListener.Events = { };
            return this;
        },

        documentReady: function(){
            if (!mc.documentFired) {
                mc.documentFired = true;

                var hd,
                    cn,
                    lg = mc.language;

                hd = document.getElementsByTagName('body')[0];
                cn = hd.className ? hd.className + ' ' : '';
                cn +=  lg == 'kr' || lg == 'jp' || lg == 'cn' ? 'mc-IME ' : '';
                cn += mc.Strict ? 'mc-Strict' : '';
                hd.className = cn;

                if (mc.removeBrowser) {
                    document.removeEventListener('DOMContentLoaded', mc.EventListener.documentReady, false);
                }
            }
            if (docReady) {
                clearInterval(docReady);
                docReady = null;
            }

            var len = execFuncion.length, 
                 i;
            for (i = 0; i < len; i++){
                execFuncion[i].apply(this);
            }
            execFuncion = [];
        },

        exec: function(fn){
            if (!mc.contentLoaded) {
                setLoadEvent();
            }
            if (!mc.documentFired) {
                execFuncion.push(fn);
            }
        }

    };
}();

mc.exec = mc.EventListener.exec;

(function(){
    var setLoadEvent = function(){
        if (mc.contentLoaded) {
            return;
        }
        mc.contentLoaded = true;
        mc.removeBrowser = false;

        if (mc.IE && window == top){
            docReady = setInterval(function(){
                try {
                    document.documentElement.doScroll('left');
                    mc.documentFired || mc.EventListener.documentReady();
                } catch (e) {
                }
            }, 20);

        } else if (mc.Safari){
            docReady = setInterval(function(){
                if (/loaded|complete/.test(document.readyState)) {
                    mc.documentFired || mc.EventListener.documentReady();
                }
            }, 20);

        } else {
            mc.removeBrowser = true;
            document.addEventListener('DOMContentLoaded', mc.EventListener.documentReady, false);
        }

        mc.EventListener._addAttach(window, 'load', mc.EventListener.documentReady);
   }
   setLoadEvent();

})();

//----- mc.Event -----

mc.Event = function(ev){
    this.NativeEvent = ev;
    this.type = ev.type;

    this.target = this._getTarget();
    this.pageX = this._getPageX();
    this.pageY = this._getPageY();

    this.charCode = ev.charCode || ev.keyCode;
    this.keyCode = this._getKeyCode();
    this.button = this._getButton();

    this.shiftKey = ev.shiftKey;
    this.ctrlKey = ev.ctrlKey || ev.metaKey;
    this.altKey = ev.altKey;

    this.chain = '';
}

mc.Event.prototype = {
    _getTarget: function(){
        var eo = this.NativeEvent.target || this.NativeEvent.srcElement;
        return this._safariText(eo);
    },

    _safariText: function(eo){
        return (mc.Safari && eo.nodeType == 3) ? eo.parentNode : eo;
    },

    stopBubble: function(){
        if (this.NativeEvent.stopPropagation) {
            this.NativeEvent.stopPropagation();
        } else {
            this.NativeEvent.cancelBubble = true;
        }
        this.chain = true;
        return this;
    },

    preventDefault: function(){
        if (this.NativeEvent.preventDefault) {
            this.NativeEvent.preventDefault();
        } else {
            this.NativeEvent.returnValue = false;
        }
        this.chain = true;
        return this;
    },

    bubbleDefault: function(){
        this.stopBubble().preventDefault();
        this.chain = true;
        return this;
    },

    getRelatedTarget: function(ne){
        var ev = ne || this.NativeEvent;
        this.chain = null;

        if (ev.type == 'mouseover'){
             this.chain = ev.relatedTarget || ev.fromElement;
        } else if (ev.type == 'mouseout'){
             this.chain = ev.relatedTarget || ev.toElement;
        }
        return this;
    },

    _getPageX: function(){
        var doc = document.documentElement || document.body;
        var ev = this.NativeEvent;
        return ev.pageX || ((ev.clientX || 0) + (doc.scrollLeft || 0));
    },

    _getPageY: function(){
        var doc = document.documentElement || document.body;
        var ev = this.NativeEvent;
        return ev.pageY || ((ev.clientY || 0) + (doc.scrollTop || 0));
    },

    _getKeyCode: function(){
        var code = null, 
             ev = this.NativeEvent;
        if (/key/.test(ev.type)) {
            code = ev.keyCode || ev.charCode;
        }
        return code;
    },

    _getButton: function(){
        var ev = this.NativeEvent, 
             btn = ev.which || ev.button;
        if (mc.IE) {
            return btn == 4 ? btn - 3 : (btn == 1 ? btn - 1 : btn);
        }
        return (btn -= 1) < 0 ? 0 : btn;
    },

    isLeftClick: function(){
        this.chain = this._getButton() == 0 ? true : false;
        return this;
    },

    isMiddleClick: function(){
        this.chain = this._getButton() == 1 ? true : false;
        return this;
    },

    isRightClick: function(){
        this.chain = this._getButton() == 2 ? true : false;
        return this;
    },

    getWheelDelta: function(){
        var ev = this.NativeEvent, 
             delta = 0;
        if (/DOMMouseScroll|mousewheel/.test(ev.type)){
            if (ev.wheelDelta){
                if (mc.IE){
                    delta = ev.wheelDelta / 120;
                } else if (mc.Opera){
                    delta = -(ev.wheelDelta / 120);
                } else if (mc.Safari){
                    delta = ev.wheelDelta / 12;
                } else if (mc.Chrome){
                    delta = ev.wheelDelta / 840;
                }
            } else if (ev.detail) {
                delta = -(ev.detail || 0) / 3;
            }
        }
        this.chain = delta;
        return this;
    }
};

//----- CustomEvent -----

mc.CustomEvent = function(){
    if (!this.Custom) {
        this.Custom = {};
    };
};

mc.CustomEvent.prototype = {
    stopFire: false,

    eventTypes: function(){
        var arg = arguments;
        if (typeof arg[0] != 'string') {
            arg = arg[0];
        }
        if (!this.Custom) {
            this.Custom = { };
        }
        this.chain = { };

        for (var i = 0, len = arg.length; i < len; i++){
            var type = mc.trim(arg[i]).chain.toLowerCase();
            if (!this.Custom[type]) {
                this.Custom[type] = type;
                this.chain[type] = type;
            }
        }
        return this;
    },

    selectTypes: function(type){
        if (type != '*'){
            this.chain = this.Custom[type] ? true : false;
            return this;
        }

        this.chain = [];
        for (var pty in this.Custom){
            this.chain.push(pty);
        }
        return this;
	},

    addEvents: function(type, fn, scope){
        var results = [], 
             row, 
             i, 
             len;
        if (typeof type == 'string'){
            if (this._addEvents(type, fn, scope)) {
                results.push(this.chain);
            }
        } else {
            if (typeof type[0] == 'string') {
                type = [type];
            }
            for (i = 0, len = type.length; i < len; i++){
                row = type[i];
                if (this._addEvents(row[0], row[1], row[2])) {
                    results.push(this.chain);
                }
            }
        }
        this.chain = results;
        return this;
    },

    _addEvents : function(type, fn, scope){
        if (mc.isUndefined(this.Custom).chain) {
            return this.chain = false;
        };

        type = type.toLowerCase();
        fn = fn || mc.emptyFn;
        scope = scope || this;

        var et = this.Custom[type];
        if (!et || mc.isUndefined(et).chain) {
            return this.chain = false;
        };

        var ce = {fn: fn, scope: scope, fire: 0};
        if (et == type) {
            this.Custom[type] = [ce];
            return this.chain = ce;
        };

        if (mc.EventListener.isExist(this.Custom[type], fn) < 0) {
            this.Custom[type].push(ce);
            return this.chain = ce;
        };
        return this.chain = false;
    },

    fireEvent : function(){
        var etype = this.Custom[arguments[0].toLowerCase()];
        if (!etype || etype == arguments[0]){
            this.chain = false;
            return this;
        }

        var rows, 
             len, 
             arg, 
             i, 
             lst, 
             fire = [];
        if (mc.isObject(etype).chain && this.stopFire == false){
            if ((len = etype.length) > 0){
                arg = Array.prototype.slice.call(arguments, 1);
                for (i = 0; i < len; i++){
                    lst = etype[i];
                    lst.fn.apply(lst.scope, arg);
                    lst.fire += 1;
                    fire.push(lst, arg);
                }
            }
        }
        this.chain = fire;
        return this;
    },

    removeEvent : function(type, fn, scope){
        var tl = type.toLowerCase(),
             eType = this.Custom[tl],
             index,
             remove = null;

        if (mc.isObject(eType).chain){
            if (mc.EventListener.isExist(eType, fn) > -1) {
                remove = eType.splice(this.chain, 1);
                var nc = this.Custom[tl];
                if (!nc || !nc[0]){
                    delete this.Custom[tl];
                }
            };
        }

        this.chain = remove;
        return this;
	},

    cancelFire: function(){
        this.chain = this.stopFire = true;
        return this;
	},

    resumeFire: function(){
        this.chain = this.stopFire = false;
        return this;
	},

    clearEvents: function(){
        this.chain = this.Custom;
        this.Custom = { };
        return this;
	},

    applyEvents: function(ets, that){
        if (!ets){return;}
        if (typeof ets[0] === 'string'){
            ets = [ets];
        }
        var len = ets.length, 
             i, 
             et, 
             pty;
        for (i = 0; i < len; i++){
            et = ets[i];
            this.eventTypes(et[0]);
            this.addEvents(et[0], et[1], et[2] || that || this);
        }
        this.chain = this.Custom;
        return this;
	}
};

//-----  mc.TemplateClass -----
mc.TemplateClass = function(tm){
    Template = '';
    this.set(tm);
};

mc.TemplateClass.prototype = {
    set: function(){
        var arg = arguments, 
             len = arg.length, 
             src = [], 
             i;
        for (i = 0; i < len; i++){
            src.push(arg[i]);
        }
        mc.chain = src.join('');
        this.Template = src.join('');
        return this;
    },

    _convert: function(data){
        return this.Template.replace(mc.templateExp, function(src, key){
                return data[key];
            }
        );
    },

    apply: function(el, adjacent, data){
        el = !el ? this.own : typeof el === 'string' ? mc.get(el).chain : el;
        adjacent = (adjacent || 'beforeEnd').toLowerCase();
        mc.insertHTML(adjacent, this._convert(data), el);

        this.chain = data;
        return mc;
    },

    replace: function(el, data){
        el = !el ? this.own : typeof el === 'string' ? mc.get(el).chain : el;
        mc.insertHTML('beforeBegin', this._convert(data), el);
        mc.removeElement(el, false);

        this.chain = data;
        return mc;
    },

    clear: function(){
        this.chain = this.Template;
        mc.chain = '';
        this.Template = '';
        return mc;
    }
};

//----- mc.Json -----
mc.Json = function(){

    var applyJson = function(that, hash, doc) {
        if (!hash){
            return doc;
        }
        if (!hash['tag']) {
            hash['tag'] = 'div';
        }
        var tagName = (hash['tag']).toLowerCase(), 
             pty, 
             lcPty, 
             chg, 
             tx, 
             nd, 
             j;
        doc.push('<' + tagName);

        for (pty in hash) {
            if (mc.moreExp.test(pty.toLowerCase())) {
                continue;
            }
            doc.push(' ' + mc.setClassFor(pty).chain + '="' + hash[pty] + '"');
        };

        if (mc.closeTagExp.test(tagName)) {
            doc.push('/>');
        } else {
            doc.push('>');
            if (tx = hash['text']) {
                doc.push(tx);
            }
            if (nd = hash['child']) {
                for (j = 0, len = nd.length; j < len; j++) {
                    doc.push(applyJson(that, nd[j], doc));
                }
            }
            doc.push('</' + tagName + '>');
        }
        return doc;
    };

    return {

        JSON : '',

        set: function(json){
            this.JSON = (mc.isArray(json).chain) ? json : [json];
            mc.chain = this.JSON;
            return this;
        },

        apply: function(json, el, ad, node){
            el = !el ? this.own : typeof el === 'string' ? mc.get(el).chain : el;

            json = mc.isArray(json).chain ? json : [json];
            var doc = [], 
                 i, 
                 one;
            for (i = 0; json[i]; i++) {
                doc = applyJson(this, json[i], doc);
            };

            ad = (ad || 'beforeend').toLowerCase();
            one = mc.insertHTML(ad, doc.join(''), el).chain;

            mc.chain = node == true ? one : json;
            return mc;
        },

        add: function(json){
            json = mc.isArray(json).chain ? json : [json];
            var tl = this.JSON, 
                 len = json.length, 
                 i;

            for (i = 0; i < len; i++) {
                this.JSON[tl.length] = json[i];
            }

            mc.chain = json;
            return mc;
        },

        addApply: function(json, el, ad, node){
            el = !el ? this.own : typeof el === 'string' ? mc.get(el).chain : el;

            this.add(json);
            var doc = [], 
                 i, 
                 one;
            for (i = 0; this.JSON[i]; i++) {
                doc = applyJson(this, this.JSON[i], doc);
            };

            ad = (ad || 'beforeend').toLowerCase();
            one = mc.insertHTML(ad, doc.join(''), el).chain;
            mc.chain = node == true ? one : json;
            return mc;
        },

        replace: function(json, el, node) {
            el = !el ? this.own : typeof el === 'string' ? mc.get(el).chain : el;
            mc.removeChild(el);
            this.apply(json, el, 'beforeend', node);

            return mc;
        },

        remove: function(index){
            if (!index) {
                this.chain = null;
                return mc;
            }
            if (mc.isNumber(index).chain) {
                index = [index];
            }

            var len = this.JSON.length, 
                 i, 
                 rtn = [], 
                 j = 0, 
                 cJSON = [];
            for (i = 0; i < len; i++){
                mc.isContains(index, i).chain ? rtn.push(this.JSON[i]) : cJSON.push(this.JSON[i]);
            }
            if (cJSON[0]){
                this.JSON = cJSON;
            }

            mc.chain = rtn;
            return mc;
        },

        clear: function(){
            mc.chain = this.JSON;
            this.JSON = [];
            return mc;
        },

        addChild: function(index, json){
            if (!index) {
                index = 0;
            }
            json = mc.isArray(json).chain ? json : [json];

            var data, 
                 len = json.length, 
                 i, 
                 cl;
            if (data = this.JSON[index]){
                if (!data.child){
                    data['child'] = [];
                }
                cl = data.child.length || 0;
                for (i = 0; i < len; i++) {
                    data.child[cl + i] = json[i];
                }
            }
            mc.chain = json;
            return mc;
        },

        convertHTML: function(json){
            json = mc.isArray(json).chain ? json : [json];
            var doc = [], 
                 i;
            for (i = 0; json[i]; i++) {
                doc = applyJson(this, json[i], doc);
            };

            mc.chain = doc.join('');
            return mc;
        },

        addKey: function(key, obj, rp){
            if (rp && this.JSON[key]){
                this.chain = false;
                return this;
            }
            this.JSON[key] = {};
            mc.allocate(this.JSON[key], obj);

            this.chain = [key, obj, rp];
            return mc;
        },

        getKeyValue: function(json, key, value){
            var i, 
                 len = json.length;
            for (i = 0; i < len; i++){
                if (mc.getKeyValueOf(json[i], key, value).chain){
                    mc.chain = json[i];
                    mc.chainIndex = i;
                    break;
                };
            }
            return mc;
        }

    };
}();

//----- mc.Selector -----
mc.Selector = function(){
    var markNumber = 1;
    var thisBaseArray = false;

    var cache = { };
    var comExp = /^(\s?[\>+~]\s?|\s|$)/;

    var alphaExp = /\D/;
    var nthExp = /(\d*)n\+?(\d*)/;
    var idExp = /^(#)([\w-]+)/;

    var attrExp = /^(?:[\[\{])?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}]/;
    var pseudoExp = /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/;

    getElements = function(els, root, tag){
        var elements = [], 
             i, 
             el, 
             nodes, 
             j, 
             nd;
        if (els){
            if (!mc.isArray(els).chain) {
                els = [els];
            }
            tag = tag || "*";
            for (i = 0; el = els[i]; i++){
                if (thisBaseArray) {
                    if (el.tagName.toLowerCase() == tag || tag == '*') {
                        elements.push(el);
                    }
                } else {
                    nodes = el.getElementsByTagName(tag);
                    for (j = 0; nd = nodes[j]; j++) {
                        if (nd.tagName !== '!') {
                            elements.push(nd);
                        }
                    };
                };
            };
        };
        return elements;
    };

    setParamNode = function(els){
        var results = [], 
             i, 
             nd;
        for (i = 0; nd = thisBaseArray[i]; i++){
            if (nd.nodeType == 1) {
                results.push(nd);
            }
        }
        return results;
    };

    getId = function(els, root, id){
        var nodes = [], 
             i, 
             el;
        if (document.getElementById(id)){
            if (!mc.isArray(els).chain) {
                els = getElements(els, root, "*");
            }
            for (i = 0; el = els[i]; i++){
                if (el && el.id == id) {
                    nodes.push(el);
                }
            }
        };
        return nodes;
    };

    getClass = function(els, root, cn){
        var elements = [], 
             i;
        if (!mc.isArray(els).chain) {
            els = getElements(els, root, '*');
        }

        for(i = 0; el = els[i]; i++){
            if ((' ' + el.className + ' ').indexOf(cn) != -1) {
                elements.push(el);
            }
        }
        return elements;
    };

    filtersOut = function(els){
        var mn = markNumber++, 
             el, 
             i, 
             elements = [];
        for (i = 0; el = els[i]; i++) {
            if (el.markNumber != mn){
                elements.push(el);
                el.markNumber = mn;
            }
        };
        deleteMark(elements);
        return elements;
    };

    deleteMark = function(els){
        var el, 
             i;
        if (mc.IE) {
            for (i = 0; el = els[i]; i++) {
                el.removeAttribute('markNumber');
                el.removeAttribute('nthNumber');
            };
        } else {
            for (i = 0; el = els[i]; i++) {
                el.markNumber = el.nthNumber = undefined;
            };
        };
    }

    getChild = function(els, root, tag){
        tag = mc.trim(tag).chain;
        if (tag == '>' || tag == '/'){
            return els;
        } else {
            tag = tag || "*";
            var elements = [], 
                 i, 
                 el, 
                 ch, 
                 j, 
                 nd;
            var uctn = tag.toUpperCase();

            for (i = 0; el = els[i]; i++){
                ch = el.childNodes || el.children;
                for (j = 0; nd = ch[j]; j++){
                    if (nd.nodeName == tag || nd.nodeName == uctn ||  tag == '*') {
                        elements.push(nd);
                    }
                };
            };
        };
        return elements;
    };

    getAdjacent = function(els, root, tag){
        tag = mc.trim(tag).chain;
        if (tag == '+'){
            return els;
        } else {
            var elements = [], 
                 i, 
                 el, 
                 uptn = tag.toUpperCase();
            for (i = 0; el = els[i]; i++){
                el = nextNode(el);
                if (el && (el.nodeName == uptn || el.nodeName == tag || tag == '*')) {
                    elements.push(el);
                }
            }
            return elements;
        }
    };

    getSibling = function(els, root, tag){
        tag = mc.trim(tag).chain;
        if (tag == '~'){
            return els;
        } else {
            var elements = [], 
                 i, 
                 el;
            for(i = 0; el = els[i]; i++){
                while((el = el.nextSibling) && (el.nodeType != 1 || (tag == '*' || el.tagName.toLowerCase()!= tag)));
                if(el) {
                    elements.push(el);
                }
            };
        };
        return elements;
    };

    nextNode = function(el){
        while((el = el.nextSibling) && el.nodeType != 1);
        return el;
    };

    prevNode = function(el){
        while((el = el.previousSibling) && el.nodeType != 1);
        return el;
    };

    getAttr = function(els, attr, op, value){
        var opFn = mc.Selector.operators[op], 
             elements = [], 
             k, 
             el, 
             at;

        for (k = 0; el = els[k]; k++){
            if (attr == 'class' || attr == 'className'){
                at = el.className;
            } else if (attr == 'for'){
                at = el.htmlFor;
            } else if (attr == 'href'){
                at = el.getAttribute('href', 2);
            } else {
                at = el.getAttribute(attr);
            }

            if ((!opFn && at) || (opFn && opFn(at, value))) {
                elements.push(el);
            }
        }
        return elements;
    };

    getCssValue = function(els, attr, op, value){
        var opFn = mc.Selector.operators[op], 
             elements = [], 
             k, 
             at;
        for (k = 0; el = els[k]; k++){
            at = mc.getStyle(attr, el).chain;
            if ((!opFn && at) || (opFn && opFn(at, value))) {
                elements.push(el);
            }
        }
        return elements;
    };

    getPseudos = function(els, psFn, abn){
        return mc.Selector.pseudos[psFn](els, abn);
    };

    setNthMark = function(nd, tag, k, markNumber, ofType){
        if (ofType){
            if (nd.tagName == tag){
                nd.nthNumber = k;
                nd.markNumber = markNumber;
                return true;
            }
        } else {
            nd.nthNumber = k++;
            nd.markNumber = markNumber;
            return true;
        }
        return false;
    };

    getNthChild = function(els, anb, reverse, ofType) {
        var nodes = [], 
             uList = [], 
             i, 
             el, 
             pn, 
             ch, 
             j, 
             k, 
             nd, 
             oe, 
             nth, 
             an, 
             b, 
             nthSet;
        markNumber++;

        for (i = 0; el = els[i]; i++) {
            pn = el.parentNode;
            if (el.markNumber != markNumber && pn.markNumber != markNumber) {
                ch = pn.childNodes || pn.children;
                pn.markNumber = markNumber;
                uList.push(pn);
                if (!reverse) {
                    for (k = 1, j = 0; nd = ch[j]; j++) {
                        if (nd.nodeType == 1){
                            nthSet = setNthMark(nd, el.tagName, k, markNumber, ofType);
                            if (nthSet){
                                k++;
                                uList.push(nd);
                            }
                        };
                    };
                } else {
                    for (k = 1, j = ch.length - 1; j >= 0; j--) {
                        nd = ch[j];
                        if (nd.nodeType == 1){
                            nthSet = setNthMark(nd, el.tagName, k, markNumber, ofType);
                            if (nthSet){
                                k++;
                                uList.push(nd);
                            }
                        };
                    };
                };
            };
        };

        oe = anb == 'even' ? '2n+0' : anb == 'odd' ? '2n+1' : null; //even, odd
        if (!oe) {
            oe = alphaExp.test(anb) ? anb : 'n+' + anb;
        }   ///\D/
        nth = oe.match(nthExp);  ///(\d*)n\+?(\d*)/
        an = Number((nth[1] || 1));
        b = Number(nth[2]);

        for (i = 0; el = els[i]; i++) {
            if (an == 1) {
                if (b == 0 || el.nthNumber == b) {
                    nodes.push(el);
                }
            } else if ((el.nthNumber + b) % an == 0){   //2n+1
                nodes.push(el);
            };
        };
        deleteMark(uList);
        return nodes;
    };

    return {

        build : function(ts, root){
            return mc.Selector.buildFunction(ts);
        },

        buildFunction : function(slt, root){
            var wrap = ['var mth = function(root){\n var el = root || document;\n'];
            if (thisBaseArray) {
                wrap.push('el = setParamNode(el);\n');
            }
            var ptns, 
                 ptFn, 
                 rpSlt, 
                 pty, 
                 mr, 
                 mName, 
                 mr1, 
                 comCheck = true;
            var bName = function(){ };
            ptns = mc.Selector.patterns;
            ptFn = mc.Selector.criteria;

            while(slt && rpSlt != slt){
                rpSlt = slt;
                for (pty in ptns) {
                    if (mr = slt.match(ptns[pty])){
                        mName = comCheck ? pty : bName;
                        mr1 = mc.trim(mr[1]).chain;

                        if (mr1 == '[' || mr1 == '{'){
                            mr = slt.match(attrExp);
                        } else if (mr1 == ':'){
                            mr = slt.match(pseudoExp);
                        }
                        if (comCheck){
                            wrap.push(ptFn[pty].replace(mc.numericExp, function(x, i){return mr[i];}));
                        } else {
                            wrap.push(ptFn[bName].replace(mc.numericExp, function(x, i){return mr[i];}));
                        }
                        comCheck = true;

                        if (mr1.match(comExp)) {  // >+~
                            bName = mName;
                            comCheck = false;
                        }
                        slt = slt.replace(mr[0], '');
                        slt = mc.trim(slt).chain;
                        break;
                    }
                }
            }
            wrap.push('return el;\n};\n');
            eval(wrap.join('\n'));
            return mth;
        },

        patterns : {
            sibling : /^(\s*~\s*)/,
            child : /^(\s*>\s*)/,
            adjacent : /^(\s*\+\s*)/,

            id : /^#([\w-]+)/,
            className : /^\.([\w-]+)/,
            tagName : /^\s*(\*|[\w\-]+)/,

            attr : /^(\[)/,
            cssValue : /^({)/,
            pseudo : /^(:)/
        },

        criteria : {
            sibling : 'el = getSibling(el, root, "{1}");\n',
            child : 'el = getChild(el, root, "{1}");\n',
            adjacent : 'el = getAdjacent(el, root, "{1}");\n',

            id : 'el = getId(el, root, "{1}");\n',
            className : 'el = getClass(el, root, "{1}");\n',
            tagName : 'el = getElements(el, root, "{1}");\n',

            attr : 'el = getAttr(el, "{1}", "{2}", "{3}");\n',
            cssValue : 'el = getCssValue(el, "{1}", "{2}", "{3}");\n',
            pseudo : 'el = getPseudos(el, "{1}", "{2}");'
        },

        operators : {
            '=': function(at, v){
                return at == v;
            },
            '*=': function(at, v){
                return at && String(at).indexOf(v) > -1;
            },
            '^=': function(at, v){
                return at && String(at).substr(0, v.length) == v;
            },
            '|=': function(at, v){
                return at && (at == v || String(at).substr(0, v.length+1) == v + '-');
            },
            '$=': function(at, v){
                return at && String(at).substr(at.length - v.length) == v;
            },
            '%=': function(at, v){
                return (at % v) == 0;
            },
            '~=': function(at, v){
                return at && (' ' + String(at) + ' ').indexOf(' ' + v + ' ') > -1;
            },
            '!=': function(at, v){
                return at != v;
            }
        },

        pseudos : {
            'first-child' : function(els){
                var nodes = [], 
                     el, 
                     k;
                for (k = 0; el = els[k]; k++){
                    if (!prevNode(el)) {
                        nodes.push(el);
                    }
                };
                return nodes;
            },

            'last-child' : function(els){
                var nodes = [], 
                     el, 
                     k;
                for(k = 0; el = els[k]; k++){
                    if (!nextNode(el)) {
                        nodes.push(el);
                    }
                };
                return nodes;
            },

            'only-child' : function(els){
                var nodes = [], 
                     el, 
                     k;
                for (k = 0; el = els[k]; k++){
                    if (!prevNode(el) && !nextNode(el)) {
                        nodes.push(el);
                    }
                }
                return nodes;
            },

            'nth-child' : function(els, anb) {
                return getNthChild(els, anb);
            },

            'nth-last-child' : function(els, anb){
                return getNthChild(els, anb, 'R');
            },

            'nth-of-type' : function(els, anb){
                return getNthChild(els, anb, false, 'T');
            },

            'nth-last-of-type' : function(els, anb){
                return getNthChild(els, anb, 'R', 'T');
            },

            'first-of-type' : function(els){
                return getNthChild(els, 1, false, 'T');
            },

            'last-of-type' : function(els){
                return getNthChild(els, 1, 'R', 'T');
            },

            'only-of-type' : function(els){
                var nodes = mc.Selector.pseudos['first-of-type'](els);
                return mc.Selector.pseudos['last-of-type'](nodes);
            },

            'empty' : function(els){
                var nodes = [], 
                     i, 
                     el, 
                     chs;
                for(i = 0; el = els[i]; i++){
                    chs = el.childNodes || el.children;
                    if (chs.length == 0) {
                        nodes.push(el);
                    }
                }
                return nodes;
            },

            'not' : function(els, s){
                var ts = mc.trim(s).chain;
                if(!cache[ts]) {
                    cache[ts] = mc.Selector.build(ts);
                }
                var sNodes = cache[ts]();

                var mn = markNumber++, 
                     i, 
                     el, 
                     nodes = [];
                for (i = 0; el = sNodes[i]; i++) {
                    if (el.markNumber != mn) {
                        el.markNumber = mn;
                    }
                };

                for (i = 0; el = els[i]; i++) {
                    if (el.markNumber != mn){
                        el.markNumber = mn;
                        nodes.push(el);
                    }
                };
                deleteMark(sNodes);
                deleteMark(nodes);
                return nodes;
            },

            'checked' : function(els){
                var nodes = [], 
                     i, 
                     el;
                for (i = 0; el = els[i]; i++){
                    if(el.checked) {
                        nodes.push(el);
                    }
                }
                return nodes;
            },

            'enabled' : function(els){
                var nodes = [], 
                     i, 
                     el;
                for (i = 0; el = els[i]; i++){
                    if (!el.disabled) {
                        nodes.push(el);
                    }
                }
                return nodes;
            },

            'disabled' : function(els){
                var nodes = [], 
                     i, 
                     el;
                for (i = 0; el = els[i]; i++){
                    if (el.disabled) {
                        nodes.push(el);
                    }
                }
                return nodes;
            },

            'first-node' : function(els){
                return els[0] || [];
            }
        },

        select : function(selector, root){
            if (!selector) {return false;}

            if (!root || root == document){
                root = document;
            } else if (root.ownElement){
                root = root.ownElement;
            } else if (typeof root === 'string'){
                var sharp;
                var rt = (sharp = root.match(idExp)) ? document.getElementById(sharp[2])
                                                   : document.getElementById(root);
                root = rt || document.getElementsByTagName(root).item(0);
            };

            var selectors = selector.split(',');
            var results = [],
                 i,
                 len = selectors.length,
                 ts,
                 els,
                 mark;

            for (i = 0; i < len; i++){
                ts = mc.trim(selectors[i]).chain;
                if (!cache[ts]) {
                    cache[ts] = mc.Selector.build(ts, root);
                }
                els = cache[ts](root);
                if (els && els != document) {
                    results = results.concat(els);
                }
            }

            if (len > 1 && results.length > 0) {
                results = filtersOut(results);
            }
            this.chain = results[0] ? results : null;
            return this;
        },

        arraySelect : function(selector, base){
            thisBaseArray = base;
            mc.Selector.select(selector);
            thisBaseArray = false;
            return this;
        }
    };
}();

//----- mc.Request -----
mc.Request = function(){
    this.Request;
    this.Interval = { };
    this.Timeout;
};

mc.Request.prototype = {
    request: function(opts, sendData) {
        try {
            var xhr = mc.Http._newXHR();
            xhr.req.open(opts.method, opts.url, opts.async);

            mc.eachHash(opts.headers, function(key, value){
                xhr.req.setRequestHeader(key, value)
            });

            this.stateChange(xhr, opts);
            xhr.req.send(sendData);
        } catch (e) { };

        return this;
    },

    stateChange: function(xhr, opts) {
        var that = this;
        this.Request = opts;

        this.Interval = window.setInterval(function() {
            if (xhr.req && xhr.req.readyState == 4){
                that.httpComplete(xhr);
            }
        }, opts.interval);

        if (opts.timeout > 0){
            this.Timeout = window.setTimeout(function() {
                that.timeoutAbort(xhr)
            }, opts.timeout);
        }
    },

    httpComplete: function(xhr){
        this.deleteTimer();

        if ((xhr.req.status > 199) && (xhr.req.status < 300)){
            this.setSuccess(xhr, this.Request);
            mc.Http._successComplete(this.Request);
        } else {
            this.setFailure(xhr, this.Request);
            mc.Http._failureComplete(this.Request);
        }
        delete this.Request;
    },

    setSuccess: function(xhr, trans){
        var req = xhr.req;
        trans.completeStatus = 'S';  // success complete
        trans.status = req.status;
        trans.statusText = req.statusText;
        trans.responseText = req.responseText;
        trans.responseXML = req.responseXML;

        try {
            trans.allHeaders = req.getAllResponseHeaders();
        } catch (e){ };

        xhr.req = req = null;
    },

    setFailure: function(xhr, trans){
        trans.completeStatus = 'F';  // failure complete
        trans.status = xhr.req.status;
        trans.statusText = xhr.req.statusText || 'Failure';
        trans.responseText = trans.responseXML = trans.getAllHeaders = trans.getHeader = null;
        xhr.req = null;
    },

    timeoutAbort: function(xhr){
        xhr.req.abort();
        this.deleteTimer();

        var trans = this.Request;
        trans.completeStatus = 'T';  // timeout complete
        trans.statusText = 'Timeout Abort';
        trans.status = trans.responseText = trans.responseXML = trans.getAllHeaders = trans.getHeader = null;

        xhr.req = null;
        mc.Http._timeoutComplete(trans);
    },

    deleteTimer: function() {
        window.clearInterval(this.Interval);
        this.Interval = null;

        if (this.Timeout){
            window.clearTimeout(this.Timeout);
            this.Timeout = null;
        }
    }
};

//----- mc.Transport -----
mc.Transport = function() {
    mc.allocate(this, MethodChain.prototype);
    this.XHRnumber = 101;
    this.XHRActiveCount = 0;
};

mc.Transport.prototype = {
    baseOptions: {
        async: true,
        caching: false,
        callbackScope: '',
        data: '',

        encode: 'UTF-8',
        form: false,
        headers: '',

        interval: 100,
        message: 'Processing...',
        method: 'POST',

        onFailure: '',
        onSuccess: '',
        onTimeout: '',

        params: '',
        put: false,
        repeat: false,
        showElement: null,
        showMessage: false,

        timeout: 0,
        url: '',
        useName: false,
        useScripts: false
    },

    defaultHeaders: {
        'X-Requested-With': 'XMLHttpRequest',
        'Accept': 'text/html, text/plain, text/javascript, application/json, application/xml, text/xml, */*'
    },

    request: function(options){
        var opts = { };
        opts['XHRid']  = this._XHRid();

        this.addHash(opts, this.baseOptions)
             .addHash(opts, options);

        this.fireStart(opts);

        if (opts.showMessage){
            mc.get(opts.showElement).chain.innerHTML = opts.message;
        }

        opts.headers = { };
        this.eachHash(this.defaultHeaders, function(key, value){
            opts.headers[key] = value;
        });

        var sendData = '',
             en;
        if (opts.form){
            sendData = this._formSerialize(opts.form, opts.useName);
        }

        opts.method = opts.method.toUpperCase();

        if (opts.data) {
            en = this._encode(opts.data);
            if (en){
                sendData ? sendData += '&' + en : sendData = en;
            }
        }

        if (opts.method == 'GET' && sendData) {
            opts['url'] += ((this.isContains(opts.url, '?').chain ? '&' : '?') + sendData);
            sendData = '';
        }

        if (opts.method == 'GET' && opts.caching === true) {
            opts['url'] += ((this.isContains(opts.url, '?').chain ? '&' : '?') +
                            'caching=' + (new Date().getTime()));
        }
        if (opts.method == 'POST'){
            this.addKeyValue(opts.headers, 'Content-type',
                'application/x-www-form-urlencoded' + ((opts.encode) ? '; charset=' + opts.encode : ''));
        }

        opts.callbackScope = opts.callbackScope || this;
        this.XHRActiveCount++;

        var newRequest = new mc.Request();
        newRequest.request(opts, sendData);

        this.chain = opts;
        return this;
    },

    fireStart: function(opts) {
        if (!this.ce){
            this.ce = new mc.CustomEvent();
        }
        this.ce.clearEvents();
        this.ce.applyEvents(opts.events, this);
        this.ce.fireEvent('start');
    },

    _successComplete: function(trans) {
        this.XHRActiveCount--;
        this._clearMessage(trans);

        this.ce.fireEvent('success', this, trans);

        if (trans.useScripts) {
            if (trans.put) {
                trans.put(trans);
            } else {
                this.splitScripts(trans.responseText);
                if (this.chain) {
                    this.execScripts(this.chain);
                }
                if (this.outScripts && mc.get(trans.showElement).chain){
                    mc.chain.innerHTML = this.outScripts;
                }
            }
        }

        if (trans.metaSuccess) {
            trans.metaSuccess.call(trans.metaSucScope, trans, 'S');
        }
        if (trans.onSuccess){
            var sc = trans.callbackScope;
            sc._successComplete ? this.call(trans.onSuccess, sc, trans) : trans.onSuccess.call(sc, trans);
        }
    },

    _failureComplete: function(trans) {
        this.XHRActiveCount--;
        this._clearMessage(trans);

        this.ce.fireEvent('failure', this, trans);

        if (trans.metaFailure) {
            trans.metaFailure.call(trans.metaFailScope, trans, 'F');
        }
        if (trans.onFailure){
            var sc = trans.callbackScope;
            sc._failureComplete ? this.call(trans.onFailure, sc, trans) : trans.onFailure.call(sc, trans);
        }
    },

    _timeoutComplete: function(trans){
        this.XHRActiveCount--;
        this._clearMessage(trans);

        this.ce.fireEvent('timeout', this, trans);

        if (trans.metaTimeout) {
            trans.metaTimeout.call(trans.metaFailScope, trans, 'T');
        }
        if (trans.onTimeout){
            var sc = trans.callbackScope;
            sc._timeoutComplete ? this.call(trans.onTimeout, sc, trans) : trans.onTimeout.call(sc, trans);
        }
    },

    _clearMessage: function(trans){
        if (trans.showMessage){
            mc.get(trans.showElement).chain.innerHTML = '';
        }
    },

    _newXHR: function() {
        var xhr, 
             obj;
        if (window.ActiveXObject){
            try {
                obj = new ActiveXObject('Microsoft.XMLHTTP');
            } catch(e){
                obj = new ActiveXObject('MSXML2.XMLHTTP');
            }
        } else {
            obj = new XMLHttpRequest();
        }
        return xhr = {req: obj};
    },

    _formSerialize: function(form, useName) {
        if (typeof form === 'string') {
            form = mc.get(form).chain;
        }
        if (form){
            return this.getEncode(form.elements, useName);
        }
        return '';
    },

    getEncode: function(nodes, useName) {
        var en = [],
            len = nodes.length,
            i,
            node,
            nm,
            tn,
            opt,
            nopt,
            j,
            vl,
            onm,
            tp;

        for (i = 0; i < len; i++){
            node = nodes[i];
            tn = node.tagName.toLowerCase();
            if (tn != 'input' && tn != 'textarea' && tn != 'select') {
                continue;
            };

            nm = useName ? node.name : node.id;
            if (!nm || node.disabled) {
                continue;
            };

            switch (tp = node.type.toLowerCase()){
                case 'radio':
                case 'checkbox':
                    if (node.checked){
                        en.push(encodeURIComponent(nm) + '=' + encodeURIComponent(node.value));
                    }
                    break;
                case 'select-one':
                case 'select-multiple':
                    nopt = node.options;
                    for (j = 0; j < nopt.length; j++){
                        opt = nopt[j];
                        if (opt.selected){
                            vl = opt.getAttribute('value') || opt.value || opt.text;
                            onm = useName ? nm : opt.id || opt.name || nm;
                            en.push(encodeURIComponent(onm) + '=' + encodeURIComponent(vl));
                        }
                    }
                    break;

                default:
                    en.push(encodeURIComponent(nm) + '=' + encodeURIComponent(node.value));
                    break;
            }
        }
        return en.join('&');
    },

    _encode: function(data) {
        if (!data) {
            return '';
        }
        var rd = [],
             ep,
             ds,
             pty;

        if (typeof data === 'string'){
            ds = data.split('=');
            data = { };
            data[ds[0]] = ds[1];
        }

        for (pty in data){
            if (typeof data[pty] === 'string'){
                rd.push(encodeURIComponent(pty) + '=' + encodeURIComponent(data[pty]));
            } else {
                ep = encodeURIComponent(pty);
                this.eachArray(data[pty], function(value){
                    rd.push(ep + '=' + encodeURIComponent(value));
                }, this)
            }
        }
        return rd.join('&');
    },

    _XHRid: function() {
        return 'XHRid' + this.XHRnumber++;
    },

    getHeader: function(trans, pty) {
        var hds = trans.allHeaders,
            spAll = hds.split('\n'),
            len = spAll.length,
            i,
            idx,
            rh = {},
            spl,
            name;

        for (i = 0; i < len; i++){
            spl = spAll[i];
            if ((idx = spl.indexOf(':')) != -1){
                name = spl.substring(0, idx);
                if ((!pty) || pty.toLowerCase() == name.toLowerCase()) {
                    rh[name] = spl.substring(idx + 2);
                }
            }
        }
        this.chain = rh;
        return this;
    },

    getTransport: function(trans, pty) {
        var hash = { };
        if (trans[pty]){
            this.chain = typeof trans[pty] == 'string' ? trans[pty] : hash[pty] = trans[pty];
        }
        return this;
    },

    getOptions: function(opts){
        var rtn = {}, 
             pty, 
             i;
        if (opts){
            var ptys = this.commaSplit(opts).chain, 
                 len = ptys.length;
            for (i = 0; i < len; i++) {
                pty = ptys[i];
                rtn[pty] = this.baseOptions[pty] ? this.baseOptions[pty] : 'Not defined';
            }
        } else {
            for (pty in this.baseOptions) {
                rtn = this.baseOptions[pty];
            }
        }
        this.chain = rtn;
        return this;
    },

    setOptions: function(opts){
        this.chain = { };
        for (var pty in opts) {
            this.chain[pty] = this.baseOptions[pty] = opts[pty];
        }
        return this;
    },

    removeOptions: function(opts){
        var ptys = this.commaSplit(opts).chain, 
             len = ptys.length, 
             pty, 
             i;
        this.chain = { };

        for (i = 0; i < len; i++) {
            pty = ptys[i];
            if (this.baseOptions[pty]){
                this.chain[pty] = this.baseOptions[pty];
                delete this.baseOptions[pty];
            }
        }
        return this;
    },

    repeat: function(opts){
        if (!opts) {
            opts = { };
        }
        this.request(opts);

        if (!opts.repeat){
            opts['repeat'] = 5000;
        };
        this.periodicTimer = this.periodical(this.request, opts.repeat, this, opts);

        this.chain = opts;
        return this;
    },

    cancelRepeat: function(){
        if (this.periodicTimer){
            this.clearTimer(this.periodicTimer);
        };
        return this;
    }

};

mc.Http = new mc.Transport();

//----- Date -----
/*
 * based on work by below site
 * http://www.php.net/manual/en/function.date.php
 * http://www.xaprb.com/blog/2005/12/20/javascript-date-parsing/
 * http://www.merlyn.demon.co.uk/js-date7.htm
 */
(function() {
mc.allocate(Date, {
    defaultFormat: 'm/d/Y',
    parseFunctions: {count: 0},
    parseRegexes: [],
    formatFunctions: {count: 0},
    daysInMonth : [31,28,31,30,31,30,31,31,30,31,30,31],
    y2kYear: 50,

    monthFullNames: {
        'January': 0,
        'February': 1,
        'March': 2,
        'April': 3,
        'May': 4,
        'June': 5,
        'July': 6,
        'August': 7,
        'September': 8,
        'October': 9,
        'November': 10,
        'December': 11
    },

    monthShortNames: {
        'Jan': 0,
        'Feb': 1,
        'Mar': 2,
        'Apr': 3,
        'May': 4,
        'Jun': 5,
        'Jul': 6,
        'Aug': 7,
        'Sep': 8,
        'Oct': 9,
        'Nov': 10,
        'Dec': 11
    },

    dayFullNames: {
        'Sunday': 0,
        'Monday': 1,
        'Tuesday': 2,
        'Wednesday': 3,
        'Thursday': 4,
        'Friday': 5,
        'Saturday': 6
    },

    dayShortNames: {
        'Sun': 0,
        'Mon': 1,
        'Tue': 2,
        'Wed': 3,
        'Thu': 4,
        'Fri': 5,
        'Sat': 6
    },

    patterns: {
        FullDate: "l, F d, Y g:i:s A",
        ISO8601Long: "Y-m-d H:i:s",
        ISO8601Short: "Y-m-d",
        LongDate: "l, F d, Y",
        LongTime: "g:i:s A",
        MonthDay: "F d",
        ShortDate: "n/j/Y",
        ShortTime: "g:i A",
        SortableDateTime: "Y-m-d\\TH:i:s",
        UniversalSortableDateTime: "Y-m-d H:i:sO",
        YearMonth: "F, Y"
    },

    getMonthNumber : function(name, use) {
        this.chain = use ? mc.firstLetter(name).getKeyOf(Date.monthFullNames, mc.chain).chain
                         : mc.firstLetter(name).getKeyOf(Date.monthShortNames, mc.chain).chain;
        return this;
    },

    getMonthName : function(month, use) {
        this.chain = use ? mc.getValueOf(Date.monthFullNames, month, false).chain
                         : mc.getValueOf(Date.monthShortNames, month, false).chain;
        return this;
    },

    getDayNumber : function(name, use) {
        this.chain = use ? mc.firstLetter(name).getKeyOf(Date.dayFullNames, mc.chain).chain
                         : mc.firstLetter(name).getKeyOf(Date.dayShortNames, mc.chain).chain;
        return this;
    },

    getDayName : function(week, use) {
        this.chain = use ? mc.getValueOf(Date.dayFullNames, week, false).chain
                         : mc.getValueOf(Date.dayShortNames, week, false).chain;
        return this;
    },

    _setFirst : function(funcName, regexNum) {
        var code = 'Date.' + funcName + ' = function(input){\n'
            + "var nd, y, m, d, rs, h = 0, i = 0, s = 0, ms = 0, o, z, ux, v;\n"
            + "input = String(input);\n"
            + "nd = new Date();\n"
            + "y = nd.getFullYear();\n"
            + "m = nd.getMonth();\n"
            + "d = nd.getDate();\n"
            + "rs = input.match(Date.parseRegexes[" + regexNum + "]);\n"
            + "if (mc.isEmpty(rs).chain) {\n"
            + "return rs;\n}\n"
        return code;
    },

    _setSecond : function(code) {
        code += "if (ux){\n"
            + "v = new Date(ux * 1000);\n"
            + "} else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0 && ms >= 0){\n"
            + "v = new Date(y, m, d, h, i, s, ms);\n"
            + "}else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0){\n"
            + "v = new Date(y, m, d, h, i, s);\n"
            + "}else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0){\n"
            + "v = new Date(y, m, d, h, i);\n"
            + "}else if (y >= 0 && m >= 0 && d > 0 && h >= 0){\n"
            + "v = new Date(y, m, d, h);\n"
            + "}else if (y >= 0 && m >= 0 && d > 0){\n"
            + "v = new Date(y, m, d);\n"
            + "}else if (y >= 0 && m >= 0){\n"
            + "v = new Date(y, m);\n"
            + "}else if (y >= 0){\n"
            + "v = new Date(y);\n"
            + "}\n return v;\n"
            + "}";
        return code;
    },

    parseDate : function(input, format) {
        if (mc.isEmpty(Date.parseFunctions[format]).chain) {
            Date._createParser(format);
        }
        this.chain = Date[Date.parseFunctions[format]](input);
        return this;
    },

    _createParser : function(format) {
        var funcName = 'parse' + Date.parseFunctions.count++;
        var regexNum = Date.parseRegexes.length, 
             cGroup = 1;
        Date.parseFunctions[format] = funcName;

        var code = this._setFirst(funcName, regexNum);
        var regex = '', 
             special = false, 
             ch = '', 
             i, 
             obj, 
             pc;

        for (i = 0; i < format.length; ++i) {
            ch = format.charAt(i);
            if (!special && ch == '\\') {
                special = true;
            } else if (special) {
                special = false;
                regex += mc.escapeExp(ch).chain;
            } else {
                pc = Date.parseCodes[ch];
                if (pc) {
                    pc = mc.isFunction(pc).chain ? pc() : pc;
                    Date.parseCodes[ch] = pc;
                    obj = mc.allocate({c: pc.c ? mc.matchText(pc.c, cGroup || '{0}').chain : pc.c}, pc, true).chain;
                } else {
                    obj = {g: 0, c: null, s: mc.escapeExp(ch).chain}
                }

                cGroup += obj.g;
                regex += obj.s;
                if (obj.g && obj.c) {
                    code += obj.c;
                }
            }
        }

        code = this._setSecond(code);
        Date.parseRegexes[regexNum] = new RegExp('^' + regex + '$', 'i');
        eval(code);
    },

    parseCodes: {
        //Year, 4 digits Year
        Y: {
            g: 1,
            c: 'y = parseInt(rs[{0}], 10);\n',
            s: '(\\d{4})'
        },
        //4 digits Year
        o: {
            g: 1,
            c: 'y = parseInt(rs[{0}], 10);\n',
            s: '(\\d{4})'
        },
        //2 digit Year
        y: {
            g: 1,
            c: 'var ty = parseInt(rs[{0}], 10);\n'
                + 'y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n',
            s: '(\\d{1,2})'
        },
        //1: leap year
        L: {g: 0,
            c: null,
            s: '(?:1|0)'
        },
        //Month, month: with leading zeros (01~12)
        m: {
            g: 1,
            c: 'm = parseInt(rs[{0}], 10) - 1;\n',
            s: '(\\d{2})'
        },
        // month: without leading zeros (1~12)
        n: {
            g: 1,
            c: "m = parseInt(rs[{0}], 10) - 1;\n",
            s: "(\\d{1,2})"
        },
        //days in the month(28 ~ 31)
        t: {
            g: 0,
            c: null,
            s: "(?:\\d{2})"
        },
        //full month name
        F: function() {
            var names = mc.getHashList(Date.monthFullNames, false).chain;
            return {
                g: 1,
                c: "m = parseInt(Date.getMonthNumber(rs[{0}], true).chain, 10);\n",
                s: '(' + names.join('|') + ')'
            }
        },
        //short month names
        M: function() {
            var names = mc.getHashList(Date.monthShortNames, false).chain;
            return {
                g: 1,
                c: "m = parseInt(Date.getMonthNumber(rs[{0}]).chain, 10);\n",
                s: '(' + names.join('|') + ')'
            }
        },
        //Day, with leading zeroes (01 ~ 31)
        d: {
            g: 1,
            c: "d = parseInt(rs[{0}], 10);\n",
            s: "(\\d{2})"
        },
        //without leading zeroes (1 ~ 31)
        j: {
            g: 1,
            c: "d = parseInt(rs[{0}], 10);\n",
            s: "(\\d{1,2})"
        },
        //short day names
        D: function() {
            var names = mc.getHashList(Date.dayShortNames, false).chain;
            return {
                g: 0,
                c: null,
                s: '(?:' + names.join('|') + ')'
            }
        },
        //Full day names
        l: function() {
            var names = mc.getHashList(Date.dayFullNames, false).chain;
            return {
                g: 0,
                c: null,
                s: '(?:' + names.join('|') + ')'
            }
        },
        //javascript day(0:sunday ~ 6:saturday)
        w: {
            g: 0,
            c: null,
            s: '[0-6]'
        },
        //ISO-8601 day(1:monday ~ 7:sunday)
        N: {
            g: 0,
            c: null,
            s: '[1-7]'
        },
        //day of the year(0 ~ 364 (365 in leap years))
        z: {
            g: 0,
            c: null,
            s: '(?:\\d{1,3})'
        },
        // Elgnish ordinal suffix(2 characters)
        S: {
            g: 0,
            c: null,
            s: '(?:st|nd|rd|th)'
        },
        //Week, ISO-8601 week number (with leading zero)
        W: {
            g: 0,
            c: null,
            s: '(?:\\d{2})'
        },
        //Time ,am/pm
        a: {
            g: 1,
            c: "if (rs[{0}] == 'am') {\n"
                + "if (h == 12) { h = 0; }\n"
                + "} else { if (h < 12) { h += 12; }}",
            s: '(am|pm)'
        },
        //AM, PM
        A: {
            g: 1,
            c: "if (rs[{0}] == 'AM') {\n"
                + "if (h == 12) { h = 0; }\n"
                + "} else { if (h < 12) { h += 12; }}",
            s: '(AM|PM)'
        },
        // 24-hr format of an hour without leading zeroes (0~23)
        G: {
            g: 1,
            c: "h = parseInt(rs[{0}], 10);\n",
            s: "(\\d{1,2})"
        },
        // 12-hr format of an hour without leading zeroes (1~12)
        g: {
            g: 1,
            c: "h = parseInt(rs[{0}], 10);\n",
            s: "(\\d{1,2})"
        },
        //24-hr format of an hour with leading zeroes (00~23)
        H: {
            g: 1,
            c: "h = parseInt(rs[{0}], 10);\n",
            s: '(\\d{2})'
        },
        //12-hr format of an hour with leading zeroes (01~23)
        h: {
            g: 1,
            c: "h = parseInt(rs[{0}], 10);\n",
            s: '(\\d{2})'
        },
        // minutes with leading zeros (00~59)
        i: {
            g: 1,
            c: "i = parseInt(rs[{0}], 10);\n",
            s: '(\\d{2})'
        },
        // seconds with leading zeros (00~59)
        s: {
            g: 1,
            c: "s = parseInt(rs[{0}], 10);\n",
            s: '(\\d{2})'
        },
        // milliseconds with leading zeroes
        u: {
            g: 1,
            c: "ms = parseInt(rs[{0}], 10);\n",
            s: '(\\d+)'
        },
        //Timezone, GMT offset in hrs and mins
        O: {
            g: 0,
            c: null,
            s: "([+\-]\\d{4})"
        },
        // GMT offset in hrs and mins (with colon separator)
        P: {
            g: 0,
            c: null,
            s: "([+\-]\\d{2}:\\d{2})"
        },
        // timezone abbrev. may be between 1 - 4 chars
        T: {
            g: 0,
            c: null,
            s: "[A-Z]{1,4}"
        },
        //Timezone offset in seconds, -43200 <= UTC offset <= 50400
        Z: {
            g: 0,
            c: null,
            s: '([+\-]?\\d{1,5})'
        },
        //Full Date/Time, ISO 8601 date
        c: {
            g: 0,
            c: null,
            s: '\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}[+\-]\\d{2}:\\d{2}'
        },
        // UNIX epoch
        U: {
            g: 1,
            c: "ux = parseInt(rs[{0}], 10);\n",
            s: "(-?\\d+)"
        }
    },

    _createNewFormat : function(format) {
        var funcName = "format" + Date.formatFunctions.count++;
        Date.formatFunctions[format] = funcName;
        var code = "Date.prototype." + funcName + " = function(){return ";
        var special = false, 
             ch, 
             i, 
             len = format.length;

        for (i = 0; i < len; ++i) {
            ch = format.charAt(i);
            if (!special && ch == '\\') {
                special = true;
            } else if (special) {
                special = false;
                code += "'" + mc.escapeExp(ch).chain + "' + ";
            } else {
                var fc = Date.formatCodes[ch];
                if (fc) {
                    fc = mc.isFunction(fc).chain ? fc() : fc;
                    Date.formatCodes[ch] = fc;
                }
                fc = fc || ("'" + mc.escapeExp(ch).chain + "'");
                code += fc + " + ";
            }
        }
        eval(code.substring(0, code.length - 3) + ";}");
    },

    formatCodes: {
        //Year
        Y: "this.getFullYear()",
        y: "('' + this.getFullYear()).substring(2, 4)",
        L: "(this.isLeapYear().chain ? 1 : 0)",
        o: "(this.getFullYear() + (this.getWeekOfYear().chain == 1 && this.getMonth() > 0 ? 1 : (this.getWeekOfYear().chain >= 52 && this.getMonth() < 11 ? -1 : 0)))",
        //Moth
        M: "Date.getMonthName(this.getMonth(), false).chain",
        n: "(this.getMonth() + 1)",
        t: "this.getDaysInMonth().chain",
        F: "Date.getMonthName(this.getMonth(), true).chain",
        m: "mc.leftPad(this.getMonth() + 1, 2, '0').chain",
        //Week
        W: "mc.leftPad(this.getWeekOfYear().chain, 2, '0').chain",
        //Day
        d: "mc.leftPad(this.getDate(), 2, '0').chain",
        j: "this.getDate()",
        D: "Date.getDayName(this.getDay(), false).chain",
        l: "Date.getDayName(this.getDay(), true).chain",
        w: "this.getDay()",
        N: "(this.getDay() ? this.getDay() : 7)",
        z: "this.getDayOfYear().chain",
        S: "this.getSuffix().chain",
        //Time
        a: "(this.getHours() < 12 ? 'am' : 'pm')",
        A: "(this.getHours() < 12 ? 'AM' : 'PM')",
        g: "((this.getHours() % 12) ? this.getHours() % 12 : 12)",
        G: "this.getHours()",
        h: "mc.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0').chain",
        H: "mc.leftPad(this.getHours(), 2, '0').chain",
        i: "mc.leftPad(this.getMinutes(), 2, '0').chain",
        s: "mc.leftPad(this.getSeconds(), 2, '0').chain",
        u: "mc.leftPad(this.getMilliseconds(), 3, '0').chain",
        //Timezone
        O: "this.getGMTOffset().chain",
        P: "this.getGMTOffset(':').chain",
        T: "this.getTimezone().chain",
        Z: "(this.getTimezoneOffset() * -60)",
        //Full Date/Time
        c: "this.getISO8601Date().chain",
        U: "Math.round(this.getTime() / 1000)"
    }
});

}());

mc.setPrototype(Date, {
    dateFormat: function(format) {
        if (Date.formatFunctions[format] == null) {
            Date._createNewFormat(format);
        }
        this.chain = this[Date.formatFunctions[format]]();
        return this;
    },

    isLeapYear: function() {
        var year = this.getFullYear();
        this.chain = !!((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
        return this;
    },

    getDaysInMonth: function() {
        Date.daysInMonth[1] = this.isLeapYear().chain ? 29 : 28;
        this.chain = Date.daysInMonth[this.getMonth()];
        return this;
    },

    getWeekOfYear: function() {
        // 864e5: milliseconds in a day
        var utcDay = Date.UTC(this.getFullYear(), this.getMonth(), this.getDate() + 3) / 864e5;
        var weekNum = Math.floor(utcDay / 7);

        var msWeek = 864e5 * 7;
        var utcYear = new Date(weekNum * msWeek).getUTCFullYear();
        this.chain =  1 + weekNum - Math.floor(Date.UTC(utcYear, 0, 7) / msWeek);
        return this;
    },

    getDayOfYear: function() {
        var num = 0, 
             i;
        Date.daysInMonth[1] = this.isLeapYear().chain ? 29 : 28;
        for (i = 0; i < this.getMonth(); ++i) {
            num += Date.daysInMonth[i];
        }
        this.chain = num + this.getDate() - 1;
        return this;
    },

    getSuffix: function() {
        switch (this.getDate()) {
            case 1:
            case 21:
            case 31:
                this.chain = 'st';
                return this;
            case 2:
            case 22:
                this.chain = 'nd';
                return this;
            case 3:
            case 23:
                this.chain = 'rd';
                return this;
            default:
                this.chain = 'th';
                return this;
        }
    },

    getGMTOffset: function(dist) {
        this.chain = (this.getTimezoneOffset() > 0 ? '-' : '+')
            + mc.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, '0').chain
            + (dist ? dist : '')
            + mc.leftPad(Math.abs(this.getTimezoneOffset() % 60), 2, '0').chain;
        return this;
    },

    getTimezone: function() {
        var mv = this.toString().match(/:[0-9]{2} ([A-Z]{3,4})[\+|\-| ].*$/);
        this.chain = mv ? mv[1] : '';
        return this;
    },

    getISO8601Date: function() {
        var ft = 'Y-m-dTH:i:sP', 
             len = ft.length, 
             rs = [], 
             i, 
             ca, 
             tm, 
             fn;
        for (i = 0; i < len; ++i) {
            ca = ft.charAt(i);
            tm = ca == 'T' ? 'T' : ((fn = Date.formatCodes[ca]) ? eval(fn) : ca);
            rs.push(tm);
        }
        this.chain = rs.join('');
        return this;
    },

    getFirstDayOfMonth: function() {
        var day = (this.getDay() - (this.getDate() - 1)) % 7;
        this.chain = (day < 0) ? (day + 7) : day;
        return this;
    },

    getLastDayOfMonth: function() {
        var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
        this.chain = (day < 0) ? (day + 7) : day;
        return this;
    }
});

//--------------------------------------------------------
/*
 * MethodChain UI
 * Copyright(c) 2008-2009, 김영보(YoungBo Kim). All rights reserved.
 * Licensed under the GPLv3 license.
 * http://www.MethodChain.com/
 * version: 2.0.0
 */

//------------------
//@package: mc.widget
//------------------

mc.widget.Widget = function(){
    return {
        options: {
            IMEmode: '',
            isExecComponent: true,
            showToHide: false
        },

        setOptions: function(that, opts, param, dfts){
            if (dfts !== true){
                mc.allocate(that, this.options, true);
            }
            this.allocate(that, opts);

            this.setShowTo(that);
            this.setComponentId(that);

            mc.widget.Event.newCustom(that, opts);
            that.ce.fireEvent('openOptions');

            mc.component.Component.add(that);
            that.paramOpts = mc.allocate({}, opts || {}).chain;
        },

        allocate: function(that, opts){
            if (opts && opts.options){
                mc.allocate(that, opts.options);
            }
            if (that.opts && that.opts.options){
                mc.allocate(that, that.opts.options);
                delete that.opts.options;
            }
            mc.allocate(that, opts ||{});
        },

        setComponentId: function(that){
            if (!that.id){
                mc.id(false, that.prefix || 'mc_widget_')
                  .setThis(that, 'id');
            }
            return this;
        },

        setShowTo: function(that, showTo, create){
            that.showTo = that.showTo || showTo;
            if (mc.isString(that.showTo).chain){
                mc.get(that.showTo)
                  .setThis(that, 'showTo');
            }
            if (!that.showTo && create == true){
                mc.getBody()
                  .createAppend('div', false, that.prefix || '', mc.chain)
                  .setThis(that, 'showTo');
            }
            if (that.showToHide && that.showTo) {
                mc.setDisplay(false, that.showTo);
                that.ce.fireEvent('showToHide', that);
            }
            return this;
        },

        cacheShowTo: function(that, ch, el){
            if (ch){
                that.showToCache = that.showTo;
                if (el){
                    that.showTo = el;
                }
            } else {
                that.showTo = that.showToCache;
                delete that.showToCache;
            }
        },

        setOutside: function(that, ccode, cn, st, showTo){
            if (!(showTo = showTo || that.showTo)){
                return;
            };
            mc.createAppend('div', false, that.prefix, showTo)
              .setThis(that, 'outside')
              .setOwn(mc.chain)
              .addClass(cn || that.outsideClass)
              .setStyle(st || that.outsideStyle)

            if (mc.component.Component.isOwn(that, ccode)){
                mc.setWH(that.width, that.height, 'BP')
                  .setXY(that.leftX, that.topY);
            }
            return this;
        },

        applyAttr: function(that, el, prior){
            el = el || mc.own;
            var tg = prior || that;
            this.setAttrNode(tg.attr || '', el);

            if (tg.value){
                mc.setValue(tg.value, el);
            }
            if (tg.name){
                el.name = tg.name;
            }
            if (!el.name){
                var tn = el.tagName.toLowerCase();
                if (mc.isInput(el).chain || tn == 'form'){
                    el.name = el.id;
                }
            }
            var ix = tg.tabIndex || tg.tabindex;
            if (mc.isNumber(ix).chain){
                el.tabIndex = ix;
            }
            if (tg.readOnly || tg.readonly){
                el.readOnly = true;
            }
            if (tg.disabled){
                this.setDisable(tg.disabledClass || '', el);
            }
            if (tg.enable){
                this.setEnable(tg.disabledClass || '', el);
            }
            return this;
        },

        setAttrNode: function(attr, el){
            if (attr){
                mc.setAttr(attr, el);
                if (attr.value){
                    mc.setValue(attr.value, el);
                }
            }
            return this;
        },

        setStyle: function(that, el, st, cn){
            el = el || mc.own;
            if (st){
                mc.setStyle(st, el);
            }
            if (cn){
                mc.addClass(cn, el);
            }
            return this;
        },

        setWH: function(that, el, prior){
            el = el || mc.own;
            var obj = prior || that;
            if (obj.width){
                mc.setWidth(obj.width, 'BP', el);
            }
            if (obj.height){
                mc.setHeight(obj.height, 'BP', el);
            }
            return this;
        },

        setXY: function(that, el, prior){
            el = el || mc.own;
            var obj = prior || that;
            if (obj.leftX){
                mc.setX(obj.leftX, el);
            }
            if (obj.topY){
                mc.setY(obj.topY, el);
            }
            return this;
        },

        setAttr: function(that, el, st, cn, prior){
            this.applyAttr(that, el, prior)
                .setStyle(that, el, st, cn)
                .setWH(that, el, prior)
                .setXY(that, el, prior);
            return this;
        },

        newTitle: function(that, parent){
            if (!that.createTitle){
                that.titleNew = '';
            } else if (!that.titleNew){
                if (!that.title){
                    that.title = {};
                }
                that.title.showTo = parent;
                that.titleNew = new mc.widget.Title(that.title);
            }
        },

        ready: function(that){
            if (that.ready && mc.isFunction(that.ready).chain){
                mc.call(that.ready);
            }
            return this;
        },

        showMessage : function(that, msg, el){
            msg = msg || that.invalidMsg;
            el = el || mc.own;

            mc.addClass(that.invalidClass, el);
            mc.Message.show('title', msg, el);

            that.ce.fireEvent('invalid', el, msg, that);
            return this;
        },

        setDisable: function(cn, el){
            mc.addClass(cn, el);
            el.disabled = true;
            return this;
        },

        setEnable: function(cn, el){
            mc.removeClass(cn, el);
            el.disabled = false;
            return this;
        },

        setZIndex: function(that, index){
            that.zindex = index || parseInt(mc.getStyle('z-index').chain, 10) || 7000;
            return this;
        },

        newTemplate: function(that, name, template){
            if (!that[name]){
                that[name] = mc.newTemplate(template).Template;
            }
            return that[name];
        }
    }
}();


mc.widget.Event = function(){
    return {
        newCustom: function(that){
            that.ce = new mc.CustomEvent();
            return this;
        },

        customEvents: function(that, opts){
            var ets = '';
            if (opts && opts.events){
                ets = opts.events;
            }
            if (!(ets = ets || that.events)){
                return this;
            };
            if (typeof ets[0] === 'string'){
                ets = [ets];
            }

            this.customOn(that, ets);
            return this;
        },

        customOn: function(that, ets){
            if (typeof ets[0] === 'string'){
                ets = [ets];
            }
            var i,
                len = ets.length,
                et;

            for (i = 0; i < len; i++){
                et = ets[i];
                that.ce.eventTypes(et[0]);
                that.ce.addEvents(et[0], et[1], et[2] || that);
            }
            return this;
        },

        isGecko229: function(e){
            return (mc.Gecko && e.keyCode == 229) ? true : false;
        },

        focusBlur: function(that, tg, fe, cln){
            tg = tg || mc.own;
            fe = fe || tg;
            cln = cln || that.focusClass;
            mc.on([tg, 'focus', mc.widget.Event.focusEvent, that, {el: fe, cn: cln}],
                  [tg, 'blur', mc.widget.Event.blurEvent, that, {el: fe, cn: cln}]
            );
            return this;
        },

        focusBlurOff: function(that, tg, fc, bl){
            tg = tg || mc.own;
            mc.off([tg, 'focus', fc || mc.widget.Event.focusEvent, that],
                   [tg, 'blur', bl || mc.widget.Event.blurEvent, that]);
            return this;
        },

        overOut: function(that, tg, fe, cln){
            tg = tg || mc.own;
            fe = fe || tg;
            mc.on([tg, 'mouseover', mc.widget.Event.mouseOverEvent, that, {el: fe, cn: cln, bubble: true}],
                  [tg, 'mouseout', mc.widget.Event.mouseOutEvent, that, {el: fe, cn: cln, bubble: true}]
            );
            return this;
        },

        overOutOff: function(that, tg, over, out){
            tg = tg || mc.own;
            mc.off([tg, 'mouseover', over || mc.widget.Event.mouseOverEvent],
                   [tg, 'mouseout', out || mc.widget.Event.mouseOutEvent]);
            return this;
        },

        downUp: function(that, tg, fe, cln){
            tg = tg || mc.own;
            fe = fe || tg;
            cln = cln || that.downClass;
            mc.on([tg, 'mousedown', mc.widget.Event.mouseDownEvent, that, {el: fe, cn: cln, stop: true}],
                  [tg, 'mouseup', mc.widget.Event.mouseUpEvent, that, {el: fe, cn: cln, stop: true}]
            );
            return this;
        },

        downUpOff: function(that, tg, dn, up){
            tg = tg || mc.own;
            mc.off([tg, 'mousedown', dn || mc.widget.Event.mouseDownEvent, that],
                   [tg, 'mouseup', up || mc.widget.Event.mouseUpEvent, that]
            );
            return this;
        },

        keyDownPress: function(that, tg, ln, opts){
            tg = tg || mc.own;
            if (this.justKeyDown()){
                mc.on(tg, 'keydown', ln || mc.widget.Event.keyDownEvent, that, opts || {});
            } else {
                mc.on([tg, 'keydown', mc.widget.Event.checkControl, that],
                      [tg, 'keypress', ln || mc.widget.Event.keyDownEvent, that, opts || {}]);
            }
            return this;
        },

        keyDownPressOff: function(that, tg, dn, up){
            tg = tg || mc.own;
            if (this.justKeyDown()){
                mc.on(tg, 'keydown', ln || mc.widget.Event.keyDownEvent, that);
            } else {
                mc.off([tg, 'keydown', mc.widget.Event.checkControl, that],
                       [tg, 'keypress', ln || mc.widget.Event.keyDownEvent, that]);
            }
            return this;
        },

        justKeyDown: function(){
            return mc.IE || mc.Safari3 || mc.Chrome;
        },

        getDocID: function(type){
            return 'doc' + type + 'ID';
        },

        setDocId: function(that, type){
            var docID = this.getDocID(type);
            if (!that[docID]){
                mc.id(false, that.prefix)
                  .setThis(that, docID);
            }
            return that[docID];
        },

        documentOn: function(that, type, ln, opts){
            var idv = this.setDocId(that, type);
            document['id'] = idv;
            opts = opts || {};
            opts['docID'] = idv;

            if (type == 'mousemove'){
                mc.on(document, 'mousemove', ln || that.documentMouseMove, that, opts);
            } else if (type == 'mousedown'){
                mc.on(document, 'mousedown', ln || that.documentMouseDown, that, opts);
            } else if (type == 'mouseup'){
                mc.on(document, 'mouseup', ln || that.documentMouseUp, that, opts);
            } else if (type == 'mouseover'){
                mc.on(document, 'mouseover', ln || that.documentMouseOver, that, opts);
            } else if (type == 'mouseout'){
                mc.on(document, 'mouseout', ln || that.documentMouseOut, that, opts);
            }
            return this;
        },

        documentOff: function(that, type, ln){
            document['id'] = this.setDocId(that, type);
            if (type == 'mousemove'){
                mc.off(document, 'mousemove', ln || that.documentMouseMove, that);
            } else if (type == 'mousedown'){
                mc.off(document, 'mousedown', ln || that.documentMouseDown, that);
            } else if (type == 'mouseup'){
                mc.off(document, 'mouseup', ln || that.documentMouseUp, that);
            } else if (type == 'mouseover'){
                mc.off(document, 'mouseover', ln || that.documentMouseOver, that);
            } else if (type == 'mouseout'){
                mc.off(document, 'mouseout', ln || that.documentMouseOut, that);
            }
            return this;
        },

        isOwnDocument: function(that, type, opts){
            var idn = this.getDocID(type);
            opts = opts || {};
            return opts.docID == that[idn];
        },

        focusEvent: function(e, tg, opts){
            if (!this.focusCheck) {
                mc.addClass(opts['cn'], opts['el']);
                this.ce.fireEvent('focus', e, this);
                this.focusCheck = true;
            }
            return this;
        },

        blurEvent: function(e, tg, opts){
            if (this.focusCheck) {
                mc.removeClass(opts['cn'], opts['el']);
                this.ce.fireEvent('blur', e, this);
                this.focusCheck = false;
            }
            return this;
        },

        mouseOverEvent : function(e, tg, opts){
            if (this.mouseOverOut != true){
                mc.addClass(opts['cn'], opts['el']);
                if (this.ce){
                    this.ce.fireEvent('mouseover', e, this);
                }
                this.mouseOverOut = true;
            }
            return this;
        },

        mouseOutEvent: function(e, tg, opts){
            if (mc.widget.Event.isChild(e, tg, this)){
                mc.removeClass(opts['cn'], opts['el']);
                if (this.ce){
                    this.ce.fireEvent('mouseout', e, this);
                }
                this.mouseOverOut = false;
            }
            return this;
        },

        mouseDownEvent: function(e, tg, opts){
            if (this.mouseDownUp != true) {
                mc.addClass(opts['cn'], opts['el']);
                this.ce.fireEvent('mousedown', e, this);
                this.mouseDownUp = true;
            }
            return this;
        },

        mouseUpEvent: function(e, tg, opts){
            if (this.mouseDownUp === true) {
                mc.removeClass(opts['cn'], opts['el']);
                this.ce.fireEvent('mouseup', e, this);
                this.mouseDownUp = false;
            }
            return this;
        },

        keyDownEvent: function(e){
            this.ce.fireEvent('keydown', e, this);
            return this;
        },

        checkControl: function(e){
            var ck = mc.getControlKey(e).chain;
            if (ck && mc.Safari2 && ck > 36 && ck < 41){
                e.bubbleDefault();
            }
        },

        isChild: function(e, tg, that){
            var rt;
            if (that.mouseOverOut == true && (rt = e.getRelatedTarget().chain)){
                if (!(mc.isDescendant(rt, tg, true).chain)){
                    return true;
                }
            }
            return false;
        },

        offEvents: function(evs){
            if (typeof evs === 'string'){
                evs = [evs];
            }
            for (var i = 0, len = evs.length; i < len; i++){
                mc.off(this.joinType, evs[i]);
            }
            return this;
        }
    }
}();


mc.widget.Position = function(){
    ccode = 'position';
    return {
        prefix: 'mc_position_',

        getWH: function(code, el){
            code = code || 'LT';
            code = code.toUpperCase();

            var x = 0,
                y = 0,
                mr = Math.round,
                fv = 0.5,
                wd = mc.getWidth(false, el).chain,
                ht = mc.getHeight(false, el).chain;

            switch(code){
                case 'LT': case 'TL':
                    x = 0, y = 0;
                break;
                case 'CT': case 'TC':
                    x = mr(wd * fv);
                break;
                case 'RT': case 'TR':
                    x = wd;
                break;
                case 'L':
                    y = mr(ht * fv);
                break;
                case 'C':
                    x = mr(wd * fv);
                    y = mr(ht * fv);
                break;
                case 'R':
                    x = wd;
                    y = mr(ht * fv);
                break;
                case 'LB': case 'BL':
                    y = ht;
                break;
                case 'CB': case 'BC':
                    x = mr(wd * fv);
                    y = ht;
                break;
                case 'RB': case 'BR':
                    x = wd;
                    y = ht;
                break;
            }
            return [x, y];
        },

        moveToXY: function(code, el, move, tg){
            var wh = this.getWH(code, el),
                xy = mc.getXY(el).chain,
                base = {};

            base.x = xy[0] + wh[0];
            base.y = xy[1] + wh[1];
            this.setXY(base, move, tg);
        },

        setXY: function(base, move, tg){
            for (var pty in move){
                var vl = move[pty];
                pty = pty.toUpperCase();
                pty == 'L' ? base.x -= vl :
                pty == 'T' ? base.y -= vl :
                pty == 'R' ? base.x += vl : base.y += vl;
            }
            mc.setXY(base.x + 'px', base.y + 'px', tg);
        }
    };
}();


mc.widget.Title = function(opts){
    mc.widget.Widget.setOptions(this, opts);
    if (this.showTo) {
        this.mainTitle(this.showTo);
    }
};

mc.widget.Title.prototype = {
    closable: false,
    closeClass: ['mc-guide-icon', 'mc-guide-icon-close'],
    closeParent: false,
    closeOverClass: 'mc-guide-icon-over',

    defaultType: {},
    guideType: {
        outsideClass: 'mc-title',
        insideClass: 'mc-hd-guide-inside mc-hd-guide-image'
    },

    iconId: '',
    insideClass: 'mc-title-inside',
    insideStyle: '',
    outsideClass: 'mc-title',
    outsideStyle: '',

    prefix: 'mc_title_',
    spread: false,
    text: '',
    textClass: 'mc-title-text',
    textId: '',
    textStyle: '',
    titleType: '',
    toggleClass: 'mc-spread-toggle',

    ccode: 'title',
    html: '',
    showStatus: true,
    spreadClass: ['mc-spread', 'mc-spread-icon'],
    spreadOverClass: 'mc-spread-over',
    spreadStatus: '',

    iconNode: '',
    inside: '',
    outside: '',
    spreadTarget: '',
    textNode: '',

    mainTitle: function(showTo){
        this.showTo = showTo || this.showTo;
        this.setType();
        this.createOutside();
        this.createInside();

        this.setIconNode();
        this.createTextNode();
        this.setOffsetHide();

        this.setTitleText(this.text);
        this.setTextStyle(this.textClass, this.textStyle);
        this.setEvents();

        mc.component.Component.isExec(this, 'title', this.showTo);
        return this;
    },

    setType: function(){
        if (!this.titleType){
            this.titleType = 'default';
        }
        mc.allocate(this, this[this.titleType + 'Type'] || {});
    },

    createOutside: function(){
        mc.createAppend('div', this.id, this.prefix, this.showTo)
          .setOwn(mc.chain)
          .setThis(this, 'outside')
          .addClass(this.outsideClass)
          .setStyle(this.outsideStyle)
          .setUnselectable();

        if (mc.component.Component.isOwn(this, 'title')){
            mc.setXY(this.leftX, this.topY);
        }
        this.width ? mc.setWidth(this.width, 'BP') : mc.setChildWidth(false, this.showTo);
        this.width = mc.chain;

        if (this.height && this.html){
            mc.setHeight(this.height, 'BP');
        }
    },

    createInside: function(){
        mc.createAppend('div', false, this.prefix, this.outside)
          .setThis(this, 'inside')
          .addClass(this.insideClass, mc.chain)
          .setStyle(this.insideStyle, this.inside)
          .setUnselectable(this.inside);
    },

    setIconNode: function(){
        if (!this.iconNode) {
            this.useClass = this.spread ? this.spreadClass : this.closable ? this.closeClass : '';

            mc.createAppend('div', this.iconId, this.prefix, this.inside)
              .setThis(this, 'iconNode')
              .addClass(this.useClass, mc.chain)
              .setStyle({'z-index': 30010}, this.iconNode);
        }
        this.spreadStatus = this.spread;
    },

    createTextNode: function(el){
        if (!this.textNode){
            mc.createAppend('span', this.textId, this.prefix, el || this.inside)
              .setThis(this, 'textNode')
              .setUnselectable(mc.chain);
        }
    },

    setTitleText: function(tx){
        this.text = tx || '';
        this.textNode.innerHTML = this.text || '&#160';
        this.showTitle();
    },

    setTextStyle: function(cn, st){
        mc.addClass(cn, this.textNode)
          .setStyle(st, this.textNode);
    },

    setOffsetHide: function(){
        if (this.titleType == 'guide'){
            this.isGuideHide() ? mc.addClass('mc-offset-hide', this.outside)
                               : mc.removeClass('mc-offset-hide', this.outside)
        }
    },

    setEvents: function(){
        if (this.spread){
            mc.on(this.iconNode, 'mousedown', this.spreadEvent, this, {stop:true});
            mc.widget.Event.overOut(this, this.iconNode, this.iconNode, this.spreadOverClass);
        }
        if (this.closable){
            mc.on(this.iconNode, 'mousedown', this.hideTitle, this, {stop:true});
            mc.widget.Event.overOut(this, this.iconNode, false, this.closeOverClass);
        }
    },

    spreadEvent: function(){
        if (this.spreadTarget){
            this.toggleSpread(this.spreadTarget);
        }
    },

    hideTitle: function(){
        this.showStatus = false;
        if (this.closeParent){
            mc.getParent(false, this.outside)
              .addClass('mc-offset-hide', mc.chain);
        } else {
            mc.addClass('mc-offset-hide', this.outside);
        }
        this.ce.fireEvent('hideTitle', this.outside, this);
    },

    isGuideHide: function(){
        return (this.titleType == 'guide' && !this.text && !this.closable) ? true : false;
    },

    showTitle: function(){
        this.showStatus = true;
        if (this.closeParent){
            mc.getParent(false, this.outside)
              .removeClass('mc-offset-hide', mc.chain);
        } else {
            mc.removeClass('mc-offset-hide', this.outside);
        }

        this.setOffsetHide();
        this.ce.fireEvent('showTitle', this.outside, this);
    },

    showHide: function(sh){
        sh ? this.showTitle() : this.hideTitle();
    },

    toggleSpread: function(el){
        this.spreadTarget = el || this.spreadTarget;
        if (!this.spreadTarget){
            return;
        }
        mc.get(this.spreadTarget)
          .setThis(this, 'spreadTarget');

        this.spreadStatus = this.spreadStatus ? false : true;
        mc.setVisibility(this.spreadStatus, this.spreadTarget);

        this.spreadStatus ? mc.removeClass(this.toggleClass, this.outside)
                          : mc.addClass(this.toggleClass, this.outside);

        var enm = this.spreadStatus ? 'close' : 'open';
        this.ce.fireEvent(enm, this.spreadTarget, this);
    },

    setSpreadTarget: function(el){
        if (el){
            mc.get(el).setThis(this, 'spreadTarget');
        }
    },

    getHeight: function(bp){
        return mc.getHeight((bp ? 'BP' : false), this.outside).chain || 0;
    },

    getOutside: function(){
        return this.outside;
    }
};


mc.widget.BoxModel = function(node, index, showIndex){
    if (node){
        this.setBoxValue(node, index, showIndex);
    }
};

mc.widget.BoxModel.prototype = {
    ccode: 'boxmodel',

    setBoxValue: function(node, index, showIndex){
        var whxy = mc.getWHXY('BP', node).chain;
        this.width = whxy[0];
        this.height = whxy[1];
        this.x = whxy[2];
        this.y = whxy[3];

        this.right = this.x + this.width;
        this.bottom = this.y + this.height;

        this.offsetWidth = node.offsetWidth;
        this.offsetLeft = node.offsetLeft;
        this.offsetRight = this.offsetLeft + this.width,
        this.offsetHeight = node.offsetHeight;
        this.offsetTop = node.offsetTop;

        this.xMinusLeft = this.x - this.offsetLeft;
        this.yMinusTop = this.y - this.offsetTop;

        this.index = index || 0;
        this.showIndex = showIndex;

        this.showHide = mc.isVisible(false, node).chain;
        this.id = node.id || '';
    },

    getValue: function(){
        return {
            width: this.width,
            height: this.height,
            x: this.x,
            y: this.y,
            right: this.right,
            bottom: this.bottom,

            offsetWidth: this.offsetWidth,
            offsetLeft: this.offsetLeft,
            offsetRight: this.offsetRight,
            offsetHeight: this.offsetHeight,
            offsetTop: this.offsetTop,

            xMinusLeft: this.xMinusLeft,
            yMinusTop: this.yMinusTop,

            index: this.index,
            showIndex: this.showIndex,
            id: this.id};
    },

    getOffset: function(){
        return {
            offsetLeft: this.offsetLeft,
            offsetRight: this.offsetRight,
            x: this.x,
            right: this.right,
            xMinusLeft: this.xMinusLeft};
    }
};


mc.widget.BoxModelGroup = function(list){
    this.bmGroup = [];
};

mc.widget.BoxModelGroup.prototype = {
    ccode: 'boxmodelgroup',

    addBoxModel: function(bm){
        var gp = this.bmGroup;
        gp[gp.length] = bm;
    },

    getPageBox: function(vl){
        var i,
            bm,
            gp = this.bmGroup,
            len = gp.length;

        for (i = 0; i < len; i++){
            bm = gp[i];
            if (vl >= bm.x && vl <= bm.right){
                return bm;
            }
        }
    },

    getPageIndex: function(vl){
        return this.getPageBox(vl).index;
    },

    getIndexBox: function(index){
        index = index || 0;
        return this.bmGroup[index];
    },

    getIdIndex: function(cid){
        return mc.Json.getKeyValue(this.bmGroup, 'id', cid).chainIndex;
    },

    getFirst: function(hd){
        if (hd){
            return this.getIndexBox(0);
        }
        var i,
            bmg = this.bmGroup,
            len = bmg.length;

        for (i = 0; i < len; i++){
            if (bmg[i].showHide) {
                return bmg[i];
            }
        }
    },

    getLast: function(hd){
        if (hd){
            return this.getIndexBox(this.bmGroup.length - 1);
        }
        var i,
            bmg = this.bmGroup,
            len = bmg.length - 1;

        for (i = len; i >= 0; i--){
            if (bmg[i].showHide) {
                return bmg[i];
            }
        }
    },

    getShowIndex: function(index){
        var i,
            bmg = this.bmGroup,
            len = bmg.length,
            bm;

        for (i = 0; i < len; i++){
            bm = bmg[i];
            if (bm.showHide && bm.showIndex == index) {
                return bm;
            }
        }
    },

    clearBox: function(){
        this.bmGroup = [];
    }
};


mc.widget.NameFormat = function(){
    ccode = 'nameformat';
    return {
        setID: function(px, idx, seq, cell){
            if (typeof idx === 'number') {
                idx = idx.toString();
            }
            if (typeof seq === 'number') {
                seq = seq.toString();
            }
            if (typeof cell === 'number') {
                cell = cell.toString();
            }
            return px + '_' + (idx ? idx + '_' : '') + (seq ? seq + '_' : '') + (cell ? cell : '');
        },

        setHeaderCell: function(base){
            return this.setID('mchdtd', base[1]) + base[2];
        },

        hypenSplit: function(tg){
            var ids = typeof tg == 'string' ? tg : tg.id;
            var spt = ids.split('_'),
                rtn = [];

            if (spt){
                var len = spt.length, i;
                for (i = 1; i < len; i++){
                    rtn[i - 1] = spt[i];
                }
            }
            return rtn;
        },

        split: function(tg, value){
            var ids = typeof tg == 'string' ? tg : tg.id;
            return ids ? (value ? ids.split(value) : ids.split('_')) : [];
        },

        splitAll: function(tg, value){
            var spt = this.split(tg, value);
            return this.hypenSplit(spt[1]);
        },

        getFieldNode: function(node, field){
            var fd = field + node.id;
            var len = node.id.length;
            var uk = node.id.substring(len - 2, len - 1);

            if (uk != '_k'){
                fd += '_k';
            }
            return mc.get(fd).chain;
        },

        getCellID: function(field, px, idx, cell){
            return field + '_' + this.setID(px, idx, cell, 'k');
        },

        getViewCell: function(field, id, cell){
            var nm = field + '_' + id + '_' + cell + '_k';
            return mc.get(nm).chain;
        },

        getTrTd: function(trNode, cell){
            var td = trNode.id.replace('mcdttr', 'mcdttd');
            return mc.get(td + '_' + cell).chain;
        },

        getCells: function(tg, str){
            var td = str ? tg.split('mcdttd') : tg.id.split('mcdttd');
            var spt = td[1] ? td[1].split('_') : [];
            return [td[0], spt[1], spt[2], spt[3], spt[4] || ''];
        },

        getRows: function(tg){
            var td = tg.id.split('mcdttr');
            var spt = td[1] ? td[1].split('_') : [];
            return ['mcdttr', spt[1], spt[2]];
        },

        changeCellNode: function(tg, index, seq, str){
            var spt = this.getCells(tg, str);
            var id = spt[0] + '_mcdttd_' + index + '_' + seq + '_' + spt[3] + '_' + spt[4];
            return mc.get(id).chain;
        },

        getRowNode: function(tg){
            var spt = tg.id.split('mcdttd'),
                ids = spt[1].split('_');

            var rs = (ids[1] + '_' + ids[2]);
            return mc.get('mcdttr_' + rs).chain;
        },

        getTdNode: function(tg){
            var spt = this.getCells(tg);
            return mc.get('mcdttd_' + spt[1] + '_' + spt[2] + '_' + spt[3]).chain;
        },

        getCalcFormat: function(ids, indirect){
            var td = this.split(ids, 'mcdttd');
            var spt = td[1] ? td[1].split('_') : [];
            var id = '_mcdttd_' + spt[1] + '_';
            return indirect ? (id + spt[2] + '_') : id;
        }
    }
}();


mc.widget.Message = function(){
    var prefix = 'mc_message_';

	return {
        code: {
            E1000: 'E1000: ccode/{ccode}, {one}',
            E1010: 'E1010: ccode/{ccode}, options.{one}를(을) 지정(작성)해 주세요.',
            E1011: 'E1011: ccode/{ccode}, {one}를(을) 지정(작성)해 주세요.',
            E1012: 'E1012: ccode/{ccode}, {one}에 {two}를(을) 지정(작성)해 주세요.',
            E1020: 'E1020: ccode/{ccode}, {one}가(이) {two}에 존재하지 않습니다.',
            E1021: 'E1021: ccode/{ccode}, {one}가(이) {two}에 존재합니다.',
            E1030: 'E1030: ccode/{ccode}, {one}가(이) {two}보다 큽니다.',
            E1031: 'E1031: ccode/{ccode}, {one}가(이) {two}보다 작습니다.',
            E1040: 'E1040: ccode/{ccode}, {one}(값)가(이) 적합하지 않습니다.',
            E1041: 'E1041: ccode/{ccode}, {one} 작성이 적합하지 않습니다.',
            E1042: 'E1042: ccode/{ccode}, {one}에(서) {two}가(이) 적합하지 않습니다.',
            I1000: 'I1000: ccode/{ccode}, {one}'
        },

        getCode: function(code){
            return this.code[code] || '';
        },

        isGuideArea: function(){
            if (!this.guideArea){
                mc.createAppend('div', false, prefix, mc.getBody().chain)
                  .setThis(this, 'guideArea');
            }
        },

        isTemplate: function(){
            if (!this.template){
                this.template = mc.newTemplate('{ccode}{msg1}').Template;
            }
        },

        show: function(code, ccode, msg1, msg2){
            var map = {},
                tmp = this.getCode(code);

            this.isTemplate();

            if (tmp){
                map.ccode = ccode;
                map.one = msg1;
                map.two = msg2 || '';

                this.isGuideArea();
                if (this.guideArea){
                    mc.resultShow(this.template.set(tmp)._convert(map), this.guideArea.id);
                }
            }
        },

        add: function(code, template){
            if (!(this.code[code])){
                this.code[code] = template;
            }
        },

        remove: function(code){
            delete this.code[code];
        }
    };
}();


mc.widget.Math = function(){
	return {
        round: function(value, psn){
            var vl = this.powValue(value, psn);
            return vl[1] ? (Math.round(vl[0] * vl[1]) / vl[1]) : vl[0];
        },

        powValue: function(value, psn){
            var vls = [];
            vls[0] = Number(value);
            if (typeof psn == 'number') {
                vls[1] = Math.pow(10, psn);
            }
            return vls;
        },

        ceil: function(value, psn){
            var vl = this.powValue(value, psn);
            return vl[1] ? (Math.ceil(vl[0] * vl[1]) / vl[1]) : vl[0];
        },

        floor: function(value, psn){
            var vl = this.powValue(value, psn);
            return vl[1] ? (Math.floor(vl[0] * vl[1]) / vl[1]) : vl[0];
        },

        arith: function(one, two, op, zero){
            if (zero && op == '/' && (one == 0 || two == 0)){
                return 0;
            }

            var splitOne = one.toString().split(/\./),
                splitTwo = two.toString().split(/\./),
                dpTotal,
                value,
                powOne,
                powTwo;

            var dpOne = splitOne[1] ? splitOne[1].length : 0;
            var dpTwo = splitTwo[1] ? splitTwo[1].length : 0;

            if (op == '*' || op == '/'){
                dpTotal = dpOne + dpTwo;
                powOne = Math.round(one * Math.pow(10, dpOne));
                powTwo = Math.round(two * Math.pow(10, dpTwo));
                value = op == '*' ? (powOne * powTwo) : (powOne / powTwo);

            } else if (op == '+' || op == '-'){
                dpTotal = dpOne > dpTwo ? dpOne : dpTwo;
                powOne = Math.round(one * Math.pow(10, dpTotal));
                powTwo = Math.round(two * Math.pow(10, dpTotal));
                value = op == '+' ? (powOne + powTwo) : (powOne - powTwo);
            }

            var pow = op == '/' ? Math.pow(10, (dpOne - dpTwo)) : Math.pow(10, dpTotal);
            if (pow != 1){
                value /= pow;
            }
            return value;
        }
    };
}();

//------------------
//@package: mc.data
//------------------


mc.data.DataFormat = function(format, hd){
    mc.Json.JSON = [];
    this.setHeaderDetail(format);

    if (hd == 'h'){
        this.headerFormat = mc.Json.JSON;
    } else {
        this.detailFormat = mc.Json.JSON;
    }

    mc.Json.chain = '';
    mc.Json.JSON = '';
};

mc.data.DataFormat.prototype = {
    combo: '',
    field: '',
    group: '',
    mapName: '',
    type: '',
    typeExp: /^int|float|boolean/,

    setHeaderDetail: function(format){
        var i,
            len,
            key,
            fmt;

        if (mc.isArray(format).chain) {
            for (i = 0, len = format.length; i < len; i++){
                fmt = this.editType(format[i]);
                mc.Json.addKey(fmt.field, fmt, false);
            }
        } else {
            for (key in format){
                fmt = this.editType({field: key, mapName: format[key]});
                mc.Json.addKey(key, fmt, false);
            }
        }
    },

    editType: function(format){
        if (!format.type){
            format.type = 'string';
        }
        if (!format.sort){
            format.sort = 'A';
        }
        if (!format.mapName){
            format.mapName = format.field;
        }
        return format;
    },

    setEventType: function(ets){
        var rtn = ets;
        if (rtn && !rtn.events){
             rtn = {};
             rtn['events'] = ets;
        }
        return rtn;
    },

    mapType: function(type, mv){
        if (type == 'int'){
            mv = parseInt(mv, 10);
        } else if (type == 'float'){
            mv = parseFloat(mv, 10);
        } else if (type == 'boolean'){
            mv = mv == '0' ? false : (mv == '1' ? true : mv);
        }
        return mv;
    },

    getGroupName: function(){
        return {hd : this['mapHeader'], dt: this['mapDetail']};
    },

    removeData: function(){
        delete this.header;
        delete this.detail;
    },

    mappingType: function(mapData, tp, fd,  attr){
        if (this.typeExp.test(tp)) {
            mapData[fd] = this.mapType(tp, mapData[fd]);
        }
        if (attr['text']){
            mapData['defaultText'] = mapData[fd];
        }
        return mapData;
    },

    getAll: function(hd){
        hd = hd ? hd.toLowerCase() : 'h';
        return hd == 'h' ? this.headerFormat : this.detailFormat;
    },

    get: function(hd, field){
        var hash = this.getAll(hd),
            cs,
            len = 0,
            i,
            result = {};

        if (field){
            cs = mc.commaSplit(field).chain;
            len = cs.length;
        }
        for (i = 0; i < len; i++){
            result[cs[i]] = hash[cs[i]];
        }
        return result;
    },

    add: function(hd, hash){
        hd = hd ? hd.toLowerCase() : 'h';
        if (hd == 'h' && !this.headerFormat){
            this.headerFormat = {};
        }
        if (hd == 'd' && !this.detailFormat){
            this.detailFormat = {};
        }

        var format = this.getAll(hd);
        mc.Json.JSON = format;

        if (!(mc.isArray(hash).chain)){
            hash = [hash];
        }
        this.setHeaderDetail(hash);

        format = mc.Json.JSON;
        mc.Json.chain = '';
        mc.Json.JSON = '';

        this.ce.fireEvent('add', this);
        return format;
    },

    remove: function(hd, fields){
        var format = this.getAll(hd),
            cs,
            len = 0,
            i;

        if (fields){
            cs = mc.commaSplit(fields).chain;
            len = cs.length;
        }
        for (i = 0; i < len; i++){
            delete format[cs[i]];
        }
        this.ce.fireEvent('remove', this);
        return format;
    },

    update: function(hd, fields){
        var format = this.getAll(hd);
        if (!(mc.isArray(fields).chain)){
            fields = [fields];
        }

        var i,
            len = fields.length,
            upt,
            fmt,
            pty;

        for (i = 0; i < len; i++){
            upt = fields[i];
            if (fmt = format[upt['field']]){
                for (pty in fmt){
                    if (pty != 'field'){
                        delete fmt[pty];
                    }
                }
                for (pty in upt){
                    if (pty != 'field'){
                        fmt[pty] = upt[pty];
                    }
                }
            }
        }

        this.ce.fireEvent('update', this);
        return format;
    },

    copy: function(hd, from, to){
        var format = this.getAll(hd),
            src;

        if (!from || !(src = format[from]) || !to){
            return null;
        }

        var cpto = format[to] = {};
        mc.allocate(cpto, src);
        cpto['field'] = to;

        this.ce.fireEvent('copy', this);
        return format;
    }
};


mc.data.ArrayFormat = function(detail, hdName, events){
    mc.widget.Event.newCustom(this).customEvents(this, this.setEventType(events));
    this.setFormat(detail, hdName);
};

mc.extend(mc.data.ArrayFormat, mc.data.DataFormat, {
    index: '',
    text: false,
    ccode: 'arrayformat',

    setFormat: function(detail, hdName){
        if (mc.isObject(detail).chain){
            if (detail.detail){
                detail = detail.detail;
            }
            mc.data.ArrayFormat.superclass.constructor.call(this, detail, 'd');
        }
        this.mapDetail = hdName ? (hdName.detail || 'detail') : 'detail';
        this.ce.fireEvent('created', this);
    },

    client: function(data){
        if (!(mc.isArray(data[0]).chain)){
            data = [data];
        }

        this.mappingData(data);
        var meta = {header: '', detail: this.detail, cf: 'Array'};
        this.removeData();
        return meta;
    },

    response: function(trans){
        var arrayData,
            meta = trans.metaDataClass;

        if (trans.responseText){
            arrayData = mc.evalJson(trans.responseText).chain;
        }
        if (!arrayData){
            meta.metaMethod.call(meta.metaScope, '', '', trans);
            return;
        }
        this.mappingData(arrayData);

        meta.metaMethod.call(meta.metaScope, '', this.detail, trans);
        this.removeData();
    },

    mappingData: function(data){
        var gn = this.getGroupName(),
            dt = data[gn.dt];

        if (this.detailFormat){
            this.arrayDetail(dt || data, this.detailFormat);
        }
    },

    arrayDetail: function(data, format){
        var i,
            len = data.length,
            rowData,
            mapData,
            pty,
            attr,
            tp,
            rowMapData = [];

        for (i = 0; i < len; i++){
            rowData = data[i];
            mapData = {};

            for (pty in format){
                attr = format[pty];
                tp = attr.type;
                mapData[pty] = rowData[attr.index] || '';
                mapData = this.mappingType(mapData, tp, pty, attr);
            }
            mapData['mc_row_index'] = i;
            rowMapData[i] = mapData;
        }

        this['detail'] = rowMapData;
        this['cf'] = 'Array';
    }
});


mc.data.CsvFormat = function(detail, hdName, events){
    mc.widget.Event.newCustom(this).customEvents(this, this.setEventType(events));
    this.setFormat(detail, hdName);
};

mc.extend(mc.data.CsvFormat, mc.data.DataFormat, {
    delimiter: ',',
    index: '',
    ccode: 'csvformat',

    setFormat: function(detail, hdName){
        if (mc.isObject(detail).chain){
            if (detail.detail){
                detail = detail.detail;
            }
            mc.data.CsvFormat.superclass.constructor.call(this, detail, 'd');
        }
        this.mapDetail = hdName ? (hdName.detail || 'detail') : 'detail';
        this.ce.fireEvent('created', this);
    },

    client: function(data){
        this.mappingData(data);
        var meta = {header: '', detail: this.detail, cf: 'CSV'};
        this.removeData();
        return meta;
    },

    response: function(trans){
        if (trans.delimiter){
            this.delimiter = trans.delimiter;
        }
        var csvData = trans.responseText,
            meta = trans.metaDataClass;

        if (!csvData){
            meta.metaMethod.call(meta.metaScope, '', '', trans);
            return;
        }

        this.mappingData(csvData);
        meta.metaMethod.call(meta.metaScope, '', this.detail, trans);
        this.removeData();
    },

    mappingData: function(data){
        var gn = this.getGroupName(),
            dt = data[gn.dt];

        if (this.detailFormat){
            this.csvDetail(dt || data, this.detailFormat);
        }
    },

    csvDetail: function(data, format){
        data = data.split('\n');
        var i,
            len = data.length,
            rowData,
            pty,
            attr,
            mapData,
            tp,
            rowMapData = [];

        for (i = 0; i < len; i++) {
            data[i] = data[i].replace(/\n/g, '');
        }
        len = data.length;

        for (i = 0; i < len; i++){
            rowData = data[i].split(this.delimiter);
            mapData = {};
            for (pty in format){
                attr = format[pty];
                tp = attr.type;
                mapData[pty] = rowData[attr.index]  || '';
                mapData = this.mappingType(mapData, tp, pty, attr);
            }
            mapData['mc_row_index'] = i;
            rowMapData[i] = mapData;
        }

        this['detail'] = rowMapData;
        this['cf'] = 'CSV';
    }
});


mc.data.HtmlFormat = function(detail, hdName, events){
    mc.widget.Event.newCustom(this).customEvents(this, this.setEventType(events));
    this.setFormat(detail, hdName);
};

mc.extend(mc.data.HtmlFormat, mc.data.DataFormat, {
    ccode: 'htmlformat',

    setFormat: function(detail, hdName){
        if (mc.isObject(detail).chain){
            if (detail.detail){
                detail = detail.detail;
            }
            mc.data.HtmlFormat.superclass.constructor.call(this, detail, 'd');
        }

        this.mapDetail = hdName ? (hdName.detail || 'detail') : 'detail';
        this.ce.fireEvent('created', this);
    },

    client: function(el){
        mc.getDescendants('*', false, el);
        this.mappingData(mc.chain);

        var meta = {header: '', detail: this.detail, cf: 'HTML'};
        this.removeData();
        return meta;
    },

    mappingData: function(data){
        var gn = this.getGroupName(),
            dt = data[gn.dt];

        if (this.detailFormat){
            this.htmlDetail(dt || data, this.detailFormat);
        }
    },

    htmlDetail: function(nodes, format){
        var pty,
            attr,
            it = [],
            itStr,
            i,
            len = nodes.length,
            nd,
            rowMapData = [];

        for (pty in format) {
            attr = format[pty];
            it.push(attr.field);
        }
        itStr = it.join(',');

        for (i = 0; i < len; i++){
            nd = nodes[i];
            mapData = mc.getAttr(itStr, nd, false).chain;

            if (nd.tagName && (nd.tagName.toUpperCase() == 'SELECT' && mapData['value'])){
                mapData['value'] = '';
            }
            for (pty in format){
                attr = format[pty];
                if (!mapData[pty]){
                    mapData[pty] = '';
                }
                mapData = this.mappingType(mapData, attr.type, pty, attr);
            }
            mapData['mc_row_index'] = i;
            rowMapData[i] = mapData;
        }

        this['detail'] = rowMapData;
        this['cf'] = 'HTML';
    }
});


mc.data.JsonFormat = function(header, detail, hdName, events){
    mc.widget.Event.newCustom(this).customEvents(this, this.setEventType(events));
    this.setFormat(header, detail, hdName);
};

mc.extend(mc.data.JsonFormat, mc.data.DataFormat, {
    ccode: 'jsonformat',

    setFormat: function(header, detail, hdName){
        if (mc.isObject(header).chain){
            if (header.header){
                header = header.header;
            }
            mc.data.JsonFormat.superclass.constructor.call(this, header, 'h');
        }

        if (mc.isObject(detail).chain){
            if (detail.detail){
                detail = detail.detail;
            }
            mc.data.JsonFormat.superclass.constructor.call(this, detail, 'd');
        }

        this.mapHeader = hdName ? (hdName.header || 'header') : 'header';
        this.mapDetail = hdName ? (hdName.detail || 'detail') : 'detail';
        this.ce.fireEvent('created', this);
    },

    client: function(data){
        this.mappingData(data);
        var meta = {header: this.header, detail: this.detail, cf: 'JSON'};
        this.removeData();
        return meta;
    },

    response: function(trans){
        var jsonData = '',
            meta = trans.metaDataClass;

        if (trans.responseText){
            jsonData = mc.evalJson(trans.responseText).chain;
        }
        if (!jsonData){
            meta.metaMethod.call(meta.metaScope, '', '', trans);
            return;
        }

        this.mappingData(jsonData);
        meta.metaMethod.call(meta.metaScope, this.header, this.detail, trans);
        this.removeData();
    },

    mappingData: function(data){
        var gn = this.getGroupName(),
            hd = data[gn.hd],
            dt = data[gn.dt];

        if (!hd && !dt && data){
            dt = data;
        }
        if (data && !hd && this.headerFormat){
            hd = this.serHeaderData(data);
        }

        if (this.headerFormat && hd){
            this.jsonHeader(hd, this.headerFormat);
        }
        if (this.detailFormat && dt){
            this.jsonDetail(dt, this.detailFormat);
        }
    },

    serHeaderData: function(data){
        var dt = this.mapDetail,
            pty,
            hd = {};

        delete data[dt];
        for (pty in data){
            hd[pty] = data[pty];
            delete data[pty];
        }
        return hd;
    },

    jsonHeader: function(data, format){
        var pty,
            attr,
            mn,
            fd,
            tp,
            mapData = {};

        for (pty in format){
            attr = format[pty];
            mn = attr.mapName;
            fd = attr.field;
            tp = attr.type;
            mapData[fd] = this.typeExp.test(tp) ? this.mapType(tp, data[mn]) : data[mn];
        }
        this['header'] = mapData;
        this['cf'] = 'JSON';
    },

    jsonDetail: function(data, format){
        var i,
            len = data.length,
            rowData,
            mapData,
            pty,
            attr,
            mn,
            fd,
            tp,
            rowMapData = [];

        for (i = 0; i < len; i++){
            rowData = data[i];
            mapData = {};
            for (pty in format){
                attr = format[pty];
                mn = attr.mapName;
                fd = attr.field;
                tp = attr.type;
                mapData[fd] = rowData[mn];
                mapData = this.mappingType(mapData, tp, fd, attr);
            }
            mapData['mc_row_index'] = i;
            rowMapData[i] = mapData;
        }
        this['detail'] = rowMapData;
        this['cf'] = 'JSON';
    }
});


mc.data.XmlFormat = function(header, detail, hdName, events){
    mc.widget.Event.newCustom(this).customEvents(this, this.setEventType(events));
    this.setFormat(header, detail, hdName);
};

mc.extend(mc.data.XmlFormat, mc.data.DataFormat, {
    ccode: 'xmlformat',

    setFormat: function(header, detail, hdName){
        if (mc.isObject(header).chain){
            if (header.header){
                header = header.header;
            }
            mc.data.XmlFormat.superclass.constructor.call(this, header, 'h');
        }
        if (mc.isObject(detail).chain){
            if (detail.detail){
                detail = detail.detail;
            }
            mc.data.XmlFormat.superclass.constructor.call(this, detail, 'd');
        }

        this.mapHeader = hdName ? (hdName.header || 'header') : 'header';
        this.mapDetail = hdName ? (hdName.detail || 'detail') : 'detail';
        this.ce.fireEvent('created', this);
    },

    client: function(data){
        this.mappingData(data);
        var meta = {header: this.header, detail: this.detail, cf: 'XML'};

        this.removeData();
        return meta;
    },

    response: function(trans){
        var meta = trans.metaDataClass;
        if (!trans.responseXML){
            meta.metaMethod.call(meta.metaScope, '', '', trans);
            return;
        }

        this.mappingData(trans.responseXML);
        meta.metaMethod.call(meta.metaScope, this.header, this.detail, trans);
        this.removeData();
    },

    mappingData: function(data){
        var docEl = data.documentElement,
            gn = this.getGroupName(),
            tn;

        if (gn.hd){
            tn = docEl.getElementsByTagName(gn.hd);
            if (tn.length == 0){
                this.xmlHeader(data);
            } else {
                this.getGroupData(tn, this.headerFormat, 'header');
                if (mc.isArray(this.header).chain){
                    this.header = mc.allocate({}, this.header[0]).chain;
                }
            }
        }

        if (gn.dt){
            tn = docEl.getElementsByTagName(gn.dt);
            this.getGroupData(tn, this.detailFormat, 'detail');
        }
    },

    xmlHeader: function(data){
        var format = this.headerFormat,
            docEl = data.documentElement;

        this['header'] = this.getFormat(format, '', docEl);
        this['cf'] = 'XML';
    },

    getGroupData: function(data, format, gn){
        var i,
            len = data.length,
            dt,
            node,
            nodes,
            rowMapData = [];

        for (i = 0; i < len; i++){
            dt = data[i];
            node = dt['firstChild'];
            nodes = [];

            while (node) {
                if (node.nodeType == 1) {
                    nodes.push(node);
                };
                node = node['nextSibling'];
            }
            rowMapData[i] = this.getFormat(format, nodes, '');
        }

        this[gn] = rowMapData;
        this['cf'] = 'XML';
    },

    getFormat: function(format, nodes, docEl){
        var mapData = {},
            pty,
            attr,
            mn,
            fd,
            tp,
            pm,
            value;

        for (pty in format){
            attr = format[pty];
            mn = attr.mapName;
            fd = attr.field;
            tp = attr.type;

            pm = nodes ? nodes : docEl.getElementsByTagName(mn);
            value = this.getFirstText(pm, mn) || '';
            mapData[fd] = value;
            mapData = this.mappingType(mapData, tp, fd, attr);
        }
        return mapData;
    },

    getFirstText: function(nodes, name){
        if (name) {
            name = name.toUpperCase();
        }
        var i,
            len = nodes.length,
            node,
            nt,
            fc;

        for (i = 0; i < len; i++){
            node = nodes[i];
            if (nt = node.tagName){
                nt = nt.toUpperCase();
            }
            if (name == nt && (fc = node.firstChild)){
                return fc.nodeValue;
            }
        }
        return '';
    }
});


mc.data.HttpData = function(that, opts){
    this.mainHttpData(that, opts);
};

mc.data.HttpData.prototype = {
    ccode: 'httpdata',
    normalProcess: true,

    mainHttpData: function(that, opts){
        if (this.normalProcess = this.checkOptions(that, opts)){
            this.setDefaultOptions();
            this.setMessage();
        };
        return this;
    },

    checkOptions: function(that, opts){
        this.opts = opts || {};
        if (!(this.opts.that = that)){
            mc.widget.Message.show('E1012', this.ccode, 'first parameter', 'this object');
            return fasle;
        }

        var that = this.opts.that,
            url = this.opts.url || that.url || this.opts.action || that.action || '';
        if (!url){
            mc.widget.Message.show('E1010', this.ccode, 'url or action');
            return false;
        }
        this.httpOpts = {};
        this.httpOpts.url = url;
        return true;
    },

    setDefaultOptions: function(){
        var http = this.httpOpts,
            opts = this.opts,
            that = opts.that,
            hd;

        http.async = (opts.async == true || that.async == true);
        http.method = opts.method || that.method || 'POST';
        http.method = http.method.toUpperCase();
        if (http.method == 'GET'){
            http.caching = (opts.caching == true || that.caching == true);
        }

        http.onSuccess = opts.onSuccess || that.onSuccess || '';
        http.onFailure = opts.onFailure || that.onFailure || '';
        http.onTimeout = opts.onTimeout || that.onTimeout || '';

        http.callbackScope = '';
        if (http.onSuccess || http.onFailure || http.onTimeout){
            http.callbackScope = opts.scope || that;
        }

        http.dataEncoded = opts.dataEncoded || that.dataEncoded || '';
        http.encode = opts.encode || that.encode || 'UTF-8';
        if (hd = (opts.headers || that.headers || '')){
            http.headers = hd;
        }

        http.interval = opts.interval || that.interval || 100;
        http.params = opts.params || that.params || '';
        http.useName = (opts.useName == true || that.useName == true);

        http.metaFailure = opts.metaFailure || that.metaFailure || '';
        http.metaTimeout = opts.metaTimeout || that.metaTimeout || '';
        http.metaFailScope = opts.metaFailScope || that.metaFailScope || '';
    },

    setMessage: function(){
        this.opts = {};
    },

    setHttpData: function(opts){
        this.httpOpts.form = opts.form || '';
        this.httpOpts.data = opts.data || '';
    },

    setHttpOptions: function(opts){
        opt = opts || {};
        var http = this.httpOpts,
            pty;

        for (pty in opts){
            http[pty] = opts[pty];
        }
    },

    setCallBack: function(){
    },

    metaCallback: function(fmt){
        if (fmt){
            var op = this.httpOpts;
            op.metaSuccess = fmt.response;
            op.metaSucScope = fmt;
            op.metaFailure = op.metaFailure || this.metaFailure;
            op.metaTimeout = op.metaTimeout || this.metaTimeout;
            op.metaFailScope = op.metaFailScope || this;
        }
    },

    setMetaMethod: function(cbf, scope){
        var md = {};
        md['metaMethod'] = cbf;
        md['metaScope'] = scope;
        this.httpOpts['metaDataClass'] = md;
    },

    request: function(){
        mc.Http.request(this.httpOpts);
    },

    metaFailure: function(){
    },

    metaTimeout: function(){
    }
};


mc.data.MetaData = function(opts){
    this.isClient(opts);
    mc.widget.Widget.setOptions(this, opts);

    this.setDelimiter();
    if (this.directExec) {
        this.mainMetaData(this.showTo);
    }
};

mc.data.MetaData.prototype = {
    callback: '',
    customDetail: '',
    customHeader: '',
    dataFormat: '',
    detail: [],

    delimiter: '',
    directExec: false,
    header: [],
    scope: '',
    showTo: '',

    ccode: 'metadata',
    createdFormat: '',
    httpNew: '',

    mainMetaData: function(showTo){
        this.showTo = showTo || this.showTo;
        if (this.client) {
            this.getClient();
        }
        if (this.server) {
            this.getServer();
        }
        mc.component.Component.isExec(this, 'metadata', this.showTo);
        return this;
    },

    getClient: function(){
        if (!this.client) {
            return this;
        }
        this.ce.fireEvent('startClient', this);

        if (!(this.dataFormat)){
            mc.widget.Message.show('E1041', this.ccode, 'dataFormat');
            return;
        }

        var data = this.dataFormat.client(this.client);
        this.header = data['header'];
        this.detail = data['detail'];
        this.createdFormat = data['cf'];

        this.userReset();
        this.ce.fireEvent('endClient', this);
    },

    getServer: function(){
        this.newHttpData();
        this.setCallback();
        this.request();
    },

    newHttpData: function(){
        if (!this.httpNew) {
            this.httpNew = new mc.data.HttpData(this, this.server);
        }
        if (this.httpNew.normalProcess){
            this.ce.fireEvent('startHttp', this);
        }
    },

    setCallback: function(){
        this.httpNew.metaCallback(this.dataFormat);
    },

    request: function(cbf, scope){
        this.componentMethod = cbf || this.componentMethod || '';
        this.componentScope = scope || this.componentScope || '';

        this.httpNew.setMetaMethod(this.setServerData, this);
        this.httpNew.request();
    },

    setServerData: function(header, detail, trans){
        if (!header && !detail) {
            this.ce.fireEvent('nullData', trans, this);
            header = {};
            detail = {};
        }

        this.header = header;
        this.detail = detail;
        this.userReset();

        var fmt = this.dataFormat;
        delete fmt.header;
        delete fmt.detail;

        this.ce.fireEvent('endHttp', trans, this);
        if (this.componentMethod) {
            mc.call(this.componentMethod, this.componentScope, this);
        }
    },

    isClient: function(opts){
        if (opts && opts.client){
            this.directExec = true;
        }
    },

    setDelimiter: function(){
        if (this.delimiter && this.dataFormat) {
            this.dataFormat.delimiter = this.delimiter;
        }
    },

    userReset: function(){
        if (this.customDetail) {
            this.detail = this.customDetail.call(this, this.detail);
        }
        if (this.customHeader) {
            this.header = this.customHeader.call(this, this.header);
        }
    },

    getHeader: function(){
        return this.header;
    },

    getHeaderNumber: function(){
        return mc.getCount(this.header).chain;
    },

    getDetail: function(){
        return this.detail || '';
    },

    getDetailCount: function(){
        return this.detail.length || 0;
    },

    getDetailData: function(start, end){
        return mc.getScope(this.getDetail(), start, end).chain;
    },

    getDetailDesc: function(end, start){
        return mc.getScopeDesc(this.getDetail(), end, start).chain;
    },

    getSortBase: function(name){
        var data = this.detail,
            len = data.length,
            row,
            i,
            sortBase = [];

        for (i = 0; i < len; i++) {
            row = data[i];
            sortBase[i] = {
                key: row[name] || '',
                seq: i,
                origin: row
            };
        }
        return sortBase;
    },

    sort: function(name, ad){
        ad = (ad == 'A' || ad == 'Asc') ? 'A' : 'D';
        var data = this.getSortBase(name),
            fn,
            result,
            i,
            len,
            dt,
            rs,
            st;

        fn = function(a, b){
            st = a.key < b.key ? -1 : (a.key > b.key ? 1 : 0);
            if (st == 0) {
                st = a.seq < b.seq ? -1 : 1;
            }
            return st;
        };

        result = mc.sortArray(data, ad, fn).chain;
        this.detail = [];
        dt = this.detail;

        len = result.length;
        for (i = 0; i < len; i++) {
            rs = result[i];
            dt[i] = rs.origin;
        }
        this.ce.fireEvent('sort', name, ad, this);
    },

    getRowIndex: function(index){
        var data = this.detail,
            len = data.length,
            i,
            row;

        for (i = 0; i < len; i++) {
            row = data[i];
            if (row.mc_row_index == index){
                return row;
            }
        }
        return '';
    },

    getIndex: function(index){
        return this.detail[index];
    },

    getIndexValue: function(index, pty){
        var idx = this.getIndex(index);
        return idx ? idx[pty] : '';
    },

    setData: function(index, field, value){
        var data = this.getRowIndex(index);
        if (data && !data[field]){
            data[field] = value;
        }
    }
};


mc.data.MetaFilter = function(opts){
    mc.widget.Widget.setOptions(this, opts);
    this.detailData = [];
    this.mainMetaFilter();
};

mc.data.MetaFilter.prototype = {
    detailData: '',
    filterData: '',
    filterRow: '',
    metaData: '',

    ccode: 'metafilter',
    existData: '',

    mainMetaFilter: function(){
        this.filterMeta();
        mc.component.Component.isExec(this, 'metafilter', '');
        return this;
    },

    filterMeta: function(){
        this.existData = false;
        var meta = this.metaData;
        if (!meta){
            return mc.Message.show('E1010', this.ccode, 'metaData');
        }
        var detail = meta.detail ? meta.detail : meta;
        if (!detail || detail.length == 0){
            this.ce.fireEvent('noData', this);
            return;
        }

        if (this.filterData){
            this.detailData = this.filterData(detail);
        } else if(this.filterRow) {
            this.getFilterRow(detail);
        } else {
            this.detailData = detail;
        }

        if (!this.detailData){
            this.detailData = [];
        }
        if (this.detailData.length != 0){
            this.existData = true;
        }
        this.ce.fireEvent('filteredData', this.detailData, this);
    },

    getFilterRow: function(detail){
        var len = detail.length,
            i,
            dt,
            rdt = [];

        for (i = 0; i < len; i++){
            if (dt = this.filterRow(detail[i], i)){
                rdt[rdt.length] = dt;
            }
        }
        this.detailData = rdt;
    },

    getAllData: function(){
        return this.detailData;
    },

    getIndex: function(ix){
        return this.detailData[ix || 0];
    },

    getData: function(start, end, ad){
        ad = ad || 'A';
        ad = ad.toUpperCase();
        return ad == 'A' ? mc.getScope(this.detailData, start, end).chain
                         : mc.getScopeDesc(this.detailData, end, start).chain;
    },

    getLength: function(){
        return this.detailData.length;
    },

    clearData: function(){
        this.detailData = [];
        this.ce.fireEvent('clearData', this);
    }
};


mc.data.MetaField = function(options){
    this.checkFields(options);
    mc.widget.Widget.setOptions(this, this.options);
    if (options){
        this.mainMetaField();
    }
};

mc.data.MetaField.prototype = {
    className: '',
    defaults: ['hidden', 'width', 'sortable'],
    editor: '',
    field: '',
    fixWidth: false,

    format: 'detail',
    hidden: false,
    metaData: '',
    sortable: true,
    style: '',

    textClass: '',
    textStyle: '',
    text: '',
    width: 100,

    ccode: 'metafield',
    childFields: '',
    fieldFormat: '',
    fieldNames: '',

    mainMetaField: function(){
        this.initMetaField();
        this.setFieldNames();
        this.setDefaultAttr();
        this.setFieldAttr();
        this.setFieldFormat();
    },

    initMetaField: function(){
        if (!this.fields){
            mc.widget.Message.show('E1010', this.ccode, 'fields');
            return;
        }
        this.fields = mc.toArray(this.fields).chain;

        this.fieldNames = [];
        this.fieldFormat = {};
        this.childFields = {};
    },

    checkFields: function(options){
        if (!options){
            return this;
        }
        if (mc.isArray(options).chain){
            this.options = {};
            this.options.fields = options;
            options = this.options;
        }
        this.options = options || {};
    },

    setFieldNames: function(){
        var names = this.fieldNames,
            fields = this.fields,
            len = fields.length,
            field,
            i;

        for (i = 0; i < len; i++){
            field = fields[i];
            names[names.length] = field['field'];
            if (field.ccode){
                this.setCodeName(field['ccode'], field['field']);
            }
        }
    },

    setCodeName: function(cc, field){
        if (cc == 'linenumber'){
            this['linenumber'] = field;
        }
        if (cc == 'gridcheckbox'){
            this['gridcheckbox'] = field;
        }
        if (cc == 'gridradio'){
            this['gridradio'] = field;
        }
    },

    setDefaultAttr: function(){
        this.defaultAttr = {};
        var dfts = this.defaults,
            len = dfts.length,
            dft,
            i;

        for (i = 0; i < len; i++){
            dft = dfts[i];
            this.defaultAttr[dft] = this[dft];
        }
    },

    setFieldAttr: function(){
        delete this.options.fields;
        delete this.options.format;

        var names = this.fieldNames,
            len = names.length,
            fld,
            i;

        for (i = 0; i < len; i++){
            fld = this.fields[i];
            mc.allocate(fld, this.defaultAttr, true)
              .allocate(fld, this.options, true);
        }
    },

    setFieldFormat: function(){
        var fields = this.fields,
            len = fields.length,
            field,
            fd,
            i,
            atr;

        for (i = 0; i < len; i++){
            field = fields[i];
            fd = field['field'];
            this.fieldFormat[fd] = {};

            atr = this.fieldFormat[fd];
            atr['index'] = i.toString();
            if (field.child){
                this.setChildFields(field.child, i);
            }
        }
        delete this.options;
    },

    setChildFields: function(child, index){
        child = mc.toArray(child).chain;
        var len = child.length,
            i,
            ch,
            fd,
            atr;

        for (i = 0; i < len; i++){
            ch = child[i];
            fd = ch['field'];

            this.childFields[fd] = {};
            atr = this.childFields[fd];
            atr['index'] = index.toString();
        }
    },

    setFieldIndex: function(){
        var fields = this.fields,
            len = fields.length,
            i,
            fd,
            atr;

        for (i = 0; i < len; i++){
            fd = fields[i];
            atr = this.fieldFormat[fd.field];
            atr['index'] = i.toString();
            if (fd.child){
                this.setChildIndex(fd.child, i);
            }
        }
    },

    setChildIndex: function(child, index){
        var len = child.length,
            i,
            ch,
            atr;

        for (i = 0; i < len; i++){
            ch = child[i];
            atr = this.childFields[ch.field];
            atr['index'] = index.toString();
        }
    },

    mergeDetailFormat: function(meta){
        var dt,
            field,
            merge;

        if (dt = meta.dataFormat.detailFormat){
            mc.eachArray(this.fieldNames, function(nm, ix){
                if (merge = dt[nm]){
                    field = this.fields[ix];
                    mc.allocate(field, merge, true);
                }
            }, this);
        }
    },

    newLineNumber: function(index){
        var lineNum = new mc.grid.LineNumber({
            startNumber: 0,
            field: 'lineNumber',
            width: 40,
            text: ''
        });

        this.initMetaField();
        var fds = this.fields,
            len = fds.length,
            i,
            fdsNew = [];

        fdsNew[0] = lineNum;
        for (i = 0; i < len; i++){
            fdsNew.push(fds[i]);
        }
        this.fields = fdsNew;

        this.options = {};
        this.setFieldNames();
        this.setDefaultAttr();
        mc.allocate(this.fields[0], this.defaultAttr, true);
        this.setFieldFormat();
    },

    getCount: function(){
        return this.fields.length;
    },

    getIndex: function(index){
        return this.fields[index];
    },

    getIndexValue: function(index, pty){
        var idx = this.getIndex(index);
        return idx ? idx[pty] : '';
    },

    getFieldNumber: function(hd){
        var i = 0,
            len = this.fields.length,
            num = 0,
            hash;

        if (hd){
            return len;
        } else {
            for (i = 0; i < len; i++){
                if (!this.fields[i].hidden){
                    num += 1;
                }
            }
        }
        return num;
    },

    getExclude: function(pty){
        var flds = this.fields,
            len = flds.length,
            fd,
            i,
            rtn = [];

        for (i = 0; i < len; i++){
            fd = flds[i];
            if (!fd[pty]){
                rtn[rtn.length] = fd['field'];
            }
        }
        return rtn;
    },

    getInclude: function(pty){
        var flds = this.fields,
            len = flds.length,
            fd,
            i,
            rtn = [];

        for (i = 0; i < len; i++){
            fd = flds[i];
            if (fd[pty]){
                rtn[rtn.length] = fd['field'];
            }
        }
        return rtn;
    },

    getFormat: function(field){
        var fmt = this.fieldFormat[field];
        return fmt ? this.fields[fmt.index] : '';
    },

    getFormatIndex: function(field){
        var fmt = this.fieldFormat[field];
        return fmt ? this.fieldFormat[field].index : false;
    },

    getChildIndex: function(field){
        var fmt = this.getFormatIndex(field);
        if (fmt){
            return fmt;
        }
        fmt = this.childFields[field];
        return fmt ? this.childFields[field].index : false;
    },

    getValue: function(field, pty){
        var fmt = this.getFormat(field);
        return fmt ? fmt[pty] : '';
    },

    getValues: function(fds, pty){
        var len = fds.length,
            i,
            rtn = [];

        for (i = 0; i < len; i++){
            rtn[i] = this.getValue(fds[i], pty) || '';
        }
        return rtn;
    },

    getChildValue: function(field, pty){
        var idx = this.getChildIndex(field);
        return idx ? this.getIndexValue(idx, pty) : '';
    },

    getChildValues: function(field, pty){
        pty = mc.toArray(pty).chain;
        var len = pty.length,
            i,
            rtn = [];

        for (i = 0; i < len; i++){
            rtn[i] = this.getChildValue(field, pty[i]);
        }
        return rtn;
    },

    setValue: function(field, pty, value){
        var fmt = this.getFormat(field);
        if (!fmt){
            this.getFormat(field) = {};
            fmt = this.getFormat(field);
        }
        fmt[pty] = value;
    },

    setIndexValue: function(index, pty, value){
        if (index && mc.numCheckExp.test(index)){
            this.fields[index][pty] = value;
        }
    },

    getAll: function(pty, value){
        var flds = this.fields,
            len = flds.length,
            i,
            fd,
            rtn = [];

        for (i = 0; i < len; i++){
            fd = flds[i];
            if (fd[pty] == value){
                rtn[rtn.length] = fd;
            }
        }
        return rtn;
    },

    getFirst: function(pty, value){
        var flds = this.fields,
            len = flds.length,
            i,
            fd;

        for (i = 0; i < len; i++){
            fd = flds[i];
            if (fd[pty] == value){
                return fd;
            }
        }
        return '';
    },

    getFieldStyle: function(index, bdw){
        var field = this.getIndex(index),
            rtn = '',
            tp,
            fs,
            st;

        tp = field['width'] - (bdw ? bdw : 0);
        rtn += ('width:' + tp + 'px;');
        if (field['hidden']){
            rtn += ' display: none; ';
        }
        if (field['showRight']){
            rtn += ' text-align: right; ';
        }

        fs = field.style;
        if (fs){
            for (pty in fs){
                st = (pty + ': ' + fs[pty] + ';');
                rtn += st;
            }
        }
        return rtn;
    },

    getHashStyle: function(index, bdw){
        var field = this.getIndex(index),
            rtn = {},
            tp,
            fs;

        tp = field['width'] - (bdw ? bdw : 0);
        rtn['width'] = (tp + 'px');

        if (field['hidden']){
            rtn['display'] = 'none';
        }
        if (field['showRight']){
            rtn['textAlign'] = 'right';
        }

        fs = field.style;
        if (fs){
            for (pty in fs){
                st = (pty + ': ' + fs[pty] + ';');
                rtn += hs;
            }
        }
        return rtn;
    },

    getLineWidth: function(){
        var flds = this.fields,
            len = flds.length,
            fd,
            i,
            total = 0;

        for (i = 0; i < len; i++){
            fd = flds[i];
            if (fd['hidden'] != true){
                total += fd['width'] || 0;
            }
        }
        return total;
    },

    getLineTotalWidth: function(){
        var flds = this.fields,
            len = flds.length,
            fd,
            i,
            total = 0;

        for (i = 0; i < len; i++){
            fd = flds[i];
            total += fd['width'] || 0;
        }
        return total;
    },

    setLineNumber: function(ftn, value){
        var fmt = this.getFormat(ftn);
        if (fmt){
            this.setValue(ftn, 'seqNumber', fmt.reset(value));
        }
    },

    moveField: function(cix, mix){
        var cd = this.getIndex(cix);
        this.fields.splice(cix, 1);
        this.fields.splice(mix, 0, cd);

        this.setFieldIndex();
    },

    isSortable: function(ix){
        return this.getIndex(ix).sortable === false ? false : true;
    },

    getAllFields: function(){
        return mc.allocate({}, this.fieldFormat)
                 .allocate(mc.chain, this.childFields).chain;
    }
};


mc.data.MetaRow = function(opts){
    mc.widget.Widget.setOptions(this, opts);
    if (this.metaData){
        this.mainMetaRow();
    }
};

mc.data.MetaRow.prototype = {
    ccode: 'metarow',
    checked: '',
    metaRow: '',
    radio: '',
    selected: '',

    mainMetaRow: function(data){
        this.setMetaRow(data);
        return this;
    },

    setMetaRow: function(data){
        this.metaRow = [];
        data = data || this.metaData || [];
        var len = data.length,
            i,
            ix,
            meta = this.metaRow;

        for (i = 0; i < len; i++){
            ix = data[i]['mc_row_index'];
            meta[ix] = {'json_index': i};
        }
        this.nameFormat = mc.widget.NameFormat;
    },

    isSelected: function(node, index){
        if (node){
            var ids = node.id.split('_');
            index = ids[1];
        }
        var ix = this.metaRow[index];
        return ix ? ix.selected : false;
    },

    setSelected: function(node, select, index){
        if (node){
            index = this.getNodeIndex(node);
        }
        this.metaRow[index].selected = select;
    },

    getNodeIndex: function(node){
        var ids = node.id.split('_');
        return ids[1];
    },

    getSelectedRow: function(){
        var i,
            meta = this.metaRow,
            len = meta.length,
            slt = 0;

        for (i = 0; i < len; i++){
            if (meta[i].selected){
                slt += 1;
            }
        }
        return slt;
    },

    getUnselectedRow: function(){
        return this.metaRow.length - this.getSelected();
    },

    setChecked: function(node, check, index){
        if (node){
            index = this.getNodeIndex(node);
        }
        this.metaRow[index].checked = check;
    },

    isChecked: function(node, index){
        if (node){
            index = this.getNodeIndex(node);
        }
        var ix = this.metaRow[index];
        return ix ? ix.checked : false;
    },

    setFieldChecked: function(field, check, index){
        var row = this.metaRow[index];
        if (row){
            var fds = row.fields;
            if (!fds){
                row['fields'] = {};
                fds = row['fields'];
            }
            fds[field] = check;
        }
    },

    isFieldChecked: function(field, index){
        var row = this.metaRow[index];
        var fds = row ? row.fields : '';
        return fds ? fds[field] : '';
    },

    clear: function(){
        this.metaRow = [];
    },

    reRender: function(data){
        this.clear();
        this.setMetaRow(dara);
    }
};


//----------------------
//@package: mc.component
//----------------------

mc.component.MemberClass = function(opts){
    this.member = {};
    this.options = opts;
    this.ce = new mc.CustomEvent();
    mc.widget.Event.customEvents(this, this.options);
};

mc.component.MemberClass.prototype = {

    add: function(key, obj, name, upt){
        if (!key || typeof key == 'undefined'){
            key = obj && name ? (obj[name] || '') : '';
            if (!key){
                key = mc.id(false, 'mc-key-').chain;
            }
        }
        var mkey = this.member[key];
        if (mkey){
            if (upt == true){
                this.ce.fireEvent('exist', key, obj, name, upt, mkey, this);
                return false;
            } else {
                return this.update(key, obj);
            }
        }

        this.member[key] = obj;
        this.ce.fireEvent('add', key, obj, name, upt, this);
        return [key, obj];
    },

    update: function(key, obj){
        if (!key || typeof key == 'undefined'){
            return false;
        }
        var mkey = this.member[key];
        if (!mkey){
            this.ce.fireEvent('notExist', key, obj, this);
            return false;
        }

        this.member[key] = obj;
        this.ce.fireEvent('update', key, obj, this);
        return obj;
    },

    get: function(key, obj, name){
        if (!key || typeof key == 'undefined'){
            if (!(key = obj && name ? (obj[name] || '') : '')){
                return false;
            };
        }
        return this.member[key];
    },

    getKeys: function(){
        var rst = [], objs = this.member, key;
        for (key in objs){
            rst.push(key);
        }
        return rst;
    },

    getName: function(name, value){
        var rst = [],
            objs = this.member,
            pty,
            kv;

        for (pty in objs){
            kv = objs[pty];
            if (value == kv[name]){
                rst.push(kv);
            }
        }
        return rst;
    },

    getFilter: function(opts){
        opts = opts || {};
        var key,
            objs = this.member,
            cp,
            pty,
            ck;

        for (key in objs){
            cp = objs[key];
            for (pty in opts){
                ck = cp[pty];
                if (ck != undefined && ck == opts[pty]){
                    return cp;
                }
            }
        }
        return null;
	},

    getFilters: function(opts){
        opts = opts || {};
        var rs = [],
            key,
            objs = this.member,
            cp,
            tg,
            pty,
            ck;

        for (key in objs){
            cp = objs[key];
            tg = '';
            for (pty in opts){
                ck = cp[pty];
                if (ck != undefined && ck == opts[pty]){
                    tg = cp;
                    break;
                }
            }
            if (tg){
                rs[rs.length] = tg;
            }
        }
        return rs;
	},

    getAll: function(){
        return this.member;
    },

    sortKey: function(ad, fn){
        return mc.sortArray(this.getKeys(), ad, fn).chain;
    },

    remove: function(key, obj, name){
        if (!key || typeof key == 'undefined'){
            key = obj && name ? (obj[name] || '') : '';
        }
        var mkey;
        if (!key || (!(mkey = this.member[key]))){
            this.ce.fireEvent('notExist', key, obj, this);
            return false;
        }

        delete this.member[key];
        this.ce.fireEvent('remove', key, mkey, this);
        return [key, mkey];
    },

    clear: function(){
        var ms = this.member;
        this.member = {};
        this.ce.fireEvent('clear', ms, this);
    }
};
mc.component.Member = new mc.component.MemberClass();


mc.component.Component = function(){

    return {
        isOwn: function(that, compare){
            return that.ccode == compare && that.isExecComponent ? true : false;
        },

        isExec: function(that, ccode, showTo){
            if (!(this.isOwn(that, ccode))){
                return false;
            }
            mc.widget.Event.customEvents(that);
            mc.widget.Widget.ready(that);
            that.ce.fireEvent('ready');

            this.exec(that, showTo);
            return true;
        },

        isGroupExec: function(that, ccode, showTo){
            if (that.ccode == ccode && that.isExecComponent){
                this.exec(that, showTo);
            }
        },

        add: function(that){
            if (!that._mc_component_id){
                var ids = mc.component.Instance.add(that.id || '', that);
                that._mc_component_id = ids[0];
            }
        },

        exec: function(that, parent){
            this.add(that);
            if (!that.component) {
                return;
            }
            if (!(mc.isArray(that.component).chain)){
                that.component = [that.component];
            }
            this.parentBox = parent;

            mc.component.Code.setDefault(that.component, that.defaultCcode);
            this.setParentNode(that, this.parentBox);
            this.mainComponent(that);
        },

        setParentNode: function(that, parent){
            mc.eachArray(that.component, function(opts){
                if (opts.priorParent){
                    parent = opts.priorParent;
                }
                opts._mc_parent_source = parent;
            }, this)
        },

        mainComponent: function(that){
            var cmpts = that.component,
                len = cmpts.length,
                i,
                cmpt,
                childCC;

            for (i = 0; i < len; i++){
                cmpt = cmpts[i];
                childCC = cmpt['ccode'];
                if (that.ccode == 'typegroup'){
                    cmpt = this.typegroupOption(childCC, cmpt, that);
                }
                this.newInstance(childCC, cmpt, this.parentBox, that);
                this.createMiddle(childCC, that, i);
            }
        },

        newInstance: function(ccode, opts, parent, that){
            var ent,
                newFn,
                pt,
                mainName;

            ent = mc.component.Code.getNewCode(ccode);
            if (!(newFn = ent ? ent : ccode)){
                return;
            };
            pt = opts._mc_parent_source;
            delete opts._mc_parent_source;

            mainName = ent ? mc.component.Code.getName(ccode) : '';
            if (!mainName){
                opts.showTo = pt;
            }
            this.cons = typeof newFn === 'string' ? eval(newFn) : newFn.call(this, opts);
            if (!this.cons){
                return;
            };
            if (that.ccode == 'toolbar'){
                this.cons['toolbar'] = that;
                this.parentBox = that.tbParent;
                parent = that.tbParent;
            }
            this.add(this.cons);
            this.setFormMember(ccode);
            if (mainName){
                this.cons[mainName](pt, that);
            }
        },

        typegroupOption: function(ccode, opts, that){
            if (ccode == 'linefeed'){
                opts._mc_parent_source = that.tgOutside;
            } else {
                that.createInside();
                opts._mc_parent_source = that.tgInside;
            }
            return opts;
        },

        setFormMember: function(ccode){
            if (mc.formMember && ccode != 'linefeed'){
                mc.formMember.add(this.cons.id, this.cons);
            }
        },

        createMiddle: function(childCC, that, index){
            if (that.component.length != (index + 1)){
                if (that.ccode == 'typegroup' && childCC == 'linefeed'){
                    that.createMiddle();
                }
            }
        },

        setCcodeIdList: function(cmpts, that, grid){
            var len = cmpts.length,
                i,
                j,
                cmpt;

            for (i = 0; i < len; i++){
                cmpt = cmpts[i];
                if (cmpt.id && cmpt.ccode != 'linenumber' && cmpt.ccode != 'linefeed'){
                    this._setCcodeIdList(cmpt, that, grid, cmpt.id);
                    if (cmpt.ccode == 'combo'){
                         if (cmpt.dataFields){
                             cmpt.dataFields = mc.toArray(cmpt.dataFields).chain;
                             for (j = 0; j < cmpt.dataFields.length; j++){
                                 this._setCcodeIdList(cmpt, that, grid, cmpt.dataFields[j], 'data');
                             }
                         }
                         if (cmpt.sendFields){
                             cmpt.sendFields = mc.toArray(cmpt.sendFields).chain;
                             for (j = 0; j < cmpt.sendFields.length; j++){
                                 this._setCcodeIdList(cmpt, that, grid, cmpt.sendFields[j], 'send');
                             }
                         }
                    }
                }
                if (cmpt.component){
                    this.setCcodeIdList(cmpt.component, that, grid);
                }
            }
        },

        _setCcodeIdList: function(cmpt, that, grid, id, field){
            that.ccodeIdList[id] = {};
            var tgvl = that.ccodeIdList[id];

            tgvl['grid'] = grid;
            tgvl['minusColor'] = cmpt.minusColor || '';
            tgvl['defaultColor'] = cmpt.defaultColor || '';
            tgvl['showRight'] = cmpt.showRight || '';
            tgvl['comma'] = cmpt.comma || '';

            if (cmpt.ccode == 'checkbox'){
                that.checkboxNodes[id] = 'c';
            } else if (cmpt.ccode == 'radio'){
                that.checkboxNodes[id] = 'r';
            } else if (cmpt.ccode == 'combo'){
                that.checkboxNodes[id] = 'm';
            } else if (cmpt.ccode == 'selectoption' || cmpt.ccode == 'labelselect'){
                that.checkboxNodes[id] = 's';
            }

            if (grid && !field) {
                id = that.setMcdttdID({id: id}, 0, field);
            }
            if (field){
                if (field == 'send'){
                    tgvl['input'] = true;
                    that.checkboxNodes[id] = 'mf';
                } else {
                    tgvl['input'] = false;
                }
                tgvl['comboID'] = cmpt.id;
            } else {
                tgvl['input'] = mc.isInput(id).chain ? true : false;
            }
        }
    }
}();


mc.component.Instance = function(){

    return {
        comp : new mc.component.MemberClass(),

        add: function(key, obj, pty, upt){
            return this.comp.add(key, obj, pty, upt);
        },

        get: function(key, obj, name){
            return this.comp.get(key, obj, name);
        },

        getFilter: function(opts){
            return this.comp.getFilter(opts);
        },

        getFilters: function(opts){
            return this.comp.getFilters(opts);
        },

        remove: function(key, obj, name){
            return this.comp.remove(key, obj, name);
        }
    };
}();


mc.component.Code = function(){
    defaultCcode: '';
    return {
        ccode: {
            button: 'new mc.types.Button(opts)',
            buttongroup: 'new mc.types.ButtonGroup(opts)',
            checkbox: 'new mc.types.CheckBox(opts)',
            checkboxgroup: 'new mc.types.CheckBoxGroup(opts)',
            combo: 'new mc.combo.Combo(opts)',
            detailselector: 'new mc.dataquery.DetailSelector(opts)',

            fieldset: 'new mc.types.FieldSet(opts)',
            formpanel: 'new mc.form.FormPanel(opts)',
            formtype: 'new mc.form.FormType(opts)',
            form: 'new mc.form.Form(opts)',

            getdata: 'new mc.form.GetData(opts)',
            grid: 'new mc.grid.Grid(opts)',
            gridentry: 'new mc.grid.GridEntry(opts)',
            gridupdate: 'new mc.grid.GridUpdate(opts)',
            gridview: 'new mc.grid.GridView(opts)',
            guide: 'new mc.guide.Guide(opts)',
            jointype: 'new mc.types.JoinType(opts)',

            label: 'new mc.types.Label(opts)',
            labelnumber: 'new mc.types.LabelNumber(opts)',
            labelselect: 'new mc.types.LabelSelect(opts)',
            labeltext: 'new mc.types.LabelText(opts)',
            labeltype: 'new mc.types.LabelType(opts)',
            linefeed: 'new mc.types.LineFeed(opts)',

            messagebox: 'new mc.guide.MessageBox(opts)',
            metafield: 'new mc.data.MetaField(opts)',
            metafilter: 'new mc.guide.MetaFilter(opts)',
            numbertype: 'new mc.types.NumberType(opts)',
            nodelist: 'new mc.combo.NodeList(opts)',

            panel: 'new mc.panel.Panel(opts)',
            radio: 'new mc.types.Radio(opts)',
            radiogroup: 'new mc.types.RadioGroup(opts)',
            resizing: 'new mc.dragdrop.Resizing(opts)',
            resizingproxy: 'new mc.dragdrop.ResizingProxy(opts)',

            selectoption: 'new mc.types.SelectOption(opts)',
            suggest: 'new mc.combo.Suggest(opts)',
            texttype: 'new mc.types.TextType(opts)',
            textarea: 'new mc.types.TextArea(opts)',
            title: 'new mc.widget.Title(opts)',
            tip: 'new mc.guide.Tip(opts)',
            type: 'new mc.types.Type(opts)',
            typegroup: 'new mc.types.TypeGroup(opts)'
        },

        mainName: {
            button: 'mainButton',
            buttongroup: 'mainButtonGroup',
            checkbox: 'mainCheckBox',
            checkboxgroup: 'mainCheckBoxGroup',
            combo: 'mainCombo',
            detailselector: 'mainDetailSelector',

            fieldset: 'mainFieldSet',
            formpanel: 'mainFormPanel',
            formtype: 'mainFormType',
            form: 'mainForm',

            getdata: 'mainGetData',
            grid: 'mainGrid',
            gridentry: 'mainGridEntry',
            gridupdate: 'mainGridUpdate',
            gridview: 'mainGridView',
            guide: 'mainGuide',
            jointype: 'mainJoinType',

            label: 'mainLabel',
            labelnumber: 'mainLabelNumber',
            labelselect: 'mainLabelSelect',
            labeltext: 'mainLabelText',
            labeltype: 'mainLabelType',
            linefeed: 'mainLineFeed',

            messagebox: 'mainMessage',
            metafield: 'mainMetaField',
            metafilter: 'mainMetaFilter',
            nodelist: 'mainNodeList',
            numbertype: 'mainNumberType',

            panel: 'mainPanel',
            radio: 'mainRadio',
            radiogroup: 'mainRadioGroup',
            resizing: 'mainResizing',
            resizingproxy: 'mainResizingProxy',

            selectoption: 'mainSelectOption',
            suggest: 'mainSuggest',
            texttype: 'mainTextType',
            textarea: 'mainTextArea',
            title: 'mainTitle',
            tip: 'mainTip',
            type: 'mainType',
            typegroup: 'mainTypeGroup'
        },

        getNewCode: function(code){
            return this.ccode[code] || '';
        },

        getName: function(code){
            return this.mainName[code] || '';
        },

        setDefault: function(cmpts, dftCode, one){
            if (!cmpts){
                return;
            }
            var len = cmpts.length,
                i,
                cmpt;

            for (i = 0; i < len; i++){
                cmpt = cmpts[i];
                if (!cmpt){
                    mc.widget.Message.show('E1041', 'mc.component.Code', 'component');
                    if (i > 0){
                        var before = cmpts[i - 1];
                        mc.widget.Message.show('I1000', 'mc.component.Code', 'ccode: ' + before.ccode + ', #id:' + (before.id || ''));
                    }
                    continue;
                }

                if (!cmpt.ccode && dftCode){
                    cmpt['ccode'] = dftCode;
                }
                if (cmpt.linefeed || cmpt.lineFeed){
                    cmpt['ccode'] = 'linefeed';
                }
                if (cmpt.component && !one){
                    this.setDefault(cmpt.component, cmpt.defaultCcode || dftCode);
                }
            }
        },

        add: function(code, newCode, name){
            if (typeof code == 'string'){
                this.ccode[code] = newCode;
                this.mainName[code] = name;
            } else {
                mc.eachArray(code, function(vl, ix){
                    this.ccode[vl[0]] = vl[1];
                    this.mainName[vl[0]] = vl[2] || '';
                }, this)
            }
        },

        remove: function(code){
            var cd;
            mc.eachArray(code, function(vl, ix){
                cd = this.ccode[vl];
                if (cd && !(/^new mc/.test(cd))){
                    delete this.ccode[cd];
                    delete this.mainName[cd];
                }
            }, this)
        }
    };
}();


//------------------
//@package: mc.types
//------------------

mc.types.Type = function(opts){
    mc.widget.Widget.setOptions(this, opts);
    if (this.showTo){
        this.mainType(this.showTo);
    }
};

mc.types.Type.prototype = {
    addEvent: true,
    adjacent: 'beforeEnd',
    attr: '',
    charsOnly: false,
    checkMethod: '',

    className: '',
    createType: '',
    defaultColor: '',
    defaultType: {tag: 'div', text: '&#160'},
    disabled: false,

    disabledClass: 'mc-types-disabled',
    errorClass: 'mc-types-error',
    focusClass: 'mc-types-focus',
    height: '',
    id: '',

    innerHTML: '',
    leftX: '',
    minusColor: '',
    name: '',
    nodeEvent: '',

    prefix: 'mc_type_',
    readOnly: '',
    resetEsc: true,
    showMsg: true,
    style: '',

    tabIndex: '',
    text: '',
    topY: '',
    typeClass: 'mc-types-type',
    unselectable: false,
    width: '',

    applyText: '',
    ccode: 'type',
    ccodeTypeClass: 'mc-type-ccode',
    checkForm: 'checkType',
    errorMsg: '',

    errorTitle: '',
    linePadding: 'mc-types-padding',
    newType: '',
    openForm: 'setOpenValue',
    openValue: '',

    ownName: 'types',
    serverClass: '',
    value: '',

    own: '',
    types: '',

    mainType: function(showTo){
        this.showTo = showTo || this.showTo;
        this.setCreateType();
        this.createElement();

        this.setText();
        this.setLinePadding();
        this.execInnerHTML();

        this.changeOwn();
        this.setAttr();
        this.setColor();

        this.cacheOpenValue();
        this.setEvents();
        mc.component.Component.isExec(this, 'type', this.showTo);
        return this;
    },

    setCreateType: function(){
        var ct = this.createType || this.defaultType;
        mc.allocate({}, ct)
          .setThis(this, 'newType');

        if (ct.id){
            this.newType.id = ct.id;
        } else if (this.id){
            this.newType.id = this.id;
        } else {
            this.newType.id = mc.id(false, this.prefix).chain;
        }
    },

    createElement: function(){
        this.adjacent = this.adjacent || 'beforeEnd';
        mc.Json.apply(this.newType, this.showTo, this.adjacent, true)
          .setOwn(mc.chain)
          .setThis(this, this.ownName)
          .setThis(this, 'own')
          .addClass([this.typeClass, this.className, this.serverClass || ''])
          .setStyle(this.style);

        if (this.ccode == 'type'){
            mc.addClass(this.ccodeTypeClass);
        }
    },

    setText: function(){
        if (this.text && !this.applyText){
            mc.setText(this.text);
        }
        if (this.unselectable){
            mc.setUnselectable(this.own);
        }
    },

    setLinePadding: function(){
        if ((this.ccode == 'type' || this.ccode == 'labeltype') && mc.isInput().chain == false){
            mc.addClass(this.linePadding);
        }
    },

    execInnerHTML: function(){
        if (this.innerHTML){
            this.own.innerHTML = this.innerHTML;
        }
    },

    changeOwn: function(){
    },

    setAttr: function(){
        mc.widget.Widget.applyAttr(this);
        if (!this.outside){
            mc.setWHXY(this.width, this.height, this.leftX, this.topY, 'BP');
        }
    },

    setColor: function(el){
        if (this.defaultColor){
            mc.setColor(this.defaultColor, el);
        }
        if (this.minusColor){
            var cm = typeof this.minusColor == 'boolean' ? 'red' : this.minusColor;
            mc.minusColor(cm, el);
        }
    },

    cacheOpenValue: function(){
        mc.isInput().chain ? mc.getValue() : mc.getText();
        mc.setThis(this, 'openValue');
    },

    setEvents: function(){
        var node = this.nodeEvent || this.own;
        if (!this._setEvents && this.addEvent){
            mc.widget.Event.keyDownPress(this, node, this.typeKeyDown);

            mc.on([node, 'focus', this.typeFocus, this],
                  [node, 'blur', this.typeBlur, this]
            );
            this._setEvents = true;
        }
    },

    removeEvents: function(){
        var node = this.nodeEvent || this.own;
        if (this._setEvents && this.addEvent){
            mc.widget.Event.keyDownPressOff(this, node, this.typeKeyDown);

            mc.off([node, 'focus', this.typeFocus, this],
                   [node, 'blur', this.typeBlur, this]
            );
            this.ce.clearEvents();
            this.ce.fireEvent('removeEvent', this.own, this);
        }
        this._setEvents = false;
    },

    typeFocus: function(e, tg, opts){
        if (this.focusInOut) {
            return;
        }
        this.focusInOut = true;
        this.focusValue = this.getValue();

        this.focusEvent(e, tg, opts, this);
        if (this.ccode == 'type'){
            this.ce.fireEvent('focus', e, tg, opts, this);
        }
    },

    focusEvent: function(e, tg, opts, that){
    },

    typeBlur: function(e, tg, opts){
        if (!this.focusInOut) {
            return;
        }
        this.focusInOut = false;

        this.blurEvent(e, tg, opts, this);
        if (this.ccode == 'type'){
            this.ce.fireEvent('blur', e, tg, opts, this);
        }
    },

    blurEvent: function(e, tg, opts, that){
    },

    typeKeyDown: function(e, tg, opts){
        var ck = mc.getControlKey(e).chain;
        if (ck){
            ck = ck.charAt(0).toLowerCase() + ck.substring(1) + 'ControlEvent';
            if (this[ck]){
                this[ck](e, tg, opts);
            }
            this.controlEvent(ck, e, tg, opts, this);

            this.ce.fireEvent('controlKey', ck, e, tg, opts, this);
            if (this.charsOnly){
                return;
            }
        }
        this.keyDownEvent(e, tg, opts, this);
        this.ce.fireEvent('keydown', e, tg, opts, this);
    },

    controlEvent: function(ck, e, tg, opts, that){
    },

    keyDownEvent: function(e, tg, opts, that){
    },

    setMsgOptions: function(opts){
        opts = opts || {};
        this.ccode == 'textarea' ? this.removeOutsideClass(opts.textAreaClass) : this.removeClass(opts.textTypeClass);

        mc.widget.Widget.allocate(this, opts);
        mc.widget.Widget.applyAttr(this, this.own);

        var vl = opts.attr ? opts.attr.value : '';
        if (opts.value || vl){
            this.openValue = opts.value || vl;
        }
        this.resetValue();
        mc.setWH(opts.width, opts.height, 'BP', this.own);
    },

    getValue: function(){
        mc.isInput(this.own).chain ? mc.getValue(this.own, true) : mc.getText(this.own);
        if (mc.chain === this.guideMsg){
            mc.chain = '';
        }
        return mc.chain;
    },

    setInputValue: function(){
        mc.getValue(this.own, true)
          .setThis(this, 'inputValue');
    },

    execCheckMethod: function(){
        var msg = '';
        if (this.checkMethod && mc.isFunction(this.checkMethod).chain){
            msg = this.checkMethod(this.inputValue);
            msg ? this.showError(msg) : this.hideError();
        }
        return msg;
    },

    showError: function(msg, el){
        if (typeof msg == 'object') {
            this.errorTitle = msg.title;
            this.errorMsg = msg.msg;
        } else if (typeof msg == 'string'){
            this.errorTitle = '';
            this.errorMsg = msg;
        }

        el = el || this.own;
        mc.addClass(this.errorClass, el);
        this.valueError = true;

        if (this.showMsg){
            mc.guide.GuideType.show(el, this.errorTitle, this.errorMsg);
        }
        this.ce.fireEvent('showMessage', this.errorTitle, this.errorMsg, el, this);
        return true;
    },

    hideError : function(el){
        el = el || this.own;
        mc.removeClass(this.errorClass, el);
        if (this.showMsg){
            mc.guide.GuideType.hide();
        }
        this.ce.fireEvent('hideMessage', el, this);
    },

    fireExactData: function(){
        if (!this.valueError) {
            if (this.ccode == this.ownName.toLowerCase() || this.parentComponent) {
                mc.removeClass(this.errorClass, this.own);
                this.ce.fireEvent('exactData', this.inputValue, this);
            }
        }
    },

    isReadOnly: function(){
        return (this.readOnly || this.own.readOnly || this.disabled) ? true : false;
    },

    checkType: function(){
    },

    resetValue: function(){
        this.setOpenValue();
        this.valueError = false;
        this.errorMsg = '';
        this.errorTitle = '';
        this.hideError();
        this.ce.fireEvent('resetValue', this.own, this);
    },

    setOpenValue: function(){
        mc.isInput(this.own).chain ? mc.setValue(this.openValue, this.own) : mc.setText(this.openValue, this.own);
    },

    setForcedValue: function(value){
        mc.isInput(this.own).chain ? mc.setValue(value, this.own) : mc.setText(value, this.own);
    },

    getOwn: function(){
        return this.own;
    },

    setEnable: function(el){
        mc.widget.Widget.setEnable(this.disabledClass, el || this.own)
    },

    setDisable: function(el){
        mc.widget.Widget.setDisable(this.disabledClass, el || this.own);
    },

    isVisible: function(){
        return mc.isVisible(false, this.own).chain;
    },

    setDisplay: function(show){
        mc.setDisplay(show || false, this.own);
    },

    remove: function(){
        this.removeEvents();
        mc.removeElement(this.own);
    },

    removeClass: function(cn){
        mc.removeClass(cn, this.own);
    },

    addClass: function(cn){
        mc.addClass(cn, this.own);
    },

    getOutside: function() {
        return this.outside;
    }
};


mc.types.Label = function(opts){
    mc.widget.Widget.setOptions(this, opts);
    if (this.showTo) {
        this.mainLabel(this.showTo);
    }
};

mc.types.Label.prototype = {
    className: '',
    decode: false,
    delimiter: ':',
    encode: false,
    insideClass: 'mc-label-inside',

    labelClass: 'mc-label',
    labelStyle: '',
    paddingLeft: 0,
    position: 'left',
    prefix: 'mc_label_',

    style: '',
    text: '&#160',
    unselectable: true,
    width: 70,

    boxGroupClass: '',
    ccode: 'label',
    labelText: '',

    labelInside: '',
    outside: '',
    ownLabel: '',

    mainLabel: function(showTo){
        this.showTo = showTo || this.showTo;
        this.createOutside();
        this.createLabel();

        this.encodeDecode();
        this.setLabelText();

        this.setForAttr();
        this.setPosition();
        this.setPadding();

        this.setEvents();
        mc.component.Component.isExec(this, 'label', this.showTo);
        return this;
    },

    createOutside: function(){
        mc.createAppend('div', false, this.prefix, this.showTo)
          .setThis(this, 'outside')
          .setOwn(mc.chain)
          .addClass([this.labelClass, this.boxGroupClass])
          .setStyle(this.labelStyle)
          .setXY(this.leftX, this.topY);

        if (this.position == 'top'){
            mc.addClass('mc-labelbox-top');
        }
    },

    createLabel: function(){
        mc.createAppend('label', this.id, this.prefix, this.outside)
          .setOwn(mc.chain)
          .setThis(this, 'ownLabel')
          .addClass(this.className)
          .setStyle(this.style);

        if (this.unselectable){
            mc.setUnselectable();
        }
        mc.widget.Widget.applyAttr(this);
    },

    encodeDecode: function(){
        this.text = this.encode ? mc.encodeHTML(this.text).chain :
                    this.decode ? mc.decodeHTML(this.text).chain : this.text;
    },

    setLabelText: function(){
        mc.setText(this.text + this.delimiter, this.ownLabel)
          .setThis(this, 'labelText');
    },

    setForAttr: function(){
        mc.id(false, this.prefix)
          .setAttr({'for': mc.chain}, this.ownLabel);
    },

    setPosition: function(){
        mc.addClass(this.labelClass + '-' + this.position, this.ownLabel);
    },

    setPadding: function(){
        this.paddingLeft = this.paddingLeft || 0;
        if (this.paddingLeft != 0){
            mc.splitNumAlpha(this.paddingLeft)
              .setStyle({'padding-left': (mc.chain[0] + mc.chain[1] || 'px')}, this.ownLabel);
        }
        this.setWH();
    },

    setEvents: function(){
        if (!this._setEvents){
            this._setEvents = true;
        }
    },

    removeEvents: function(){
        this._setEvents = false;
    },

    setLabelInside: function(){
        mc.createAppend('div', false, this.prefix, this.outside)
          .setThis(this, 'labelInside');

        var wd = parseInt(this.width, 10) || 0;
        var dp = parseInt(this.paddingLeft, 10) || 0;
        var pl = {};
        pl['padding-left'] = this.position == 'top' ? '0px' : (wd + dp) + 'px';

        mc.addClass(this.insideClass, this.labelInside)
          .setStyle(pl, this.labelInside);
    },

    setOutsideWidth: function(wd){
        var pl = wd + mc.getPaddingValue('L', this.labelInside).chain;
        if (mc.IE6){
            pl += 3;
        }
        mc.setWidth(pl, false, this.outside);
    },

    setWH: function(wd, ht){
        mc.setWH(wd || this.width, ht || this.height);
    },

    setDelimiter: function(dl){
        this.delimiter = dl || '';
    },

    labelReset: function(){
        this.setLabelText();
    },

    getOwnLabel: function(){
        return this.ownLabel;
    },

    getInside: function(){
        return  this.labelInside;
    },

    getOutside: function(){
        return  this.outside;
    }
};


mc.types.LabelType = function(opts){
    mc.widget.Widget.setOptions(this, opts);
    if (this.showTo){
        this.mainLabelType(this.showTo);
    }
};

mc.extend(mc.types.LabelType, mc.types.Type, {
    label: '',
    prefix: 'mc_labeltype_',
    ccode: 'labeltype',
    _ownName: 'labelType',
    labelInside: '',
    labelNew: '',

    mainLabelType: function(showTo){
        this.showTo = showTo || this.showTo;
        this.newLabel();
        this.mainType(this.labelInside);

        this.setOutsideWidth();
        this.setEvents();

        mc.widget.Widget.cacheShowTo(this, false);
        mc.component.Component.isExec(this, 'labeltype', this.showTo);
        return this;
    },

    newLabel: function(){
        if (!this.labelNew){
            this.labelNew = new mc.types.Label(this.label);
        }
        this.labelNew.mainLabel(this.showTo);
        this.labelNew.setLabelInside();
        this.labelInside = this.labelNew.labelInside;

        mc.widget.Widget.cacheShowTo(this, true);
    },

    setOutsideWidth: function(){
        mc.getWidth(false, this.types);
        this.labelNew.setOutsideWidth(mc.chain);
    },

    setEvents: function(){
        if (!this._setEvents){
            mc.types.LabelType.superclass.setEvents.call(this);
            this._setEvents = true;
        }
    },

    removeEvents: function(){
        mc.types.LabelType.superclass.removeEvents.call(this);
    },

    remove: function(){
        this.removeEvents();
        mc.removeElement(this.labelNew.outside);
    },

    getLabelNew: function(){
        return this.labelNew;
    }
});


mc.types.TextType = function(opts){
    mc.widget.Widget.setOptions(this, opts);
    if (this.showTo){
        this.mainTextType(this.showTo);
    }
};

mc.extend(mc.types.TextType, mc.types.Type, {
    autoCheck: true,
    customExp: '',
    customExpMsg: {title: '입력 오류', msg: '적절하지 않은 값입니다.'},
    defaultType: {tag: 'input', type: 'text', autocomplete: 'off'},
    disableExp: '',

    emptyCheck: true,
    emptyMsg: {title: '필수 입력', msg: '필수 입력 항목입니다.'},
    escClear: true,
    guideClass: 'mc-types-guide',
    guideMsg: '',

    maxLength: Number.MAX_VALUE,
    maxLengthMsg: {title: '최대 자릿수 초과', msg: '입력 가능한 최대 자릿수는 {0}입니다.'},
    minLength: 0,
    minLengthMsg: {title: '최소 자릿수', msg: '최소 입력 자릿수는 {0}입니다.'},
    operator: '',

    patternExp: '',
    patternExpMsg: '',
    prefix: 'mc_texttype_',
    selected: false,
    textTypeClass: '',
    textTypeStyle: '',
    unselectable: false,

    ccode: 'texttype',
    checkForm: 'checkTexttype',
    inputValue: '',
    ownName: 'textType',
    openForm: 'resetValue',

    periodicTimer: '',
    suggest: false,
    suggestValue: '',
    _textTypeClass: 'mc-types-texttype',
    valueError: false,

    own: '',
    operatorNew: '',

    mainTextType: function(showTo){
        this.showTo = showTo || this.showTo;
        this.mainType(this.showTo);

        this.setTextType();
        this.setGuide();
        this.createOperator();
        this.setEvents();

        mc.component.Component.isExec(this, 'texttype', this.showTo);
        return this;
    },

    setTextType: function(){
        mc.addClass([this._textTypeClass, this.textTypeClass])
          .setStyle(this.textTypeStyle)
          .setWHXY(this.width, this.height, this.leftX, this.topY, 'BP');
    },

    setGuide: function(msg){
        this.guideMsg = msg || this.guideMsg;
        if (!this.own.value && this.guideMsg){
            mc.setValue(this.guideMsg, this.own);
            mc.addClass(this.guideClass, this.own);
        }
    },

    createOperator: function(){
        if (this.operator && !this.operatorNew){
            this.operatorNew = new mc.form.Operator({
                optsOperator: this.operator,
                newComponent: this
            });
        }
    },

    setEvents: function(){
        if (!this._setEvents && this.addEvent){
            mc.types.TextType.superclass.setEvents.call(this);
            if (!this.isReadOnly()){
                mc.on(this.own, 'keyup', this.keyUpEvent, this, {bubble: true});
            }
            this._setEvents = true;
        }
    },

    removeEvents: function(){
        if (this._setEvents && this.addEvent) {
            mc.types.TextType.superclass.removeEvents.call(this);
            if (!this.isReadOnly()){
                mc.off(this.own, 'keyup', this.keyUpEvent, this);
            }
        }
        this._setEvents = false;
    },

    focusEvent: function(e, tg, opts){
        this.clearGuideMsg();
        mc.addClass(this.focusClass, this.own);
        if (this.selected){
            mc.selected(this.own);
        }
        this.valueError ? this.showError() : this.hideError();

        if (this.suggest && (mc.Gecko || mc.Opera)){
            this.periodicTimer = mc.periodical(this.suggestCheck, 100, this);
        }
        this.ce.fireEvent('focus', e, tg, opts, this);
    },

    keyUpEvent: function(e, tg, opts){
        this.hideError();
        if (mc.widget.Event.isGecko229(e)){
            this.blurEvent(e, tg, opts);
            return;
        }
        this.isCheck(e, tg, opts);
        if (!this.valueError && !this.keyupOverride){
            this.ce.fireEvent('keyup', e, tg, opts, this);
        }
    },

    blurEvent: function(e, tg, opts){
        if (this.suggest && (mc.Gecko || mc.Opera)){
            clearTimeout(this.periodicTimer);
        }
        this.focusInOut = false;
        mc.removeClass(this.focusClass, this.own);
        this.checkTexttype();
        this.ce.fireEvent('blur', e, tg, opts, this);
    },

    escControlEvent: function(e, tg, opts){
        if (this.escClear){
            this.clearValue();
            this.hideError();
            this.escClearEvent = true;
        }
        this.ce.fireEvent('EscKey', e, tg, opts, this);
    },

    clearGuideMsg: function(){
        mc.removeClass(this.guideClass, this.own);
        var gm = this.guideMsg;
        if (gm && gm == this.own.value && this.openValue == ''){
            this.own.value = '';
            this.setInputValue();
        }
    },

    isCheck: function(e, tg, opts){
        this.doCheck = false;
        if (mc.isBlurKey(e).chain || (mc.Gecko && e.keyCode == 229)){
            return;
        }
        this.checkTexttype();
    },

    checkTexttype: function(){
        this.valueError = false;
        this.doCheck = false;
        if (this.escClearEvent){
            this.escClearEvent = false;
            return;
        }
        if (this.isReadOnly() || this.parentComponent){
            return;
        }
        this.doCheck = true;

        this.clearGuideMsg();
        this.checkPre();

        if (this.autoCheck) {
            this.checkText();
            this.fireExactData();
        } else {
            this.execCheckMethod();
        }
    },

    checkPre: function(){
        this.hideError();
        this.applyDisableExp(this.getValue());
        this.setInputValue();
    },

    applyDisableExp: function(vl){
        if (this.disableExp){
            var val = vl ? vl.replace(this.disableExp, '') : '';
            mc.setValue(val, this.own);
        }
    },

    checkText: function(){
        var len = this.inputValue.length;
        if (this.emptyCheck && len == 0){
            return this.showError(this.emptyMsg);
        }
        if (this.checkLength(len)){
            return;
        }
        if (!this.editDec){
            this.checkOperator();
        }
        if (!this.valueError){
            this.checkUseExp();
        }
        if (!this.valueError){
            if (this.customExp && !this.customExp.test(this.inputValue)){
                return this.showError(this.customExpMsg);
            }
        }
    },

    checkLength: function(len){
        if (len < this.minLength){
            var ml = this.minLengthMsg;
            ml.msg = mc.matchText(ml.msg, this.minLength).chain;
            return this.showError(ml);
        }
        if (len > this.maxLength){
            var ml = this.maxLengthMsg;
            ml.msg = mc.matchText(ml.msg, this.maxLength).chain;
            return this.showError(ml);
        }
        return false;
    },

    checkOperator: function(len){
        if (this.operatorNew){
            this.operatorNew.checkTextType();
        }
    },

    checkUseExp: function(){
        if (this.patternExp){
            var exp = mc.types.PatternExp,
                name = this.patternExp;

            if (!(exp[name](this.inputValue))){
                if (this.patternExpMsg){
                    this.showError(this.patternExpMsg);
                } else {
                    name += 'Msg';
                    this.showError(this[name] || exp[name]);
                }
            }
        }
    },

    suggestCheck: function(){
        var value = this.getValue();
        if (this.suggestValue != value){
            this.suggestValue = value;
            if (mc.isLocalChars(value).chain){
                this.suggestEvent(value, this);
                this.ce.fireEvent('suggest', value, this);
            }
        };
    },

    suggestEvent: function(vl, that){
    },

    resetValue: function(){
        mc.types.TextType.superclass.resetValue.call(this);
        this.setGuide();
    },

    clearValue: function(){
        this.own.value = '';
        this.ce.fireEvent('clearValue', this.own, this);
    }
});


mc.types.LabelText = function(opts){
    mc.widget.Widget.setOptions(this, opts);
    if (this.showTo){
        this.mainLabelText(this.showTo);
    }
};

mc.extend(mc.types.LabelText, mc.types.TextType, {
    prefix: 'mc_labeltext_',

    _ownName: 'labelText',
    ccode: 'labeltext',

    labelNew: '',

    mainLabelText: function(showTo){
        this.showTo = showTo || this.showTo;

        this.newLabel();
        this.mainTextType(this.labelInside);

        this.setOutsideWidth();
        this.setEvents();

        mc.widget.Widget.cacheShowTo(this, false);
        mc.component.Component.isExec(this, 'labeltext', this.showTo);
        return this;
    },

    newLabel: function(){
        if (!this.labelNew){
            this.labelNew = new mc.types.Label(this.label);
        }
        this.labelNew.mainLabel(this.showTo);
        this.labelNew.setLabelInside();
        this.labelInside = this.labelNew.labelInside;

        mc.widget.Widget.cacheShowTo(this, true);
    },

    setOutsideWidth: function(){
        mc.getWidth(false, this.textType);
        this.labelNew.setOutsideWidth(mc.chain);
    },

    setEvents: function(){
        if (!this._setEvents){
            mc.types.LabelText.superclass.setEvents.call(this);
            this._setEvents = true;
        }
    },

    removeEvents: function(){
        mc.types.LabelText.superclass.removeEvents.call(this);
    },

    remove: function(){
        this.removeEvents();
        mc.removeElement(this.labelNew.outside);
    }
});


mc.types.JoinType = function(opts){
    mc.widget.Widget.setOptions(this, opts);
    if (this.showTo){
        this.mainJoinType(this.showTo);
    }
};
mc.extend(mc.types.JoinType, mc.types.TextType, {
    imageClass: '',
    imageTitle: '',
    imageType: 'combo',
    joinOverClass: 'mc-join-over',
    joinTypeClass: 'mc-join-type',
    joinTypeStyle: '',

    outsideClass: 'mc-join-outside',
    outsideStyle: '',
    prefix: 'mc_join_',
    width: '',

    ccode: 'jointype',
    comboTypeClass: 'mc-join-combo',
    dateTypeClass: 'mc-join-date',
    joinMousedown: false,
    selectTypeClass: 'mc-join-select',

    outside: '',
    joinType: '',

    mainJoinType: function(showTo){
        this.showTo = showTo || this.showTo;
        this.setOutside();
        this.setJoinType();

        this.mainTextType(this.outside);
        this.setOutsideWidth();
        this.setEvents();

        mc.component.Component.isExec(this, 'jointype', this.showTo);
        return this;
    },

    setOutside: function(){
        mc.createAppend('div', false, this.prefix, this.showTo)
          .setThis(this, 'outside')
          .setOwn(mc.chain)
          .addClass(this.outsideClass)
          .setStyle(this.outsideStyle)

        if (this.ccode == 'jointype' || this.ccode == 'combo'){
            mc.setWH(this.width, this.height, 'BP')
              .setXY(this.leftX, this.topY);
        }

        mc.widget.Widget.cacheShowTo(this, true);
    },

    setJoinType: function(){
        mc.createAppend('div', false, this.prefix, this.outside)
          .setThis(this, 'joinType')
          .setOwn(mc.chain)
          .addClass(this.joinTypeClass)
          .setStyle(this.joinTypeStyle);

        var st = '';
        if (this.imageClass){
            st = this.imageClass;
        } else {
            st = this.imageType == 'combo' ? this.comboTypeClass :
                 this.imageType == 'date' ? this.dateTypeClass :
                 this.imageType == 'select' ? this.selectTypeClass : '';
        }
        mc.addClass(st);

        this.setImageTitle();
        if (this.width){
            mc.getWidth(false, this.joinType);
            this.width -= mc.chain;
        }
    },

    setImageTitle: function(text){
        var tt = text || this.imageTitle;
        if (tt){
            mc.setAttr({title: tt});
        }
    },

    setOutsideWidth: function(){
        mc.widget.Widget.cacheShowTo(this, false);
        if (this.width){
            if (mc.Opera){
                mc.getWidth('BP', this.textType)
                  .setWidth(mc.chain - 3, 'BP', this.textType);
            }
        } else {
            mc.getWidth(false, this.textType)
              .chainDup()
              .getWidth(false, this.joinType)
              .setWidth(mc.dup + mc.chain, 'BP', this.outside);
        }
    },

    setEvents: function(){
        if (!this._setEvents){
            mc.types.JoinType.superclass.setEvents.call(this);

            mc.on(this.joinType, 'click', this.joinClick, this);
            mc.widget.Event.overOut(this, this.joinType, false, this.joinOverClass);

            this._setEvents = true;
        }
    },

    removeEvents: function(){
        mc.types.JoinType.superclass.removeEvents.call(this);
        mc.off(this.joinType, 'click', this.joinClick, this);
        mc.widget.Event.overOutOff(this, this.joinType);
    },

    joinClick: function(e, tg, opts){
        this.ce.fireEvent('click', e, tg, opts, this);
    },

    getJoinType: function() {
        return this.joinType;
    },

    getOutside: function() {
        return this.outside;
    }
});


mc.types.NumberType = function(opts){
    mc.widget.Widget.setOptions(this, opts);
    if (this.showTo) {
        this.mainNumberType(this.showTo);
    }
};

mc.extend(mc.types.NumberType, mc.types.TextType, {
    decDelimiter: '.',
    decPrecision: 0,
    prefix: 'mc_numbertype_',
    useNegative: true,
    useNumeric: '0123456789',

    beforeValue: '',
    ccode: 'numbertype',
    checkForm: 'checkNumbertype',
    ownName: 'numberType',
    possibledExp: '',

    mainNumberType: function(showTo){
        this.showTo = showTo || this.showTo;

        this.mainTextType();

        this.setLimit();
        this.setEvents();

        mc.component.Component.isExec(this, 'numbertype', this.showTo);
        return this;
    },

    setLimit: function(){
        var check = this.useNumeric + '';
        if (this.decPrecision){
            check += ('\\' + this.decDelimiter);
        }
        if (this.useNegative){
            check += '-';
        }
        this.possibledExp = new RegExp('[' + check + ']');

        mc.setStyle('ime-mode:disabled');
    },

    setEvents: function(){
        if (!this._setEvents){
            mc.types.NumberType.superclass.setEvents.call(this);

            if (!this.isReadOnly()){
                mc.on(this.own, 'keypress', this.numberKeyPress, this);
            }
            this._setEvents = true;
        }
    },

    removeEvents: function(){
        mc.types.NumberType.superclass.removeEvents.call(this);

        if (!this.isReadOnly()){
            mc.off(this.own, 'keypress', this.numberKeyPress, this);
        }
    },

    numberKeyPress: function(e, tg){
        var ek = e.keyCode;
        if ((e.shiftKey && (ek != 9 && ek != 35 && ek != 36 && ek != 37 && ek != 39)) || e.ctrlKey || e.altKey || ek == 32){
            e.bubbleDefault();
            return;
        }

        var ccd = String.fromCharCode(ek);
        if (!mc.Gecko && mc.isPressKey(e).chain && !ccd){
            return;
        }
        if (mc.Gecko && mc.isPressKey(e).chain){
            return;
        }

        if (!(this.possibledExp.test(ccd))){
            e.bubbleDefault();
            return;
        }
    },

    keyUpEvent: function(e, tg, opts){
        this.keyupOverride = true;
        mc.types.NumberType.superclass.keyUpEvent.call(this, e, tg, opts);
        this.keyupOverride = false;

        if (this.doCheck && !this.valueError){
            this.checkNumbertype(true);
        }

        if (!this.valueError){
            this.ce.fireEvent('keyup', e, tg, opts, this);
        }
    },

    blurEvent: function(e, tg, opts){
        mc.types.NumberType.superclass.blurEvent.call(this, e, tg, opts);
        if (this.doCheck && !this.valueError){
            this.checkNumbertype(true)
        }
    },

    checkNumbertype: function(did){
        if (!did){
            this.checkTexttype();
        }
        if (!this.doCheck || this.valueError || !this.autoCheck){
            return;
        }

        this.editDec();
        this.checkOperator();
        this.fireExactData();
    },

    editDec: function(){
        if (this.inputValue && this.decPrecision) {
            var sl = this.inputValue.split(this.decDelimiter);

            if (sl[1] && sl[1].length > this.decPrecision) {
                mc.setValue(this.beforeValue, this.own);
            } else {
                this.beforeValue = this.inputValue;
            }
        }
    }
});


mc.types.LabelNumber = function(opts){
    mc.widget.Widget.setOptions(this, opts);
    if (this.showTo){
        this.mainLabelNumber(this.showTo);
    }
};

mc.extend(mc.types.LabelNumber, mc.types.NumberType, {
    prefix: 'mc_labelnumber_',

    _ownName: 'labelnumber',
    ccode: 'labelnumber',

    labelNew: '',

    mainLabelNumber: function(showTo){
        this.showTo = showTo || this.showTo;

        this.newLabel();

        this.mainNumberType(this.labelInside);

        this.setOutsideWidth();
        this.setEvents();

        mc.component.Component.isExec(this, 'labelnumber', this.showTo);
        return this;
    },

    newLabel: function(){
        if (!this.labelNew){
            this.labelNew = new mc.types.Label(this.label);
        }

        this.labelNew.mainLabel(this.showTo);
        this.labelNew.setLabelInside();
        this.labelInside = this.labelNew.labelInside;

        this.cacheShowTo(true);
    },

    cacheShowTo: function(ch){
        ch ? this.showToCache = this.showTo : this.showTo = this.showToCache;
    },

    setOutsideWidth: function(){
        this.cacheShowTo(false);
        mc.getWidth(false, this.numberType);
        this.labelNew.setOutsideWidth(mc.chain);
    },

    setEvents: function(){
        if (!this._setEvents){
            mc.types.LabelNumber.superclass.setEvents.call(this);
            this._setEvents = true;
        }
    },

    removeEvents: function(){
        mc.types.LabelNumber.superclass.removeEvents.call(this);
    },

    remove: function(){
        this.removeEvents();
        mc.removeElement(this.labelNew.outside);
    },

    getLabelNew: function(){
        return this.labelNew;
    }
});


mc.types.TextArea = function(opts){
    mc.widget.Widget.setOptions(this, opts);
    if (this.showTo) {
        this.mainTextArea(this.showTo);
    }
};

mc.extend(mc.types.TextArea, mc.types.TextType, {
    defaultType: {tag: 'textarea', rows: '2', cols: '20'},
    prefix: 'mc_textarea_',
    textAreaClass: '',
    textAreaStyle: '',

    ccode: 'textarea',
    ownName: 'textArea',

    outside: '',

    mainTextArea: function(showTo){
        this.showTo = showTo || this.showTo;

        this.createOutside();
        this.cacheShowTo(true);
        this.setRowsCols();

        this.mainTextType(this.outside);

        this.cacheShowTo(false);

        mc.component.Component.isExec(this, 'textarea', this.showTo);
        return this;
    },

    createOutside: function(){
        mc.createAppend('div', false, this.prefix, this.showTo)
          .setOwn(mc.chain)
          .setThis(this, 'outside')
          .addClass(this.textAreaClass)
          .setStyle(this.textAreaStyle);
    },

    cacheShowTo: function(cache){
        mc.widget.Widget.cacheShowTo(this, cache, this.outside);
    },

    setRowsCols: function(){
        if (this.rows){
            this.defaultType.rows = this.rows;
        }
        if (this.cols){
            this.defaultType.cols = this.cols;
        }
        this._textTypeClass = '';
    },

    isVisible: function(){
        var vs = mc.isVisible(false, this.outside).chain;
        if (vs){
            vs = mc.types.TextArea.superclass.isVisible.call(this);
        }
        return vs;
    },

    setDisplay: function(show){
        mc.setDisplay(show || false, this.outside);
    },

    removeOutsideClass: function(){
        mc.removeClass(this.textAreaClass, this.outside);
    },

    addOutsideClass: function(){
        mc.addClass(this.textAreaClass, this.outside);
    }
});


mc.types.GroupModel = function(){
};

mc.types.GroupModel.prototype = {
    eachWidth: [],
    insideClass: '',
    insideStyle: '',
    labelClass: 'mc-boxgroup-label',
    labelStyle: '',

    linesideClass: '',
    linesideStyle: '',
    middleClass: '',
    middleStyle: '',
    outsideClass: '',
    outsideStyle: '',

    cacheComp: '',
    ccode: 'groupmodel',
    _insideClass: 'mc-boxgroup-inside',
    _linesideClass: 'mc-boxgroup-line',
    lineTotalWidth: '',

    maxNumber: '',
    _middleClass: 'mc-boxgroup-middle',
    ownIdLsit: '',
    objectID: '',
    _outsideClass: 'mc-boxgroup',

    ownGroup: '',
    replaceID: false,
    outside: '',

    mainGroupModel: function(showTo){
        this.showTo = showTo || this.showTo;
        this.cacheComponent();
        this.createOutside();
        this.setCCode();
        this.getOwnCCode();

        this.setMaxNumber();
        this.setLineWidth();
        this.setEachWidth();
        this.setCCodeWidth();

        return this;
    },

    cacheComponent: function(){
        this.cacheComp = mc.toArray(this.component || this.comp).chain;
        if (this.cacheComp.length == 0){
            mc.widget.Message.show('E1010', this.ccode, 'component');
        }
    },

    createOutside: function(){
        mc.createAppend('div', this.id, this.prefix, this.showTo)
          .setThis(this, 'outside')
          .setOwn(mc.chain)
          .addClass([this._outsideClass, this.outsideClass])
          .setStyle(this.outsideStyle)
          .setWH(this.width, this.height, 'BP')
          .setXY(this.leftX, this.topY);

        mc.widget.Widget.applyAttr(this);
    },

    setCCode: function(){
        mc.component.Code.setDefault(this.cacheComp, this.defaultCcode)
    },

    getOwnCCode: function(){
        var cb = [];
        mc.eachArray(this.cacheComp, function(cache){
            if (cache.ccode == this.defaultCcode){
                cb[cb.length] = cache;
            }
            if (cache.ccode == 'label'){
                this.label = cache;
                this.label['boxGroupClass'] = 'mc-label-boxgroup';
            }
        }, this)

        this.ownGroup = cb;
    },

    setMaxNumber: function(){
        this.maxNumber = this.maxNumber || this.ownGroup.length;
    },

    setLineWidth: function(){
        this.lineTotalWidth = this.width;
        var lb = this.label;
        if (lb){
            this.lineTotalWidth -= ((lb.width || 0) + (lb.paddingLeft || 0));
        }
    },

    setEachWidth: function(){
        this.eachWidth = mc.toArray(this.eachWidth).chain;
        if (this.eachWidth.length == 0 ){
            this.setAverageWidth();
        }
    },

    setAverageWidth: function(){
        var avg,
            ews = this.eachWidth,
            i,
            total = 0;

        avg = Math.round(this.lineTotalWidth / this.maxNumber);
        for (i = 0; i < this.maxNumber; i++){
            ews[i] = avg;
            total += avg;
        }
        ews[ews.length - 1] += this.lineTotalWidth - total;
    },

    setCCodeWidth: function(){
        var i,
            len = this.cacheComp.length,
            j = 0,
            k = 0,
            m = 0,
            gr,
            cmpt;

        this.objectID = [];
        this.ownIdLsit = [];

        for (i = 0; i < len; i++){
            cmpt = this.cacheComp[i];
            if (cmpt.ccode == this.defaultCcode) {
                gr = this.ownGroup[k];
                gr.width = this.eachWidth[j];

                if (this.tdWidth){
                    this.tdWidth[k] = this.eachWidth[j];
                }
                if (this.replaceID || !gr.id){
                    gr.id = mc.id(false, this.prefix).chain;
                }

                this.ownIdLsit[k] = gr.id;
                this.objectID[k] = mc.id(false, this.prefix).chain;
                j++, k++;
            }

            if (this.isLinefeed(cmpt) || (this.arrange && this.arrange[m] == j)){
                j = 0, m++;
            }
        }
    },

    isLinefeed: function(cmpt){
        return (cmpt.ccode == 'linefeed') ? true : false;
    },

    fireOwnClose: function(){
        if (mc.component.Component.isOwn(this, this.ccode)){
            this.ce.fireEvent('ready', this);
        }
    },

    removeEvents: function(){
        this.ce.clearEvents();
        this._setEvents = false;
    },

    clickEvent: function(e, tg){
        this.ce.fireEvent('click', e, this);
    },

    getOutside: function(){
        return this.outside;
    }
};


mc.types.Button = function(opts){
    if (typeof opts === 'string'){
        opts = {'text': opts};
    }
    mc.widget.Widget.setOptions(this, opts);
    if (this.showTo){
        this.mainButton(this.showTo);
    }
};

mc.extend(mc.types.Button, mc.types.Type, {
    buttonClass: 'mc-button-bmo',
    buttonClick: '',
    buttonStyle: '',
    buttonType: 'button',
    centerClass: 'mc-button-center',

    createData: '',
    defaultType: {tag: 'button', type: 'button'},
    deleteData: '',
    downUpClass: 'mc-button-down',
    focusClass: '',

    image: '',
    imageAlign: 'left',
    imageClass: '',
    imageTitle: '',
    leftClass: 'mc-button-left',

    outsideClass: 'mc-button-outside',
    outsideStyle: '',
    overOutClass: 'mc-button-over',
    padding: 7,
    prefix: 'mc_button_',

    resetData: '',
    rightClass: 'mc-button-right',
    scope: '',
    space: 0,
    submit: false,

    text: '&#160;',
    updateData: '',
    width: '',

    applyText: true,
    ccode: 'button',
    traceMouseOver: true,
    twiceClass: 'mc-button-twice',
    typeClass: '',
    ownName: 'button',

    button: '',
    center: '',
    outside: '',

    mainButton: function(showTo){
        this.showTo = showTo || this.showTo;
        this.createOutSide();
        this.createInside();
        this.setDefaultType();

        this.mainType(this.center);
        this.setButtonImage();
        this.setEvents();

        mc.component.Component.isExec(this, 'button', this.showTo);
        return this;
    },

    createOutSide: function(){
        mc.createAppend('div', false, this.prefix, this.showTo)
          .setThis(this, 'outside')
          .setOwn(mc.chain)
          .addClass(['mc-button', this.outsideClass])
          .setStyle(this.outsideStyle)
          .setHeight(this.height, 'BP')
          .setXY(this.leftX, this.topY);

        this.setSpace();
        mc.widget.Widget.cacheShowTo(this, true);
    },

    setSpace: function(){
        if (this.space){
            mc.splitNumAlpha(this.space)
              .setStyle({'margin-left': (mc.chain[0] + mc.chain[1] || 'px')}, this.outside);
        }
    },

    createInside: function(){
        var tpl = '<div class="{0}"></div>' +
                  '<div id="{1}" class="{2}" unselectable="on"></div>' +
                  '<div class="{3}"></div>' +
                  '<div class="mc-clear"></div>';

        var bid = mc.id(false, this.prefix).chain,
            map = [this.leftClass, bid, this.centerClass, this.rightClass];

        mc.newTemplate(tpl).Template.apply(this.outside, 'beforeEnd', map);

        mc.get(bid)
          .setThis(this, 'center');
    },

    setDefaultType: function(){
        var dt = this.defaultType;
        dt.id = this.id || mc.id(false, this.prefix).chain;

        dt.type = this.buttonType || dt.type;
        if (dt.type == 'submit'){
            dt.type = 'button';
            this.submit = true;
        }

        dt.className = this.buttonClass || '';
        dt.style = this.buttonStyle || '';
        dt.text = this.text || '&#160;';
    },

    setButtonImage: function(img, icls){
        this.image = img || this.image;
        this.imageClass = icls || this.imageClass;

        this.setImage(this.image);
        this.setImageClass(this.imageClass);

        this.width ? this.setWidth(this.width) : this.setOutsideWidth();
        mc.widget.Widget.cacheShowTo(this, false);
    },

    setEvents: function(){
        if (!this._setEvents){
            mc.types.Button.superclass.setEvents.call(this);

            mc.setOwn(this.outside);
            mc.onOwn(['click', this.clickEvent, this, {stop:true}],
                     ['mouseover', this.mouseOverEvent, this],
                     ['mouseout', this.mouseOutEvent, this],
                     ['mousedown', this.mouseDownEvent, this, {stop:true}],
                     ['mouseup', this.mouseUpEvent, this]);

            this._setEvents = true;
        }
    },

    removeEvents: function(){
        mc.types.Button.superclass.removeEvents.call(this);

        mc.setOwn(this.outside);
        mc.offOwn(['click', this.clickEvent, this],
                  ['mouseover', this.mouseOverEvent, this],
                  ['mouseout', this.mouseOutEvent, this],
                  ['mousedown', this.mouseDownEvent, this],
                  ['mouseup', this.mouseUpEvent, this]);
    },

    setImage: function(image, txt){
        if (image){
            this.getAlign();
            mc.setStyle({'background-image': "url(" + image + ")"}, this.button);
            this.setPadding();
            this.setImageTitle();
        }
    },

    getAlign: function(){
        var lr = this.imageAlign == 'left' ? 'mc-button-image-left' : 'mc-button-image-right';
        mc.addClass(lr, this.outside);
    },

    setPadding: function(pad){
        pad = (pad || this.padding) + 20;
        var wd = 'padding-' + ((this.imageAlign == 'left') ? 'left:' : 'right:') + pad + 'px';
        mc.setStyle(wd, this.button);
    },

    setImageClass: function(cn){
        this.imageClass = cn || this.imageClass;
        if (this.imageClass){
            mc.addClass(this.imageClass, this.button)
              .getStyle('background-image', this.button);

            if (mc.chain){
                this.getAlign();
                this.setPadding();
                this.setImageTitle();
            }
        }
    },

    setImageTitle: function(txt){
        mc.setAttr({title: txt || this.imageTitle || this.text || ''}, this.outside);
    },

    setWidth: function(wd){
        if (wd){
            mc.setWidth(wd, 'BP', this.outside);
        }
        mc.getWidth('BP', this.outside)
          .setWidth((mc.chain - 6), 'BP', this.center);
    },

    setOutsideWidth: function(){
        var nodes = mc.getChildNodes(false, this.outside).chain,
            i,
            len = nodes.length,
            vl = 0;

        for (i = 0; i < len; i++){
            vl += mc.getWidth(false, nodes[i]).chain;
        }
        mc.setWidth(vl, 'BP', this.outside);
    },

    focusEvent: function(e, tg, opts){
        this.focusInOut = true;
        this.ce.fireEvent('focus', e, tg, opts, this);
    },

    blurEvent: function(e, tg, opts){
        this.focusInOut = false;
        mc.removeClass(this.focusClass, this.outside);
        this.ce.fireEvent('blur', e, tg, opts, this);
    },

    mouseOverEvent: function(e, tg, opts){
        if (!this.traceMouseOver || this.disabled) {
            return;
        }

        mc.isDescendant(tg, this.outside);
        if (mc.chain){
            mc.addClass(this.overOutClass, this.outside);
            mc.widget.Event.documentOn(this, 'mouseover', this.documentMouseOver);

            this.traceMouseOver = false;
            this.ce.fireEvent('mouseover', e, tg, opts, this);
        }
    },

    mouseOutEvent: function(e, tg, opts){
        if (!this.traceMouseOver && !this.disabled) {
            if (!(mc.isDescendant(tg, this.outside).chain)){
                this.outsideBlur(e, tg, opts);
            }
        }
    },

    documentMouseOver: function(e, tg, opts){
        if (!this.traceMouseOver && !this.disabled) {
            if (mc.widget.Event.isOwnDocument(this, 'mouseover', opts)){
                this.mouseOutEvent(e, tg, opts);
            }
        }
    },

    outsideBlur: function(e, tg, opts){
        if (this.traceMouseOver || this.disabled) {
            return;
        }
        mc.removeClass(this.overOutClass, this.outside);
        mc.widget.Event.documentOff(this, 'mouseover');

        this.traceMouseOver = true;
        this.ce.fireEvent('mouseout', e, tg, opts, this);
    },

    mouseDownEvent: function(e, tg, opts){
        mc.addClass(this.downUpClass, this.outside);
        mc.widget.Event.documentOn(this, 'mouseup', this.mouseUpEvent);
        this.ce.fireEvent('mousedown', e, tg, opts, this);
    },

    mouseUpEvent: function(e, tg, opts){
        mc.removeClass(this.downUpClass, this.outside);
        mc.widget.Event.documentOff(this, 'mouseup', this.mouseUpEvent);
        this.ce.fireEvent('mouseup', e, tg, opts, this);
    },

    clickEvent: function(e, tg, opts){
        if (e.button != 0 || this.disabled) {
            return;
        }

        mc.removeClass(this.focusClass, this.outside);
        this.focusInOut = false;

        this.ce.fireEvent('click', this.buttonType, e, tg, opts, this);

        if (this.buttonClick) {
            if (!this.createData && !this.updateData && !this.getData && !this.resetData && !this.deleteData) {
                this.buttonClick.call(this.scope || this, e, tg, opts, this);
            }
        }
    },

    spaceControlEvent: function(e, tg, opts){
        this.clickEvent(e, tg, opts);
    },

    setOpenValue: function(){
    },

    setType: function(tp){
        this.buttonType = tp;
        mc.setAttr({type: tp}, this.button);
        this.ce.fireEvent('typechanged', tp, this.button, this);
    },

    getType: function(){
        return mc.getAttr(['type'], this.button, true).chain;
    },

    setButtonText: function(text){
        this.text = text;
        mc.setText(text, this.button);
        this.setWidth();
    },

    setButtonClick: function(method, scope){
        this.buttonClick = method;
        this.scope = scope;
    },

    getCenter: function() {
        return this.center;
    },

    remove: function(){
        this.removeEvents();
        mc.removeElement(this.outside);
        this.fireRemove();
    },

    setDisplay: function(show){
        mc.setDisplay(show, this.outside);
        this.ce.fireEvent('showButton', show, this.outside, this);
    }
});


mc.types.ButtonGroup = function(opts){
    mc.widget.Widget.setOptions(this, opts);
    if (this.showTo) {
        this.mainButtonGroup(this.showTo);
    }
};

mc.extend(mc.types.ButtonGroup, mc.types.GroupModel, {
    arrange: [1],
    buttonAlign: 'center',
    defaultCcode: 'button',
    paddingTop: '',
    space: '',

    ccode: 'buttongroup',
    alignClass: 'mc-btngroup-center',
    tdWidth: '',
    trNodes: '',

    mainButtonGroup: function(showTo){
        this.showTo = showTo || this.showTo;
        this.initGroup();
        this.mainGroupModel();

        this.checkOptions();
        this.createLineside()
        this.execComponent();
        this.fireOwnClose();
        return this;
    },

    initGroup: function(){
        this.tdWidth = [];
    },

    checkOptions: function(){
        if (!this.arrange){
            this.arrange = 1;
        }
        this.arrange = mc.toArray(this.arrange).chain;

        var total = mc.getTotal(this.arrange).chain,
            count = this.getTotalCount();

        if (count > total){
            mc.widget.Message.show('E1031', this.ccode, 'options.arrange', 'component.ccode.button');
        }
    },

    getTotalCount: function(){
        var count = 0;
        mc.eachArray(this.component, function(hash){
            if (hash.ccode == 'button'){
                count += 1;
            }
        })
        return count;
    },

    setMaxNumber: function(){
        var ag = this.arrange;
        if (ag.length == 1 && ag[0] == 1){
            ag[0] = this.ownGroup.length;
        }
        this.maxNumber = ag[0];

        if (this.arrange.length > 1){
            this.maxNumber = mc.collectMax(this.arrange).chain[0];
        }
    },

    isLinefeed: function(cmpt){
    },

    createLineside: function(){
        var tpl1 = '<table id="{0}" {1} border="0" cellpadding="0" cellspacing="0"><tbody>',
            tpl2 = '</tbody></table>';

        var map = [],
            tpl;

        map[0] = mc.id(false, this.prefix).chain;
        map[1] = this.buttonAlign == 'center' ? (' class=' + '"' + this.alignClass + '"') : '';

        tpl = tpl1 + this.createTrTd() + tpl2;
        mc.newTemplate(tpl).Template.apply(this.outside, 'beforeEnd', map);
    },

    createTrTd: function(){
        var tro = '<tr id="{0}">',
            trc = '</tr>',
            tdtpl = '<td id="{0}" class="{1}" style="{2}"></td">',
            i,
            j,
            k = 0,
            len = this.arrange.length,
            ag,
            wd,
            maptr = [],
            maptd = [],
            trs = [],
            tds;

        this.trNodes = [];
        for (i = 0; i < len; i++) {
            maptr[0] = mc.id(false, this.prefix).chain;
            this.trNodes[i] = mc.chain;

            ag = this.arrange[i];
            tds = [];

            for (j = 0; j < ag; j++){
                maptd[0] = this.objectID[k];
                maptd[1] = 'mc-button-one';

                wd = this.tdWidth[k];
                if (this.space && ((j + 1) < ag)){
                    wd += parseInt(this.space, 10);
                }
                maptd[2] = 'width:' + wd + 'px;';

                if (this.paddingTop){
                    maptd[2] += ' padding-top:' + this.paddingTop + 'px;';
                }
                tds[tds.length] = mc.newTemplate(tdtpl).Template._convert(maptd);
                k++;
            };

            trs[i] = mc.newTemplate(tro).Template._convert(maptr) + tds.join('') + trc;
        }
        return trs.join('');
    },

    execComponent: function(){
        var i,
            len = this.cacheComp.length,
            k = 0,
            cmpt;

        for (i = 0; i < len; i++){
            cmpt = this.cacheComp[i];
            this.component = this.cacheComp[i];

            if (cmpt.ccode == this.defaultCcode){
                cmpt['mc_parent_id'] = this.objectID[k++];

                if (!cmpt.id){
                    cmpt.id = mc.id(false, this.prefix).chain;
                }
                this.execOwnGroup(cmpt);
            }
        }
    },

    execOwnGroup: function(cmpt){
        mc.component.Component.isGroupExec(this, this.ccode, cmpt.mc_parent_id);
    },

    hideButton: function(btns, ids){
        mc.getChildNodes(false, this.trNodes[0])
          .eachArray(mc.chain, function(node, idx){
              btns[idx] ? mc.removeClass('mc-display-none', node) : mc.addClass('mc-display-none', node)
           }, this);
    }
});


mc.types.Radio = function(opts){
    mc.widget.Widget.setOptions(this, opts);
    if (this.showTo) {
        this.mainRadio(this.showTo);
    }
};

mc.extend(mc.types.Radio, mc.types.Type, {
    checked: false,
    defaultType: {tag: 'input', type: 'radio', id: '', autocomplete: 'off', tabIndex: "0"},
    labelClass: 'mc-check-label',
    labelStyle: '',

    outsideClass: '',
    outsideStyle: '',
    overOutClass: 'mc-check-over',
    prefix: 'mc_radio_',
    text: '',

    applyText: true,
    ccode: 'radio',
    createLabel: true,
    ownName: 'radio',
    _outsideClass: 'mc-check-outside',
    showFocusGrid: '',

    outside: '',
    label: '',

    mainRadio: function(showTo){
        this.showTo = showTo || this.showTo;

        this.setOutside();
        this.setId();

        this.mainType(this.outside);

        this.setCheckValue();
        this.setLabel();
        this.setEvents();

        mc.component.Component.isExec(this, 'radio', this.showTo);
        return this;
    },

    setOutside: function(){
        mc.createAppend('div', false, this.prefix, this.showTo)
          .setThis(this, 'outside')
          .setOwn(mc.chain)
          .addClass([this._outsideClass, this.outsideClass])
          .setStyle(this.outsideStyle)
          .setWH(this.width, this.height, 'BP')
          .setXY(this.leftX, this.topY);

        if (this.showFocusGrid){
            mc.setVisibility(false);
        }
    },

    setId: function(){
        this.defaultType.id = this.id || mc.id(false, this.prefix).chain;
    },

    cacheOpenValue: function(){
        this.openValue = this.checked;
    },

    setCheckValue: function(){
        this.addMember();
    },

    setLabel: function(){
        if (this.createLabel){
            mc.createAppend('label', false, this.prefix, this.outside)
              .setThis(this, 'label')
              .setOwn(mc.chain)
              .addClass(this.labelClass)
              .setAttr({'htmlFor': this.own.id})
              .setText(this.text, this.label);

            if (this.unselectable){
                mc.setUnselectable();
            }
        }
    },

    setEvents: function(){
        if (!this._setEvents){
            mc.types.Radio.superclass.setEvents.call(this);

            mc.widget.Event.overOut(this, this.outside, this.outside, this.overOutClass);
            this._setEvents = true;
        }
    },

    removeEvents: function(){
        mc.types.Radio.superclass.removeEvents.call(this);
        mc.widget.Event.overOutOff(this, this.outside);
    },

    addMember: function(){
        mc.component.Member.add(this.radio.id, this);

        if (this.checked){
            this.firstSet = true;
            this.setCheck(this.radio.id);
        }
    },

    setOpenValue: function(){
        this.own.checked = this.openValue;
    },

    getName: function(nm){
        return  mc.component.Member.getName('name', nm || this.name);
    },

    setCheck: function(el, forced) {
        var node = mc.get(el || this.radio).chain,
            id = node.id,
            objs,
            obj,
            i,
            len,
            checkObj = '';

        if (forced || mc.IE || this.firstSet){
            objs = this.getName();
            objs = mc.toArray(objs).chain;
            len = objs.length;

            for (i = 0; i < len; i++){
                obj = objs[i];
                if (obj.radio.id == id){
                    obj.radio.checked = true;
                    checkObj = obj;
                } else {
                    obj.radio.checked = '';
                }
            }
        }

        this.firstSet = false;
        this.ce.fireEvent('checked', checkObj || node, this);
    },

    resetRadio: function(){
        if (this.checked){
            this.setCheck(this.radio.id);
        }
    },

    getRadio: function() {
        return this.radio;
    },

    remove: function(){
        this.removeEvents();
        mc.removeElement(this.outside);
        this.fireRemove();
    },

    getValue: function(){
        return this.own.checked;
    },

    setForcedValue: function(value){
        this.own.checked = value || '';
    },

    showOutside: function(){
        mc.setVisibility(true, this.outside);
    },

    hideOutside: function(){
        mc.setVisibility(false, this.outside);
    }
});


mc.types.RadioGroup = function(opts){
    mc.widget.Widget.setOptions(this, opts);
    if (this.showTo) {
        this.mainRadioGroup(this.showTo);
    }
};

mc.extend(mc.types.RadioGroup, mc.types.GroupModel, {
    defaultCcode: 'radio',
    prefix: 'mc_radiogroup_',

    ccode: 'radiogroup',
    radioCount: 0,
    radioList: '',
    radioIndex: '',

    outside: '',
    lineside: '',

    mainRadioGroup: function(showTo){
        this.showTo = showTo || this.showTo;
        this.mainGroupModel();
        this.setName();
        this.setEvents();

        this.setRadioList();
        this.execComponent();
        this.fireOwnClose();
        return this;
    },

    setName: function(){
        var optName = mc.id(false, this.prefix).chain,
            ogp = this.ownGroup,
            len = ogp.length,
            i;

        for (i = 0; i < len; i++){
            ogp[i].name = optName;
        }
    },

    setEvents: function(){
        if (!this._setEvents){
            mc.on([this.outside, 'click', this.outsideClick, this],
                  [this.outside, 'keyup', this.outsideKeyup, this]);
            this._setEvents = true;
        }
    },

    removeEvents: function(){
        mc.types.RadioGroup.superclass.removeEvents.call(this);

        mc.off([this.outside, 'click', this.outsideClick, this],
               [this.outside, 'keyup', this.outsideKeyup, this]);

        this._setEvents = false;
    },

    createLineside: function(){
        mc.createAppend('div', false, this.prefix, this.outside)
          .setThis(this, 'lineside')
          .addClass([this._linesideClass, this.linesideClass], this.lineside)
          .setStyle(this.linesideStyle, this.lineside);
    },

    createMiddle: function(){
        mc.createAppend('div', false, this.prefix, this.lineside)
          .setThis(this, 'middle')
          .addClass([this._middleClass, this.middleClass], this.middle)
          .setStyle(this.middleStyle, this.middle);
    },

    createInside: function(){
        mc.createAppend('div', false, this.prefix, this.middle)
          .setThis(this, 'inside')
          .addClass([this._insideClass, this.insideClass], this.inside)
          .setStyle(this.insideStyle, this.inside);
    },

    labelExec: function(check){
        if (!this.lineside){
            this.createLineside();
        }
        this.middle = '';

        if (check){
            this.component = this.label;
            this.component.text = '';
            this.component.delimiter = '';
        }
        mc.component.Component.isGroupExec(this, this.ccode, this.lineside);
    },

    execOwnGroup: function(){
        if (this.beforeCcode == 'linefeed'){
            var saveComponent = this.component;
            this.labelExec(true);
            this.component = saveComponent;
        }

        if (!this.lineside) {
            this.createLineside();
        }
        if (!this.middle) {
            this.createMiddle();
        }

        this.createInside();
        mc.component.Component.isGroupExec(this, this.ccode, this.inside);
    },

    execComponent: function(){
        var i,
            len = this.cacheComp.length,
            cmpt;

        for (i = 0; i < len; i++){
            cmpt = this.cacheComp[i];
            this.component = this.cacheComp[i];

            if (cmpt.ccode == 'label'){
                this.labelExec();
            } else if (cmpt.ccode == this.defaultCcode) {
                this.execOwnGroup();
            } else {
                mc.component.Component.isGroupExec(this, this.ccode, this.outside);
            }

            this.beforeCcode = cmpt.ccode;
            if (this.isLinefeed(cmpt) && ((i + 1) != len)){
                this.createLineside();
            }
        }
    },

    setRadioList: function(){
        this.radioList = {};
        this.radioIndex = [];
        this.radioCount = 0;

        var cmpts = this.cacheComp,
            len = cmpts.length,
            i,
            cmpt,
            list,
            j = 0;

        for (i = 0; i < len; i++){
            cmpt = cmpts[i];
            if (cmpt.ccode == 'radio'){
                this.radioList[cmpt.id] = {};
                list = this.radioList[cmpt.id];

                list['index'] = j;
                this.radioIndex[j] = cmpt.id;
                this.radioCount = j;
                j++;
            }
        }
    },

    outsideClick: function(e, tg){
        var mbr;
        if (mbr = mc.component.Instance.get(tg.id)){
            if (mbr.setCheck){
                mbr.setCheck(tg, true);
                if (mc.IE){
                    mc.focus(tg);
                }
                this.ce.fireEvent('click', e, tg, this);
            }
        }
    },

    outsideKeyup: function(e, tg, opts, that){
        var ek = e.keyCode,
            id = tg.id;

        if (ek > 40 || (ek < 37 && ek != 32 || !id || !this.radioList[id])){
            return;
        }

        var ek = e.keyCode,
            list = this.radioList[id],
            index = list.index,
            dirIndex,
            dirId,
            ix,
            mbr;

        if (mc.IE){
            if (ek == 37 || ek == 38){
                ix = index - 1;
                dirIndex = ix < 0 ? this.radioCount : ix;
            } else if (ek == 39 || ek == 40){
                ix = index + 1;
                dirIndex = ix > this.radioCount ? 0 : ix;
            } else {
                dirIndex = index;
            }
        } else {
            dirIndex = index;
        }

        dirId = this.radioIndex[dirIndex];
        if (mbr = mc.component.Instance.get(dirId)){
            mbr.setCheck(dirId, true);
            mc.focus(dirId);
            this.ce.fireEvent('keyup', e, mc.chain, this);
        }
    }
});


mc.types.CheckBox = function(opts){
    mc.widget.Widget.setOptions(this, opts);
    if (this.showTo) {
        this.mainCheckBox(this.showTo);
    }
};

mc.extend(mc.types.CheckBox, mc.types.Radio, {
    defaultType: {tag: 'input', type: 'checkbox', id: '', autocomplete: 'off'},
    prefix: 'mc_checkbox_',

    ccode: 'checkbox',
    ownName: 'checkBox',

    mainCheckBox: function(showTo){
        this.showTo = showTo || this.showTo;
        this.mainRadio(this.showTo);
        this.setEvents();

        mc.component.Component.isExec(this, 'checkbox', this.showTo);
        return this;
    },

    setCheckValue: function(){
        this.setCheck(this.checked);
    },

    setEvents: function(){
        if (!this._setEvents){
            mc.types.CheckBox.superclass.setEvents.call(this);
            mc.onOwn(['click', this.clickEvent, this]);
            this._setEvents = true;
        }
    },

    removeEvents: function(){
        mc.types.CheckBox.superclass.removeEvents.call(this);
    },

    clickEvent: function(e, tg){
        this.ce.fireEvent('checked', e, tg, this);
    },

    setCheck: function(st){
        this.checkBox.checked = st || '';
    },

    getValue: function(){
        return this.checkBox.checked;
    },

    setForcedValue: function(vl){
        this.setCheck(vl);
    },

    toggleCheck : function(st){
        this.checkBox.checked = this.checkBox.checked ? '' : true;
    },

    getCheckBox: function() {
        return this.checkBox;
    },

    getLabel: function() {
        return this.label;
    }
});


mc.types.CheckBoxGroup = function(opts){
    mc.widget.Widget.setOptions(this, opts);
    if (this.showTo) {
        this.mainCheckBoxGroup(this.showTo);
    }
};

mc.extend(mc.types.CheckBoxGroup, mc.types.RadioGroup, {
    defaultCcode: 'checkbox',
    mustCheck: false,
    mustCheckMsg: {title: '필수 선택', msg: '하나 이상을 선택해 주세요'},
    prefix: 'mc_boxgroup_',

    boxNodes: '',
    ccode: 'checkboxgroup',
    checkForm: 'checkNodes',

    mainCheckBoxGroup: function(showTo){
        this.showTo = showTo || this.showTo;

        this.mainRadioGroup();
        this.getFilters();

        return this;
    },

    setName: function(){
    },

    getFilters: function(){
        var objs = mc.component.Instance.getFilters({ccode: 'checkbox'});
        this.boxNodes = [];
        var nds = this.boxNodes;

        mc.eachArray(objs, function(obj){
            if (mc.isContains(this.ownIdLsit, obj.id).chain){
                box = obj['checkBox'];
                nds[nds.length] = box;
            }
        }, this)
    },

    outsideClick: function(e, tg){
        var chk,
            rst;

        if (this.mustCheck){
            chk = mc.get(tg).chain.checked;
            chk ? this.hideError() : (this.isChecked() ? this.hideError() : this.showMessage(tg));
        }

        this.ce.fireEvent('click', e, tg, this);
    },

    checkNodes: function(){
        this.errorNode = '';
        if (this.mustCheck){
            if (this.isChecked()) {
                this.hideError();
            } else {
                this.errorNode = this.boxNodes[this.boxNodes.length - 1];
                this.showMessage(this.errorNode);
            }
        }
    },

    isChecked: function(){
        var len = this.boxNodes.length,
            i,
            node;

        for (i = 0; i < len; i++){
            node = this.boxNodes[i];
            if (node.checked == true){
                return true;
            }
        }
        return false;
    },

    showMessage: function(el){
        el = el || this.errorNode;
        this.valueError = true;
        var msg = this.mustCheckMsg || {};
        mc.guide.GuideType.show(el, msg.title, msg.msg);
        this.ce.fireEvent('mustCheck', msg, el, this);
    },

    hideError : function(){
        mc.guide.GuideType.hide();
        this.valueError = false;
    },

    getNodes: function(){
        return this.boxNodes;
    }
});


mc.types.SelectOption = function(opts){
    mc.widget.Widget.setOptions(this, opts);
    if (this.showTo) {
        this.mainSelectOption(this.showTo);
    }
};

mc.extend(mc.types.SelectOption, mc.types.TextType, {
    defaultType: {tag: 'select'},
    emptyMsg: {title: '필수 선택', msg: '필수 선택 항목입니다.'},

    failureMessage: {
        title: '통신 실패',
        msg: '통신 장애로 인해 서버에서 데이터를 수신하지 못했습니다.'
    },

    height: '',
    htmlSelect: '',
    mapAttr: false,
    metaData: '',
    multiple: '',

    nullFirst: false,
    outsideClass: '',
    outsideStyle: '',
    prefix: 'mc_selectoption_',
    scriptSelect: '',

    selectClass: '',
    selectStyle: '',
    size: '',
    timeoutMessage: {
        title: '통신 실패',
        msg: '통신 시간 경과로 인해 서버에서 데이터를 수신하지 못했습니다.'
    },
    width: 70,

    ccode: 'selectoption',
    checkForm: 'checkSelect',
    createdMeta: '',
    gridEntry: '',
    ownName: 'selectType',

    openForm: 'resetValue',
    valueError: false,
    outside: '',
    own: '',
    selectNode: '',

    htmlFormat: '',
    scriptFormat: '',

    mainSelectOption: function(showTo){
        this.showTo = showTo || this.showTo;
        this.checkOptions();
        this.createOutside();
        this.mainType(this.outside);

        this.setSelectType();
        this.setHtmlSelect();
        this.setScriptSelect();
        this.getClient();
        this.setEvents();

        mc.component.Component.isExec(this, 'selectoption', this.showTo);
        return this;
    },

    checkOptions: function(){
        if (!this.metaData && !this.htmlSelect && !this.scriptSelect) {
            mc.widget.Message.show('E1010', this.ccode, 'metaData');
        }
    },

    createOutside: function(){
        mc.createAppend('div', false, this.prefix, this.showTo)
          .setThis(this, 'outside')
          .setOwn(mc.chain)
          .addClass(this.outsideClass)
          .setStyle(this.outsideStyle)
          .setWidth(this.width, 'BP')
          .setXY(this.leftX, this.topY, 'BP');
    },

    setSelectType: function(){
        mc.setHeight(this.height, 'BP', this.selectType)
          .setChildWidth(this.selectType, this.outside);

        if (this.size){
            mc.setAttr({size: this.size}, this.selectType);
        }
        if (this.multiple){
            mc.setAttr({multiple: this.multiple}, this.selectType);
        }
    },

    setHtmlSelect: function(){
        if (!this.htmlSelect){
            return;
        }
        mc.get(this.htmlSelect)
          .setThis(this, 'selectNode')
          .setDisplay(false, this.selectNode);

        if (!this.selectNode){
            mc.widget.Message.show('E1020', this.ccode, 'html 파일', 'htmlSelect.#id');
            return;
        }
        this.htmlFormat = new mc.data.HtmlFormat([
            {field: 'id'},
            {field: 'value'},
            {field: 'text'},
            {field: 'selected'}
        ]);

        this.metaData = new mc.data.MetaData({
            client : this.htmlSelect,
            dataFormat: this.htmlFormat
        });
    },

    setScriptSelect: function(){
        if (!this.scriptSelect){
            return;
        }
        this.scriptFormat = new mc.data.JsonFormat('', [
            {field: 'id'},
            {field: 'value'},
            {field: 'text'},
            {field: 'selected'}]
        );

        this.metaData = new mc.data.MetaData({
            client : this.scriptSelect,
            dataFormat: this.scriptFormat
        });
    },

    getClient: function(){
        if (this.metaData && this.metaData.client && !this.gridEntry){
            this.getClientData();
        }
    },

    getClientData: function(){
        this.createdMeta = true;
        this.metaData.mainMetaData();
        this.createNodeList();
    },

    setEvents: function(){
        if (!this._setEvents){
            mc.types.SelectOption.superclass.setEvents.call(this);
            mc.on([this.outside, 'click', this.clickEvent, this]);
            this._setEvents = true;
        }
    },

    removeEvents: function(){
        if (this._setEvents) {
            mc.types.SelectOption.superclass.removeEvents.call(this);
            mc.off([this.outside, 'click', this.outsideClick, this]);
        }
        this._setEvents = false;
    },

    focusEvent: function(e, tg, opts){
        if (this.createdMeta){
            this.valueError ? this.showError() : this.hideError();
        } else {
            this.hideError();
            if (this.metaData.server) {
                this.getServerData();
            }else if (this.gridentry) {
                this.getClientData();
            }
        }
        this.ce.fireEvent('focus', e, tg, opts, this);
    },

    keyUpEvent: function(e, tg, opts){
        if (!this.errorHttp){
            this.hideError();
            this.checkSelect(e, tg, opts);
            if (!this.valueError){
                this.ce.fireEvent('keyup', e, tg, opts, this);
            }
        }
    },

    blurEvent: function(e, tg, opts){
        this.focusInOut = false;
        this.checkSelect();
        this.ce.fireEvent('blur', e, tg, opts, this);
    },

    clickEvent: function(e, tg, opts){
        this.ce.fireEvent('click', e, tg, opts, this, this.own);
    },

    getServerData: function(){
        if (this.protectClick){
            return;
        }
        this.protectClick = true;
        this.createdMeta = true;

        var meta = this.metaData;
        meta.componentMethod = this.callbackHttp;
        meta.componentScope = this;

        var server = meta.server || {};
        server.metaFailure = this.metaFailure;
        server.metaTimeout = this.metaTimeout;
        server.metaFailScope = this;
        meta.mainMetaData();
    },

    callbackHttp: function(trans){
        this.createNodeList();
        this.protectClick = false;
        this.errorHttp = false;
        this.ce.fireEvent('receiveData', trans, this);
    },

    createNodeList: function(){
        var detail = this.metaData.detail || [],
            dataCount = detail.length,
            i,
            map,
            data;

        if (this.nullFirst){
            mc.addSelect(null, {}, this.selectType);
        }
        for (i = 0; i < dataCount; i++){
            data = detail[i];
            map = {};
            map.id = data.id || (mc.id(false, this.prefix).chain + '_' + data.mc_row_index);
            map.value = data.value || '';
            map.text = data.text || '';

            if (data.selected){
                map.selected = data.selected;
            }
            mc.addSelect(null, map, this.selectType);
        }
    },

    metaFailure: function(trans){
        this.setHttpError(this.failureMessage);
        this.ce.fireEvent('failure', trans, this);
    },

    metaTimeout: function(trans){
        this.setHttpError(this.timeoutMessage);
        this.ce.fireEvent('timeout', trans, this);
    },

    setHttpError: function(msg){
        this.createdMeta = false;
        this.protectClick = false;
        this.errorHttp = true;
        this.showError(msg);
    },

    cacheOpenValue: function(){
    },

    getValue: function(type){
        return mc.getSelected(type, this.own).chain;
    },

    checkSelect: function(){
        this.valueError = false;
        if (this.autoCheck && this.emptyCheck) {
            var rst = mc.getSelected('selected', this.selectType, 'first').chain;
            if (rst.length == 0 || (this.nullFirst && rst[0] == 0)){
                return this.showError(this.emptyMsg);
            }
        }
    },

    setOpenValue: function(){
        mc.removeChild(this.selectType);
        this.createNodeList();
    },

    setForcedValue: function(value){
        var nodes = this.own.options;
        var opts = mc.getOpts(this.own).chain,
            len = opts.length,
            opt,
            i;

        for (i = 0; i < len; i++){
            opt = opts[i];
            if ((this.mapAttr && opt.value == value) || (!this.mapAttr && opt.text == value)){
                nodes[i].selected = true;
                break;
            }  else {
                nodes[i].selected = false;
            }
        }
    }
});


mc.types.LabelSelect = function(opts){
    mc.widget.Widget.setOptions(this, opts);
    if (this.showTo){
        this.mainLabelSelect(this.showTo);
    }
};

mc.extend(mc.types.LabelSelect, mc.types.SelectOption, {
    prefix: 'mc_labelselect_',

    _ownName: 'labelSelect',
    ccode: 'labelselect',

    labelNew: '',

    mainLabelSelect: function(showTo){
        this.showTo = showTo || this.showTo;
        this.newLabel();
        this.mainSelectOption(this.labelInside);
        this.setOutsideWidth();
        this.setEvents();

        mc.widget.Widget.cacheShowTo(this, false);
        mc.component.Component.isExec(this, 'labelselect', this.showTo);
        return this;
    },

    newLabel: function(){
        if (!this.labelNew){
            this.labelNew = new mc.types.Label(this.label);
        }
        var nw = this.labelNew;
        nw.mainLabel(this.showTo);
        nw.setLabelInside();
        this.labelInside = nw.labelInside;
        mc.widget.Widget.cacheShowTo(this, true);
    },

    setOutsideWidth: function(){
        mc.getWidth(false, this.outside);
        this.labelNew.setOutsideWidth(mc.chain);
    },

    setEvents: function(){
        if (!this._setEvents){
            mc.types.LabelSelect.superclass.setEvents.call(this);
            this._setEvents = true;
        }
    },

    removeEvents: function(){
        mc.types.LabelSelect.superclass.removeEvents.call(this);
    },

    remove: function(){
        this.removeEvents();
        mc.removeElement(this.labelNew.outside);
    },

    getLabelNew: function(){
        return this.labelNew;
    }
});


mc.types.FieldSet = function(opts){
    mc.widget.Widget.setOptions(this, opts);
    if (this.showTo) {
        this.mainFieldSet(this.showTo);
    }
};

mc.types.FieldSet.prototype = {
    fieldsetClass: 'mc-fieldset',
    fieldsetStyle: '',
    legendAttr: '',
    legendClass: '',
    legendStyle: '',

    legendText: '',
    prefix: 'mc_fieldset_',
    useLegend: true,
    width: 300,

    ccode: 'fieldset',

    fieldSet: '',
    legend: '',

    mainFieldSet: function(showTo){
        this.showTo = showTo || this.showTo;

        this.setFieldSet();
        this.setLegend();

        mc.component.Component.isExec(this, 'fieldset', this.fieldSet);
        return this;
    },

    setFieldSet: function(){
        mc.createAppend('fieldset', this.id, this.prefix, this.showTo)
          .setThis(this, 'fieldSet')
          .setOwn(mc.chain)
          .addClass(this.fieldsetClass)
          .setStyle(this.fieldsetStyle)
          .setWH(this.width, this.height, 'BP')
          .setXY(this.leftX, this.topY);

        mc.widget.Widget.applyAttr(this);
    },

    setLegend: function(){
        if (this.useLegend){
            mc.createAppend('legend', false, this.prefix, this.fieldSet)
              .setThis(this, 'legend')
              .setOwn(mc.chain)
              .addClass(this.legendClass)
              .setStyle(this.legendStyle)
              .setAttr(this.legendAttr)
              .setText(this.legendText);
        }
    },

    getFieldSet: function(){
        return this.fieldSet;
    },

    getLegend: function(){
        return this.legend;
    }
};


mc.types.TypeGroup = function(opts){
    mc.widget.Widget.setOptions(this, opts);
    if (this.showTo) {
        this.mainTypeGroup(this.showTo);
    }
};

mc.types.TypeGroup.prototype = {
    defaultCcode: 'labeltext',
    insideClass: '',
    insideStyle: '',
    middleClass: '',
    middleStyle: '',

    outsideClass: '',
    outsideStyle: '',
    prefix: 'mc_tggroup_',

    ccode: 'typegroup',
    _insideClass: 'mc-tg-inside',
    _middleClass: 'mc-tg-middle',
    _outsideClass: 'mc-tg-outside',

    tgOutside: '',
    tgMiddle: '',
    tgInside: '',

    mainTypeGroup: function(showTo){
        this.showTo = showTo || this.showTo;
        this.createOutside();
        this.createMiddle();

        mc.component.Component.isExec(this, 'typegroup', this.showTo || this.tgInside);
        return this;
    },

    createOutside: function(){
        mc.createAppend('div', this.id, this.prefix, this.showTo)
          .setThis(this, 'tgOutside')
          .setOwn(mc.chain)
          .addClass([this._outsideClass, this.outsideClass])
          .setStyle(this.outsideStyle)
          .setWidth(this.width, false);
    },

    createMiddle: function(){
        mc.createAppend('div', false, this.prefix, this.tgOutside)
          .setThis(this, 'tgMiddle')
          .setOwn(mc.chain)
          .addClass([this._middleClass, this.middleClass])
          .setStyle(this.middleStyle);
    },

    createInside: function(){
        mc.createAppend('div', false, this.prefix, this.tgMiddle)
          .setThis(this, 'tgInside')
          .setOwn(mc.chain)
          .addClass([this._insideClass, this.insideClass])
          .setStyle(this.insideStyle)
          .setStyle({width: 'auto'});
    }
};


mc.types.LineFeed = function(opts){
    if (opts.linefeed &&  opts.linefeed != 'boolean'){
        opts['height'] = opts.linefeed;
        delete opts.linefeed;
    }
    mc.widget.Widget.allocate(this, opts);
    if (this.showTo) {
        this.mainLineFeed(this.showTo);
    }
};

mc.types.LineFeed.prototype = {
    className: '',
    height: '',
    linefeedClass: 'mc-linefeed',

    prefix: 'mc_lf_',
    style: '',
    width: '',

    ccode: 'linefeed',
    ownName: 'lineFeed',

    mainLineFeed: function(showTo){
        this.showTo = showTo || this.showTo;
        this.createLF();
        mc.component.Component.isExec(this, 'linefeed', this.showTo);
        return this;
    },

    createLF: function(){
        mc.appendEnd(document.createElement('div'), this.showTo)
          .setThis(this, 'own')
          .addClass([this.className, this.linefeedClass], this.own)
          .setStyle(this.style, this.own)
          .setWH(this.width, this.height, 'BP', this.own);
    }
};


mc.types.PatternExp = function(){
    return {
        alphaExp: /^[a-zA-Z_]+$/,
        alpha: function(vl){
            return this.alphaExp.test(vl);
        },
        alphaMsg: '영문자 이외의 값이 존재합니다.',

        numericAlpha: function(vl){
            return mc.numericAlphaExp.test(vl);
        },
        numericAlphaMsg: '영문자와 숫자 이외의 값이 존재합니다.',

        emailExp: /^[\w]([-_\.]?[\w])*@[\w]([-_\.]?[\w])*\.[a-zA-Z]{2,3}$/i,
        email: function(vl){
            return this.emailExp.test(vl);
        },
        emailMsg: 'E-Mail 형식에 맞지 않습니다.',

        urlExp: /((http|ftp|https):\/\/[\w\-_]+(\.[\w\-_]+)+([\w\.\\\/\?\-,~@#%^&=+:]*[\w\\\/\?\-~@#%^&=+])?)/i,
        url: function(vl){
            return this.urlExp.test(vl);
        },
        urlMsg: 'url 형식에 맞지 않습니다.'
    }
}();


//-------------------
//@package: mc.combo
//-------------------

mc.combo.NodeList = function(opts){
    mc.widget.Widget.setOptions(this, opts);
    if (this.showTo) {
        this.mainNodeList(this.showTo);
    }
};

mc.extend(mc.combo.NodeList, mc.data.MetaFilter, {
    eventNode: '',
    insideClass: '',
    insideStyle: '',
    nodeTemplate: '<div id="{id}" class="{className}" {style}>{data}</div>',
    outsideClass: '',
    outsideStyle: '',

    overClass: '',
    prefix: 'mc_nodelist_',
    showFields: '',
    width: 300,
    wrapClass: '',
    wrapStyle: '',
    wrapTemplate: '<div id="{wrapID}" class="{wrapClass}" {wrapStyle}>',

    ccode: 'nodelist',
    detailData: '',
    fieldAttr: [],
    showNodes: '',

    inside: '',
    outside: '',
    templateNew: '',
    templateWrap: '',

    mainNodeList: function(showTo){
        this.showTo = showTo || this.showTo;
        this.mainMetaFilter();
        this.createOutside();
        this.createInside();

        if (this.existData && this.setEventNode()){
            this.setShowNodes();
            this.newTemplate();
            this.createNodeList();
            this.setEvents();
        }
        mc.component.Component.isExec(this, 'nodelist', this.showTo);
        return this;
    },

    createOutside: function(){
        if (!this.outside){
            mc.widget.Widget.setOutside(this, 'nodelist');
        }
        if (this.ccode == 'nodelist'){
            mc.setStyle({overflow: 'auto'});
        }
        this.hideOutside();
    },

    hideOutside: function(){
    },

    createInside: function(){
        if (!this.inside){
            mc.createAppend('div', false, this.prefix, this.outside)
              .setThis(this, 'inside')
              .addClass(this.insideClass, this.insdie)
              .setStyle(this.insideStyle, this.inside)
              .setChildWidth(this.insdie, this.outside);
        }
    },

    setEventNode: function(){
        if (!this.showFields){
            mc.widget.Message.show('E1010', this.ccode, 'showFields');
            return false;
        }
        this.showFields = mc.toArray(this.showFields).chain;

        if (!this.eventNode){
            this.eventNode = this.inside;
        }
        this.nameFormat = mc.widget.NameFormat;
        return true;
    },

    setShowNodes: function(){
        if (!this.showNodes || this.showNodes.length == 0){
            this.showNodes = [];
            var len = this.showFields.length,
                i,
                field;

            for (i = 0; i < len; i++){
                field = this.showFields[i];
                this.showNodes[i] = field['field'];
            }
        }
    },

    newTemplate: function(){
        if (!this.templateNew){
            mc.widget.Widget.newTemplate(this, 'templateNew', this.nodeTemplate);
        }
        if (this.getFieldCount() > 1){
            mc.widget.Widget.newTemplate(this, 'templateWrap', this.wrapTemplate);
        }
    },

    createNodeList: function(){
        if (!this.inside){
            return;
        }
        this.inside.innerHTML = '';

        var fieldCount = this.getFieldCount(),
            detail = this.detailData,
            dataCount = detail.length,
            prefix = mc.id(false, this.prefix).chain + '_',
            i,
            data,
            wrap,
            nodes,
            rows = [];

        this.setAttribute();
        for (i = 0; i < dataCount; i++){
            data = detail[i];
            this.setNodePrefix(data.mc_row_index, prefix);
            nodes = this.createNodes(data);
            wrap = fieldCount > 1 ? this.setWrapper() : '';
            rows[i] = wrap ? (wrap + nodes + '</div>') : nodes;
        }

        this.inside.innerHTML = rows.join('');
        this.ce.fireEvent('renderData', this);
    },

    setNodePrefix: function(index, prefix){
        this.nodePrefix = prefix + index;
    },

    setWrapper: function(){
        var map = {};
        map.wrapID = this.nodePrefix;

        var cls = 'mc-nodelist-wrap ';
        cls += this.suggestField ? 'mc-suggest-node' : 'mc-nodelist-free';
        if (this.wrapClass){
            cls += (' ' + this.wrapClass);
        }
        map.wrapClass = cls;

        map.wrapStyle = this.wrapStyle ? ('style=' + '"' + this.wrapStyle + '"') : '';
        return this.templateWrap._convert(map);
    },

    createNodes: function(data){
        var fieldCount = this.getFieldCount(),
            attr = this.fieldAttr,
            map,
            i,
            nodes = [];

        for (i = 0; i < fieldCount; i++){
            map = attr[i];
            map.id = fieldCount > 1 ? (this.nodePrefix + '_' + i) : this.nodePrefix;
            map.data = data[this.showNodes[i]];
            nodes[i] = this.templateNew._convert(map);
        }
        return nodes.join('');
    },

    setAttribute: function(){
        this.fieldAttr = [];
        var fieldCount = this.getFieldCount(),
            attr = this.fieldAttr,
            map,
            i,
            vl,
            wd,
            wdpx = '',
            stl,
            styl;

        for (i = 0; i < fieldCount; i++){
            attr[i] = {};
            map = attr[i];
            map['className'] = fieldCount > 1 ? 'mc-nodelist-node ' : 'mc-suggest-node';
            if (vl = this.getFieldValue(i, 'className')){
                map.className += vl;
            }
            if (wd = this.getFieldValue(i, 'width')){
                wdpx = 'width:' + wd + 'px;';
            }
            stl = this.getFieldValue(i, 'style');
            styl = stl ? ('style=' + '"' + stl + wdpx + '"') : (wdpx ? 'style=' + '"' + wdpx + '"' : '');
            map.style = styl ? styl : '';
        }
    },

    setEvents: function(){
        if (this.combo && this.suggestBox){
            this.eventNode = this.suggestBox;
        }
        if (!this._setEvents && this.eventNode){
            mc.setOwn(this.eventNode);
            mc.onOwn(['click', this.clickEvent, this, {bubble: true}],
                     ['mouseover', this.mouseoverEvent, this, {bubble: true}],
                     ['mouseout', this.mouseoutEvent, this]);

            this._setEvents = true;
        }
    },

    removeEvents: function(){
        if (this._setEvents && this.eventNode){
            mc.setOwn(this.eventNode);
            mc.offOwn(['click', this.clickEvent, this],
                      ['mouseover', this.mouseoverEvent, this],
                      ['mouseout', this.mouseoutEvent, this]);
        }

        this.ce.clearEvents();
        this._setEvents = false;
    },

    clickEvent: function(e, tg){
        this.ce.fireEvent('click', e, tg, this);
    },

    mouseoverEvent: function(e, tg){
        this.ce.fireEvent('mouseover', e, tg, this);
    },

    mouseoutEvent: function(e, tg){
        this.ce.fireEvent('mouseout', e, tg, this);
    },

    getFieldCount: function(){
        return this.showNodes ? this.showNodes.length : 0;
    },

    getFieldValue: function(index, pty){
        var fd = this.showFields[index];
        return fd[pty] || '';
    },

    getFieldTotal: function(pty){
        var count = this.getFieldCount(),
            i,
            total = 0,
            vl;

        for (i = 0; i < count; i++){
            if (vl = this.getFieldValue(i, pty)){
                total += vl;
            };
        }
        return total;
    },

    getOutside: function(){
        return this.outside;
    },

    getInside: function(){
        return this.inside;
    },

    getNodes: function(){
        return mc.getChildNodes(false, this.inside).chain;
    },

    getNodeCount: function(){
        return this.inside.childNodes.length;
    },

    getChildNodes: function(index){
        var parents = this.getNodes();
        if (parents.length == 0){
            return false;
        }
        var len = parents.length,
            i,
            nodes = [];

        for (i = 0; i < len; i++){
            nodes[i] = document.getElementById(parents[i].id + '_' + index);
        }
        return nodes;
    },

    getTextNodes: function(index){
        return this.getFieldCount() == 1 ? this.getNodes() : this.getChildNodes(index);
    },

    getIndexNode: function(ix){
        var nodes = this.getNodes();
        if (nodes){
            return nodes[ix || 0];
        }
    }
});


mc.combo.Suggest = function(opts){
    mc.widget.Widget.setOptions(this, opts);
    if (this.showTo) {
        this.mainSuggest(this.showTo);
    }
};

mc.extend(mc.combo.Suggest, mc.combo.NodeList, {
    maxNodes: 7,
    nodeOverClass: 'mc-combo-over',
    parentBox: '',
    prefix: 'mc_suggest_',
    suggestClass: 'mc-combo-box',

    suggestField: '',
    suggestOutsideClass: 'mc-combo-outside',
    ccode: 'suggest',
    choiceNode: null,
    choiceSeq: 0,

    combo: '',
    keyDownUp: '',
    nodeClass: 'mc-suggest-node',
    nodeIndex: '',
    nodeStyle: '',

    suggestPrefix: '',
    suggestList: '',
    targetIndex: '',
    textList: [],
    suggestOutside: '',
    suggestBox: '',

    mainSuggest: function(showTo){
        this.showTo = showTo || this.showTo;
        this.createSuggestOutside();
        this.createSuggestBox();

        this.mainNodeList(this.showTo);
        this.setTargetIndex();
        this.setEvents();

        mc.component.Component.isExec(this, 'suggest', this.showTo);
        return this;
    },

    createSuggestOutside: function(){
        if (this.suggestOutside){
            return;
        };
        mc.widget.Widget.setZIndex(this);
        mc.getBody()
          .createAppend('div', false, this.prefix, mc.chain)
          .setThis(this, 'suggestOutside')
          .setOwn(mc.chain)
          .addClass(this.suggestOutsideClass)
          .setPos('absolute')
          .setVisibility(false)
          .setStyle({'z-index': this.zindex});

        var combo = this.combo;
        if (combo.fitWidth){
            mc.getWHXY('BP', combo.outside)
              .setXY(mc.chain[2], mc.chain[1] + mc.chain[3])
              .setWidth(mc.getWidth('BP', combo.outside).chain, 'BP');
        } else {
            mc.setWidth(this.getFieldTotal('width') + 25, 'BP');
        }
    },

    createSuggestBox: function(){
        if (!this.suggestBox){
            mc.createAppend('div', false, this.prefix, this.suggestOutside)
              .setThis(this, 'suggestBox')
              .setOwn(mc.chain)
              .addClass(this.suggestClass)
              .getWidth('BP', this.suggestOutside)
              .setWidth(mc.chain)
              .setOverflow('auto');
        }
        this.suggestPrefix = this.prefix + 's_';
    },

    setTargetIndex: function(){
        if (!this.suggestField && this.showNodes.length == 1){
            this.suggestField = this.showNodes[0];
        }
        mc.indexOfArray(this.showNodes, this.suggestField)
          .setThis(this, 'targetIndex');

        if (this.targetIndex < 0){
            mc.widget.Message.show('E1020', this.ccode, 'suggestField', 'showFields');
        }
    },

    setChoiceList: function(value){
        if (!(this.setSuggestList()) || !this.suggestBox){
            return;
        };
        var el = this.suggestBox;
        el.innerHTML = '';

        this.choiceList = [];
        var nodes = this.getNodes(),
            len = nodes.length,
            i,
            j = 0,
            nd,
            list = [],
            count = this.getFieldCount(),
            vlen = value ? value.length : 0;

        for (i = 0; i < len; i++) {
            if (vlen != 0 && value != this.textList[i].substring(0, vlen)) {
                continue;
            }
            nd = nodes[i];
            nd.nodeIndex = i;
            nd.choiceSeq = j;
            el.appendChild(nd);
            list[j] = nd;
            j += 1;
        }
        this.choiceCount = j;
        this.choiceList = list || [];
    },

    setSuggestList: function(){
        this.createNodeList();
        this.textList = [];

        var idx = this.getTargetIndex();
        if (!idx && idx != 0){
            return false;
        }
        var nodes = this.getTextNodes(idx) || [];
        var len = nodes.length,
            i,
            nd;

        for (i = 0; i < len; i++){
            nd = nodes[i];
            if (nd.nodeType == 1) {
                this.textList[i] = mc.getText(nd).chain;
            };
        }
        return true;
    },

    hideOutside: function(){
        mc.setDisplay(false, this.getOutside());
    },

    setEvents: function(){
        if (!this._setEvents && this.suggestBox){
            mc.combo.Suggest.superclass.setEvents.call(this);
            mc.on(this.suggestBox, 'mousemove', this.mousemoveEvent, this);
            this._setEvents = true;
        }
    },

    removeEvents: function(){
        if (this._setEvents && this.suggestBox) {
            mc.combo.Suggest.superclass.removeEvents.call(this);
            mc.off(this.suggestBox, 'mousemove', this.mousemoveEvent, this);
        }
        this.ce.clearEvents();
        this._setEvents = false;
    },

    mouseoverEvent: function(e, tg){
        if (this.keyDownUp){
            return;
        }
        this.removeOverClass();

        var tn = this.getParentNode(tg);
        if (tn){
            this.choiceNode = tn;
            this.choiceSeq = tn.choiceSeq;
            mc.addClass(this.nodeOverClass, this.choiceNode);
            this.ce.fireEvent('mouseover', e, tg, this);
        }
    },

    mouseoutEvent: function(e, tg){
        if (!this.keyDownUp){
            this.ce.fireEvent('mouseout', e, tg, this);
        }
    },

    mousemoveEvent: function(){
        this.keyDownUp = false;
    },

    clickEvent: function(e, tg){
        mc.get(tg)
          .setThis(this, 'choiceNode');

        this.removeOverClass();
        if (this.getParentNode(tg)){
            this.ce.fireEvent('click', e, this.choiceNode, this);
        }
    },

    upKey: function(){
        if (!this.choiceNode || this.choiceSeq == 0 || !(this.isVisible())) {
            return false;
        }
        this.removeOverClass();
        this.choiceSeq -= 1;

        this.setChoiceNode(this.choiceSeq);
        this.moveScroll();
        return true;
    },

    getParentNode: function(tg){
        var ids = this.nameFormat.split(tg);
        if (ids[1] == 'suggest'){
            return ids[4] ? tg.parentNode : ids[3] ? tg : false;
        }
        return false;
    },

    getParentID: function(tg){
        var node = this.getParentNode(tg);
        return node ? this.nameFormat.split(node) : false;
    },

    setKeyDownUp: function(){
        this.keyDownUp = true;
    },

    hideSuggestOutside: function(){
        this.initValue();
        var chilchun = -7000;
        mc.setXY(chilchun, chilchun, this.suggestOutside)
          .setVisibility(false, this.suggestOutside)
          .clearScroll(true, false, this.suggestBox);
    },

    showSuggestOutside: function(whxy){
        mc.setXY(whxy[2], whxy[1] + whxy[3], this.suggestOutside)
          .setVisibility(true, this.suggestOutside);
    },

    getList: function(tg){
        return tg ? this.textList : this.suggestList;
    },

    getIndexNode: function(ix){
        return this.suggestList[ix || 0];
    },

    getIndexNodes: function(start, end, ad){
        ad = ad || 'A';
        ad = ad.toUpperCase();
        return ad == 'A' ? mc.getScope(this.suggestList, start, end).chain
                         : mc.getScopeDesc(this.suggestList, end, start).chain;
    },

    getIndexText: function(ix){
        return this.textList[ix || 0];
    },

    isExistValue: function(vl){
        var i,
            len = this.textList.length;

        for (i = 0; i < len; i++){
            if (vl == this.textList[i]){
                return true;
            }
        }
        return false;;
    },

    clearList: function(){
        this.textList = [];
        this.suggestList = [];
        this.ce.fireEvent('clearList', this);
    },

    getId: function(id){
        return mc.get(id).chain;
    },

    setSuggestHeight: function(){
        mc.setOwn(this.suggestBox);
        var rowCount = this.getChoiceLength();
        this.nodeHeight = '';

        if (rowCount > 0) {
            mc.firstChild(false)
              .getHeight(false, mc.chain)
              .setThis(this, 'nodeHeight');
        } else {
            mc.setHeight('0px', false);
        }

        if (this.nodeHeight){
            var cnt = rowCount < this.maxNodes ? rowCount : this.maxNodes;
            this.suggestHeight = this.nodeHeight * cnt;
            mc.setHeight(this.suggestHeight + 'px', 'BP');
        }
    },

    isChoiced: function(){
        return this.choiceNode;
    },

    initValue: function(){
        this.choiceSeq = -1;
        this.choiceNode = null;
    },

    resetReady: function(){
        this.removeOverClass();
        if (this.isChoiced()){
            this.hideSuggestOutside();
            return true;
        }
        return false;
    },

    isVisible: function(){
        return !this.suggestOutside ? false : mc.isVisible(false, this.suggestOutside).chain;
    },

    setFirst: function(){
        if (this.getChoiceLength() > 0){
            this.choiceSeq = 0;
            this.setChoiceNode(0);
        }
    },

    nextNode: function(){
        this.removeOverClass();
        this.choiceSeq += 1;
        this.setChoiceNode(this.choiceSeq);
        this.moveScroll();
    },

    setChoiceNode: function(index){
        this.choiceNode = this.getIndexChoice(index);
        var tn = this.getParentNode(this.choiceNode);
        if (tn){
            mc.addClass(this.nodeOverClass, tn);
        }
    },

    removeOverClass: function(){
        if (this.choiceNode){
            var tn = this.getParentNode(this.choiceNode);
            if (tn){
                mc.removeClass(this.nodeOverClass, tn);
            }
        }
    },

    moveScroll: function(){
        if (this.choiceSeq > -1){
            this.scrollTopNode();
        }
    },

    scrollTopNode: function(){
        var vl = 0,
            box = this.suggestBox,
            node = this.choiceNode,
            boxY = mc.getY(box).chain,
            nodeY = mc.getY(node).chain,
            nmb = nodeY - boxY,
            ww = node.offsetTop + nmb + node.clientHeight;

        if (nmb < 0){
            vl = ww;
        } else if (nmb >= 0 && nmb < this.suggestHeight){
            vl = box.scrollTop;
        } else {
            vl = box.scrollTop + node.clientHeight;
        }
        box.scrollTop = vl;
     },

    getTargetIndex: function(){
        return this.targetIndex;
    },

    getIndexChoice: function(ix){
        return this.choiceList ? this.choiceList[ix || 0] : '';
    },

    getChoiceLength: function(){
        return this.choiceList ? this.choiceList.length : 0;
    }
});


mc.combo.Combo = function(opts){
    mc.widget.Widget.setOptions(this, opts);
    if (this.showTo) {
        this.mainCombo(this.showTo);
    }
};

mc.extend(mc.combo.Combo, mc.types.JoinType, {
    blurSetValue: true,
    collectOnlyOne: true,
    failureMessage: {
        title: '통신 실패',
        msg: '통신 장애로 인해 서버에서 데이터를 수신하지 못했습니다.'
    },

    fitWidth: true,
    httpClass: '',
    httpMinChars: 3,
    httpHashKey: 'httpData',
    keyField: '',

    maxNodes: 7,
    message: '처리중...',
    metaData: '',
    notExistMessage: {title: '입력 값 오류', msg: '드롭다운 리스트에 없는 값입니다.'},

    prefix: 'mc_combo_',
    sendFields: '',
    showElement: '',
    showFields: '',

    showMessage: false,
    timeoutMessage: {
        title: '통신 실패',
        msg: '통신 시간 경과로 인해 서버에서 데이터를 수신하지 못했습니다.'
    },
    width: '',

    ccode: 'combo',
    charsOnly: '',
    createFocus: true,
    lastValue: '',
    openForm: 'resetValue',

    suggest: true,
    suggestNew: '',

    mainCombo: function(showTo){
        this.showTo = showTo || this.showTo;
        this.checkOptions();
        this.setTypesOption();
        this.mainJoinType();

        this.createSendFields();
        this.createDataFields();
        this.newSuggest();
        this.checkWidth();
        this.setDataResource();
        this.setEvents();

        mc.component.Component.isExec(this, 'combo', this.showTo);
        return this;
    },

    checkOptions: function(){
        if (!this.metaData && !this.htmlSelect) {
            mc.widget.Message.show('E1010', this.ccode, 'metaData or htmlSelect');
        }
    },

    setTypesOption: function(){
        this.charsOnly = true;
        mc.guide.GuideType.xOffset = 30;
        this.nameFormat = mc.widget.NameFormat;
    },

    createSendFields: function(){
        if (this.sendFields){
            this.sendFields = mc.toArray(this.sendFields).chain;
            var len = this.sendFields.length,
                field,
                tpl,
                i;

            for (i = 0; i < len; i++){
                field = this.sendFields[i];
                tpl = {tag: 'input', type: 'hidden', id: field, name: field};
                this.createHiddenNode(tpl, field);
            }
        }
    },

    createHiddenNode: function(tpl, field){
        var element = field + '_hiddenNode';
        mc.firstChild(false, this.outside)
          .Json.apply(tpl, mc.chain, 'beforeBegin', true)
          .setThis(this, element);

        if (this.serverClass){
            var spt = this.id.split('_mcdttd_');
            mc.chain.id = field + '_mcdttd_' + spt[1];
            mc.addClass(this.serverClass, this.getHiddenNode(field));
        }
    },

    getHiddenNode: function(id){
        return this[id + '_hiddenNode'] || '';
    },

    createDataFields: function(){
        if (this.dataFields){
            this.dataFields = mc.toArray(this.dataFields).chain;
            var len = this.dataFields.length,
                field,
                tpl,
                i;

            for (var i = 0; i < len; i++){
                field = this.dataFields[i];
                if (!(this.getHiddenNode(field))){
                    tpl = {tag: 'div', id: field};
                    this.createHiddenNode(tpl, field);
                    mc.setDisplay(false, this.getHiddenNode(field));
                };
            }
        }
    },

    newSuggest: function(){
        if (this.suggestNew){
            return;
        };
        var pm = this.paramOpts;
        delete pm.showTo;
        pm.combo = this;

        this.suggestNew = new mc.combo.Suggest(this.paramOpts);
        this.suggestNew.createSuggestOutside();
        this.suggestNew.createSuggestBox();
        delete this.paramOpts.combo;
    },

    checkWidth: function(){
        var sgt = this.suggestNew,
            tw,
            wd;

        sgt.setShowNodes();
        if (this.fitWidth && sgt.getFieldCount()){
            tw = sgt.getFieldTotal('width');
            wd = mc.getWidth('BP', this.outside).chain - 25;
            if (tw > wd){
                mc.widget.Message.show('E1030', this.ccode, 'showFields.width total:' + tw, 'texttype width: ' + wd);
            }
        }
    },

    setDataResource: function(){
        if (this.metaData.client){
            this.collectOnlyOne = true;
            this.dataResource = 'client';
        } else {
            this.dataResource = this.collectOnlyOne ? 'serverOne' : 'server';
        }
    },

    getClientData: function(){
        if (this.createFocus || this.createdMeta){
            return;
        }
        this.metaData.mainMetaData();
        this.selectMetaData();
        this.createdMeta = true;
    },

    getServerData: function(){
        if (this.createFocus || this.createdMeta){
            return;
        }
        this.createdMeta = true;
        this.requestServer();
    },

    setEvents: function(){
        if (!this._setEvents && this.suggestNew){
            mc.combo.Combo.superclass.setEvents.call(this);
            mc.widget.Event.customOn(this.suggestNew, [
                ['click', this.clickEvent, this],
                ['mouseover', this.mouseoverEvent, this],
                ['mouseout', this.mouseoutEvent, this]
            ]);
            this._setEvents = true;
        }
    },

    removeEvents: function(){
        mc.combo.Combo.superclass.removeEvents.call(this);
        this.suggestNew.removeEvents();
    },

    joinClick: function(e){
        if (this.protectJoinClick){
            return;
        }
        this.protectJoinClick = true;
        this.hideError(this.textType);
        this.valueError = false;
        mc.focus(this.textType);

        this.ce.fireEvent('joinClick', this);
        this.createCombo();
    },

    createCombo: function(e){
        if (this.dataResource == 'server'){
            this.requestServer();
            return;
        } else if (!this.createdMeta){
            this.createFocus = false;
            if (this.dataResource == 'client'){
                this.getClientData();
            } else {
                this.dataResource == 'client';
                this.getServerData();
                return;
            }
        }

        if (this.gridData){
            this.setGridTextType();
        }
        this.setComboList();
    },

    requestServer: function(){
        var meta = this.metaData,
            hk = this.httpHashKey;

        if (!this.setHttpObject){
            meta.server = this.setHttpOptions();
        }
        this.getValue();
        meta.server['data'] = mc.chain ? {hk : mc.chain} : '';
        meta.httpNew ? meta.request() : meta.mainMetaData();
    },

    setHttpOptions: function(){
        var meta = this.metaData,
            opts = mc.allocate({}, meta.server || {}).chain;

        if (this.showMessage){
            opts.showMessage = true;
            opts.message = this.message;
            if (!opts.showElement){
                if (!this.httpMsgElement){
                    mc.createElement('div', false, this.prefix)
                      .setThis(this, 'this.httpMsgElement');
                }
                opts.showElement = this.httpMsgElement;
            }
            mc.appendEnd(this.httpMsgElement, this.outside)
              .setVisibility(true, mc.chain);

            if (this.httpClass){
                mc.addClass(this.httpClass, opts.showElement);
            }
        }

        meta.componentMethod = this.callbackHttp;
        meta.componentScope = this;
        opts.metaFailure = this.metaFailure;
        opts.metaTimeout = this.metaTimeout;
        opts.metaFailScope = this;
        this.setHttpObject = true;
        return opts;
    },

    callbackHttp: function(){
        if (this.showMessage && this.httpMsgElement) {
            mc.getBody()
              .appendEnd(this.httpMsgElement, mc.chain)
              .setVisibility(false, mc.chain);
        }
        this.selectMetaData();

        if (this.gridData){
            this.setGridTextType();
        }
        this.setComboList();

        if (this.gridData){
            this.setSuggestValue();
            this.setOptionValue();
            this.comboBlur();
            this.gridData = '';
            this.mapName = '';
        }
    },

    metaFailure: function(trans){
        this.setHttpError(this.failureMessage);
        this.ce.fireEvent('failure', trans, this);
    },

    metaTimeout: function(trans){
        this.setHttpError(this.timeoutMessage);
        this.ce.fireEvent('timeout', trans, this);
    },

    setHttpError: function(msg){
        this.createdMeta = false;
        this.protectJoinClick = false;
        this.valueError = true;
        this.showError(msg, this.textType);
    },

    selectMetaData: function(){
        mc.getBody();
        this.suggestNew.mainSuggest(mc.chain);
        if (this.suggestNew.getNodeCount() == 0){
            this.ce.fireEvent('emptyData', this);
        }
    },

    setComboList: function(){
        this.hideError(this.textType);
        this.valueError = false;
        var sgt = this.suggestNew;
        sgt.initValue();

        this.getValue();
        this.setLastValue(mc.chain);
        sgt.setChoiceList(mc.chain);

        var rowCount = sgt.getChoiceLength();
        if (rowCount == 0){
            sgt.hideSuggestOutside();
        } else {
            mc.getWHXY('BP', this.outside)
            sgt.showSuggestOutside(mc.chain);
        }

        sgt.setSuggestHeight();
        sgt.setFirst();
        if (rowCount > 0){
            this.setChoiceValue();
        }
        this.protectJoinClick = false;
        this.ce.fireEvent('showSuggest', this);
    },

    setLastValue: function(vl){
        this.lastValue = vl;
    },

    getLastValue: function(){
        return this.lastValue;
    },

    clearLastValue: function(){
        this.lastValue = '';
    },

    mouseoverEvent: function(e, tg){
        this.setChoiceValue();
        this.ce.fireEvent('mouseover', e, this);
    },

    mouseoutEvent: function(e, tg){
        this.ce.fireEvent('mouseout', e, this);
    },

    clickEvent: function(e, tg){
        mc.focus(this.textType);
        this.setChoiceValue(true);
        this.ce.fireEvent('click', e, tg, this);
        this.comboBlur();
    },

    blurEvent: function(e, tg, opts){
        this.setChoiceValue(true);
        this.comboBlur();

        if (!(this.suggestNew.isVisible())){
            this.checkTextType(e, tg, opts);
        }
    },

    downControlEvent: function(e){
        this.suggestNew.setKeyDownUp();
        this.ce.fireEvent('downKey', e, this);
        if (!(this.suggestNew.isVisible())){
            this.createCombo();
            return;
        }

        if (this.getValue() == this.getLastValue()){
            this.nextNode();
        } else {
            this.setLastValue(mc.chain);
            this.createdMeta ? this.setComboList()
                             : (this.checkMinChars() ? this.requestServer() : this.setComboList());
        }
    },

    upControlEvent: function(){
        this.suggestNew.setKeyDownUp();
        this.ce.fireEvent('upKey', this);
        if (this.suggestNew.upKey()){
            this.setChoiceValue();
        }
    },

    tabControlEvent: function(e, tg, opts){
        this.blurEvent(e, tg, opts);
    },

    enterControlEvent: function(e){
        if (this.suggestNew.isChoiced()){
            this.setChoiceValue(true);
            this.comboBlur();
        }
        e.bubbleDefault();
        this.ce.fireEvent('enterKey', this);
    },

    escControlEvent: function(e, tg, opts){
        this.hideError();
        if (this.suggestNew.resetReady()){
            this.clearLastValue();
            mc.combo.Combo.superclass.escControlEvent.call(this, e, tg, opts);
        }
    },

    keyUpEvent: function(e){
        if (mc.getFnKey(e).chain && mc.chain.charAt(0) == 'F'){
            return;
        }
        if ((mc.Gecko && e.keyCode == 229) || (mc.isValueKey(e).chain && (e.keyCode != 8 && e.keyCode != 46))){
            return;
        }
        this.hideError();
        this.showComboList();
    },

    showComboList: function(){
        if (!(this.suggestNew.isVisible())){
            this.createCombo();
        }
        this.createdMeta ? this.setComboList()
                         : (this.checkMinChars() ? this.requestServer() : this.setComboList());
    },

    suggestEvent: function(){
        this.showComboList();
    },

    comboBlur: function(){
        this.suggestNew.removeOverClass();
        if (this.blurSetValue && this.suggestNew.isChoiced()){
            this.clearLastValue();
            this.suggestNew.hideSuggestOutside();
        }
    },

    setChoiceValue: function(choice){
        var sgt = this.suggestNew,
            ids;

        if (sgt.choiceNode){
            ids = sgt.getParentID(sgt.choiceNode);
            sgt.nodeIndex = ids ? ids[3] : '';

            if (choice && sgt.nodeIndex){
                this.setSuggestValue();
                mc.setValue(this.suggestValue, this.textType);
                this.setOptionValue();
            }
        }
    },

    setSuggestValue: function(){
        var sgt = this.suggestNew;
        this.suggestValue = sgt.getIndexText(sgt.nodeIndex);
    },

    setOptionValue: function(){
        var sgt = this.suggestNew;
        this.setSendValue(sgt.nodeIndex);
        this.setChoicedFields(sgt.nodeIndex);
        this.ce.fireEvent('choiced', this.textType, this.choicedFields, this);
    },

    setSendValue: function(index){
        if (this.sendFields){
            var data = this.suggestNew.getIndex(index),
                fields = this.sendFields,
                len = fields.length,
                i,
                field,
                vl;

            for (i = 0; i < len; i++){
                field = fields[i];
                vl = data ? data[field] : '';
                mc.setValue(vl, this.getHiddenNode(field));
            }
        }
    },

    setChoicedFields: function(index){
        this.choicedFields = [];
        if (this.dataFields){
            var data = this.suggestNew.getIndex(index),
                fields = this.dataFields,
                len = fields.length,
                i,
                field;

            for (i = 0; i < len; i++){
                field = fields[i];
                this.choicedFields[i] = this.getHiddenNode(field).id;
                if (!(mc.isContains(this.sendFields, field).chain)){
                    mc.setText(data ? data[field] : '', this.getHiddenNode(field));
                }
            }
        }
    },

    checkTextType: function(e, tg, opts){
        this.valueError = false;
        if (this.isReadOnly()){
            return;
        }
        var vl = this.getValue();
        if (this.autoCheck && vl && !(this.suggestNew.isExistValue(vl))) {
            this.showError(this.notExistMessage, this.textType);
            return;
        }
        mc.combo.Combo.superclass.checkTexttype.call(this, e, tg, opts);

        this.parentComponent = true;
        this.fireExactData();
        this.parentComponent = false;
    },

    checkMinChars: function(){
        mc.getValue(this.textType, true);
        return  mc.chain.length >= this.httpMinChars ? true : false;
    },

    nextNode: function(){
        var sgt = this.suggestNew,
            rowCount = sgt.getChoiceLength();

        if (rowCount > 0 && sgt.choiceSeq < (rowCount - 1)){
            sgt.nextNode();
            this.setChoiceValue();
            this.ce.fireEvent('downKey', this);
        }
    },

    setForcedValue: function(data, mapName){
        this.gridData = data || '';
        this.mapName = mapName || '';

        if (!this.createNodeList){
            this.joinClick();
            this.createNodeList = true;
        } else {
            this.selectMetaData();
            this.setGridTextType();
            this.setComboList();
            this.setSuggestValue();
            this.setOptionValue();
            this.comboBlur();
            this.gridData = '';
            this.mapName = '';
        }
    },

    setGridTextType: function(){
        var detail = this.suggestNew.detailData;
        if (detail){
            mc.Json.getKeyValue(detail, this.mapName, this.gridData)
              .setValue(mc.chain[this.suggestField], this.textType);
        };
    },

    resetValue: function(){
        mc.combo.Combo.superclass.resetValue.call(this);
        if (this.sendFields){
            var len = this.sendFields.length,
                i,
                element;

            for (i = 0; i < len; i++){
                if (element = this.getHiddenNode(this.sendFields[i])){
                    element.value = '';
                };
            }
        }
    }
});


//------------------
//@package: mc.guide
//------------------

mc.guide.Guide = function(opts){
    mc.widget.Widget.setOptions(this, opts);
    if (!this.showTo){
        this.showTo = mc.getBody().chain;
    }
    this.mainGuide(this.showTo);
};

mc.guide.Guide.prototype = {
    closable: '',
    createTitle: true,
    draggable: '',
    guideClass: '',
    guideStyle: '',

    html: '',
    guideboxClass: 'mc-guidebox',
    guideboxStyle: '',
    outsideClass: ['mc-guide-outside', 'mc-display-none'],
    outsideStyle: '',

    prefix: 'mc_guide_',
    showGuide: true,
    showStatus: '',
    title: '',
    width: 120,

    ccode: 'guide',
    handleNode: '',
    titleType: 'guide',

    outside: '',
    guidebox: '',
    inside: '',
    guideside: '',

    mainGuide: function(showTo){
        this.showTo = showTo || this.showTo;

        this.createOutside();
        this.setThisTitle();
        this.newTitle();

        this.createGuidebox();
        this.createInside();

        this.createGuideSide();
        this.setText(this.html);

        this.newDragDrop();
        this.setEvents();

        mc.component.Component.isExec(this, 'guide', this.outside);
        return this;
    },

    createOutside: function(){
        mc.createAppend('div', this.id, this.prefix, this.showTo)
          .setOwn(mc.chain)
          .setThis(this, 'outside')
          .addClass(this.outsideClass)
          .setStyle(this.outsideStyle)
          .setWHXY(this.width, this.height, this.leftX, this.topY, 'BP')
          .setUnselectable();

        mc.widget.Widget.applyAttr(this);
        this.showGuide ? this.show() : this.hide();

        mc.widget.Widget.cacheShowTo(this, true);
        this.showTo = this.outside;
    },

    setThisTitle: function(){
        if (!this.title){
            this.title = {};
        }
    },

    newTitle: function(){
        mc.widget.Widget.newTitle(this, false);
        var tit = this.titleNew;
        if (!tit){
            return;
        }
        if (this.closable){
            this.title.closable = true;
        }
        tit.closable = this.title.closable;

        tit.titleType = this.titleType || 'guide';
        tit.isExecComponent = false;

        this.titleNew.mainTitle(this.outside);
        if (tit.closable){
            this.draggable = true;
        }
    },

    createGuidebox: function(){
        mc.createAppend('div', false, this.prefix, this.outside)
          .setOwn(mc.chain)
          .setThis(this, 'guidebox')
          .addClass(this.guideboxClass)
          .setStyle(this.guideboxStyle);

        if (!this.titleNew || this.titleNew.isGuideHide()){
            mc.addClass('mc-guide-notitle');
        }
    },

    createInside: function(){
        mc.createAppend('div', false, this.prefix, this.guidebox)
          .setOwn(mc.chain)
          .setThis(this, 'inside')
          .addClass(this.frameClass)
          .setStyle(this.frameStyle);
    },

    createGuideSide: function(){
        mc.createAppend('div', false, this.prefix, this.inside)
          .setOwn(mc.chain)
          .setThis(this, 'guideside')
          .addClass(this.guideClass)
          .setStyle(this.guideStyle)
          .setUnselectable();
    },

    setText: function(html){
        this.guideside.innerHTML = '';
        mc.createChild(html || '&#160', this.guideside);
    },

    isGuideHide: function(){
        return (this.titleType == 'guide' && !this.text && !this.closable) ? true : false;
    },

    newDragDrop: function(){
        if (this.draggable && !this.dragdrop){
            if (this.handleNode && this.titleNew){
                this.handleNode = this.titleNew.getOutside();
            }

            this.dragdrop = new mc.dragdrop.DragDrop({
                dragTarget: this.outside,
                handleNode: this.handleNode,
                directDrag: true
            })
        }
    },

    setEvents: function(){
        if (!this._setEvents && this.titleNew){
            mc.widget.Event.customOn(this.titleNew, ['hideTitle', this.hideEvent, this]);
        }
        this._setEvents = true;
    },

    hideEvent: function(){
        this.hide();
        this.clickClose = true;
    },

    show: function(){
        this.showStatus = true;
        mc.removeClass('mc-display-none', this.outside);
        this.ce.fireEvent('showGudie', this.outside, this);
    },

    hide: function(){
        this.showStatus = false;
        mc.addClass('mc-display-none', this.outside);
        this.ce.fireEvent('hideGudie', this.outside, this);
    },

    toggleShow: function(){
        this.showStatus ? this.hide() : this.show();
    },

    showXY: function(x, y){
        if (!this.showStatus){
            this.show();
        }
        mc.setXY(x, y, this.outside);
    },

    moveTo: function(move){
        if (!this.showStatus){
            this.show();
        }
        mc.moveTo(move, this.outside);
    },

    adjustShow: function(code, trbl, el){
        if (!this.showStatus){
            this.show();
        }
        mc.widget.Position.moveToXY(code, el, trbl, this.outside);
    },

    setTitleText: function(txt){
        if (this.titleNew){
            this.titleNew.setTitleText(txt);
        }
        this.show();
    },

    getTitleNew: function(){
        return this.titleNew || '';
    },

    getOutside: function(){
        return this.outside;
    }
};


mc.guide.GuideType = function(){

    var dragdrop = '';
    var guide = '';

    return {

        prefix: 'mc_guidetype_',
        showXY: false,
        xOffset: 15,
        yOffset: 5,

        ccode: 'guidetype',
        formFirst: false,
        onlyOne: false,

        newGuide: function(opts){
            guide = new mc.guide.Guide({
                width: 170,
                title: {text: '&#160', closable: false},
                html: '&#160'
            })
        },

        newDragDrop: function(tg){
            dragdrop = new mc.dragdrop.DragDrop({
                dragTarget: tg,
                directDrag: true
            })
        },

        setPosition: function(tg){
            var xy = mc.getXY(tg).chain;
            if (this.showXY){
                this.x = xy[0];
                this.y = xy[1] + this.yOffset + mc.getHeight(false, tg).chain;
            } else {
                this.x = xy[0] + this.xOffset + mc.getWidth(false, tg).chain;
                this.y = xy[1];
            }
        },

        showGuide: function(tit, html){
            var obj = guide.getTitleNew();
            obj.closable = tit ? true : false;

            guide.setTitleText(tit);
            guide.setText(html);
            guide.showXY(this.x, this.y);
        },

        show: function(el, tit, html){
            if (this.formControl){
                return;
            }
            if (!guide){
                this.newGuide();
                this.newDragDrop(guide.getOutside());
            }

            if (el != this.beforeNode){
                this.hide();
                this.setPosition(el);
                this.beforeNode = el;

            }
            this.showGuide(tit, html);
        },

        hide: function(){
            if (guide && !this.onlyOne){
                guide.hide();
            }
        }
    };
}();


mc.guide.MessageBox = function(){
    mc.widget.Widget.setOptions(this, {});
};

mc.extend(mc.guide.MessageBox, mc.guide.Guide, {
    buttons: {ok: '확인', yes: '예', no: '아니오', cancel: '취소'},
    closable: true,
    draggable: true,
    method: '',

    prefix: 'mc_msgbox_',
    scope: '',
    width: 300,

    ccode: 'messagebox',
    buttonList: ['ok', 'yes', 'no', 'cancel'],
    instanceList: ['mc_msg_OK', 'mc_msg_YES', 'mc_msg_NO', 'mc_msg_CANCEL'],

    originDefault: {
        closable: true, createTitle: true, draggable: true, guideClass: '',
        guideStyle: '', html: '', insideClass: 'mc-guide-inside', insideStyle: '',
        outsideClass: ['mc-guide-outside', 'mc-display-none'],
        outsideStyle: '', showGuide: true, width: 300,
        buttons: {ok: '확인', yes: '예', no: '아니오', cancel: '취소'},
        method: '', scope: '', title: ''
    },

    targetComponent: '',
    titleType: 'default',
    hideClass: 'mc-offset-hide',

    mainMessageBox: function(opts){
        this.setOptions(opts);

        if (!this.outside){
            this.mainGuide(mc.getBody().chain);
            this.createPrompt();
            this.createButtonSide();
            this.newButton();
        }

        this.setTitleText(this.title.text);
        this.setText(this.html);

        this.hideElements();
        this.setButtonText();

        this.setWHXY();
    },

    setOptions: function(opts){
        mc.allocate(this, this.originDefault)
          .allocate(this, opts || {});

        this.setThisTitle();
        this.handleNode = 'title';
    },

    createPrompt: function(){
        this.component = [
            {ccode: 'linefeed', id: 'mc_msg_promptTop'},
            {ccode: 'texttype', id: 'mc_msg_promptText', textTypeClass: this.hideClass},
            {ccode: 'numbertype', id: 'mc_msg_promptNumber', textTypeClass: this.hideClass},
            {ccode: 'textarea', id: 'mc_msg_promptArea', textAreaClass: this.hideClass, cols: 40}
        ];

        mc.component.Component.isExec(this, 'messagebox', this.inside);
        this.promptTextArea = mc.component.Instance.get('mc_msg_promptText').outside;
    },

    createButtonSide: function(){
        mc.createAppend('div', false, this.prefix, this.guidebox)
          .setOwn(mc.chain)
          .setThis(this, 'buttonSide')
          .addClass(this.buttonClass)
          .setStyle(this.buttonStyle);
    },

    newButton: function(){
        this.component = [
            {ccode: 'linefeed', id: 'mc_msg_bottomTop'},
            {ccode: 'buttongroup', id: 'mc_msg_btnGroup', arrange:[4], eachWidth: [80, 80, 80, 80],
             component: [
                {text: 'OK', id: 'mc_msg_OK', 'events': ['click', this.buttonClick, this]},
                {text: 'Yes', id: 'mc_msg_YES', 'events': ['click', this.buttonClick, this]},
                {text: 'No', id: 'mc_msg_NO', 'events': ['click', this.buttonClick, this]},
                {text: 'Cancel', id: 'mc_msg_CANCEL', 'events': ['click', this.buttonClick, this]}
            ]},
            {ccode: 'linefeed', id: 'mc_msg_bottomBottom'}
        ];

        mc.component.Component.isExec(this, 'messagebox', this.buttonSide);
    },

    hideElements: function(){
        var cmpt = mc.component.Instance;
        cmpt.get('mc_msg_btnGroup')
            .hideButton(this.showButtons, this.instanceList);
        cmpt.get('mc_msg_promptText')
            .addClass(this.hideClass);
        cmpt.get('mc_msg_promptNumber')
            .addClass(this.hideClass);
        cmpt.get('mc_msg_promptArea')
            .addOutsideClass(this.hideClass);
    },

    setButtonText: function(){
        var btns = this.showButtons,
            len = btns.length,
            id,
            first = '';

        for (i = 0; i < len; i++){
            if (btns[i]){
                id = this.instanceList[i];
                mc.component.Instance.get(id)
                  .setButtonText(this.buttons[this.buttonList[i]]);

                if (!first){
                    mc.focus(id);
                    first = true;
                }
            }
        }
    },

    setWHXY: function(){
        mc.setWH(this.width, this.height, 'BP', this.outside);

        if (this.leftX && this.topY){
            mc.setXY(this.leftX, this.topY, this.outside);
        } else {
            var wd, ht, ot;
            wd = Math.round(mc.getViewportWidth().chain / 2);
            ht = Math.round(mc.getViewportHeight().chain / 2);
            ot = mc.widget.Position.getWH('C', this.outside);
            mc.setXY(wd - ot[0], ht - ot[1], this.outside);
        }
    },

    hideEvent: function(e, tg){
        if (this.method){
            this.method.call(this.scope || this, 'close', '', tg, this, e);
        }
        mc.guide.MessageBox.superclass.hideEvent.call(this);

        this.ce.fireEvent('choice', 'close', '', tg, this, e);
    },

    buttonClick: function(type, e, tg, opts, that){
        var code,
            obj,
            error;

        mc.get(that.own)
          .indexOfArray(this.instanceList, mc.chain.id);

        code = this.buttonList[mc.chain];
        this.getComponent();
        this.nodeValue = '';

        if (mc.chain < 2){
            if (this.targetComponent){
                error = this.checkValue(this.targetComponent);
            }
            if (!error && this.method){
                this.method.call(this.scope || this, code, this.nodeValue, that.own, this, e);
            }
        } else {
            this.clearMessage();
        }

        if (!error){
            this.hide();
            this.ce.fireEvent('choice', code, this.nodeValue, that.own, this, e);
        }
    },

    getComponent: function(){
        this.targetComponent = '';
        var tp = this.calledType,
            id;

        if (tp != 'textType' && tp != 'numberType' && tp != 'textArea'){
            return false;
        }
        id = tp == 'textType' ? 'mc_msg_promptText' : tp == 'numberType' ? 'mc_msg_promptNumber' : 'mc_msg_promptArea';
        this.targetComponent = mc.component.Instance.get(id);
    },

    checkValue: function(obj){
        if (obj.valueError){
            return true;
        }
        obj.ccode == 'numbertype' ? obj.checkNumbertype() : obj.checkTexttype();
        if (obj.valueError){
            return true;
        }

        this.getInputValue(obj);
        return false;
    },

    getInputValue: function(obj){
        this.nodeValue = obj.isVisible() ? obj.getValue() : '';
    },

    clearMessage: function(){
        var cmpt = this.targetComponent;
        if (cmpt){
            cmpt.hideError();
        }
    },

    alert: function(opts){
        this.calledType = 'alert';
        this.showButtons = [true, false, false, false];
        this.mainMessageBox(opts);
    },

    yesNoCancel: function(opts){
        this.calledType = 'ync';
        this.showButtons = [false, true, true, true];
        this.mainMessageBox(opts);
    },

    yesNo: function(opts){
        this.calledType = 'yn';
        this.showButtons = [false, true, true, false];
        this.mainMessageBox(opts);
    },

    yesCancel: function(opts){
        this.calledType = 'yc';
        this.showButtons = [false, true, false, true];
        this.mainMessageBox(opts);
    },

    textPrompt: function(opts){
        this.calledType = 'textType';
        this.showButtons = [false, true, false, true];

        opts = opts || {};
        this.mainMessageBox(opts);

        var cmpt = opts.options || {};
        cmpt.textTypeClass = this.hideClass;
        mc.component.Instance.get('mc_msg_promptText').setMsgOptions(cmpt);
    },

    numberPrompt: function(opts){
        this.calledType = 'numberType';
        this.showButtons = [false, true, false, true];

        opts = opts || {};
        this.mainMessageBox(opts);

        var cmpt = opts.options || {};
        cmpt.textTypeClass = this.hideClass;
        mc.component.Instance.get('mc_msg_promptNumber').setMsgOptions(cmpt);
    },

    textareaPrompt: function(opts){
        this.calledType = 'textArea';
        this.showButtons = [false, true, false, true];

        opts = opts || {};
        this.mainMessageBox(opts);

        var cmpt = opts.options || {};
        cmpt.textAreaClass = this.hideClass;

        var obj = mc.component.Instance.get('mc_msg_promptArea');
        obj.setMsgOptions(cmpt);
        mc.setVisibility(true, obj.outside);
    }
});
mc.Message = new mc.guide.MessageBox;


mc.guide.Tip = function(opts){
    mc.widget.Widget.setOptions(this, opts);
    if (this.target) {
        this.mainTip(this.target);
    }
};

mc.extend(mc.guide.Tip, mc.guide.Guide, {
    autoHide: true,
    closable: '',
    createTitle: false,
    draggable: '',

    offsetX: {trbl: 'r', value: 10},
    offsetY: {trbl: 'b', value: 5},
    position: 'CB',

    prefix: 'mc_tip_',
    target: '',
    withMouse: false,

    ccode: 'tip',
    dragdrop: '',

    mainTip: function(target){
        this.target = target || this.target;
        this.setPosition();
        this.setTipEvents();
        return this;
    },

    setPosition: function(){
        this.pos = {};
        this.pos[this.offsetX.trbl] = this.offsetX.value;
        this.pos[this.offsetY.trbl] = this.offsetY.value;
    },

    setTipEvents: function(){
        if (!this._setTipEvents && this.target){
            mc.setOwn(this.target)
              .onOwn(['mouseover', this.mouseoverEvent, this]);

            if (!this.closable){
                mc.onOwn(['mouseout', this.mouseoutEvent, this]);
            };
            if (this.withMouse) {
                mc.onOwn(['mousemove', this.mousemoveEvent, this]);
            };
            this._setTipEvents = true;
        }
    },

    mouseoutEvent: function(e, tg, opts){
        if (this.autoHide){
            this.hide();
        }
        this.ce.fireEvent('mouseout', e, tg, opts, this);
    },

    mousemoveEvent: function(e, tg, opts){
        var base = {},
            move = {};

        base.x = e.pageX;
        base.y = e.pageY;

        move[this.offsetX.trbl] = this.offsetX.value;
        move[this.offsetY.trbl] = this.offsetY.value;

        mc.widget.Position.setXY(base, move, this.outside);
        mc.guide.Tip.superclass.show.call(this);

        this.ce.fireEvent('mousemove', e, tg, opts, this);
    },

    mouseoverEvent: function(e, tg, opts){
        if (this.outside){
            this.showTip();
            return;
        }

        if (this.draggable){
            this.autoHide = false;
        }
        this.mainGuide(mc.getBody().chain);
        this.showTip();

        this.ce.fireEvent('mouseover', e, tg, opts, this);
    },

    showTip: function(){
        mc.guide.Tip.superclass.show.call(this);
        if (!this.withMouse){
            mc.widget.Position.moveToXY(this.position, this.target, this.pos, this.outside);
        }
    }
});


mc.guide.TipGroup = function(opts){
    mc.widget.Widget.setOptions(this, opts);
    if (!this.showTo){
        this.showTo = mc.getBody().chain;
    }
    this.mainTipGroup(this.showTo);
};

mc.guide.TipGroup.prototype = {
    ccodeOpts: {},
    prefix: 'mc_tipgroup_',

    ccode: 'tipgroup',
    defaultCcode: 'tip',

    mainTipGroup: function(showTo){
        this.showTo = showTo || this.showTo;
        this.setCcodeOpts();
        mc.component.Component.isExec(this, 'tipgroup', this.centerBox);
        return this;
    },

    setCcodeOpts: function(e, tg, opts){
        var hash = {};
        mc.eachHash(this.ccodeOpts, function(key, value){
            hash[key] = value;
            mc.eachArray(this.component, function(cmpt, ix){
                mc.allocate(cmpt, hash, true);
            }, this)
        }, this)
    }
};


//---------------------
//@package: mc.dragdrop
//---------------------

mc.dragdrop.DragProxy = function(opts){
    mc.widget.Widget.setOptions(this, opts);
    if (this.dragTarget) {
        this.mainDragProxy(this.dragTarget);
    }
};

mc.dragdrop.DragProxy.prototype = {
    adjustY: 0,
    dragProxy: '',
    dragProxyClass: 'mc-drag-proxy',
    prefix: 'mc_dragproxy_',
    showFirstChild: false,

    ccode: 'dragproxy',
    proxyChild: '',

    mainDragProxy: function(dragTarget){
        this.dragTarget = dragTarget || this.dragTarget;
        this.createProxy();
        this.setCursorMove(this.dragProxy);

        mc.component.Component.isExec(this, 'dragproxy', this.groupNode || this.dragTarget);
        return this;
    },

    createProxy: function(){
        if (!this.dragProxy){
            mc.createAppend('div', false, this.prefix, mc.getBody().chain)
              .setThis(this, 'dragProxy')
              .addClass(this.dragProxyClass, this.dragProxy);
        }
    },

    setCursorMove: function(el){
        if (this.cursorMove){
            mc.setStyle({cursor: 'move'}, el);
        }
    },

    setEvents: function(){
    },

    removeEvents: function(){
    },

    dragProxyMouseDown: function(e, tg, opts){
        mc.setStyle({visibility: 'visible', display: 'block'}, this.dragProxy)
          .setWHXY(this.downWHXY[0], this.downWHXY[1], this.downWHXY[2], this.downWHXY[3] + this.adjustY, 'BP', this.dragProxy);

        this.createProxyChild();
    },

    createProxyChild: function(){
        if (this.proxyChild){
            mc.removeElement(this.proxyChild);
        }
        if (this.showFirstChild){
            var nodes = mc.get(this.getDragTarget()).chain.cloneNode(true);
            mc.cleanNode(nodes)
              .setThis(this, 'proxyChild', mc.chain[0])
              .addClass(this.proxyChildClass, this.proxyChild);

            this.proxyChild.id = '';
            this.dragProxy.appendChild(this.proxyChild);
        }
    },

    dragProxyMouseMove: function(e, tg, opts){
    },

    dragProxyMouseUp: function(){
        mc.setStyle({visibility: 'hidden', display: 'none'}, this.dragProxy);
    }
};


mc.dragdrop.DragDrop = function(opts){
    mc.widget.Widget.setOptions(this, opts);
    if (this.dragTarget) {
        this.mainDragDrop(this.dragTarget);
    }
};

mc.extend(mc.dragdrop.DragDrop, mc.dragdrop.DragProxy, {
    clone: false,
    cursorMove: true,
    directDrag: false,
    draggable: true,

    dragTarget: '',
    dragTargetClass: '',
    dragTargetStyle: '',

    handleNode: '',
    limitAxis: '',
    limitNode: '',
    prefix: 'mc_dragdrop_',

    ccode: 'dragdrop',
    limitWHXY: '',
    _mouseMoved: false,
    openWHXY: '',

    mainDragDrop: function(dragTarget){
        this.dragTarget = dragTarget || this.dragTarget;
        this.setDragTarget();
        this.mainDragProxy()
        this.setHandleNode();
        this.setCalcBaseXY();
        this.getLimitNode();
        this.setEvents();

        mc.component.Component.isExec(this, 'dragdrop', this.groupNode || this.dragTarget);
        return this;
    },

    setDragTarget: function(){
        mc.setOwn(this.dragTarget)
          .addClass(this.dragTargetClass)
          .setStyle(this.dragTargetStyle)
          .getWHXY()
          .setThis(this, 'openWHXY', mc.chain)
          .setUnselectable();

        this.openWHXY[4] = this.openWHXY[0] + this.openWHXY[2];
        this.openWHXY[5] = this.openWHXY[1] + this.openWHXY[3];
    },

    setHandleNode: function(el){
        this.handleNode = el || this.handleNode || this.dragTarget;
        mc.get(this.handleNode)
          .setThis(this, 'handleNode');

        this.setCursorMove(this.handleNode);
    },

    setCalcBaseXY: function(){
        this.calcX = false;
        this.calcY = false;
        if (!this.limitAxis){
            this.calcX = true;
            this.calcY = true;
        } else if (this.limitAxis == 'x'){
            this.calcX = true;
        } else if (this.limitAxis == 'y'){
            this.calcY = true;
        }
    },

    getLimitNode: function(){
        if (this.limitNode){
            mc.getWHXY(false, this.limitNode)
              .setThis(this, 'limitWHXY');

            this.limitWHXY[4] = this.limitWHXY[0] + this.limitWHXY[2];
            this.limitWHXY[5] = this.limitWHXY[1] + this.limitWHXY[3];
        }
    },

    setEvents: function(){
        if (!this._setEvents){
            mc.dragdrop.DragDrop.superclass.setEvents.call(this);
            mc.on(this.handleNode, 'mousedown', this.mouseDownDD, this, {prevent: true});
            this._setEvents = true;
        }
    },

    removeEvents: function(){
        mc.dragdrop.DragDrop.superclass.removeEvents.call(this);
        mc.off(this.handleNode, 'mousedown', this.mouseDownDD, this);
        this._setEvents = false;
    },

    mouseDownDD: function(e, tg, opts){
        if (this.checkDraggable(e) && this.checkHandle(tg)){
            this.setDDMouseDown(e, tg, opts);
        }
    },

    checkDraggable: function(e){
        return (this.draggable && e.button == 0) ? true : false;
    },

    checkHandle: function(tg){
        return (tg == this.handleNode || mc.isDescendant(tg, this.handleNode).chain) ? true : false;
    },

    setDDMouseDown: function(e, tg, opts){
        this._mouseMoved = true;
        this.cacheXY(e);
        this.dragProxyMouseDown(e, tg, opts);
        this.setDocEvents();
        this.mouseDownEvent(e, tg, opts);
        this.ce.fireEvent('mousedown', e, tg, opts, this);
    },

    cacheXY: function(e){
        mc.getWHXY(false, this.dragTarget)
          .setThis(this, 'downWHXY');

        this.downX = this.downWHXY[2];
        this.downY = this.downWHXY[3];
        this.downPageX = e.pageX;
        this.downPageY = e.pageY;
        this.dragX = this.downX;
        this.dragY = this.downY;
    },

    setDocEvents: function(){
        mc.widget.Event.documentOn(this, 'mousemove')
                       .documentOn(this, 'mouseup');
    },

    removeDocEvents: function(){
        mc.widget.Event.documentOff(this, 'mousemove')
                       .documentOff(this, 'mouseup');
    },

    documentMouseMove: function(e, tg, opts){
        if (!this.checkDraggable(e) || this.getMouseMoveSide()){
            return;
        }

        this._mouseMoved = true;
        var dgX = this.downX + e.pageX - this.downPageX;
        var dgY = this.downY + e.pageY - this.downPageY;
        this.limitNodeCheck(dgX, dgY);

        if (this.calcX && this.limitX){
            this.dragX = dgX;
            mc.setX(this.dragX, this.dragProxy);
            if (this.directDrag) {
                mc.setX(this.dragX, this.dragTarget);
            }
        }
        if (this.calcY && this.limitY){
            this.dragY = dgY;
            mc.setY(this.dragY, this.dragProxy);
            if (this.directDrag) {
                mc.setY(this.dragY, this.dragTarget);
            }
        }

        this.setPointer(e, e.pageX);
        this.mouseMoveEvent(e, tg, opts);
        this.ce.fireEvent('mousemove', e, tg, opts, this);
    },

    limitNodeCheck: function(dragX, dragY){
        if (!this.limitNode){
            this.limitX = true;
            this.limitY = true;
            return;
        }
        this.limitX = false;
        this.limitY = false;

        if (dragX >= this.limitWHXY[2]){
            if (dragX < this.limitWHXY[4]){
                this.limitX = true;
            }
        }
        if (dragY >= this.limitWHXY[3]){
            if (dragY < this.limitWHXY[5]){
                this.limitY = true;
            }
        }
    },

    getMouseMoveSide: function(){
        return '';
    },

    documentMouseUp: function(e, tg, opts){
        if (!this._mouseMoved){
            return;
        }
        this._mouseMoved = false;

        this.removeDocEvents();
        if (this.calcX && this.limitX && !this.directDrag){
            mc.setX(this.dragX, this.dragTarget);
        }
        if (this.calcY && this.limitY && !this.directDrag){
            mc.setY(this.dragY, this.dragTarget);
        }

        this.upPageX = e.pageX;
        this.upPageY = e.pageY;
        this.dragProxyMouseUp(e, tg, opts);
        this.mouseUpEvent(e, tg, opts);
        this.ce.fireEvent('mouseup', this.dragX, this.dragY, this.dragTarget, this);
    },

    mouseDownEvent: function(e, tg, opts){
    },

    mouseMoveEvent: function(e, tg, opts){
    },

    mouseUpEvent: function(e, tg, opts){
    },

    setPointer: function(){
    },

    isDragging: function(){
        return this._mouseMoved;
    },

    getDragTarget: function(){
        return this.dragTarget;
    },

    setDraggable: function(dg){
        this.draggable = dg;
    },

    resetXY: function(){
        mc.setXY(this.openWHXY[2], this.openWHXY[3], this.dragTarget);
    }
});


mc.dragdrop.DragGroup = function(opts){
    mc.widget.Widget.setOptions(this, opts);
    if (this.groupNode) {
        this.mainDragGroup(this.groupNode);
    }
};

mc.extend(mc.dragdrop.DragGroup, mc.dragdrop.DragDrop, {
    autoCollect: false,
    eventNodes: [],
    groupNode: '',

    prefix: 'mc_draggroup_',
    ccode: 'draggroup',
    manyChild: true,

    mainDragGroup: function(groupNode){
        this.groupNode = groupNode || this.groupNode;
        this.setGroupNode();
        this.applyAutoCollect();
        this.setEventNodes();
        this.setEvents();

        mc.component.Component.isExec(this, 'draggroup', this.groupNode);
        return this;
    },

    setGroupNode: function(){
        mc.get(this.groupNode || this.dragTarget)
          .setThis(this, 'groupNode');
    },

    applyAutoCollect: function(){
        if (this.autoCollect){
            mc.getChildNodes(false, this.groupNode)
              .setThis(this, 'eventNodes');
        }
    },

    setEventNodes: function(ens){
        if (this.eventNodes.length == 0){
            this.eventNodes[0] = mc.get(this.groupNode).chain;
        };
    },

    setEvents: function(){
        if (!this._setEvents){
            mc.on(this.groupNode, 'mousedown', this.mouseDownGroup, this);
            this._setEvents = true;
        }
    },

    removeEvents: function(){
        mc.off(this.groupNode, 'mousedown', this.mouseDownGroup, this);
        this._setEvents = false;
    },

    mouseDownGroup: function(e, tg, opts){
        if (!(tg = this.checkEventNode(tg)) || !(this.checkDraggable(e))){
            return false;
        }
        this.dragTarget = tg;
        if (this.manyChild){
            this.mainDragDrop(tg);
            if (this.eventNodes.length == 1){
                this.manyChild = false;
            }
        }
        this.setDDMouseDown(e, tg, opts);
        return this;
    },

    checkEventNode: function(tg){
        if (!tg){
            return false;
        }
        var i,
            en = this.eventNodes,
            len = en.length;

        if (mc.isContains(en, tg).chain){
            return tg;
        }
        for (i = 0; i < len; i++){
            if (mc.isDescendant(tg, en[i]).chain){
                return tg;
            }
        }
        return false;
    },

    addEventNodes: function(ens){
        var i,
            ens = mc.toArray(ens).chain,
            len = ens.length,
            en;

        for (i = 0; i < len; i++) {
            en = ens[i];
            if (mc.isDescendant(en, this.groupNode).chain) {
                if (!(mc.isContains(this.eventNodes, en).chain)) {
                    this.eventNodes[this.eventNodes.length] = typeof en === 'string' ? en : en.id;
                }
            };
        }
    }
});


mc.dragdrop.ResizingProxy = function(opts){
    mc.widget.Widget.setOptions(this, opts);
    this.mainResizingProxy();
};

mc.dragdrop.ResizingProxy.prototype = {
    prefix: 'mc_resizingproxy_',
    proxyClass: 'mc-resizing-proxy',
    proxyParent: null,
    useRange: true,
    ccode: 'resizingproxy',

    mainResizingProxy: function(target){
        this.target = target || this.target;
        this.createResizeProxy();
        this.createRangeProxy();
        this.setEvents();

        mc.component.Component.isExec(this, 'resizingproxy', this.target);
        return this;
    },

    createResizeProxy: function(){
        if (!this.resizeProxy){
            this.setProxyParent();
            mc.createAppend('div', false, this.prefix, this.proxyParent)
              .setThis(this, 'resizeProxy')
              .addClass(this.proxyClass, this.resizeProxy);
        }
        if (this.directDrag){
            mc.setVisibility(false, this.resizeProxy);
        }
    },

    setProxyParent: function(el){
        this.proxyParent = el || this.proxyParent || mc.getBody().chain;
    },

    createRangeProxy: function(){
        if (!this.rangeProxy){
            mc.createAppend('div', false, this.prefix, this.proxyParent)
              .setThis(this, 'rangeProxy')
              .addClass('mc-resizing-range', mc.chain);
        }
    },

    setEvents: function(){
        if (!this._setEvents && this.useRange){
            mc.on([this.rangeProxy, 'mousemove', this.mouseMoveEvent, this],
                  [this.rangeProxy, 'mouseup', this.mouseUpEvent, this]);
            this._setEvents = true;
        }
    },

    removeEvents: function(){
        mc.off([this.rangeProxy, 'mousemove', this.mouseMoveEvent, this],
               [this.rangeProxy, 'mouseup', this.mouseUpEvent, this]);
        this._setEvents = false;
    },

    setDocEvents: function(){
        mc.widget.Event.documentOn(this, 'mousemove', this.mouseMoveEvent)
                       .documentOn(this, 'mouseup', this.mouseUpEvent);
    },

    removeDocEvents: function(){
        mc.widget.Event.documentOff(this, 'mousemove', this.mouseMoveEvent)
                       .documentOff(this, 'mouseup', this.mouseUpEvent);
    },

    mouseMoveEvent: function(e, tg, opts){
    },

    mouseUpEvent: function(){
        mc.setDisplay(false, this.rangeProxy);
        if (!this.directDrag){
            mc.setDisplay(false, this.resizeProxy);
        }
    },

    setProxyWHXY: function(){
        mc.setOwn(this.resizeProxy)
          .getBPValue('LR')
          .setThis(this, 'dragWidthLR')
          .getBPValue('TB')
          .setThis(this, 'dragHeightTB')
          .setStyle({display : 'block'})
          .setWHXY(this.stw - this.dragWidthLR, this.sth - this.dragHeightTB, this.stx, this.sty, 'BP');
    },

    setRangeProxy: function(tg){
        mc.getStyle('cursor', tg)
          .chainDup()
          .getDocWH()
          .setStyle({width: mc.chain[0], height: mc.chain[1], display: 'block', cursor: mc.dup}, this.rangeProxy);
    },

    setRangeStyle: function(tg){
        mc.getStyle('cursor', tg)
          .setStyle({display: 'block', cursor: mc.chain}, this.rangeProxy);
    }
};


mc.dragdrop.Resizing = function(opts){
    mc.widget.Widget.setOptions(this, opts);
    if (this.target) {
        this.mainResizing(this.target);
    }
};

mc.extend(mc.dragdrop.Resizing, mc.dragdrop.ResizingProxy, {
    autoRatio: false,
    directDrag: false,
    dragBar: false,
    handles: 'e,s,se',
    handlesText: {
        e: 'east',
        w: 'west',
        s: 'south',
        n: 'north',
        se: 'southeast',
        sw: 'southwest',
        ne: 'northeast',
        nw: 'northwest'
    },

    height: 50,
    maxHeight: 5000,
    maxWidth: 5000,
    minHeight: 10,
    minWidth: 20,

    mouseOver: false,
    needWrap: false,
    prefix: 'mc_resizing_',
    resizable: true,

    target: '',
    targetClass: '',
    targetStyle: '',
    width: 100,

    ccode: 'resizing',
    dragStatus: false,
    targetChild: '',

    mainResizing: function(target){
        this.target = target || this.target;
        this.setTarget();
        this.applyOptions();
        this.mainResizingProxy();
        this.setHandles();

        mc.component.Component.isExec(this, 'resizing', this.target);
        return this;
    },

    setTarget: function(){
        if (!(mc.get(this.target).chain)){
            mc.widget.Message.show('E1010', this.ccode, 'Target Element');
            return;
        }
        var need = /button|img|input|select|textarea/i.test(mc.chain.tagName);
        this.needWrap || need ? this.createWrap(mc.chain) : this.target = mc.chain;
    },

    createWrap: function(tg){
        mc.setThis(this, targetChild, tg)
          .createElement('div', this.id, this.prefix)
          .insertAhead(mc.chain, tg)
          .setThis(this, 'target')
          .setOwn(this.target)
          .appendEnd(tg)
          .addClass('mc-resizing-wrap')
          .getTrblStyle(tg)
          .setStyle(mc.chain)
          .getStyle('position', tg)
          .setStyle({'position': mc.chain});
    },

    applyOptions: function(){
        mc.setOwn(this.target);
        this.setOptionsAttr();
        this.setResizingOptions();
        this.cacheBP();
        this.setTargetChild();
    },

    setOptionsAttr: function(){
        mc.getStyle('position');
        if (mc.chain != 'fixed' && mc.chain != 'absolute'){
            mc.setStyle({position: 'relative'});
        }
        mc.addClass(this.targetClass)
          .setStyle(this.targetStyle);

        if (mc.component.Component.isOwn(this, 'resizing')){
            mc.setWHXY(this.width, this.height, this.leftX, this.topY, 'BP');
            mc.widget.Widget.applyAttr(this);
        }
    },

    setResizingOptions: function(){
        if (this.dragBar && !this.mouseOver){
            mc.addClass('mc-resizing-bar');
        }
        this.autoRatio = this.autoRatio === true;
    },

    cacheBP: function(){
        mc.getBPValue('LR')
          .setThis(this, 'targetWidthLR')
          .getBPValue('TB')
          .setThis(this, 'targetHeightTB');
    },

    setTargetChild: function(){
        if (this.targetChild){
            mc.setStyle({positon: 'static'}, this.targetChild)
              .setTrblStyle('', '', '', '', this.targetChild)
              .setChildWidth(this.targetChild)
              .setChildHeight(this.targetChild);
        }
    },

    setHandles: function(){
        if (!this.newTemplate){
            var tp = '<div id="{0}" class="mc-resizing mc-resizing-{1}"></div>';
            this.newTemplate = mc.newTemplate(tp).Template;
        }
        this.setSideBar();
        this.ce.fireEvent('setHandles', this.handles, this.target, this);
    },

    setSideBar: function(){
        if (this.handles == 'all'){
            this.handles = 'e,w,s,n,se,sw,ne,nw';
        }
        mc.commaSplit(this.handles)
          .setThis(this, 'handles');

        var tx;
        mc.eachArray(this.handles, function(hd){
            if (tx = this.handlesText[hd]){
                this.createSideNode(tx);
                this.setSideEvent(tx);
            }
        }, this)
    },

    createSideNode: function(tx){
        var map = [],
            txt,
            sn;

        map[0] = mc.id(false, this.prefix).chain;
        map[1] = tx;
        sn = this.newTemplate.apply(this.target, 'beforeEnd', map).chain;

        if (mc.IE6 && (tx == 'east' || tx == 'west')){
            mc.getParent(false, sn)
              .getHeight(false, mc.chain)
              .setHeight(mc.chain, 'BP', sn);
        }
        this[tx] = sn;
    },

    setSideEvent: function(tx){
        var nd = this[tx],
            barClass = this.dragBar && this.mouseOver ? 'mc-resizing-bar' : '';

        mc.widget.Event.overOut(this, nd, this.target, barClass);
        mc.on(nd, 'mousedown', this.mouseDownEvent, this, {bubble: true, side: tx});
    },

    setEvents: function(){
        if (!this._setEvents && this.useRange){
            mc.dragdrop.Resizing.superclass.setEvents.call(this);
            this._setEvents = true;
        }
    },

    removeEvents: function(){
        mc.dragdrop.Resizing.superclass.removeEvents.call(this);
        this._setEvents = false;
    },

    mouseDownEvent: function(e, tg, opts){
        if (!this.resizable){
            return;
        }
        this.setDragConfig(opts);
        mc.getWHXY(false, this.target);
        this.setDragBase(mc.chain, e);

        this.setProxyWHXY();
        this.setRangeProxy(tg);
        this.setChangeXY();
        this.ce.fireEvent('resizeStart', e, tg, opts, this);
    },

    setDragConfig: function(opts){
        this.eventSide = opts.side;
        this.setDragStatus(true);
        this.targetWidthLR = this.targetWidthLR || 0;
        this.targetHeightTB = this.targetHeightTB || 0;
    },

    setDragBase: function(whxy, e){
        this.stw = whxy[0];
        this.sth = whxy[1];
        this.stx = whxy[2];
        this.sty = whxy[3];
        this.stex = e.pageX;
        this.stey = e.pageY;

        this.psw = whxy[0];
        this.psh = whxy[1];
        this.psx = whxy[2];
        this.psy = whxy[3];
        this.psex = e.pageX;
        this.psey = e.pageY;
    },

    setChangeXY: function(){
        this.changeXY = '';
        if (mc.isInclude(this.eventSide, 'west').chain){
                this.changeXY += 'x';
        }
        if (mc.isInclude(this.eventSide, 'north').chain){
                this.changeXY += 'y';
        }
    },

    mouseMoveEvent: function(e, tg, opts){
        if (!this.resizable || !this.dragStatus){
            return false;
        }
        this.moveX = e.pageX - this.stex;
        this.moveY = e.pageY - this.stey;
        this[this.eventSide + 'Move'](this.autoRatio);

        this.setMovedWHXY(true);
        if (this.directDrag){
            this.targetUpdate();
        }
        this.ce.fireEvent('resizeMove', e, tg, opts, this);
    },

    eastMove: function(ar){
        this.psw = Math.min(Math.max(this.stw + this.moveX, this.minWidth), this.maxWidth);
        if (ar){
            var ht = Math.round(this.sth * (this.psw / this.stw));
            this.psh = Math.min(Math.max(this.minHeight, ht), this.maxHeight);
        }
    },

    westMove: function(ar){
        var mw = this.stw - this.moveX;
        if (mw >= this.minWidth && mw <= this.maxWidth){
            this.psw = mw;
            this.psx = this.stx + this.moveX;
        }
        if (ar){
            var ht = Math.round(this.sth * (this.psw / this.stw));
            if (ht >= this.minHeight && ht <= this.maxHeight){
                this.psh = ht;
                this.psy = this.sty + (this.sth - ht);
            }
        }
    },

    southMove: function(ar){
        this.psh = Math.min(Math.max(this.sth + this.moveY, this.minHeight), this.maxHeight);
        if (ar){
            var wd = Math.round(this.stw * (this.psh / this.sth));
            this.psw = Math.min(Math.max(this.minWidth, wd), this.maxWidth);
        }
    },

    northMove: function(ar){
        var dh = this.sth - this.moveY;
        if (dh >= this.minHeight && dh <= this.maxHeight){
            this.psh = dh;
            this.psy = this.sty + this.moveY;
        }
        if (ar){
            var wd = Math.round(this.stw * (this.psh / this.sth));
            if (wd >= this.minWidth && wd <= this.maxWidth){
                this.psw = wd;
                this.psx = this.stx + (this.stw - wd);
            }
        }
    },

    southeastMove: function(){
        this.eastMove(false);
        this.southMove(false);
    },

    southwestMove: function(){
        this.westMove(false);
        this.southMove(false);
    },

    northeastMove: function(){
        this.eastMove(false);
        this.northMove(false);
    },

    northwestMove: function(){
        this.westMove(false);
        this.northMove(false);
    },

    westGrid: function(){
        if ((this.moveX > 0 && this.moveX < this.maxWidth) || (this.moveX < 0 && ((this.esWidth + this.moveX) >= this.minWidth))){
            this.psx = this.stx + this.moveX;
        } else if (this.moveX == 0){
            this.psx = this.stx;
        }
    },

    setMovedWHXY: function(tn){
        var node = tn ? this.resizeProxy : this.target;
        var stl = node.style,
            value;

        value = this.psw - (tn ? this.dragWidthLR : this.targetWidthLR);
        if (value > 0){
            stl.width = value + 'px';
        }
        value = this.psh - (tn ? this.dragHeightTB : this.targetHeightTB);
        if (value > 0){
            stl.height = value + 'px';
        }
        if (this.changeXY){
            this.setMovedXY(node);
        }
    },

    setMovedXY: function(node){
        if (this.changeXY == 'x'){
            mc.setX(this.psx, node);
        } else if (this.changeXY == 'y'){
            mc.setY(this.psy, node);
        } else {
            mc.setXY(this.psx, this.psy, node);
        }
    },

    mouseUpEvent: function(e, tg, opts){
        mc.dragdrop.Resizing.superclass.mouseUpEvent.call(this);
        this.grid ? this.gridMouseUpEvent() : this.targetUpdate();
        this.setDragStatus(false);
        this.ce.fireEvent('resizeEnd', e, tg, opts, this);
    },

    targetUpdate: function(){
        this.setMovedWHXY(false);
        if (this.targetChild){
            mc.setChildWidth(this.targetChild, this.target)
              .setChildHeight(this.targetChild, this.target);
        }
        if (mc.IE6){
            if (this.east){
                mc.getParent(false, this.east)
                  .getHeight(false, mc.chain)
                  .setHeight(mc.chain, 'BP', this.east);
            }
            if (this.west){
                mc.getParent(false, this.east)
                  .getHeight(false, mc.chain)
                  .setHeight(mc.chain, 'BP', this.west);
            }
        }
    },

    setDragStatus: function(st){
        this.dragStatus = st;
    },

    isResizing: function(){
        return this.dragStatus;
    },

    setAutoRatio: function(ar){
        this.autoRatio = ar;
        this.ce.fireEvent('autoRatio', this.autoRatio, this.target, this);
    }
});


//---------------------
//@package: mc.panel
//---------------------

mc.panel.Panel = function(opts){
    mc.widget.Widget.setOptions(this, opts);
    if (this.showTo) {
        this.mainPanel(this.showTo);
    }
};

mc.panel.Panel.prototype = {
    autoScroll: false,
    createTitle: true,
    height: '',
    html: '',

    insideClass: 'mc-panel-inside',
    insideStyle: '',
    panelClass: 'mc-panel',
    panelStyle: '',

    prefix: 'mc_panel_',
    showBorder: false,
    width: '',

    ccode: 'panel',
    frameName: ['top', 'center', 'bottom', 'footer'],
    forcedWH: false,
    paramDup: true,
    usedFrameName: '',
    usedFrame: '',

    inside: '',
    outside: '',
    spreadTarget: '',
    titleNew: '',

    mainPanel: function(showTo){
        this.showTo = showTo || this.showTo;
        this.initPanel();
        this.createOutside();
        this.initAcumHeight();

        this.newTitle();
        this.setInside();
        this.setUsedName();

        this.createUsedFrame();
        this.setFrameWH();
        return this;
    },

    initPanel: function(){
        if (this.component){
            this.saveComponent = this.component;
        }
    },

    createOutside: function(){
        mc.createAppend('div', this.id, this.prefix, this.showTo)
          .setOwn(mc.chain)
          .setThis(this, 'outside')
          .addClass(this.panelClass)
          .setStyle(this.panelStyle);

        if (this.forcedWH || mc.component.Component.isOwn(this, 'panel')){
            mc.setWHXY(this.width, this.height, this.leftX, this.topY, 'BP');
            mc.widget.Widget.applyAttr(this);
        } else {
            mc.setChildWidth(this.outside, this.showTo);
        }
    },

    initAcumHeight: function(){
        if (this.height && this.height != 'auto'){
            this.acumHeight = 0;
        }
    },

    newTitle: function(parent){
        if (this.title){
            mc.widget.Widget.newTitle(this, parent || this.outside);
        }
    },

    setInside: function(){
        if (!this.inside){
            mc.createAppend('div', false, this.prefix, this.outside)
              .setThis(this, 'inside')
              .setOwn(mc.chain)
              .addClass(this.insideClass)
              .setStyle(this.insideStyle);
        };
        mc.setChildWidth(this.inside, this.outside);

        var title = this.titleNew,
            height = 0;

        if (title){
            title.setSpreadTarget(this.inside);
            height = title.getHeight();
        }
        mc.getHeight('BP', this.outside)
          .setHeight(mc.chain - height, 'BP');
    },

    setUsedName: function(){
        this.usedFrameName = {};
        this.usedFrame = [];

        var frame = this.frameName,
            len = frame.length,
            i,
            fm,
            usedLen;

        for (i = 0; i < len; i++){
            usedLen = this.usedFrame.length;
            fm = frame[i];
            mc.firstLetter(fm);
            this['checkUsed' + mc.chain](usedLen, fm);
        }
    },

    setName: function(ids){
        var i,
            len = ids.length,
            names = [];

        for (i = 0; i < len; i++){
            if (this[ids[i]]){
                names[names.length] = ids[i];
            }
        }
        return names;
    },

    checkUsedTop: function(len, fm){
        if (this.top) {
            this.usedFrame[len] = fm;
            var ids = ['top'];
            this.usedFrameName['top'] = this.setName(ids);
        }
    },

    checkUsedCenter: function(len, fm){
        this.usedFrame[len] = fm;
        var ids = ['center', 'component', 'html', 'nodes', 'server'];
        this.usedFrameName['center'] = this.setName(ids);
    },

    checkUsedBottom: function(len, fm){
        if (this.bottom || this.buttons) {
            this.usedFrame[len] = fm;
            var ids = ['bottom', 'buttons'];
            this.usedFrameName['bottom'] = this.setName(ids);
        }
    },

    checkUsedFooter: function(len, fm){
        if (this.footer) {
            this.usedFrame[len] = fm;
            var ids = ['footer'];
            this.usedFrameName['footer'] = this.setName(ids);
        }
    },

    createUsedFrame: function(){
        var used = this.usedFrame,
            len = used.length,
            i,
            frame;

        for (i = 0; i < len; i++){
            frame = used[i];
            this.createFrame(frame, i);

            if (frame != 'center'){
                mc.firstLetter(frame);
                this['set' + mc.chain]();
            }
        }
        delete this.component;
    },

    createFrame: function(frame, ix){
        var box = frame + 'Box',
            opts = this.getOptionName(frame),
            value;

        if (!this[box]){
            value = this.getOptionValue(opts, 'id');
            mc.createAppend('div', value, this.prefix, this.inside)
              .setThis(this, box);
        }
        value = this.getOptionValue(opts, 'style');
        mc.addClass(('mc-panel-' + frame), this[box])
          .setStyle(value, mc.chainNode);

        if (!this.showBorder && this.usedFrame[ix + 1]){
            mc.addClass('mc-noborder-bottom', this[box]);
        }
        if (!this.titleNew && ix == 0 || (this.titleNew && mc.isVisible(this.titleNew.outside).chain == false)){
            mc.addClass('mc-panel-notitle', this[box]);
        }
    },

    getOptionName: function(frame){
        return this.usedFrameName[frame] || [];
    },

    getOptionValue: function(opts, pty){
        var value = '',
            i,
            len = opts.length,
            hash;

        for (i = 0; i < len; i++){
            hash = this[opts[i]];
            if (hash && !value){
                value = hash[pty];
            }
        }
        return value || '';
    },

    setEvents: function(){
    },

    setTop: function(){
        this.component = this.top;
        mc.component.Component.isExec(this, 'panel', this.topBox);
    },

    setCenter: function(){
        if (this.saveComponent){
            this.component = this.saveComponent;
            mc.component.Component.isExec(this, 'panel', this.centerBox);
        }
        if (this.center){
            this.component = this.center;
            mc.component.Component.isExec(this, 'panel', this.centerBox);
        }
        if (this.html){
            mc.createChild(this.html, this.centerBox);
        }
        if (this.nodes){
            ct.nodes = this.nodes;
            this.setNodes(this.centerBox, this[frame]);
        }
    },

    setBottom: function(){
        if (this.bottom){
            this.component = this.bottom;
            mc.component.Component.isExec(this, 'panel', this.bottomBox);
        }
        if (this.buttons){
            this.component = this.buttons;
            mc.component.Component.isExec(this, 'panel', this.bottomBox);
        }
    },

    setFooter: function(){
        this.component = this.footer;
        mc.component.Component.isExec(this, 'panel', this.footerBox);
    },

    setFrameWH: function(ah){
        var used = this.usedFrame,
            len = used.length,
            i,
            frame,
            ct,
            opts,
            el;

        for (i = 0; i < len; i++){
            frame = used[i];
            ct = this.usedFrameName[i],
            opts = this.paramOpts[ct] || {},
            el = this[frame + 'Box'];
            opts.width ? mc.setWidth(opts.width, 'BP', el) : mc.setChildWidth(el, this.outside);

            if (frame != 'center'){
                if (opts.height){
                    me.setHeight(opts.height, 'BP', el);
                }
                if (this.height && this.height != 'auto'){
                    this.acumHeight += mc.getHeight(false, el).chain;
                }
            }
        }

        this.setCenterHeight(ah);
        opts = this.paramOpts['center'];
        if ((opts && opts.autoScroll) || this.autoScroll){
            mc.setOverflow('auto', this.centerBox);
        }
        if (this.centerBox) {
            this.setCenter();
        }
    },

    setCenterHeight: function(ah){
        if (this.height && this.height != 'auto'){
            this.acumHeight += (ah || 0);
            mc.getHeight('BP', this.inside)
              .setHeight((mc.chain - this.acumHeight), 'BP', this.centerBox);
        }
    },

    getCenter: function(){
        return this.centerBox;
    },

    getCenterWH: function(){
        return mc.getWH('BP', this.centerBox).chain;
    },

    getTitleNew: function(){
        return this.titleNew;
    }
};


mc.panel.Tabs = function(opts){
    mc.widget.Widget.setOptions(this, opts);
    if (this.showTo) {
        this.mainTabs(this.showTo);
    }
};

mc.panel.Tabs.prototype = {
    closable: true,
    createTitle: true,
    id: '',
    ime: false,
    insideClass: 'mc-tabs-inside',
    insideStyle: '',

    leftBtnClass: 'mc-tabs-scroll-left',
    outsideClass: ['mc-tabs', 'mc-font-one'],
    outsideStyle: '',
    prefix: 'mc_tabs_',
    rightBtnClass: 'mc-tabs-scroll-right',

    scrollWidth: '',
    showTabIndex: 0,
    tabCloseTitle: '텝 닫기',
    tabDisable: false,
    tabHideClass: 'mc-display-none',

    tabClass: '',
    tabScroll: true,
    tabStyle: '',
    tabText: '',
    tabWidth: 100,

    tabTextAlign: '',
    textClass: '',
    textStyle: '',

    ccode: 'tabs',
    componentIndex: 'init',
    defaultCcode: 'panel',
    memberIndex: '',
    minWidth: 40,
    tabNodes: [],

    boxInside: '',
    inside: '',
    leftButton: '',
    outside: '',
    rightButton: '',
    tabBox: '',
    tabNodes: '',

    mainTabs: function(showTo){
        this.showTo = showTo || this.showTo;
        this.tapsOptions();
        this.createOutside();
        this.newTitle();
        this.createInside();

        this.createTabBox();
        this.createTable();
        this.setTabs();

        this.setScroll();
        this.setScrollShow();
        this.setEvents();
        this.setPanelCcode();
        this.execComponent();
    },

    tapsOptions: function(){
        this.memberIndex = [];
    },

    createOutside: function(){
        mc.createAppend('div', this.id, this.prefix, this.showTo)
          .setOwn(mc.chain)
          .setThis(this, 'outside')
          .addClass(this.outsideClass)
          .setStyle(this.outsideStyle);

        if (this.forcedWH || mc.component.Component.isOwn(this, 'tabs')){
            mc.setWHXY(this.width, this.height, this.leftX, this.topY, 'BP');
            mc.widget.Widget.applyAttr(this);
        } else {
            mc.setChildWidth(this.outside, this.showTo);
        }
    },

    newTitle: function(){
        this.title = this.title || {};
        this.title.titleType = 'default';
        mc.widget.Widget.newTitle(this, this.outside);
    },

    createInside: function(){
        mc.createAppend('div', false, this.prefix, this.outside)
          .setThis(this, 'inside')
          .setOwn(mc.chain)
          .addClass(this.insideClass)
          .setStyle(this.insideStyle);

        if (this.tabScroll){
            mc.addClass('mc-tabs-scroll');
        }
        mc.getWidth('BP')
          .setWidth(mc.chain, false);

        this.tabWidth = parseInt(this.tabWidth, 10);
        if (this.tabWidth < this.minWidth){
            this.tabWidth = this.minWidth;
        }
        this.scrollWidth = this.scrollWidth || this.tabWidth;
    },

    createTabBox: function(){
        mc.createAppend('div', false, this.prefix, this.inside)
          .setThis(this, 'tabBox')
          .addClass('mc-tabs-box', mc.chain)
          .setChildWidth(this.tabBox, this.inside)
          .createAppend('div', false, this.prefix, this.tabBox)
          .setThis(this, 'boxInside')
          .addClass('mc-tabs-boxinside', mc.chain)
          .toArray(this.tabText)
          .setThis(this, 'tabText');
    },

    createTable: function(){
        var tps = '<table id="{0}" border="0" cellpadding="0" cellspacing="0"><tbody><tr id="{1}">',
            tpe = '</tr></tbody></table>',
            map = [],
            tbl;

        map[0] = mc.id(false, this.prefix).chain;
        map[1] = mc.id(false, this.prefix).chain;
        tbl = tps + this.createTrTd() + tpe;
        mc.newTemplate(tbl).Template.apply(this.boxInside, 'beforeEnd', map);
        mc.get(map[1])
          .setThis(this, 'trElement');

        this.tabNodes = mc.getChildNodes(false, this.trElement).chain;
    },

    createTrTd: function(){
        var tdTpl = '<td id="{0}"></td>',
            i,
            len = this.component.length,
            mapTd = [],
            tds = [];

        this.tdNodes = [];
        for (i = 0; i < len; i++) {
            mapTd[0] = mc.id(false, this.prefix).chain;
            this.tdNodes[i] = mc.chain;
            tds[i] = mc.newTemplate(tdTpl).Template._convert(mapTd);
        }
        return tds.join('');
    },

    setTabs: function(){
        this.setTemplate();
        mc.eachArray(this.paramOpts.component, function(cmpt, ix){
            this.createEachTab(cmpt, ix);
        }, this);
    },

    setTemplate: function(){
        if (!this.newTemplate){
            var tpl = '<div id="{wrapID}" class="{wrapClass}" {wrapStyle}>' +
                          '<div class="mc-tabs-left" unselectable="on"></div>' +
                          '<div class="mc-tabs-center" style="{wd}">' +
                              '<span id="{textID}" class="{txcn}" {txst} unselectable="on">{text}</span></div>' +
                          '<div class="mc-tabs-right"></div>' +
                          '<div id="{btnID}" {close} title="{closeTitle}"></div>' +
                      '</div>';

            this.newTemplate = mc.newTemplate(tpl).Template;
        }
    },

    createEachTab: function(cmpt, idx){
        var ta = '';
        var map = this.setEachText(cmpt, this.setClosable(cmpt), idx);
        if (this.tabTextAlign || cmpt.tabTextAlign){
            ta = cmpt.tabTextAlign ? ('text-align:' + cmpt.tabTextAlign + '; ') : '';
            if (!ta){
                ta = this.tabTextAlign ? ('text-align:' + this.tabTextAlign + '; ') : '';
            }
        }
        map.wrapStyle = '';
        if (cmpt.tabStyle || ta){
            map.wrapStyle = 'style="' + ((cmpt.tabStyle || '') + ta) + '"';
        }
        this.newTemplate.apply(this.tabNodes[idx], 'beforeEnd', map);
    },

    setClosable: function(cmpt){
        var map = {},
            wrap = 'mc-tabs-wrap',
            close = 'class="mc-tabs-closable"';

        map.btnID = mc.id(false, this.prefix).chain;
        map.close = this.closable ? close : '';

        if (cmpt.closable !== undefined){
            map.close = cmpt.closable ? close : '';
        }
        map.closeTitle = this.tabCloseTitle;
        map.wrapID = mc.id(false, this.prefix).chain;

        wrap +=  map.close ? ' mc-tabs-close-show' : '';
        wrap += cmpt.tabDisable ? ' mc-disable' : '';
        wrap += cmpt.tabClass ? (' ' + cmpt.tabClass) : '';

        if (this.ime && cmpt.ime !== false){
            wrap += ' mc-ime';
        }
        map.wrapClass = wrap;
        return map;
    },

    setEachText: function(cmpt, map, idx){
        map.textID = mc.id(false, this.prefix).chain;
        this.setTabText(cmpt.tabText, idx);

        map.text = this.tabText[idx];
        map.txcn = 'mc-unselectable mc-tabs-text' + (cmpt.textClass ? (' ' + cmpt.textClass) : '');

        var wd = cmpt.tabWidth || this.tabWidth;
        wd = parseInt(wd, 10);
        if (wd < this.minWidth){
            wd = this.minWidth;
        }
        map.wd = 'width:' + (wd - 20) + 'px;'

        map.txst = '';
        if (this.textStyle || cmpt.textStyle){
            var ts = cmpt.textStyle ? (cmpt.textStyle + ';') : '';
            if (!ts){
                ts = this.textStyle ? (this.textStyle + ';') : '';
            }
            map.txst = 'style="' + ts + '"';
        }
        return map;
    },

    setTabText: function(text, idx){
        if (text){
            this.tabText[idx || 0] = text || '';
        }
    },

    setScroll: function(scroll){
        if (this.tabScroll && !this.leftButton){
            mc.getHeight('BP', this.tabBox)
              .chainDup()
              .createElement('div', false, this.prefix)
              .setThis(this, 'rightButton')
              .insertAhead(mc.chain, this.tabBox)
              .addClass(this.rightBtnClass, mc.chain)
              .setHeight(mc.dup, false, this.rightButton)
              .createElement('div', false, this.prefix)
              .setThis(this, 'leftButton')
              .insertAhead(mc.chain, this.rightButton)
              .addClass(this.leftBtnClass, mc.chain)
              .setHeight(mc.dup, false, this.leftButton);
        }
    },

    setScrollShow: function(){
        if (!this.tabScroll){
            return;
        }
        var total = 0,
            sh;

        mc.eachArray(this.tabNodes, function(node){
            total += mc.getWidth(false, node).chain;
        }, this);

        sh = (total + 32) >= parseInt(this.width, 10);
        this.setButtonHide(sh);
        if (sh) {
            this.setUsable();
        } else if (mc.getScroll('L', this.tabBox).chain){
            mc.scrollElement({L: this.scrollWidth * -1}, this.tabBox);
        }
    },

    setButtonHide: function(show){
        if (this.tabScroll){
            mc.setVisibility(show, this.leftButton)
              .setVisibility(show, this.rightButton);
        }
        show ? mc.addClass('mc-tabs-scroll', this.inside) :
               mc.removeClass('mc-tabs-scroll', this.inside);

        mc.getWidth('BP', this.inside);
        if (show){
            mc.chain -= 32;
        }
        mc.setWidth(mc.chain + 'px', 'BP', this.tabBox);
    },

    setUsable: function(){
        if (!this.tabScroll){
            return;
        }
        var sl,
            lb,
            sw,
            rb;

        sl = mc.getScroll('L', this.tabBox).chain;
        lb = sl == 0 ? true : false;
        lb ? mc.addClass('mc-tabs-left-disabled', this.leftButton) :
             mc.removeClass('mc-tabs-left-disabled', this.leftButton);

        sw = this.getScrollWidth() - mc.getClient('W', this.tabBox).chain;
        rb = sl < sw ? false : true;
        rb ? mc.addClass('mc-tabs-right-disabled', this.rightButton) :
             mc.removeClass('mc-tabs-right-disabled', this.rightButton);
    },

    getScrollWidth: function(){
        return this.getOffsetX() + mc.getScroll('L', this.tabBox).chain;
    },

    getOffsetX : function(){
        var tn = this.tabNodes,
            el = tn[tn.length - 1];
        return mc.getOffsetX(el).chain - mc.getX(this.tabBox).chain;
    },

    scrollElement: function(pos){
        mc.scrollElement({L: pos}, this.tabBox);
        this.setUsable();
        this.ce.fireEvent('tabScroll', pos, this);
    },

    setPanelCcode: function(addCmpt){
        var paramOpts = addCmpt || this.paramOpts.component;
        if (paramOpts){
            mc.eachArray(paramOpts, function(cmpt, idx){
                if (!cmpt.ccode){
                    cmpt.ccode = 'panel';
                }
            }, this)
        }
        return paramOpts;
    },

    execComponent: function(addCmpt, index){
        var paramOpts = addCmpt || this.paramOpts.component;
        if (!paramOpts){
            return;
        }
        if (!this.compSide){
            mc.createAppend('div', false, this.prefix, this.outside)
              .setThis(this, 'compSide')
              .addClass('mc-tabs-contents', mc.chain)
              .setChildWidth(this.compSide, this.outside);
        }

        if (this.height){
            var height = parseInt(this.height, 10);
            if (this.titleNew){
                height -= this.titleNew.getHeight();
            }
            height -= mc.getHeight(false, this.inside).chain;
            mc.setHeight(height, 'BP', this.compSide);
        }

        if (!addCmpt){
            mc.eachArray(paramOpts, function(cmpt, idx){
                this.eachComponent(cmpt, idx);
            }, this)
        }
    },

    eachComponent: function(codeComp, idx){
        this.component = this.setPanelOptions(codeComp);
        delete this.component.showTo;

        mc.component.Component.isExec(this, 'tabs', this.compSide);
        this.memberIndex[idx] = this.component.id;

        mc.getChildNodes(false, this.compSide)
          .setThis(this, 'compParents');

        var ix = this.componentIndex == 'init' ? idx : this.componentIndex;
        if (this.componentIndex == 'init'){
            ix == this.showTabIndex ? this.showContent(ix) :
                                      mc.addClass(this.tabHideClass, this.compParents[ix]);
        } else {
            var nds = this.compParents;
            mc.insertAhead(nds[nds.length - 1], nds[ix])
              .getChildNodes(false, this.compSide)
              .setThis(this, 'compParents');

            this.showContent(ix);
        }
    },

    setPanelOptions: function(cmpt){
        cmpt.id = cmpt.id || mc.id(false, this.prefix).chain;
        cmpt.autoScroll = this.autoScroll;

        if (this.height){
            cmpt.height = mc.getHeight('BP', this.compSide).chain;
        }
        if (!cmpt.title){
            cmpt.createTitle = false;
        }
        return cmpt;
    },

    setCompOptions: function(cmpt){
        cmpt.ccode = 'panel';
        cmpt.id = cmpt.id || mc.id(false, this.prefix).chain;
        cmpt.autoScroll = this.autoScroll;

        if (this.height){
            cmpt.height = mc.getHeight('BP', this.compSide).chain;
        }
        if (!cmpt.title){
            cmpt.createTitle = false;
        }
    },

    setEvents: function(){
        mc.on(this.tabBox, 'mousedown', this.mousedownTab, this);
        if (this.leftButton){
            mc.on([this.leftButton, 'mousedown', this.mousedownLeft, this],
                  [this.rightButton, 'mousedown', this.mousedownRight, this]
            );
        }
        mc.eachArray(this.tabNodes, function(node){
            this.addEvent(node);
        }, this)
    },

    addEvent: function(el){
        mc.on([el, 'mouseover', this.mouseOverEvent, this, {bubble: true}],
              [el, 'mouseout', this.mouseOutEvent, this, {bubble: true}]
        );
    },

    removeEvent: function(el){
        mc.off([el, 'mouseover', this.mouseOverEvent, this],
               [el, 'mouseout', this.mouseOutEvent, this]
        );
    },

    mouseOverEvent: function(e, tg, opts){
        var ch = this.choicedTab(e, tg);
        if (this.showTabIndex != ch){
            var node = this.getIndexTab(ch);
            mc.widget.Event.mouseOverEvent(e, tg, {cn: 'mc-tabs-over', el: node});
        }
    },

    mouseOutEvent: function(e, tg, opts){
        var node = this.getIndexTab(this.choicedTab(e, tg));
        mc.widget.Event.mouseOutEvent(e, tg, {cn: 'mc-tabs-over', el: node});
    },

    mousedownTab: function(e, tg){
        var index = this.choicedTab(e, tg);
        if (index < 0){
            return;
        }
        this.showTabIndex = index;
        this.ce.fireEvent('mousedownTab', e, tg, this);

        var closeClick = this.isDownClose(tg);
        if (closeClick){
            this.removeTab(this.showTabIndex);
        } else {
            var node = this.getIndexTab(this.showTabIndex);
            mc.removeClass('mc-tabs-over', node);
            this.showContent(this.showTabIndex);
        }
    },

    isDownClose: function(tg){
        return tg['className'] == 'mc-tabs-closable' ? true : false;
    },

    choicedTab: function(e, tg){
        var idx,
            evn,
            pt,
            i;

        if ((idx = this.getTabIndex(tg)) < 0){
            evn = tg;
            for (i = 0; i < 4; i++){
                pt = mc.getParent(false, evn).chain;
                if ((idx = this.getTabIndex(pt)) > -1) {
                    break;
                }
                evn = pt;
            }
        };
        return idx;
    },

    mousedownLeft: function(e, tg){
        var sl = mc.getScroll('L', this.tabBox).chain;
        var mw = Math.max(0, sl - this.scrollWidth);
        if(sl != mw){
            this.scrollElement(mw);
        }
        this.ce.fireEvent('mousedownLeft', e, tg, this);
    },

    mousedownRight: function(e, tg){
        var sw = this.getScrollWidth() - mc.getClient('W', this.tabBox).chain;
        var sl = mc.getScroll('L', this.tabBox).chain;
        var mw = Math.min(sw, sl + this.scrollWidth);
        if(sl != mw){
            this.scrollElement(mw);
        }
        this.ce.fireEvent('mousedownRight', e, tg, this);
    },

    getTabIndex: function(el){
        return mc.indexOfArray(this.tabNodes, el).chain;
    },

    getIndexTab: function(index){
        return this.tabNodes[index];
    },

    showContent: function(index){
        var tn = this.tabNodes,
            nd = tn[index];

        mc.eachArray(this.compParents, function(cp, idx){
            if (index == idx){
                mc.removeClass(this.tabHideClass, cp)
                  .addClass('mc-tabs-down', nd);
            } else {
                mc.addClass(this.tabHideClass, cp)
                  .removeClass('mc-tabs-down', tn[idx])
            }
        }, this)

        this.ce.fireEvent('tabChange', index, this.compParents[index], this);
    },

    addTabs: function(){
        var args = Array.prototype.slice.call(arguments);
        mc.eachArray(args, function(tab, ix){
            this.addTab(tab[0], tab[1]);
        }, this)
    },

    addTab: function(index, comp){
        comp = comp || {};
        if (index > this.tabNodes.length){
            index = this.tabNodes.length;
        }
        var tdNode = this.trElement.insertCell(index);
        tdNode.id = mc.id(false, this.prefix).chain;

        this.tabNodes = mc.getChildNodes(false, this.trElement).chain;
        mc.addIndex(this.tabText, index, '')
          .setThis(this, 'tabText');

        this.createEachTab(comp, index);
        this.setScroll();
        this.setScrollShow();

        this.showTabIndex = index;
        this.componentIndex = index;
        mc.addIndex(this.memberIndex, index, '')
          .setThis(this, 'memberIndex');

        this.addEvent(this.tabNodes[index], index);
        if (!comp.ccode){
            comp.ccode = 'panel';
        }
        this.execComponent(comp, index);
        this.eachComponent(comp, index);
        this.ce.fireEvent('addTab', index, this);
    },

    removeTab: function(index){
        var tg = this.tabNodes[index];
        if (!tg) {
            return;
        }
        var idx,
            minusOne = this.tabNodes.length - 1;

        this.ce.fireEvent('removeTab', index, tg, this);
        if (minusOne != 0 && this.showTabIndex == index){
            idx = minusOne > index ? index + 1 : index - 1;
            this.showContent(idx);
        }

        this.removeEvent(tg);
        this.trElement.deleteCell(index);
        this.removeComponent(index);
        this.removeInstance(index);

        mc.removeIndex(this.tabNodes, index)
          .setThis(this, 'tabNodes');

        this.setScroll();
        this.setScrollShow();
        this.showTabIndex = this.isContains();
    },

    isContains: function(){
        var cp = this.compParents,
            i,
            len = cp.length,
            tc = this.tabHideClass;

        for (i = 0; i < len; i++){
            if (!(mc.hasClass(tc, cp[i]).chain)){
                return i;
            }
        }
        return false;
    },

    removeInstance: function(index){
        var mi = this.memberIndex[index];
        if (mi){
            mc.component.Instance.remove(mi);
            mc.removeIndex(this.memberIndex, index)
              .setThis(this, 'memberIndex');
        }
    },

    removeComponent: function(index){
        var el = this.compParents[index];
        if (el){
            mc.removeElement(el)
              .removeIndex(this.compParents, index)
              .setThis(this, 'compParents');
        }
    }
};

//------------------
//@package: mc.form
//------------------

mc.form.Calculator = function(opts){
    this.calcNodes = [];
    this.calcOptions = [];
    this.inputNodes = {};
    mc.widget.Widget.setOptions(this, opts);
};

mc.form.Calculator.prototype = {
    calcExp: /^\+|\-|\*|\/|max|min/i,
    ccode: 'calculator',
    compareExp: /==|!=|<|<=|>|>=/i,
    gridEvent: false,
    idCheckExp: /^\-|\*|\//i,
    mathExp: /abs|ceil|floor|round/i,

    mainCalculator: function(cmpt, msgName){
        this.setCalcOptions(cmpt, msgName);
        this.setEntryNodes();
        this.setEvents();
    },

    setCalcOptions: function(){
        if (typeof this.calcOptions[0] == 'string'){
            this.calcOptions = [this.calcOptions];
        }
        this.calcStatus = [];
        var calc = this.calcOptions,
            len = calc.length,
            i,
            opts,
            status;

        for (i = 0; i < len; i++){
            opts = calc[i];
            if (!opts){
                mc.widget.Message.show('E1041', this.ccode, 'options.calculator');
            }
            if ((opts[1] == 'checked' || opts[1] == 'selected') && opts[2]){
                opts = mc.addIndex(opts, 2, false).chain;
                calc[i] = opts;
            }
            if (opts[1] == '=' && opts[2]){
                opts[3] = opts[2];
                calc[i] = opts;
            }

            this.calcStatus[i] = [];
            status = this.calcStatus[i];

            this.addNode(status, 0, opts[0]);
            this.checkOperator(status, opts, i);
            this.checkNode(status, opts[1], opts[2]);
            this.addNode(status, 3, opts[3]);
            this.checkMath(status, opts[4]);
        }
    },

    addNode: function(status, index, id){
        var ccode = this.newComponent.ccodeIdList[id];
        if (!ccode){
            mc.widget.Message.show('E1020', this.ccode, id, 'options.ccode');
            return;
        }
        if (!(this.calcNodes[id])){
            this.calcNodes[id] = true;
        }
        status[index] = 'id';
        status[5] = this.setStatus(status, ccode);
    },

    checkOperator: function(status, opts, i){
        var op = opts[1];
        if (op == 'checked' || op == 'selected'){
            var type = this.newComponent.checkboxNodes[opts[0]];
            status[1] = type == 'r' ? 'rd' : type == 'c' ? 'ck' : type == 's' ? 'st' : '';
        } else if (op == '='){
            status[1] = 'set';
        } else {
            var rst = this.calcExp.test(op);
            status[1] = 'calc';
            if (!rst){
                rst = this.compareExp.test(op);
                status[1] = 'comp';
                if (!rst){
                    mc.widget.Message.show('E1042', this.ccode, 'options.calculator[' + this.calcOptions[i] + ']', op);
                }
            }
        }
    },

    checkNode: function(status, one, id){
        if (typeof one == 'number'){
            status[2] = 'nbr';
            return;
        }
        if ((one == 'checked' || one == 'selected') && !id){
            status[2] = status[1];
            return;
        }
        if (typeof id == 'string'){
            var ccode = this.newComponent.ccodeIdList[id];
            if (ccode){
                this.addNode(status, 2, id);
                return;
            }
            if (/^\-|\*|\//.test(one)){
                mc.widget.Message.show('E1020', this.ccode, id, 'options.ccode');
                return;
            }
        }
        status[2] = 'str';
    },

    checkMath: function(status, vl){
        if (!vl){
            status[4] = false;
            return;
        }
        if (typeof vl == 'number'){
            status[4] = 'nbr';
            return;
        }
        if (typeof vl == 'string'){
            if (status[1] == 'st' && (vl == 'value' || vl == 'text')){
                return status[4] = vl;
            }
            return this.mathExp.test(vl) ? status[4] = 'math' : this.addNode(status, 4, vl);
        }
        status[4] = 'str';
    },

    setStatus: function(status, ccode){
        var st = status[5];
        if (ccode.grid){
            st = (st == 'form' || st == 'all') ? 'all' : 'grid';
        } else {
            st = (st == 'grid' || st == 'all') ? 'all' : 'form';
        }
        return st;
    },

    setEntryNodes: function(mfd){
        var calc = this.calcNodes,
            nodes = this.inputNodes,
            list = this.newComponent.ccodeIdList,
            id,
            node;

        for (id in calc){
            node = list[id];
            if (node && node.input){
                nodes[id] = true;
            }
        }
    },

    setEvents: function(){
        var calc = this.calcNodes,
            newc = this.newComponent,
            list = newc.ccodeIdList,
            member = newc.formMember,
            event = mc.widget.Event,
            id,
            ck,
            cmpts,
            cmpt,
            ccc,
            type,
            len,
            i;

        for (id in calc){
            ck = list[id];
            if (ck && ck['input']){
                if (cmpt = member.get(id)){
                    ccc = cmpt.ccode;
                    if (ccc != 'radio' && ccc != 'radiogroup'){
                        type = ccc == 'checkbox' ? 'checked' : 'keyup';
                        event.customOn(cmpt, [type, this.keyupEvent, this]);
                    };
                };
            }
        }

        cmpts = newc.formMember.getFilters({ccode: 'radiogroup'});
        len = cmpts.length;
        for (i = 0; i < len; i++){
            cmpt = cmpts[i];
            event.customOn(cmpt, [['click', this.keyupEvent, this],
                                  ['keyup', this.keyupEvent, this]]);
        }

        cmpts = newc.formMember.getFilters({ccode: 'combo'});
        len = cmpts.length;
        for (i = 0; i < len; i++){
            cmpt = cmpts[i];
            event.customOn(cmpt, ['choiced', this.comboFormEvent, this]);
        }

        if (!mc.Gecko){
            cmpts = newc.formMember.getFilters({ccode: 'selectoption'});
            if (cmpts.length == 0){
                cmpts = newc.formMember.getFilters({ccode: 'labelselect'});
            }
            len = cmpts.length;
            for (i = 0; i < len; i++){
                cmpt = cmpts[i];
                event.customOn(cmpt, ['click', this.selectOptionEvent, this]);
            }
        }
    },

    keyupEvent: function(e, tg, opts, that, eventID, formGrid){
        if (e.type == 'click' && (tg.type != 'radio' && tg.type != 'checkbox' && tg.type != 'select-one')){
            return;
        }
        this.setEventOrigin(tg, eventID);
        if (this.eventOrigin == 'form' && (!eventID || !eventID[1]) && !formGrid){
            eventID = tg.id || '';
        }

        var mcdt = (typeof eventID == 'string' || '') ? '' : this.setMcdttd(eventID[1]);
        if (this.eventOrigin == 'form' && this.calcNodes[eventID] && this.gridEvent){
            this.applyFormValue();
        } else {
            this.setNodeValue(mcdt);
        };
    },

    setNodeValue: function(mcdt){
        var calcOpt = this.calcOptions,
            len = calcOpt.length,
            i,
            calc,
            status,
            value,
            values,
            check,
            value,
            mcdtId;

        for (i = 0; i < len; i++){
            calc = calcOpt[i];
            status = this.calcStatus[i];
            if (!this.forcedCalc && (this.eventOrigin == 'form' && status[5] == 'grid') || this.eventOrigin == 'grid' && status[5] == 'form'){
                continue;
            }
            if (status[1] == 'ck' || status[1] == 'rd' || status[1] == 'st'){
                status[1] == 'ck' ? this.applyCheckBox(calc, i, mcdt, status) :
                status[1] == 'rd' ? this.applyRadio(calc, i, mcdt, status)
                                  : this.applySelect(calc, i, mcdt, status);
                continue;
            }

            values = [];
            values[0] = this.getValue(calc[0], mcdt);
            check = status[2];
            values[2] = check == 'id' ? this.getValue(calc[2], mcdt)
                                      : (check == 'nbr' || check == 'str') ? calc[2] : '';

            value = this.getCalcValue(values[0], calc[1], values[2], i, mcdt);
            check = status[4];
            if (check == 'math' && toString(value)){
                value = this.applyMath(value, calc[4], calc[5]);
            }

            mcdtId = this.setValue(calc[3], mcdt, value, calc[5], calc[6] || '');
            if (value || value == 0){
                this.setColor(mcdtId, calc[3]);
            }
        }
    },

    applyFormValue: function(){
        var cmpt = this.newComponent,
            count = cmpt.getTrNodes ? cmpt.getTrNodes() : 0;
        var node,
            ids,
            spt,
            mcdt;

        for (i = 0; i < count; i++){
            if (node = cmpt.hasCellValue(i)){
                ids = cmpt.splitId(node);
                spt = ids[1].split('_');
                mcdt = '_mcdttd_' + spt[0] + '_';
                this.forcedCalc = true;
                this.setNodeValue(mcdt);
                this.forcedCalc = false;
            };
        }
    },

    applyRadio: function(calc, index, mcdt, status){
        var id,
            isid,
            formid,
            value,
            mcdtId;

        id = this.getID(calc[0], mcdt);
        if (mc.getChecked(id).chain){
            value = status[4] == 'id' ? this.getValue(calc[4], mcdt) : mc.zeroToValue(calc[4]).chain;
            mcdtId = this.setValue(calc[3], mcdt, value, calc[5]);
            if (value){
                this.setColor(mcdtId, calc[3]);
            }
        }
        this.setMetaData(calc[3], value);
    },

    applyCheckBox: function(calc, index, mcdt, status){
        var id,
            value = '',
            mcdtId;

        id = this.getID(calc[0], mcdt);
        if (mc.getChecked(id).chain){
            value = status[4] == 'id' ? this.getValue(calc[4], mcdt) : (calc[4] || '');
            mcdtId = this.setValue(calc[3], mcdt, value, calc[5]);
            if (mc.get(mcdtId).chain){
                mc.chain['_lastUpdateID'] = id;
            }
            if (value){
                this.setColor(mcdtId, calc[3]);
            }
            this.setMetaData(calc[3], value);
            return;
        }

        mcdtId = this.getID(calc[3], mcdt);
        if (mc.get(mcdtId).chain && mc.chain._lastUpdateID == id ){
            this.setValue(calc[3], mcdt, value, calc[5]);
            this.setMetaData(calc[3], value);
        }
        return;
    },

    applySelect: function(calc, index, mcdt, status){
        var id,
            isid,
            formid,
            value,
            mcdtId;

        id = this.getID(calc[0], mcdt);
        mc.getSelected(status[4], id, 'first');
        value = mc.chain.length > 0 ? mc.chain[0] : '';

        mcdtId = this.setValue(calc[3], mcdt, value, calc[5]);
        if (value){
            this.setColor(mcdtId, calc[3]);
        }
        this.setMetaData(calc[3], value);
    },

    getCalcValue: function(one, opr, two, index, mcdt){
        if (opr == '='){
            return one;
        }
        var pmmd = /^\+|\-|\*|\//.test(opr);
        var pm = /^\+|\-/.test(opr);
        if (pmmd){
            if (pm && mc.isNumber(one).chain && !two){
                return mc.widget.Math.arith(one, two, opr);
            }
            if (mc.isNumber(one).chain && mc.isNumber(two).chain){
                return mc.widget.Math.arith(one, two, opr, true);
            }
            if (opr == '+'){
                return one + two;
            }
            return '';
        }

        opr = opr ? opr.toLowerCase() : opr;
        if (opr == 'max' || opr == 'min'){
            return this.getMaxMin(one, opr, two);
        }
        if (this.compareExp.test(opr)){
            return this.calcOperator(one, opr, two, index, mcdt);
        };
        return vl = '';
    },

    applyMath: function(value, math, psn){
        if (math == 'abs'){
            return Math.abs(value);
        }
        return mc.widget.Math[math](value, psn);
    },

    calcOperator: function(one, opr, two, index, mcdt){
        var status = this.calcStatus[index];
        if (mc.isNumber(one).chain && (mc.isNumber(two).chain || !two)){
            one = Number(one);
            two = Number(two);
        }
        var rst = this.execOperator(one, opr, two);
        if (!rst || !status){
            return '';
        }
        if (status[3] == 'id' && status[4] == false){
            return rst;
        }

        var calc = this.calcOptions[index];
        if (status[3] == 'id' && (status[4] == 'nbr' || status[4] == 'str')){
            return calc[4];
        }
        if (status[3] == 'id' && status[4] == 'id'){
            return this.getValue(calc[4], mcdt);
        }
        return '';
    },

    getValue: function(id, mcdt){
        var mcdtId = this.getID(id, mcdt),
            comma;

        if (mc.get(mcdtId).chain){
            if (this.inputNodes[id]){
                mc.getValue(mc.chain);
            } else {
                mc.getText(mc.chain);
                if (comma = this.newComponent.getAttr(id, 'comma')){
                    mc.removeComma(mc.chain);
                }
            }
            return mc.chain;
        };
        return '';
    },

    setValue: function(id, mcdt, value, calc, read){
        var mcdtId = this.getID(id, mcdt),
            comma;

        if (mc.get(mcdtId).chain){
            if (calc == 'radio' || calc == 'checkbox'){
                if (!read){
                    mc.setChecked(value, mc.chain);
                } else if (this.newComponent.processStatus == 'read'){
                    mc.setChecked(value, mc.chain);
                }
            } else {
                if (this.inputNodes[id]){
                    mc.setValue(value, mc.chain);
                } else {
                    comma = '';
                    if (this.newComponent.getAttr(id, 'comma')){
                        comma = mc.insertComma(value).chain;
                    }
                    mc.setText(comma || value, mcdtId);
                }
            }
            this.setMetaData(id, value);
        };
        return mcdtId;
    },

    isTargetID: function(node){
        var id = typeof node == 'string' ? node : node.id;
        var spt = id.split('_mcdttd_'),
            list;

        if (this.calcNodes[spt[0]]){
            list = this.newComponent.ccodeIdList[spt[0]];
            return list.grid ? [spt[0], '_mcdttd_' + spt[1]] : spt[0];
        }
        return false;
    },

    setMcdttd: function(eventID){
        return mc.widget.NameFormat.getCalcFormat(eventID, this.indirectEvent);
    },

    getID: function(id, mcdt){
        var ccode = this.newComponent.ccodeIdList[id];
        if (ccode && ccode.grid && mcdt){
            var indexID = ccode.comboID ? ccode.comboID : id;
            return ccode.grid ? id + mcdt + this.newComponent.metaField.getChildIndex(indexID) + '_k' : id;
        }
        return id;
    },

    setMetaData: function(id, value){
        if (this.applyMetaData) {
            this.newComponent.metaData.setData(this.metaRowIndex, id, value);
        }
    },

    setColor: function(node, field){
        if (mc.get(node).chain){
            var value;
            if (value = this.newComponent.getAttr(field, 'defaultColor')) {
                mc.setColor(value, node);
            };
            if (value = this.newComponent.getAttr(field, 'minusColor')){
                mc.minusColor(value, node);
            };
        }
    },

    getMaxMin: function(fs, op, sc){
        switch(op){
            case 'max':
                if (mc.isNumber(fs).chain && mc.isNumber(sc).chain){
                    return Math.max(fs, sc);
                }
                return fs > sc ? fs : sc;
            case 'min':
                if (mc.isNumber(fs).chain && mc.isNumber(sc).chain){
                    return Math.min(fs, sc);
                }
                return fs < sc ? fs : sc;
        }
    },

    isFormNode: function(node){
        var id = node && node.id ? node.id : typeof node == 'string' ? node : '';
        if (id){
            var ccode = this.newComponent.ccodeIdList[id];
            if (ccode){
                return ccode.grid ? false : true;
            }
        }
        return false;
    },

    setEventOrigin: function(tg, eventID){
        this.eventOrigin = (!eventID || this.isFormNode(tg)) ? 'form' : 'grid';
        if (this.eventOrigin == 'grid'){
            this.gridEvent = true;
        }
    },

    execOperator: function(bs, op, tg){
        switch(op){
            case '==':
                return bs == tg ? bs : false;
            case '!=':
                return bs != tg ? bs : false;
            case '<':
                return bs < tg ? bs : false;
            case '<=':
                return bs <= tg ? bs : false;
            case '>':
                return bs > tg ? bs : false;
            case '>=':
                return bs >= tg ? bs : false;
        }
        return false;
    },

    getCalcNode: function(){
        return this.calcNodes;
    },

    selectOptionEvent: function(e, tg, opts, that, own){
        this.keyupEvent({}, own, {}, that);
    },

    setGridForm: function(that, tg, ids, index){
        var event = {};
        event.type = 'forced';
        if (index){
            this.metaRowIndex = index;
        }
        this.indirectEvent = true;
        this.keyupEvent(event, tg, {}, that, ids || '');
    },

    comboFormEvent: function(tg, fields, that){
        var event = {},
            len = fields.length,
            i;

        event.type = 'forced';
        for (i = 0; i < len; i++){
            this.keyupEvent(event, tg, {}, that, fields[i]);
        }
    },

    setChoicedCombo: function(tg, fields, that, formGrid){
        var event = {},
            len = fields.length,
            i,
            field;

        event.type = 'forced';
        for (i = 0; i < len; i++){
            field = formGrid ? fields[i] : ['', fields[i]];
            this.forcedCalc = formGrid;
            this.keyupEvent(event, tg, {}, that, field, formGrid);
            this.forcedCalc = false;
        }
    }
};


mc.form.Operator = function(opts){
    this.optsOperator = [];
    this.optrNodes = [];
    this.cellIndex = [];

    mc.widget.Widget.allocate(this, opts);
};

mc.form.Operator.prototype = {
    eqMsg: '값이 같습니다.',
    neMsg: '값이 다릅니다.',
    steqMsg: '값과 형식이 같습니다.',
    stneMsg: '값 또는 형식이 다릅니다.',

    ltMsg: '값이 작습니다.',
    gtMsg: '값이 큽니다.',
    lteqMsg: '값이 작거나 같습니다.',
    gteqMsg: '값이 크거나 같습니다.',

    ccode: 'operator',
    gridType: false,

    mainOperator: function(cmpt, msgName){
        this.setUniqueNode();
        this.checkOptions(cmpt, msgName);
    },

    setUniqueNode: function(){
        this.setArray();
        mc.eachArray(this.optsOperator, function(optr, ix){
            if (mc.isArray(optr).chain){
                mc.eachArray(optr, function(id, idx){
                    this.addOptrNode(id, idx);
                }, this)
            } else {
                this.addOptrNode(optr, ix);
            }
        }, this)
    },

    addOptrNode: function(nd, ix){
        if (ix == 0 || ix == 2){
            var cn = this.optrNodes;
            if (typeof nd == 'string' && !(mc.isContains(this.optrNodes, nd).chain)){
                cn[cn.length] = nd;
            }
        }
    },

    _checkOptions: function(cmpt){
        var nodes = this.optrNodes,
            len = nodes.length,
            chn = this.checkNodes,
            i,
            j,
            id,
            count = cmpt.length,
            ccode;

        for (i = 0; i < len; i++){
            id = nodes[i];
            if (!chn[id]){
                for (j = 0; j < count; j++){
                    ccode = cmpt[j];
                    if (ccode.component){
                        this._checkOptions(ccode.component);
                    }
                    if (id == ccode['id']){
                        chn[id] = true;
                        break;
                    }
                }
            }
        }
    },

    checkOptions: function(cmpt, msgName){
        this.checkNodes = {};
        var chn = this.checkNodes,
            nodes = this.optrNodes,
            len = nodes.length,
            i,
            id,
            result = true;

        for (i = 0; i < len; i++){
            id = nodes[i];
            chn[id] = false;
        }
        this._checkOptions(cmpt);

        chn = this.checkNodes;
        for (id in chn){
            if (!chn[id]){
                mc.widget.Message.show('E1020', this.ccode, 'options.operator.' + id, msgName);
                result = false;
            }
        }

        this.checkNodes = '';
        return result;
    },

    checkNumber: function(vl){
        if (mc.numCheckExp.test(vl)){
            vl = Number(vl);
        }
        return vl;
    },

    execOperator: function(vl, op, tg){
        if (mc.isNumber(vl).chain && mc.isNumber(tg).chain){
            vl = Number(vl);
            tg = Number(tg);
        }

        switch(op){
            case '==':
                return vl == tg ? this.eqMsg : false;
            case '!=':
                return vl != tg ? this.neMsg : false;
            case '<':
                return vl < tg ? this.ltMsg : false;
            case '<=':
                return vl <= tg ? this.lteqMsg : false;
            case '>':
                return vl > tg ? this.gtMsg : false;
            case '>=':
                return vl >= tg ? this.gteqMsg : false;
        }
        return false;
    },

    compare: function(vl, op, tg){
        tg = mc.toArray(tg).chain;
        var i,
            len = tg.length,
            msg;

        for (i = 0; i < len; i++){
            if (msg = this.execOperator(vl, op, tg[i])){
                return [tg[i], msg];
            };
        }
        return false;
    },

    compareNode: function(base, op, tg){
        tg = mc.toArray(tg).chain;
        var i,
            len = tg.length,
            msg,
            el,
            baseValue,
            value;

        if (this.gridType){
            base = this.setGridOptrID(base);
        }
        mc.isInput(base).chain ? mc.getValue(base) : mc.getText(base);
        baseValue = mc.removeComma(mc.chain).chain;

        for (i = 0; i < len; i++){
            el = tg[i];
            if (this.gridType){
                el = this.setGridOptrID(el);
            }
            mc.isInput(el).chain ? mc.getValue(el) : mc.getText(el);
            value = mc.removeComma(mc.chain).chain;

            if (msg = this.execOperator(baseValue, op, value)){
                return [el, msg];
            };
        }
        return false;
    },

    checkTextType: function(){
        this.setArray();
        var ops = this.optsOperator,
            len = ops.length,
            that = this.newComponent,
            i,
            op,
            result;

        for (i = 0; i < len; i++){
            op = ops[i];
            result = this.compare(that.inputValue, op[0], op[1]);
            if (result && !that.valueError){
                this.setMessage(op[2] || '', result);
                that.showError(that.errorMsg);
            }
        }
    },

    setMessage: function(message, result){
        var that = this.newComponent,
            hash = {};

        if (message){
            if (typeof message == 'string'){
                hash['title'] = 'Operator';
                hash['msg'] = message;
                that.errorMsg = hash;
            } else {
                that.errorMsg = {};
                that.errorMsg['title'] = message.title;
                that.errorMsg['msg'] = message.msg;
            }
        } else {
            that.errorMsg = result;
        }
    },

    checkFormType: function(){
        this.setArray();
        var opts = this.optsOperator,
            len = opts.length,
            opt,
            i;

        for (i = 0; i < len; i++){
            opt = opts[i];
            typeof opt[1] == 'string' ?  this.formOperator(opt) : this.userOperator(opt);
        }
    },

    formOperator: function(op){
        var that = this.newComponent,
            result,
            hash = {};

        if (result = this.compareNode(op[0], op[1], op[2])){
            that.valueError = true;
            this.checkGridError = true;
            if (!that.errorMsg || that.showMessage){
                this.setMessage(op[3], result);
                that.showError(op[0], op[2], that.errorMsg, this.gridRowNumber || '');
            }
        } else if (this.newComponent.realtimeCheck && !this.checkGridError){
            that.clearError(op[0], op[2], this.gridRowNumber || '');
        }
    },

    userOperator: function(op){
        var that = this.newComponent,
            result;

        if (result = op[1].call(op[3] || that, op[0], op[2])){
            that.valueError = true;
            if (!that.errorMsg){
                that.errorMsg = result;
                that.showError(op[0], op[2], result);
            }
        };
    },

    setCellIndex: function(metaField){
        var cell = this.cellIndex,
            optr = this.optrNodes,
            len = optr.length,
            i,
            id,
            index,
            mcdta = '_mcdttd_0_',
            mcdtb = '_e';

        for (i = 0; i < len; i++){
            id = optr[i];
            index = metaField.getChildIndex(id);
            cell[index] = id;
        }
    },

    setGridOptrID: function(id){
        return id + '_mcdttd_' + this.gridRowNumber + '_' + this.newComponent.metaField.getChildIndex(id) + '_k';
    },

    setGridEventID: function(node){
        var ids = node.id.split('_mcdttd_'),
            rows;

        if (ids[1]){
            rows = ids[1].split('_');
            this.gridRowNumber = rows[0];
        } else {
            rows = ids[0].split('_');
            this.gridRowNumber = rows[1];
        }
    },

    checkGridType: function(tg){
        if (tg){
            this.setGridEventID(tg);
            this.checkGridError = false;

            this.callFormGridUser();
        }
    },

    setArray: function(){
        if (typeof this.optsOperator[0] == 'string'){
            this.optsOperator = [this.optsOperator];
        }
    },

    callFormGridUser: function(){
        this.setArray();
        var opts = this.optsOperator,
            len = opts.length,
            opt,
            i;

        for (i = 0; i < len; i++){
            opt = opts[i];
            typeof opt[1] == 'string' ?  this.formOperator(opt) : this.gridUserOperator(opt);
        }
    },

    checkSubmit: function(id){
        var ids = id.split('mcdttr_')
        this.gridRowNumber = ids[1];

        this.callFormGridUser();
    }
};


mc.form.FormType = function(opts){
    mc.widget.Widget.setOptions(this, opts);
    if (this.showTo) {
        this.mainFormType(this.showTo);
    }
};

mc.form.FormType.prototype = {
    actionStatus: '',
    allowError: false,
    autoCheck: true,
    buttonClass: '',
    buttonStyle: '',

    cancelConfirm: {
        title: {text: '입력 취소 확인'},
        html: '"확인"을 클릭하면 입력한 자료가 지워집니다. <br />"아니오"를 클릭하면 지워지지 않습니다.',
        buttons: {yes: '예', no: '아니오'}
    },
    clearData: true,

    createConfirm: {
        title: {text: '입력 저장 확인'},
        html: '"확인"을 클릭하면 입력한 자료를 저장합니다.<br /> "아니오"를 클릭하면 저장하지 않습니다.',
        buttons: {yes: '확인', no: '아니오'}
    },
    createTitle: true,
    defaultCcode: 'labeltext',

    deleteConfirm: {
        title: {text: '자료 삭제 확인'},
        html: '"확인"을 클릭하면 자료를 삭제합니다.<br /> "아니오"를 클릭하면 삭제하지 않습니다.',
        buttons: {yes: '확인', no: '아니오'}
    },

    failureSendConfirm: {
        title: {text: '통신 실패 확인'},
        html: '통신 장애로 인해 입력한 데이터가 서버에 저장되지 않았습니다.<br />',
        buttons: {ok: '확인'}
    },
    formClass: '',
    formStyle: '',

    getDataConfirm: {
        title: {text: '자료 지움 확인'},
        html: '표시된 데이터가 있습니다.<br /> "확인"을 클릭하면 지웁니다.<br /> "아니오"를 클릭하면 지우지 않습니다.',
        buttons: {yes: '예', no: '아니오'}
    },

    insideClass: '',
    insideStyle: '',
    onFailure: '',
    onSuccess: '',
    onTimeout: '',

    operator: '',
    outsideClass: 'mc-form',
    outsideStyle: '',
    prefix: 'mc_formtype_',

    resetConfirm: {
        title: {text: '입력 취소 확인'},
        html: '입력한 자료를 취소하시겠습니까? <br />"예"를 클릭하면 입력한 자료가 지워집니다. <br />"아니오"를 클릭하면 지워지지 않습니다.',
        buttons: {yes: '예', no: '아니오'}
    },
    showMessage: true,

    successConfirm: {
        title: {text: '저장 성공'},
        html: '입력한 데이터가 서버에 저장되었습니다.<br /> "확인"을 클릭하세요.',
        buttons: {ok: '확인'}
    },
    submitAsync: true,
    textErrorClass: 'mc-types-error',

    timeoutSendConfirm: {
        title: {text: '통신 실패 확인'},
        html: '통신 시간 경과로 인해 입력한 데이터가 서버에 저장되지 않았습니다.<br />',
        buttons: {ok: '확인'}
    },

    updateConfirm: {
        title: {text: '변경 저장 확인'},
        html: '"예"를 클릭하면 변경한 자료를 저장합니다. <br />"아니오"를 클릭하면 저장하지 않습니다.',
        buttons: {yes: '확인', no: '아니오'}
    },

    ccode: 'formtype',
    ccodeIdList: {},
    checkboxNodes: {},
    errorNodes: [],
    openReadOnly: {},

    responseText: '',
    useCreate: false,
    useDelete: false,
    useUpdate: false,

    mainFormType: function(showTo){
        this.showTo = showTo || this.showTo;
        this.initFormType();
        this.createOutside(this.ccode);
        this.createForm();
        this.createInside();
        this.setButtonCcode();
        this.newMessageBox();

        if (!this._setEvents) {
            this.setEvents(this.ccode == 'getdata' ? (this.buttons || this.component) : (this.buttons || this.bottom || this.component));
            this._setEvents = true;
        }
        return this;
    },

    initFormType: function(){
        this.ccodeIdList = {};
        this.openReadOnly = {};
        this.checkboxNodes = {};
    },

    createOutside: function(ccode){
        if (!this.outside){
            mc.widget.Widget.setOutside(this, 'formtype');
            mc.setChildWidth();
        }

        mc.formMember = new mc.component.MemberClass();
        this.component = mc.toArray(this.component).chain;
    },

    createForm: function(){
        if (!this.formside){
            mc.createAppend('form', this.id, this.prefix, this.outside)
              .setThis(this, 'formside')
              .setOwn(mc.chain)
              .addClass(this.formClass)
              .setStyle(this.formStyle);

            mc.widget.Widget.applyAttr(this);

            mc.createAppend('input', false, this.prefix, this.formside)
              .setThis(this, 'disabledNode')
              .setAttr({type: 'text', disabled: 'true'}, this.disabledNode)
              .setDisplay(false, this.disabledNode);
        }
    },

    createInside: function(){
        if (!this.inside){
            mc.createAppend('div', false, this.prefix, this.formside)
              .setThis(this, 'inside')
              .addClass(this.insideClass, this.insdie)
              .setStyle(this.insideStyle, this.inside);
        }
        this.priorParent = this.inside;
    },

    setButtonCcode: function(){
        if (this.buttons || this.bottom){
            mc.component.Code.setDefault(this.buttons || this.bottom, 'button');
        }
    },

    newMessageBox: function(){
        if (!this.messageNew){
            this.messageNew = new mc.guide.MessageBox();
        }
    },

    newCalculator: function(){
        mc.component.Component.setCcodeIdList(this.component, this, false);

        if (this.calculator && !this.calculatorNew){
            this.calculatorNew = new mc.form.Calculator({
                calcOptions: this.calculator || [],
                newComponent: this
            });
            this.calculatorNew.mainCalculator(this.component, 'options.component');
        }
    },

    newOperator: function(){
        if (this.operator && !this.operatorNew){
            this.operatorNew = new mc.form.Operator({
                optsOperator: this.operator,
                newComponent: this
            });
            this.operatorNew.mainOperator(this.component, 'options.component');
        }
    },

    setEvents: function(cmpts){
        var len = cmpts.length,
            i,
            cmpt;

        for (i = 0; i < len; i++){
            cmpt = cmpts[i];
            if (cmpt.ccode == 'button'){
                if (cmpt.getData) {
                    cmpt.events = ['click', this.getEvent, this];
                } else if (cmpt.createData) {
                    cmpt.events = ['click', this.createEvent, this];
                    this.useCreate = true;
                } else if (cmpt.updateData) {
                    cmpt.events = ['click', this.updateEvent, this];
                    this.useUpdate = true;
                } else if (cmpt.deleteData) {
                    cmpt.events = ['click', this.deleteEvent, this];
                    this.useDelete = true;
                } else if (cmpt.resetData) {
                    cmpt.events = ['click', this.resetEvent, this];
                }
            }
            if (cmpt.id && cmpt.ccode != 'linenumber' && cmpt.ccode != 'linefeed'){
                if (cmpt.readonly || cmpt.readOnly){
                    this.openReadOnly[cmpt.id] = true;
                }
            }
            if (cmpt.component){
                this.setEvents(cmpt.component);
            }
        }
    },

    setFormMember: function(){
        this.formMember = mc.formMember;
        mc.formMember = '';
    },

    createButtonSide: function(parent){
        if (this.buttons && !this.buttonside){
            mc.createAppend('div', false, this.prefix, parent || this.outside)
              .setThis(this, 'buttonside')
              .setOwn(mc.chain)
              .addClass(this.buttonClass)
              .setStyle(this.buttonStyle)
        }
    },

    checkSubmitData: function(e, tg, opts, that){
        if (this.errorMsg){
            this.clearAllError();
        }
        this.checkFormType();

        if (!this.valueError || this.allowError){
            if (this.operatorNew){
                this.operatorNew.checkFormType();
            }
            if (!this.valueError || this.allowError){
                this.userMethod(e, tg, opts, that);
            }
        }
    },

    checkFormType: function(){
        this.valueError = false;
        mc.guide.GuideType.formControl = true;
        this.errorObject = '';
        var obj = this.errorObject;

        if (this.autoCheck){
            var members = this.formMember.getAll() || {};
            var id,
                mbr,
                fn;

            for (id in members){
                mbr = members[id];
                if (fn = mbr.checkForm){
                    mbr[fn]();
                    if (mbr.valueError){
                        if (!this.valueError){
                            obj = mbr;
                        }
                        this.valueError = true;
                    }
                };
            }
        }
        mc.guide.GuideType.formControl = false;
        if (obj){
            obj.ccode == 'checkboxgroup' ? obj.showMessage() : mc.focus(obj.id);
        }
    },

    userMethod: function(e, tg, opts, that){
        if (that.buttonClick){
            var rst = that.buttonClick(that.callScope || this, e, tg, opts, this);
            if (rst){
                this.valueError = true;
            }
        }
    },

    showError: function(first, second, message){
        var el;
        if (el = mc.get(first).chain){
            mc.addClass(this.textErrorClass, el)
              .appendArray(this.errorNodes, el.id);
        }

        mc.toArray(second);
        if (el = mc.get(mc.chain[0]).chain){
            mc.addClass(this.textErrorClass, el)
              .appendArray(this.errorNodes, el.id);
        }

        if (this.showMessage){
            mc.guide.GuideType.show(el, message.title, message.msg);
        }
    },

    clearError: function(){
    },

    clearAllError: function(){
        mc.eachArray(this.errorNodes, function(id, ix){
            mc.removeClass(this.textErrorClass, id)
        }, this)

        this.errorNodes = [];
        this.errorMsg = '';

        if (this.showMessage){
            mc.guide.GuideType.hide();
        }
    },

    createActionNode: function(){
        if (!this.actionNode){
            var tmp = '<input id="actionStatus" type="hidden" />';
            mc.beforeBegin(tmp, this.inside)
              .setThis(this, 'actionNode');
        }
        mc.setValue(this.actionStatus, this.actionNode);
    },

    resetEvent: function(){
        this.initFormData();
    },

    initFormData: function(){
        mc.eachHash(this.formMember.getAll(), function(id, mbr){
            if (this.ccodeIdList[id] && mbr.openForm) {
                mbr[mbr.openForm]();
            }
        }, this);
    },

    getAttr: function(field, attr){
        var fd = this.ccodeIdList[field];
        return fd ? (fd[attr] || '') : '';
    },

    getForm: function(){
        return this.formside;
    },

    getComp: function(id){
        return this.formMember.get(id);
    },

    getFormComp: function(){
        return this.formMember;
    }
};


mc.form.GetData = function(opts){
    mc.widget.Widget.setOptions(this, opts);
    if (this.showTo) {
        this.mainGetData(this.showTo);
    }
};

mc.extend(mc.form.GetData, mc.form.FormType, {
    failureConfirm: {
        title: {text: '통신 실패 확인'},
        html: '통신 장애로 인해 서버에서 데이터를 수신하지 못했습니다.<br />',
        buttons: {ok: '확인'}
    },
    getDataConfirm: {
        title: {text: '자료 지움 확인'},
        html: '표시된 데이터가 있습니다.<br /> "확인"을 클릭하면 지웁니다.<br /> "아니오"를 클릭하면 지우지 않습니다.',
        buttons: {yes: '예', no: '아니오'}
    },
    prefix: 'mc_getdata_',
    timeoutConfirm: {
        title: {text: '통신 실패 확인'},
        html: '통신 시간 경과로 인해 서버에서 데이터를 수신하지 못했습니다.<br />',
        buttons: {ok: '확인'}
    },

    ccode: 'getdata',
    noGetData: false,

    mainGetData: function(showTo){
        this.showTo = showTo || this.showTo;
        this.mainFormType();
        this.newCalculator();
        this.newOperator();
        this.setGetDataEvents();

        if (mc.component.Component.isExec(this, 'getdata', this.inside)){
            this.setFormMember();
        };
        return this;
    },

    setGetDataEvents: function(){
        if (!this._setEvents) {
            this.setEvents(this.component);
            this._setEvents = true;
        }
    },

    getEvent: function(e, tg, opts, that){
        if (this.noGetData){
            this.getMetaData();
        } else {
            this.checkSubmitData(e, tg, opts, that);
            if (!this.valueError || this.allowError) {
                this.getDataConfirm ? this.ce.fireEvent('getClick', this) : this.getMetaData();
            };
        }
    },

    getMetaData: function(){
        this.actionStatus = 'read';
        this.newComponent.processStatus = 'read';
        this.createActionNode();
        this.execMetaData();
    },

    execMetaData: function(){
        var supper = this.newComponent,
            meta = supper.metaData,
            server;

        if (!meta){
            return;
        }
        server = meta.server;
        if (!server){
            mc.widget.Message.show('E1012', this.ccode, 'mc.data.MetaData', 'server');
            return;
        }

        server.form = this.formside || '';
        meta.componentMethod = this.receiveData;
        meta.componentScope = this;

        server.metaFailure = this.failure;
        server.metaTimeout = this.timeout;
        server.metaFailScope = this;
        meta.mainMetaData(supper.inside);
    },

    receiveData: function(trans){
        this.ce.fireEvent('receiveData', trans, this);
    },

    failure: function(trans){
        if (!this.messageNew){
            this.messageNew = new mc.guide.MessageBox();
        }
        this.messageNew.alert(this.failureConfirm);
        this.ce.fireEvent('getFailure', trans, this);
    },

    timeout: function(trans){
        if (!this.messageNew){
            this.messageNew = new mc.guide.MessageBox();
        }
        this.messageNew.alert(this.timeoutConfirm);
        this.ce.fireEvent('getTimeout', trans, this);
    },

    createSendData: function(parent){
        return mc.get(parent).chain.cloneNode(true);
    },

    getOutsideHeight: function(bp){
        bp = bp || '';
        return mc.getHeight(bp, this.outside).chain;
    }
});


mc.form.Form = function(opts){
    mc.widget.Widget.setOptions(this, opts);
    if (this.showTo) {
        this.mainForm(this.showTo);
    }
};

mc.extend(mc.form.Form, mc.form.FormType, {
    action: '',
    appendSend: [],
    async: true,
    enableForm: true,
    formOutsideClass: '',
    formOutsideStyle: '',

    getData: '',
    getFailure: '',
    getSuccess: '',
    getTimeout: '',

    metaData: '',
    method: 'POST',
    name: '',
    prefix: 'mc_form_',
    updateMode: true,

    ableClass: 'mc-types-disabled',
    ccode: 'form',
    existMetaData: false,
    existGetData: false,

    mainForm: function(showTo){
        this.showTo = showTo || this.showTo;
        this.checkOptions();
        this.createFormOutside();
        this.newTitle();

        this.setMetaServer();
        this.newGetData();
        this.mainFormType();
        this.setFormEvents();

        if (mc.component.Component.isExec(this, 'form', this.inside)){
            this.followControl();
            this.execGetData();
        };
        return this;
    },

    checkOptions: function(){
        if (!this.component){
            mc.widget.Message.show('E1010', this.ccode, 'component');
        }
    },

    createFormOutside: function(){
        mc.createAppend('div', false, this.prefix, this.showTo)
          .setThis(this, 'formOutside')
          .setOwn(mc.chain)
          .addClass(this.formOutsideClass)
          .setStyle(this.formOutsideStyle)

        if (mc.component.Component.isOwn(this, 'form')){
            mc.setWHXY(this.width, this.height, this.leftX, this.topY, 'BP');
        }
        mc.widget.Widget.cacheShowTo(this, true);
        this.showTo = this.formOutside;
    },

    newTitle: function(){
        if (this.title){
            mc.widget.Widget.newTitle(this, this.formOutside);
        }
    },

    setMetaServer: function(){
        var meta = this.metaData;
        this.existMetaData = meta ? true : false;
        this.existGetData = this.getData ? true : false;

        if (meta && meta.server){
            meta.server.async = this.async == true;
            meta.server.method = this.method;
        }
    },

    newGetData: function(){
        if (!this.existMetaData){
            return;
        }
        if (!this.existGetData){
            this.getData = {noGetData: true};
        }

        var chk = mc.isInstance(this.getData, mc.form.GetData).chain;
        if (chk){
            this.getDataNew = this.getData;
        } else {
            var showTo = this.getData.showTo;
            delete this.getData.showTo;

            this.getDataNew = new mc.form.GetData(this.getData);

            this.getDataNew.showTo = showTo;
        }
        var gd = this.getDataNew;

        gd.getDataConfirm = this.getDataConfirm;
        gd.newComponent = this;
        gd.events = [['getClick', this.getClickEvent, this],
                     ['receiveData', this.setServerData, this],
                     ['getFailure', this.failure, this],
                     ['getTimeout', this.timeout, this]];

        gd.mainGetData(gd.showTo || this.showTo || mc.getBody().chain);
    },

    followControl: function(){
        this.setFormMember();
        this.newCalculator();
        this.newOperator();
        this.setReadOnly(true);

        this.createButtonSide();
        this.newButtons();
        this.initEnableForm();
    },

    setReadOnly: function(rd){
        if (this.existGetData && this.updateMode){
            var form = mc.get(this.formside).chain,
                els = form.elements,
                len = els.length,
                i,
                el;

            for (i = 0; i < len; i++){
                el = els[i];
                if (!(this.openReadOnly[el.id]) && mc.isInput(el).chain){
                    el.readOnly = rd;
                }
            }
        }
    },

    newButtons: function(ccode){
        if (this.buttons){
            var cmptSave = this.component;
            this.component = this.buttons;
            mc.component.Component.isExec(this, ccode || 'form', this.buttonside);
            this.component = cmptSave;
        }
    },

    initEnableForm: function(){
        if (!this.existMetaData || !this.existGetData) {
            if (this.enableForm){
                this.setEnableForm();
            }
            this.setEnableButton();
        }
        if (this.existMetaData && this.existGetData){
            if (this.enableForm){
                this.setDisableForm();
            }
            this.setDisableButton();
        }
    },

    execGetData: function(){
        if (this.existMetaData && !this.existGetData){
            if (this.getDataNew.noGetData){
                this.getDataNew.getEvent();
            }
        }
    },

    getClickEvent: function(){
        this.finishGetData ? this.showConfirm('getData') : this.getDataNew.getMetaData();
    },

    setEnableForm: function(){
        mc.widget.Widget.setEnable(this.ableClass, this.outside);
        this.checkEnableButton();
    },

    checkEnableButton: function(){
        if (this.buttons){
            mc.widget.Widget.setEnable(this.ableClass, this.buttonside);
        }
    },

    setDisableForm: function(){
        mc.widget.Widget.setDisable(this.ableClass, this.outside);
        this.checkDisableButton();
    },

    checkDisableButton: function(){
        if (this.buttons){
            mc.widget.Widget.setDisable(this.ableClass, this.buttonside);
        }
    },

    setEnableButton: function(){
        if (this.useCreate){
            this.createEnable = true;
        }
        if (this.useUpdate){
            this.updateEnable = true;
        }
        if (this.useDelete){
            this.deleteEnable = true;
        }
    },

    setDisableButton: function(){
        if (this.useCreate){
            this.createEnable = false;
        }
        if (this.useUpdate){
            this.updateEnable = false;
        }
        if (this.useDelete){
            this.deleteEnable = false;
        }
    },

    setFormEvents: function(){
        if (!this._setFormEvents){
            mc.widget.Event.customOn(this.messageNew, ['choice', this.choiceEvent, this]);
        }
        this._setFormEvents = true;
    },

    setServerData: function(trans, that){
        this.finishGetData = true;
        this.setEnableForm();
        this.setReadOnly(false);

        this.setNodesData();
        this.execCalculator();
        this.setEnableButton();

        this.ce.fireEvent('applyData', this.formside, this);
        if (this.getSuccess){
            this.getSuccess.call(this, this.metaData.getHeader(), trans, this);
        }
    },

    setNodesData: function(){
        var meta = this.metaData;
        if (!meta){
            return;
        }
        this.existMetaData = true;
        this.twiceCombo = {};

        var format = meta.dataFormat.headerFormat,
            header = meta.getHeader(),
            member = this.formMember,
            id,
            pty,
            fieldID,
            cmpt,
            data;

        for (id in format){
            pty = format[id];
            fieldID = pty.field;

            if (cmpt = member.get(fieldID)){
                mc.removeClass([cmpt.errorClass, this.textErrorClass], fieldID);

                if (data = header[fieldID]){
                    pty.combo ? this.setComboData(data, pty.combo) : cmpt.setForcedValue(data);
                };
            }
        }
    },

    setComboData: function(data, ccodeID){
        var cmpt;
        if (!(cmpt = this.formMember.get(ccodeID))){
            return mc.widget.Message.show('E1012', this.ccode, 'ccode:combo', 'id:' + ccodeID);
        };
        var keyField,
            keyName;

        keyField = cmpt['keyField'];
        if (!keyField){
            return mc.widget.Message.show('E1012', this.ccode, 'ccode:combo', 'keyField');
        }

        keyName = keyField.field;
        if (!this.twiceCombo[keyName]){
            this.twiceCombo[keyName] = keyName;
            cmpt.setForcedValue(data, keyField.mapName || keyName);
        }
    },

    execCalculator: function(){
        if (!this.calculatorNew){
            return;
        }
        this.calculatorNew.keyupEvent({}, {}, {}, this, '', true);
        this.processStatus = '';
    },

    failure: function(trans){
        if (this.getFailure){
            this.getFailure.call(this, trans.status, trans.statusText, trans, this);
        }
    },

    timeout: function(trans){
        if (this.getTimeout){
            this.getTimeout.call(this, trans, this);
        }
    },

    createEvent: function(e, tg, opts, that){
        if (!this.createEnable){
            return;
        }
        this.checkSubmitData(e, tg, opts, that);

        if (this.valueError && !this.allowError){
            return;
        }
        this.actionStatus = 'create';
        this.createConfirm ? this.showConfirm('create') : this.sendToServer();
    },

    updateEvent: function(e, tg, opts, that){
        if (!this.updateEnable){
            return;
        }
        this.checkSubmitData(e, tg, opts, that);

        if (this.valueError && !this.allowError){
            return;
        }
        this.actionStatus = 'update';
        this.updateConfirm ? this.showConfirm('update') : this.sendToServer();
    },

    deleteEvent: function(){
        if (this.deleteEnable){
            this.actionStatus = 'delete';
            this.deleteConfirm ? this.showConfirm('delete') : this.sendToServer();
        }
    },

    resetEvent: function(){
        this.resetConfirm ? this.showConfirm('reset') : this.resetConfirmEvent();
    },

    showConfirm: function(type){
        this.messageNew.execType = type;
        this.messageNew.yesNo(this[type + 'Confirm']);
    },

    choiceEvent: function(code, vl, tg, that, e){
        if (code == 'yes'){
            var type = this.messageNew.execType;
            if (type == 'create' || type == 'update' || type == 'delete'){
                this.sendToServer();
            } else if (type == 'reset'){
                this.resetConfirmEvent();
            } else if (type == 'getData'){
                this.resetConfirmEvent('getdata');
                this.getDataNew.getMetaData();
            }
        }
    },

    sendToServer: function(){
        this.setDisableButton();
        this.createActionNode();

        this.async ? this.execHttpRequest() : this.execSubmit();
        this.setEnableButton();
        this.finishGetData = false;
    },

    resetConfirmEvent: function(getData){
        this.initFormData();
        if (this.finishGetData && !getData){
            this.setNodesData();
            this.execCalculator();
        }
    },

    execHttpRequest: function(){
        this.appendGetData();
        this.setAppendSend();
        this.httpRequest();

        if (this.existGetData){
            this.setDisableForm();
        }
        this.setReadOnly(true);
    },

    appendGetData: function(){
        if (this.sendDataNode) {
            this.sendDataNode.innerHTML = '&#160';
        }
        this.sendGetData = mc.toArray(this.sendGetData).chain;
        if (!this.sendGetData[0]){
            return;
        }

        if (!this.sendDataNode){
            mc.createElement('div', '_sendDataNode')
              .setThis(this, 'sendDataNode')
              .insertAhead(mc.chain, this.inside)
              .setDisplay(false, mc.chain);
        }

        mc.eachArray(this.sendGetData, function(parent, ix){
            if (this.existGetData){
                var dt = this.getDataNew.createSendData(parent);
                if (dt){
                    this.sendDataNode.appendChild(dt);
                }
            }
        }, this)
    },

    setAppendSend: function(){
        var data = {};
        this.appendSend = mc.toArray(this.appendSend).chain;

        mc.eachArray(this.appendSend, function(node, ix){
            data[node] = mc.getText(node).chain;
        })
        this.appendSendData = this.appendSend.length > 0 ? data : '';
    },

    httpRequest: function(){
        if (!this.httpDataNew){
            this.httpDataNew = new mc.data.HttpData(this, {
                onSuccess : this.submitSuccess,
                onFailure: this.submitFailure,
                onTimeout: this.submitTimeout
            });
        }

        this.httpDataNew.setHttpData({
            form: this.formside,
            data: this.appendSendData
        })
        this.httpDataNew.request();
    },

    execSubmit: function(){
        this.name = this.name || this.formside.id;
        mc.setAttr({method: this.method, action: this.action, name: this.name}, this.formside);
        this.formside.submit();
    },

    submitSuccess: function(trans){
        this.setResponseText(trans);

        if (this.onSuccess){
            this.onSuccess.call(this, this.responseText, trans, this);
        }
        if (this.clearData){
            this.initFormData();
            if (this.getDataNew){
                this.getDataNew.initFormData();
            }
        }
        this.setReadOnly(true);
    },

    submitFailure: function(trans){
        this.messageNew.alert(this.failureSendConfirm);
        if (this.onFailure){
            this.onFailure.call(this, trans.status, trans.statusText, trans, this);
        }
    },

    submitTimeout: function(trans){
        this.messageNew.alert(this.timeoutSendConfirm);
        if (this.onTimeout){
            this.onTimeout.call(this, trans, this);
        }
    },

    setResponseText: function(trans){
        this.responseText = '';
        if (trans.responseText){
            this.responseText = mc.evalJson(trans.responseText).chain;
        }
        this.responseXML = trans.responseXML;
    }
});


mc.form.FormPanel = function(opts){
    mc.widget.Widget.setOptions(this, opts);
    if (this.showTo) {
        this.mainFormPanel(this.showTo);
    }
};

mc.extend(mc.form.FormPanel, mc.form.Form, {
    prefix: 'mc_formpanel_',

    ccode: 'formpanel',
    forcedWH: false,
    paramDup: true,

    mainFormPanel: function(showTo, that){
        this.showTo = showTo || this.showTo;

        this.newPanel(that);
        this.deleteTitle();
        this.mainForm(this.panelNew.centerBox);

        mc.component.Component.isExec(this, 'formpanel', this.inside);

        this.followControl();
        this.setFrameWH();
        this.execGetData();
        return this;
    },

    newPanel: function(that){
        if (!this.panelNew){
            var opts = this.paramOpts;
            delete opts.showTo;
            this.panelNew = new mc.panel.Panel(opts);
        }

        var pnl = this.panelNew;
        pnl.isExecComponent = false;
        pnl.width = (that && that.width) ? that.width : opts.width ? opts.width : mc.getWidth('BP', this.showTo).chain;
        pnl.height = (that && that.height) ? that.height - (that.titleHeight || 0)
                                           : opts.height ? opts.height : '';
        pnl.forcedWH = true;
        pnl.newComponent = this;

        pnl.mainPanel(this.showTo);
    },

    deleteTitle: function(){
        if (this.title){
            this.titleSave = this.title;
         