if (typeof Ext != 'undefined') {
    var Core = function(){
        var msgCt;

        function createBox(t, s){
            return ['<div class="msg">',
                    '<div class="x-box-tl"><div class="x-box-tr"><div class="x-box-tc"></div></div></div>',
                    '<div class="x-box-ml"><div class="x-box-mr"><div class="x-box-mc"><h3>', t, '</h3>', s, '</div></div></div>',
                    '<div class="x-box-bl"><div class="x-box-br"><div class="x-box-bc"></div></div></div>',
                    '</div>'].join('');
        }
        return {
            msg : function(title, format){
                if(!msgCt){
                    msgCt = Ext.DomHelper.insertFirst(document.body, {id:'msg-div'}, true);
                }
                msgCt.alignTo(document, 't-t');
                var s = String.format.apply(String, Array.prototype.slice.call(arguments, 1));
                var m = Ext.DomHelper.append(msgCt, {html:createBox(title, s)}, true);
                m.slideIn('t').pause(1).ghost("t", {remove:true});
            }
        };
    }();
} else {
//    var Core = {};
}

Core.request = function(processor, page, action, params, callback) {
    jQuery.ajax({
        cache : false,
        url : processor,
        success : callback,
        data : params,
        dataType : 'json',
        type : params ? 'post' : 'get'
    });
};

Core.defaultFormRequestFailure = function(form, action) {
    switch (action.failureType) {
        case Ext.form.Action.CONNECT_FAILURE:
            Core.msg('Failure', 'Connection Error');
            break;
        default:
            Core.msg('Failure', action.result.msg);
    }
    if (action.result && action.result.errors) {
        Core.handleErrors(action.result.errors);
    }
}

Core.formRequest = function(formPanel, processor, page, action, options) {
    if (formPanel.getForm().isValid()) {

        var submitOptions = {
            url : processor,
            waitMsg: 'Submitting...'
        };

        var clientValidation = typeof options['clientValidation'] != 'undefined' ? options['clientValidation'] : true;
        submitOptions.clientValidation = clientValidation;

        var params = typeof options['params'] != 'undefined' ? options['params'] : null;
        submitOptions.params = {
            page: page,
            action: action,
            data: Base64.encode(Ext.encode(params))
        };

        if (typeof options['success'] == 'function') {
            submitOptions.success = options['success'];
        }

        if (typeof options['failure'] == 'function') {
            submitOptions.failure = options['failure'];
        } else {
            submitOptions.failure = Core.defaultFormRequestFailure;
        }

        formPanel.getForm().submit(submitOptions);
    } else {
        Core.msg('Failure', 'Some fields have invalid values');
    }
}

Core.formatDate = function(value)
{
    return value ? value.dateFormat('d-M-Y') : '';
}

Core.formatPrice = function(v)
{
    if(v == 'null' || !v) return '';

    return v;
}

Core.formatPriceDot = function(v)
{
    if(v == 'null' || !v) return '';

    return Ext.util.Format.number(v, '0.0');
}

Core.formatNumber = function(v)
{
    if (v == 'null' || !v) {
        return '';
    }
    v = v - 0;
    v = (v == Math.floor(v)) ? v + ".00" : ((v*10 == Math.floor(v*10)) ? v + "0" : String(v));
    var ps = v.split('.');
    var whole = ps[0];
    var r = /(\d+)(\d{3})/;
    while (r.test(whole)) {
        whole = whole.replace(r, '$1' + ',' + '$2');
    }
    v = whole + '.' + ps[1];
    return v;
}

/**
 * Returns non-assoc array combining assoc array (source) with its index.
 * {'id' : 1, 'title' : 'Title'}, ['id', 'title'] => [1, 'Title']
 */
Core.hashToArray = function(source, indexSequence)
{
    var result = [];
    for (var i = 0; i < indexSequence.length; i++) {
        result[i] = source[indexSequence[i]];
    }
    return result;
}

/**
 * Iterates through source assoc array set and applies to each element Core.hashToArray.
 * [{'id' : 1, 'title' : 'Title'}, {'id' : 2, 'title' : 'Title2'}], ['id', 'title'] => [[1, 'Title'], [2, 'Title2']]
 */
