(function() {
	var DEV = false && typeof console != 'undefined';
	
	var Dom = YAHOO.util.Dom,
		JSON = YAHOO.lang.JSON,
		Cookie = YAHOO.util.Cookie;
	
	fec = {
		/**
		 * @var Object 	user data {uid,ug,...}
		 */
		_user: null,
		
		/**
		 * Items added by cache() method - stored to futher invalidating...
		 * @var Array
		 */
		_items:[],
		
		/**
		 * @var YAHOO.util.CustomEvent
		 */
		_onStatusChangedEvent: null,
		
		
		/**
		 * Called just after creating this object
		 */
		init: function() {
			this._onStatusChangedEvent = new YAHOO.util.CustomEvent('onStatusChanged', this);
		},
		
		/**
		 * 
		 * @param Integer uid
		 * @param Array ug
		 * 
		 * @public
		 */
		cache:function(elID, reqUG, showCallback) {
			var item = Dom.get(elID);
			if (!item) {
				if (DEV) console.log('fec::cache(): no item '+elID+' found...')
				return;
			}
			if (!reqUG.length) {
				if (DEV) console.log('fec::cache(): no ug items...')
				return;
			}
			
			this.processEl(item, reqUG, showCallback);
			
			this._items.push(arguments);
		},
		
		/**
		 * Invalidate all elements when login status changed
		 * 
		 * @public
		 */
		invalidate:function() {
			var _oldUserID = parseInt(this._user.uid); // store to compare later
			this._user = null; // user data have to be refreshed
			
			for (var k in this._items) {
				this.processEl.apply(this, this._items[k]);
			}
			
			if (_oldUserID != this.getUserData().uid) {
				if (DEV) console.log('FE user changed, onStatusChangedEvent fired...', 'fec::invalidate()');
				this._onStatusChangedEvent.fire(this.getUserData());
			}
		},
		
		_getEvent: function(eventName) {
			var eventObj = this['_'+eventName+'Event'];
			if (!eventObj) {
				throw new Error('FEC_UNKNOWN_EVENT_NAME');
			}
			return eventObj;
		},
		subscribe: function(eventName, callback, obj) {
			this._getEvent(eventName).subscribe(callback, obj);
		},
		unsubscribe: function(eventName, callback, obj) {
			this._getEvent(eventName).unsubscribe(callback, obj);
		},
		unsubscribeAll: function(eventName) {
			this._getEvent(eventName).unsubscribeAll();
		},
		
		/**
		 * Reads FE-user data from memc cookie and set them in this._user
		 * 
		 * @public
		 * 
		 * @return Object this._user
		 */
		getUserData: function() {
			if(this._user && this._user.uid) return this._user;
			
			// make default required this._user object
			this._user = {
				uid: 0,
				ug: []
			};
			
			var cookie = Cookie.get(this._getCookieName());
			var typo3Cookie = Cookie.get(this._getTypo3CookieName());
			if (!cookie || !typo3Cookie) {
				if (DEV) console.log('no cookie or typo3Cookie', 'fec::getUserData()')
				return this._user;
			}
			
			var cookieData = cookie.split('_');
			if (!cookieData.length) {
				if (DEV) console.log('no data in cookieData, cookieData should be an array', 'fec::getUserData()')
				return this._user;
			}
			
			var hash = cookieData.shift();
			if (hash != typo3Cookie) {
				if (DEV) console.log('hash is not equal to typo3Cookie', 'fec::getUserData()')
				return this._user;
			}

			var uid = cookieData.shift();
			
			this._user = JSON.parse(cookieData.join('_'));
			if (!this._user) return this._user;
			this._user.uid = uid;
			
			if (DEV) console.log(this._user, 'fec::getUserData()');
			return this._user;
		},
		
		/**
		 * @private
		 *  
		 * @param HTMLElement elRef
		 * @param Array reqUG
		 * @param Function showCallback
		 */
		processEl: function(elRef, reqUG, showCallback) {
			var visibility,
				userData = this.getUserData();
			
			//if (DEV) console.log(reqUG, 'fec::processEl(): reqUG');
			
			
			for (k in reqUG) {
				switch (reqUG[k]) {
					// show at any login
					case -2:
						visibility = userData.uid > 0;
						this._setVisibility(elRef, visibility);
						break;
					// hide at login
					case -1:
						visibility = userData.uid == 0
						this._setVisibility(elRef, visibility);
						break;
					// visible for specified group
					default:
						visibility = userData.uid && this._userInGroup(reqUG[k])
						this._setVisibility(elRef, visibility);
						break;
				}
			}
			
			if (showCallback && visibility) showCallback.call();
		},
		
		_setVisibility: function(elRef, visible) {
			if (DEV) console.log(elRef, 'fec::_setVisibility(): element '+(visible?'to show':'to hide'));
			
			Dom.removeClass(elRef, visible ? 'fec-hide':'fec-show');
			Dom.addClass(elRef, visible ? 'fec-show':'fec-hide');
		},
		
		
		/**
		 * Is current logged in user in given group?
		 * 
		 * @param Integer group
		 */
		_userInGroup: function(group) {
			var userData = this.getUserData();
			if (!userData.ug) return false;
			
			for (k in userData.ug) {
				if (userData.ug[k] == parseInt(group)) {
					return true;
				}
			}
			
			return false;
		},
		
		_getCookieName: function() {
			return FEC_DATA.cookieName; 
		},
		_getTypo3CookieName: function() {
			return FEC_DATA.typo3CookieName; 
		}
	}
	
	fec.init();
		
	/* /
	fec.subscribe('onStatusChanged', function(eventName, feUserData, params) {
		console.log(feUserData);
	});
	/* */

})();
