/**
 * Correção de diversos bugs dos componentes  
 * Ext.form.Checkbox e Ext.form.Radio reportados
 * na secao de bugs do Forum do Ext.
 * 
 * http://extjs.com/forum/showthread.php?t=44603
 *  
 */
Ext.override(Ext.form.Checkbox, {
	onRender: function(ct, position){
		Ext.form.Checkbox.superclass.onRender.call(this, ct, position);
		if(this.inputValue !== undefined){
			this.el.dom.value = this.inputValue;
		}
		//this.el.addClass('x-hidden');
		this.innerWrap = this.el.wrap({
			//tabIndex: this.tabIndex,
			cls: this.baseCls+'-wrap-inner'
		});
		this.wrap = this.innerWrap.wrap({cls: this.baseCls+'-wrap'});
		if(this.boxLabel){
			this.labelEl = this.innerWrap.createChild({
				tag: 'label',
				htmlFor: this.el.id,
				cls: 'x-form-cb-label',
				html: this.boxLabel
			});
		}
		this.imageEl = this.innerWrap.createChild({
			tag: 'img',
			src: Ext.BLANK_IMAGE_URL,
			cls: this.baseCls
		}, this.el);
		if(this.checked){
			this.setValue(true);
		}else{
			this.checked = this.el.dom.checked;
		}
		this.originalValue = this.checked;
	},
	afterRender: function(){
		Ext.form.Checkbox.superclass.afterRender.call(this);
		//this.wrap[this.checked ? 'addClass' : 'removeClass'](this.checkedCls);
		this.imageEl[this.checked ? 'addClass' : 'removeClass'](this.checkedCls);
	},
	initCheckEvents: function(){
		//this.innerWrap.removeAllListeners();
		this.innerWrap.addClassOnOver(this.overCls);
		this.innerWrap.addClassOnClick(this.mouseDownCls);
		//this.innerWrap.on('click', this.onClick, this);
		this.el.on('click', this.onClick, this);
		this.imageEl.on('click', this.onClick, this);
		//this.innerWrap.on('keyup', this.onKeyUp, this);
	},
	onFocus: function(e) {
		Ext.form.Checkbox.superclass.onFocus.call(this, e);
		//this.el.addClass(this.focusCls);
		this.innerWrap.addClass(this.focusCls);
	},
	onBlur: function(e) {
		Ext.form.Checkbox.superclass.onBlur.call(this, e);
		//this.el.removeClass(this.focusCls);
		this.innerWrap.removeClass(this.focusCls);
	},
	onClick: function(e){
		if (Ext.isSafari) {
			this.el.focus();
		}
		if (!this.disabled && !this.readOnly) {
			this.toggleValue();
		}
		//e.stopEvent();
	},
	onEnable: Ext.form.Checkbox.superclass.onEnable,
	onDisable: Ext.form.Checkbox.superclass.onDisable,
	onKeyUp: undefined,
	setValue: function(v) {
		var checked = this.checked;
		this.checked = (v === true || v === 'true' || v == '1' || String(v).toLowerCase() == 'on');
		if(this.rendered){
			this.el.dom.checked = this.checked;
			this.el.dom.defaultChecked = this.checked;
			//this.wrap[this.checked ? 'addClass' : 'removeClass'](this.checkedCls);
			this.imageEl[this.checked ? 'addClass' : 'removeClass'](this.checkedCls);
		}
		if(checked != this.checked){
			this.fireEvent("check", this, this.checked);
			if(this.handler){
				this.handler.call(this.scope || this, this, this.checked);
			}
		}
	}
});
Ext.override(Ext.form.Radio, {
	checkedCls: 'x-form-radio-checked'
});

/**
 * Adição do método serialize aos comonentes Store.
 * Esse método retorna um array de records codificados como
 * objetos JSON.
 * Recebe como parametro o valor modifiedOnly, se for true envia somente os registros alterados
 * se for false envia todos os registros. Default: true.
 * 
 * Obs: Até o momento só foi testado com JsonStore.
 */