Core.hashSetToArraySet = function(source, indexSequence)
{
    var result = [];
    for (var i = 0; i < source.length; i++) {
        result[i] = Core.hashToArray(source[i], indexSequence);
    }
    return result;
}

/**
 * Requests server for given page, action and params.
 * On success data received from the server will be loaded to component with id equal to target (target either must a component itself) data store.
 * If parameter dataTransformMask is defined, data will be transformed using Core.hashSetToArraySet before load.
 */
Core.loadRemoteData = function(page, action, params, target, dataTransformMask) {
    Core.request('/event/', page, action, params, function(o, s, r) {
        if (s) {
            var response = Ext.decode(r.responseText);
            if (response.success) {
                Core.msg('Success', response.msg);
                if (response.data) {
                    var d = typeof dataTransformMask != 'undefined' ? Core.hashSetToArraySet(response.data, dataTransformMask) : response.data,
                        t = typeof target == 'string' ? Ext.getCmp(target) : target;

                    t.getStore().loadData(d);
                }
            }
            else {
                Core.msg('Failure', response.msg);
            }
        }
        else {
            Core.msg('Failure', "Connection Error");
        }
    });
}

Core.performAction = function(page, action, params) {
    Core.request('/event/', page, action, params, function(o, s, r) {
        if (s) {
            var response = Ext.decode(r.responseText);
            if (response.success) {
                Core.msg('Success', response.msg);
            }
            else {
                Core.msg('Failure', response.msg);
            }
        }
        else {
            Core.msg('Failure', 'Connection Error');
        }
    });
}

Core.performActionWithCallback = function(page, action, params) {
    Core.request('/event/', page, action, params, function(o, s, r) {
        if (s) {
            var response = Ext.decode(r.responseText);
            if (response.success) {
                Core.msg('Success', response.msg);
                if (typeof Core.successCallback == 'function') {
                    Core.successCallback();
                }
            }
            else {
                Core.msg('Failure', response.msg);
                if (typeof Core.failureCallback == 'function') {
                    Core.failureCallback();
                }
            }
        }
        else {
            Core.msg('Failure', 'Connection Error');
        }
    });
}

Core.handleErrors = function(errors, form) {
    var message = '';
    for (var i in errors) {
        if (typeof errors[i] == 'string') {
            message += '* ' + errors[i] + '<br />';
        } else {
            // "i" is an element name, so it seems we can find and element, which this error array is referred to.
            // perhaps we will have to extend Ext.form.field class to display these errors (let's say a red-backgrounded box beneath the field).
            for (var l in errors[i]) {
                if (typeof errors[i][l] == 'string') {
                    message += '* ' + errors[i][l] + '<br />';
                }
            }
        }
    }

    Ext.Msg.alert('Errors', message);
}

Core.handleClientErrors = function(form) {
    var fields = form.findByType('field'),
        message = '';
    if (fields && fields.length) {
        for (var i = 0; i < fields.length; i++) {
            if (!fields[i].isValid()) {
                message = '* ' + fields[i] + ' is not valid<br />';
            }
        }
    }

    if (message) {
        Ext.Msg.alert('Errors', message);
    }
}

/**
 * Add new event to element
 *
 * @DOM Element obj -- DOM Element
 * @DOM string      -- event type ('click', 'load', ...)
 * @function fn     -- function
 *
 * @return bool -- true or false
 */
function addEvent(obj, evType, fn) {
    if(obj.addEventListener) {
        obj.addEventListener(evType, fn, false);
        return true;
    } else if(obj.attachEvent) {
        return obj.attachEvent("on" + evType, fn);
    }
    return false;
}

/**
 * @function `createElement` create and return a new element
 *
 * @string name     -- html name of new element
 * @array attrs     -- array of attributes
 * @DOM Element doc -- DOM element witch will contained new element
 * @t               -- append text
 *
 * @return DOM Element
 */
function createElement(name, attrs, text, doc) {
    var doc = doc ? doc : document;
    var elm = doc.createElement(name);
    if (text != null) elm.appendChild(doc.createTextNode(text));
    if (attrs) {
        for(attr in attrs) {
            elm.setAttribute(attr, attrs[attr]);
        }
    }
    return elm;
}

/**
 * @function `getChilds` return array of child nodes
 *
 * @DOM Element el  -- DOM element
 * @string tagName -- Tags name
 *
 * @return array of DOM Elements
 */
function getChilds(el, tagName) {
    var nodes = [];
    for(var i = 0; i < el.childNodes.length; i++)
        if(el.childNodes[i].nodeName.toLowerCase() == tagName)
            nodes.push(el.childNodes[i]);
    return nodes;
}

/**
 * set styles for element
 *
 * @DOM Element el  -- DOM element
 * @string styles -- array of styles, like `{color: 'red', margin: '0'}`
 *
 * @return void
 */
function style(el, styles) {
    for (var i in styles) {
        el.style[i] = styles[i];
    }
}

/**
 * return childs array
 *
 * @param DOM Element e -- Element to search
 * @param string tag -- tag name of child element
 *
 * @return array of DOM Elements
 */
function getChildByTagName(el, tag) {
    var regExp = new RegExp('^' + tag + '$', 'i');
    var childs = el.childNodes;
    var rezult = [];
    for (var i in childs) {
        if (childs[i].tagName && regExp.test(childs[i].tagName)) {
            rezult.push(childs[i]);
        }
    }
    return rezult;
}

/**
 * Core Mask Object
 * Core.mask.setMsg() -- LoadMask message
 * Core.mask.show()   -- shows LoadMask window
 * Core.mask.hide()   -- hide LoasMask window
 */
Core.mask = {};
Core.mask.load = function() {
    Core.mask.obj = new Ext.LoadMask(Ext.getBody(), {msg:'Loading...'});
}
Core.mask.setMsg = function(msg) {
    if (!Core.mask.obj) {
        Core.mask.load();
    }
    Core.mask.obj.msg = (msg) ? msg : 'Loading...';
}
Core.mask.show = function(msg) {
    if (msg || !Core.mask.obj) {
        Core.mask.setMsg(msg);
    }
    Core.mask.obj.show();
}
Core.mask.hide = function() {
	if (Core.mask.obj != undefined) {
    	Core.mask.obj.hide();
	}
}

/**
 * Returns Element object by class name
 *
 * @param string className  --  Class name
 * @param string node  --  Nodes name for faster searching. Search in Document if null
 * @param Element tag  --  Tag name for faster searching. It is '*' if null
 *
 * @return array of Element objects
 */
function getElementsByClass(className, node, tag) {
    var rezult = [];
    if (node == null) node = document;
    if (tag == null) tag = '*';
    var elements = node.getElementsByTagName(tag);
    var pattern = new RegExp(className);
    for (var i in elements) {
		if (elements[i] != undefined) {
        	if (pattern.test(elements[i].className)) rezult.push(elements[i]);
		}
    }
    return rezult;
}

/**
 * Returns mouse X and Y coords in all brausers
 *
 * @param event e  --  mouse event object
 *
 * @return array
 */
function mousePageXY(e)
{
  var x = 0, y = 0;

  if (!e) e = window.event;

  if (e.pageX || e.pageY)
  {
    x = e.pageX;
    y = e.pageY;
  }
  else if (e.clientX || e.clientY)
  {
    x = e.clientX + (document.documentElement.scrollLeft || document.body.scrollLeft) - document.documentElement.clientLeft;
    y = e.clientY + (document.documentElement.scrollTop || document.body.scrollTop) - document.documentElement.clientTop;
  }

  return {"x":x, "y":y};
}

Core.changeCellColor = function(elem, checked)//col, checked)
{
	if(checked) {
		elem.style.color = '#f00';
	}else{
		elem.style.color = '#000';
	}
	/*var gridPanel = Ext.getCmp('gridPanel');
	gridPanel.getStore().findBy(function(record, id) {
			if(record.data.id) {
				if(checked) {
					gridPanel.getView().getCell(record.data.lineNumber - 1, col).className += ' holdRow';
				}else{
					var elem = gridPanel.getView().getCell(record.data.lineNumber - 1, col);
					elem.className = elem.className.replace(' holdRow', '');
				}
			}
		});*/
}