Ext.override(Ext.data.Store, {
	serialize: function(modifiedOnly){
		var recordsRange;
		var retornar = [];

		if (modifiedOnly == null){
			modifiedOnly = true;
		}

		if (modifiedOnly){
			recordsRange = this.getModifiedRecords();
		} else {
			recordsRange = this.getRange();
		}

		for (var r=0; r<recordsRange.length; r++){
			retornar.push(Ext.util.JSON.encode(recordsRange[r].data));
		}

		return retornar;
	}
});

Ext.override(Ext.form.BasicForm, {
    /**
     * Ext.form.BasicForm.clearDirty()
     * Restores the dirty status of all fields back to clean
     */
    clearDirty: function() {
        var i, it = this.items.items, l = it.length, c;
        for (i = 0; i < l; i++) {
            c = it[i];
            c.originalValue = String(c.getValue());
        }
    },
    /**
     * Ext.form.BasicForm.findField()
     * Sobrescrito método para buscar também campos radioGroup ou checkGroup
     * 
     * @param id
     * @returns {Object}
     */
    findField : function(id){
        var field = this.items.get(id);
        if(!field){
            this.items.each(function(f){
                if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
                    field = f;
                    return false;
                } else if (f.items) {
                    //do it again for each subitem
                    f.items.each(function(f2){
                        if(f2.isFormField && (f2.dataIndex == id || f2.id == id || f2.getName() == id)){
                            field = f2;
                            return false;
                        }
                    });
                }
            });
        }
        return field || null;
    }
});

/**
 * Ext.form.Field.setFieldLabel(text)
 * Update a form field label text
 * 
 * Ext.form.Field.setHideLabel(mod)
 * Hide or show field label
 * 
 * http://www.sencha.com/forum/showthread.php?16902-change-fieldLabel-of-Ext.form.Field&p=417493#post417493
 * 
 * @param {String} text
 */
Ext.override(Ext.form.Field, {
    setFieldLabel : function(text) {
        if (this.rendered) {
            this.el.up('.x-form-item', 10, true).child('.x-form-item-label').update(text);
        }
        this.fieldLabel = text;
    },
	
	setHideLabel : function(mod){
		mod = (mod)? false : true;
		if (this.rendered) {
			this.el.up('.x-form-item', 10, true).child('.x-form-item-label').setVisible(mod);
        }
	}
});

/**
 * Ext.form.HtmlEditor.onFirstFocus
 * Correção de bug que disparava um erro no Firebug ao dar foco pela primeira vez a um HtmlEditor
 * Ticket #12382
 * 
 * Fonte da correção: http://www.sencha.com/forum/showthread.php?55199-adding-html-editor-dynamically&p=263391#post263391
 */
Ext.override(Ext.form.HtmlEditor, {
    onFirstFocus : function(){
        this.activated = true;
        this.tb.items.each(function(item){
           item.enable();
        });
        if(Ext.isGecko){ 
            this.win.focus();
            var s = this.iframe.contentWindow.getSelection();
                if(!s.focusNode || s.focusNode.nodeType != 3){
                    var r = s.getRangeAt(0);
                    r.selectNodeContents(this.getEditorBody());
                    r.collapse(true);
                    this.deferFocus();
                }
            try{
                this.execCmd('useCSS', true);
                this.execCmd('styleWithCSS', false);
            }catch(e){}
        }
        this.fireEvent('activate', this);
    }  
});

/*
 * (Ext.DatePicker fix: INÍCIO)
 * 
 * Correções para o problema com a seleção da data em datepickers do ExtJs
 * (durante o primeiro mês do DST ("horário de verão") o DatePicker utiliza um
 * dia anterior ao selecionado)
 * 
 * FONTE: http://www.sencha.com/forum/showthread.php?62250-CLOSED-35-3.x-2.x-DatePicker-Picks-wrong-date
 * NOTA 1: Para o Windows XP, poderá ser necessário atualizar os TZ no registro
 *     http://support.microsoft.com/kb/914387
 * Nota 2: O bug foi corrigido no Ext 3.x. Quando o sistema for atualizado, os 
 *     overrides a seguir poderão ser removidos
 */