Core.minelem = function(v)
{
    var m = v[0];
    for (var i=0; i < v.length; i++)
    {
        if (v[i] < m) {
            m = v[i];
        }
    }
    return m;
}

var timer = {b: 0, e: 0, d: 0, a: {}};
timer.start = function() {
    this.b = new Date();
}
timer.app = function(t) {
    this.a[t] = new Date();
}
timer.end = function() {
    this.e = new Date();
    this.d = this.e - this.b;
    var a = this.a;
    var str = '';
    for (var i in a) {
        var t = a[i] - this.b;
        str += i + ': ' + t + '\n';
    }
    alert(str + 'end: ' + this.d);
}

/* Base 64 */

var Base64 = {

//		 private property
		_keyStr : "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",

//		 public method for encoding
		encode : function (input) {
			var output = "";
			var chr1, chr2, chr3, enc1, enc2, enc3, enc4;
			var i = 0;

			input = Base64._utf8_encode(input);

			while (i < input.length) {

				chr1 = input.charCodeAt(i++);
				chr2 = input.charCodeAt(i++);
				chr3 = input.charCodeAt(i++);

				enc1 = chr1 >> 2;
				enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
				enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
				enc4 = chr3 & 63;

				if (isNaN(chr2)) {
					enc3 = enc4 = 64;
				} else if (isNaN(chr3)) {
					enc4 = 64;
				}

				output = output +
				this._keyStr.charAt(enc1) + this._keyStr.charAt(enc2) +
				this._keyStr.charAt(enc3) + this._keyStr.charAt(enc4);

			}

			return output;
		},

//		 public method for decoding
		decode : function (input) {
			var output = "";
			var chr1, chr2, chr3;
			var enc1, enc2, enc3, enc4;
			var i = 0;

			input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");

			while (i < input.length) {

				enc1 = this._keyStr.indexOf(input.charAt(i++));
				enc2 = this._keyStr.indexOf(input.charAt(i++));
				enc3 = this._keyStr.indexOf(input.charAt(i++));
				enc4 = this._keyStr.indexOf(input.charAt(i++));

				chr1 = (enc1 << 2) | (enc2 >> 4);
				chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
				chr3 = ((enc3 & 3) << 6) | enc4;

				output = output + String.fromCharCode(chr1);

				if (enc3 != 64) {
					output = output + String.fromCharCode(chr2);
				}
				if (enc4 != 64) {
					output = output + String.fromCharCode(chr3);
				}

			}

			output = Base64._utf8_decode(output);

			return output;

		},

//		 private method for UTF-8 encoding
		_utf8_encode : function (string) {
			string = string.replace(/\r\n/g,"\n");
			var utftext = "";

			for (var n = 0; n < string.length; n++) {

				var c = string.charCodeAt(n);

				if (c < 128) {
					utftext += String.fromCharCode(c);
				}
				else if((c > 127) && (c < 2048)) {
					utftext += String.fromCharCode((c >> 6) | 192);
					utftext += String.fromCharCode((c & 63) | 128);
				}
				else {
					utftext += String.fromCharCode((c >> 12) | 224);
					utftext += String.fromCharCode(((c >> 6) & 63) | 128);
					utftext += String.fromCharCode((c & 63) | 128);
				}

			}

			return utftext;
		},

//		 private method for UTF-8 decoding
		_utf8_decode : function (utftext) {
			var string = "";
			var i = 0;
			var c = c1 = c2 = 0;

			while ( i < utftext.length ) {

				c = utftext.charCodeAt(i);

				if (c < 128) {
					string += String.fromCharCode(c);
					i++;
				}
				else if((c > 191) && (c < 224)) {
					c2 = utftext.charCodeAt(i+1);
					string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
					i += 2;
				}
				else {
					c2 = utftext.charCodeAt(i+1);
					c3 = utftext.charCodeAt(i+2);
					string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
					i += 3;
				}

			}

			return string;
		}

	}


/**
 * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
 * @param {String} value The string to encode
 * @return {String} The encoded text
 */
function htmlspecialchars(value)
{
   return !value ? value : String(value).replace(/&/g, "&amp;").replace(/>/g, "&gt;").replace(/</g, "&lt;").replace(/"/g, "&quot;");
}

/**
 * Converts newline characters to the HTML tag &lt;br/>
 * @param {String} The string value to format.
 * @return {String} The string with embedded &lt;br/> tags in place of newlines.
 */
function nl2br(v) {
	return v === undefined || v === null ? '' : v.replace(/\n/g, '<br/>');
}

function textareaSpecialchars(v) {
	return '<pre>' + nl2br(htmlspecialchars(v)) + '</pre>';
}

/**
 * Converts email group lists into array
 * Shows Ext.MessageBox.alert if any error found
 *
 * @param string emails -- emails to check
 * @param string msg    -- name of errors
 *
 * @return array
 */
Core.checkEmailGroup = function(emails, msg) {
    newEmails = emails.split('\n');
    emails = [];
    var regExp = /^\s+|\s+$/g;
    for (var i = 0; i < newEmails.length; i++) {
        var email = newEmails[i].replace(regExp, '');
        if (email != '') {
            emails.push(email);
        }
    }
    var regExp = /^(.*)\<(.*)\>$/;
    var validEmails = [];
    var email = [];
    for (var j = 0; j < emails.length; j++) {
        email = regExp.exec(emails[j]);
		if (email) {
        	validEmails.push({'address': email[2], 'name': email[1]});
		} else if (Ext.form.VTypes.email(emails[j])) {
        	validEmails.push({'address': emails[j], 'name': ''});
		} else if (emails[j] != '') {
			Ext.MessageBox.alert(htmlspecialchars(msg) + ' Error', '<span class="span-error-accent">' + htmlspecialchars(emails[j]) + '</span> is not correct email address!');
			return false;
		}
    }
    return validEmails;
}

/**
 * This function removes dirty class and resets form's original values
 *
 * @param Ext.form form -- a form to clean
 * @return void
 */
Core.cleanDirty = function(form) {
	form.getForm().items.each(function (B) {
		B.originalValue = B.getValue();
		B.removeClass('dirty-text-field');
	});
}

/**
 * Popup window object
 */
Core.Popup = new Object();
Core.Popup.obj = false;
Core.Popup.opened = false;
Core.Popup.show = function(processor, page, action, params, width, height, title) {
	if (Core.Popup.obj.el && !Core.Popup.obj.hidden) {
		Core.Popup.obj.el.mask('Loading...', 'x-mask-loading');
	}

	if (Core.Popup.obj) {
		if (Core.Popup.obj.hidden) {
			Core.Popup.createObj(width, height, title);
		}
	} else {
		Core.Popup.createObj(width, height, title);
	}

	Core.request(processor, page, action, params, function(r, s, o){
		if (s) {
			var r = Ext.decode(o.responseText);
			if (!r.errors) {
				Core.Popup.update(r.fields, r.title);
			} else {
				var errors = '';
				for (var i = 0; i < r.errors.length; i++) {
					errors += (i + 1 < r.errors.length) ? r.errors[i] + '<br />' : r.errors[i];
				}
				if (Core.Popup.obj.el) {
					Core.Popup.obj.el.unmask();
					Core.Popup.obj.hide();
				}
				Ext.MessageBox.alert(r.errors.length > 1 ? 'Errors' : 'Error', errors);
			}
		} else {
			Core.Popup.obj.el.unmask();
			Core.Popup.obj.hide();
			Core.msg('Failure', 'Connection Error');
		}
	}, true);

}

Core.Popup.getHtml = function(fields) {
	var html = '<table width="100%" cellspacing="0" border="0" cellpadding="3">';
	for(var i in fields) {
	    if(fields[i]) {
	        fields[i] = fields[i].replace("\n", '<br>');
	    } else {
	        fields[i] = '';
	    }
   		html += '<tr><td class="myPopupText" width="120" align="left"><b>' + i + ':</b></td><td class="myPopupText">' + fields[i] + '</td></tr>';
	}
	html += '</table>';
	return html;
}

Core.Popup.createObj = function(width, height, title) {//fields, title) {

	if (Core.Popup.obj) {
		Core.Popup.obj.destroy();
	}

	var wwidth=(window.innerWidth)?window.innerWidth:
	    ((document.all)?document.body.offsetWidth:null);

	Core.Popup.obj = new Ext.Window({
		title: title,
		width: width,
		minHeight: 200,
		autoHeight: true,
		modal: false,
		layout: 'fit',
		plain: true,
		autoEl: {id:'popupWindow', html: ''},
		'bodyStyle': 'padding:5px;',
		buttonAlign: 'center',
		html: '',
		x: wwidth - (width+50),
		y: 50
	});

	Core.Popup.obj.on('beforeclose',
		function() {
			Core.Popup.obj.hide();
			Core.Popup.opened = false;
		}
	);

	Core.Popup.obj.show();
	Core.Popup.opened = true;
	Core.Popup.obj.el.mask('Loading...', 'x-mask-loading');
}

Core.Popup.update = function(data, title) {

	Core.Popup.obj.setTitle(title);

	/*var form = Core.Popup.obj.items.itemAt(0).getForm();
	var keys = form.items.keys;
	for (var B = 0, A = keys.length; B < A; B++) {
		form.items.items[B].setValue(data[keys[B]]);
	}*/
	var html = Core.Popup.getHtml(data);
	Core.Popup.obj.body.update(html);

	Core.Popup.obj.el.unmask();
	if (Core.Popup.obj.hidden) {
		Core.Popup.obj.show();
	}
}

Core.showLoginPopupObject = false;
Core.showLoginPopup = function() {

    var form = new Ext.form.FormPanel({
		id: 'loginForm',
        baseCls: 'x-plain',
        url: '/',
        defaultType: 'textfield',
        labelWidth: 90,
        items: [
			{
				fieldLabel: 'Login',
				name: 'login',
				id: 'login',
				itemCls: 'left',
				anchor: '100%',
				allowBlank: false
			}
			,{
				fieldLabel: 'Security Code',
				name: 'securityCode',
				id: 'securityCode',
				itemCls: 'left',
				anchor: '100%',
				allowBlank: false,
				autoCreate: {
			        tag: 'input',
			        type: 'password',
			        autocomplete: 'off'
			    }
			}
			,{
				fieldLabel: 'Password',
				name: 'password',
				id: 'password',
				itemCls: 'left',
				anchor: '100%',
				allowBlank: false,
                autoCreate: {
                    tag: 'input',
                    type: 'password',
                    autocomplete: 'off'
                }
			}
		]
    });

    if (Core.showLoginPopupObject) {
        Core.showLoginPopupObject.destroy();
    }

    Core.showLoginPopupObject = new Ext.Window({
        title: 'Session Expired',
        width: 300,
        height: 166,
        minWidth: 300,
        minHeight: 166,
        modal: true,
        layout: 'fit',
        plain: true,
        bodyStyle:'padding:10px;',
        buttonAlign:'center',
        items: form,
        keys: [{
            key: [10, 13],
            fn: function() {
                if (Ext.getCmp('loginForm').getForm().isValid()) {
                    Core.mask.show('Loading...');
                    Ext.getCmp('loginForm').getForm().submit();
                } else {
                    Core.msg('Failure', 'Some fields have invalid values');
                }
            }
        }],
        buttons: [{
            'text': 'Enter',
            'id': 'btnSubmitLogin',
			'type': 'submit',
            'handler': function(){
                if (Ext.getCmp('loginForm').getForm().isValid()) {
                    Core.mask.show('Loading...');
                    Ext.getCmp('loginForm').getForm().submit();
                } else {
                    Core.msg('Failure', 'Some fields have invalid values');
                }
            }
        }]
    });
    form.getForm().reset();
    Core.showLoginPopupObject.on('beforeclose',
        function() {
            return false;
        }
    )
    Core.showLoginPopupObject.on('show',
        function() {
            Ext.getCmp('login').focus();
        }
    )
    Core.showLoginPopupObject.show();
}