/**
 * Correção do DatePicker
 * 
 * http://www.sencha.com/forum/showthread.php?62250-CLOSED-35-3.x-2.x-DatePicker-Picks-wrong-date&p=302310#post302310
 */
Ext.override(Ext.DatePicker, {
    // PUBLIC -- to be documented
    // default value used to initialise each date in the DatePicker
    // (note: 12 noon was chosen because it steers well clear of all DST timezone changes)
    initHour: 12, // 24-hour format

    // private
    update : function(date, forceRefresh) {
        var vd = this.activeDate;
        this.activeDate = date;
        if (!forceRefresh && vd && this.el) {
            var t = date.getTime();
            if (vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()) {
                this.cells.removeClass("x-date-selected");
                this.cells.each(function(c) {
                    if (c.dom.firstChild.dateValue == t) {
                        c.addClass("x-date-selected");
                        setTimeout(function() {
                            try {
                                c.dom.firstChild.focus();
                            } catch(e) {
                            }
                        }, 50);
                        return false;
                    }
                });
                return;
            }
        }
        var days = date.getDaysInMonth(),
            firstOfMonth = date.getFirstDateOfMonth(),
            startingPos = firstOfMonth.getDay() - this.startDay;

        if (startingPos <= this.startDay) {
            startingPos += 7;
        }
        days += startingPos;

        var pm = date.add("mo", -1),
            prevStart = pm.getDaysInMonth() - startingPos,
            cells = this.cells.elements,
            textEls = this.textNodes,

            // convert everything to numbers so it's fast
            // var day = 86400000; // not in use throughout the update() method
            d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart, this.initHour)), // .clearTime();
            today = new Date().clearTime().getTime(),
            sel = date.clearTime(true).getTime(),
            min = this.minDate ? this.minDate.clearTime(true) : Number.NEGATIVE_INFINITY,
            max = this.maxDate ? this.maxDate.clearTime(true) : Number.POSITIVE_INFINITY,
            ddMatch = this.disabledDatesRE,
            ddText = this.disabledDatesText,
            ddays = this.disabledDays ? this.disabledDays.join("") : false,
            ddaysText = this.disabledDaysText,
            format = this.format;

        if (this.showToday) {
            var td = new Date().clearTime();
            var disable = (td < min || td > max ||
                           (ddMatch && format && ddMatch.test(td.dateFormat(format))) ||
                           (ddays && ddays.indexOf(td.getDay()) != -1));

            this.todayBtn.setDisabled(disable);
            this.todayKeyListener[disable ? 'disable' : 'enable']();
        }

        var setCellClass = function(cal, cell) {
            cell.title = "";
            var t = d.clearTime(true).getTime();
            cell.firstChild.dateValue = t;
            if (t == today) {
                cell.className += " x-date-today";
                cell.title = cal.todayText;
            }
            if (t == sel) {
                cell.className += " x-date-selected";
                setTimeout(function() {
                    try {
                        cell.firstChild.focus();
                    } catch(e) {
                    }
                }, 50);
            }
            // disabling
            if (t < min) {
                cell.className = " x-date-disabled";
                cell.title = cal.minText;
                return;
            }
            if (t > max) {
                cell.className = " x-date-disabled";
                cell.title = cal.maxText;
                return;
            }
            if (ddays) {
                if (ddays.indexOf(d.getDay()) != -1) {
                    cell.title = ddaysText;
                    cell.className = " x-date-disabled";
                }
            }
            if (ddMatch && format) {
                var fvalue = d.dateFormat(format);
                if (ddMatch.test(fvalue)) {
                    cell.title = ddText.replace("%0", fvalue);
                    cell.className = " x-date-disabled";
                }
            }
        };

        var i = 0;
        for (; i < startingPos; i++) {
            textEls[i].innerHTML = (++prevStart);
            d.setDate(d.getDate() + 1);
            cells[i].className = "x-date-prevday";
            setCellClass(this, cells[i]);
        }
        for (; i < days; i++) {
            var intDay = i - startingPos + 1;
            textEls[i].innerHTML = (intDay);
            d.setDate(d.getDate() + 1);
            cells[i].className = "x-date-active";
            setCellClass(this, cells[i]);
        }
        var extraDays = 0;
        for (; i < 42; i++) {
            textEls[i].innerHTML = (++extraDays);
            d.setDate(d.getDate() + 1);
            cells[i].className = "x-date-nextday";
            setCellClass(this, cells[i]);
        }

        this.mbtn.setText(this.monthNames[date.getMonth()] + " " + date.getFullYear());

        if (!this.internalRender) {
            var main = this.el.dom.firstChild;
            var w = main.offsetWidth;
            this.el.setWidth(w + this.el.getBorderWidth("lr"));
            Ext.fly(main).setWidth(w);
            this.internalRender = true;
            // opera does not respect the auto grow header center column
            // then, after it gets a width opera refuses to recalculate
            // without a second pass
            if (Ext.isOpera && !this.secondPass) {
                main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth + main.rows[0].cells[2].offsetWidth)) + "px";
                this.secondPass = true;
                this.update.defer(10, this, [date]);
            }
        }
    }
});

/**
 * Correção do DateField
 * 
 * http://www.sencha.com/forum/showthread.php?62250-CLOSED-35-3.x-2.x-DatePicker-Picks-wrong-date&p=302310#post302310
 */
Ext.override(Ext.form.DateField, {
    // PUBLIC -- to be documented
    // in the absence of a time value, a default value of 12 noon will be used
    // (note: 12 noon was chosen because it steers well clear of all DST timezone changes)
    initTime: '12', // 24 hour format
    
    // PUBLIC -- to be documented
    initTimeFormat: 'H',

    // PUBLIC -- to be documented
    // Should be explictly stated that this method should be overriden
    // for use in timezones which experience DST
    //
    // note: this turned out to be reaaaaaalllly difficult to customize to
    // fit every situation, so what i've put up here is a real naive implementation which 
    // works for the online examples (disclaimer: i've only tried it on one, but most of the configs are similar).
    // i suggest customizing it so it fits your particular situation. ask if you don't understand what on earth
    // i'm trying to achieve with this function.
    safeParse : function(value, format) {
        if (/[gGhH]/.test(format.replace(/(\\.)/g, ''))) {
            // if parse format contains hour information, no DST adjustment is necessary
            return Date.parseDate(value, format);
        } else {
            // set time to 12 noon, then clear the time
            var date = Date.parseDate(value + ' ' + this.initTime, format + ' ' + this.initTimeFormat);
            return !Ext.isEmpty(date) ? date.clearTime() : false;
        }
    },

    parseDate : function(value) {
        if(!value || Ext.isDate(value)){
            return value;
        }
    
        var v = this.safeParse(value, this.format),
            af = this.altFormats,
            afa = this.altFormatsArray;
        
        if (!v && af) {
            afa = afa || af.split("|");
        
            for (var i = 0, len = afa.length; i < len && !v; i++) {
                v = this.safeParse(value, afa[i]);
            }
        }
        return v;
    }
});

/**
 * Correção do método new Date().clearTime()
 * 
 * http://www.sencha.com/forum/showthread.php?62250-CLOSED-35-3.x-2.x-DatePicker-Picks-wrong-date&p=401259#post401259
 * 
 * @param clone
 * @returns
 */
Date.prototype.clearTime = function(clone) {    
    if (clone) {
        return this.clone().clearTime();
    }     

    // get current date before clearing time
    var d = this.getDate();
    
    // clear time
    this.setHours(0);
    this.setMinutes(0);
    this.setSeconds(0);
    this.setMilliseconds(0);

    if (this.getDate() != d) { // account for DST (i.e. day of month changed when setting hour = 0)
        // note: DST adjustments are assumed to occur in multiples of 1 hour (this is almost always the ca
        // refer to http://www.timeanddate.com/time/aboutdst.html for the (rare) exceptions to this rule
        // increment hour until cloned date == current date
        for (var hr = 1, c = this.add(Date.HOUR, hr); c.getDate() != d; hr++, c = this.add(Date.HOUR, hr));
        this.setDate(d);
        this.setHours(c.getHours());
    }     

    return this; 
};
/*
 * (Ext.DatePicker fix: FIM)
 */

