Ext.ns('Ext.ux');

Ext.ux.MotionCardMenu = Ext.extend(Ext.util.Observable, {
	hideStartText: true,
	itemsUseInnerText: true,
	el: null,
	buttonCfg: {},
	collapsed: false,
	start: null,
	startEl: null,
	items: {},
	itemsCollapsed: {},
	arrow: null,
	arrowEl: null,
	containerEl: null,
	isFreezed: false,
	constructor: function(el, config)
	{
		config = config || {};
		Ext.apply(this, config);
		this.el = el;

		Ext.ux.MotionCardMenu.superclass.constructor.call(this, config);

		this.addEvents(
			'startclick',
			'collapsed',
			'expanded'
		);

		this.initMarkup();
	},

	initMarkup: function()
	{
		var itemEls, i, itItemId, task, tick;
		var self = this;

		this.startEl = this.el.child('.start');
		this.arrowEl = this.el.child('.closer');
		this.containerEl = this.el.child('.itemContainer');

		this.start = new Ext.ux.MotionCardMenu.StartButton(this.startEl);
		this.arrow = new Ext.ux.MotionCardMenu.Arrow(
			this.arrowEl,
			{
				containerEl: this.containerEl
			}
		);
		this.arrow.on('folded', function(){
			this.fireEvent('collapsed', this);
		}, this);
		this.arrow.on('unfolded', function(){
			this.expand();
		}, this);

		itemEls = this.containerEl.query('.x-mcm-button-wrapLeft');

		for (i=0; i<itemEls.length; i++)
		{
			itItemId = 'item-' + i.toString();
			this.items[itItemId] = new Ext.ux.MotionCardMenu.Button(
				Ext.get(itemEls[i]).parent(),
				{
					itemId: itItemId,
					containerEl: this.containerEl
				}
			);
			this.itemsCollapsed[itItemId] = false;
			this.items[itItemId].on('beforefold', function(el){
				this.itemsCollapsed[el.itemId] = true;
			}, this);
			this.items[itItemId].on('beforeunfold', function(el){
				this.itemsCollapsed[el.itemId] = false;
			}, this);
		}

		this.items[itItemId].on('folded', function(el){
			this.arrow.fold();
		}, this);
		this.items[itItemId].on('unfolded', function(el){
			this.fireEvent('expanded', this);
		}, this);

		if (!this.hasSelected())
		{
			tick = false;
			task = {
				run: function()
				{
					if (tick)
					{
						self.collapse();
						Ext.TaskMgr.stop(task);
						self.start.on('click', function(){
							this.arrow.unfold();
						}, self);
					}
					tick = true;
				},
				interval: 800
			};
			Ext.TaskMgr.start(task);

			this.monitorTick = false;
			this.monitorTask = {
				run: function()
				{
					if (self.isFreezed) return;

					if (self.hovered)
					{
						Ext.TaskMgr.stop(self.monitorTask);
						self.monitorTick = false;
						return;
					}
					if (self.monitorTick)
					{
						if (!self.hovered)
						{
							self.collapse();
							Ext.TaskMgr.stop(self.monitorTask);
							self.monitorTick = false;
						}
					}
					self.monitorTick = true;
				},
				interval: 1200
			};

			this.el.on('mouseover', function(){
				this.hovered = true;
			}, this);
			this.el.on('mouseout', function(){
				this.hovered = false;
				if (!this.isCollapsed()) Ext.TaskMgr.start(this.monitorTask);
			}, this);
		}
		else
		{
			this.start.on('click', function(){
				this.fireEvent('startclick', this);
			}, this);
		}
	},

	animateHover: function()
	{
		this.hovered = false;
		if (!this.isCollapsed()) Ext.TaskMgr.start(this.monitorTask);
	},

	isCollapsed: function()
	{
		var result = false;
		var i;

		for (i in this.itemsCollapsed)
		{
			if (this.itemsCollapsed[i])
			{
				result = true;
				break;
			}
		}

		return result;
	},

	collapse: function()
	{
		var i;

		if (!this.isCollapsed())
		{
			for (i in this.items)
			{
				this.items[i].fold();
			}
		}
	},

	expand: function()
	{
		var i;

		if (this.isCollapsed())
		{
			for (i in this.items)
			{
				this.items[i].unfold();
			}
		}
	},

	hasSelected: function()
	{
		var result = false;
		for (var i in this.items)
		{
			if (this.items[i].isSelected)
			{
				result = true;
				break;
			}
		}
		return result;
	}
});

Ext.ux.MotionCardMenu.StartButton = Ext.extend(Ext.util.Observable, {
	elHoverClsSuffix: '-hover',
	elSelectedClsSuffix: '-selected',
	el: null,
	isSelected: false,
	constructor: function(el, config)
	{
		config = config || {};
		Ext.apply(this, config);
		this.el = el;

		Ext.ux.MotionCardMenu.StartButton.superclass.constructor.call(this, config);

		this.addEvents(
			'mouseover',
			'mouseout',
			'click'
		);

		this.initMarkup();
	},

	initMarkup: function()
	{
		var clsSwRe = new RegExp('(' + this.elHoverClsSuffix + '|' + this.elSelectedClsSuffix + ')$');
		var clsSelRe = new RegExp(this.elSelectedClsSuffix + '$');
		var testCls = this.el.dom.className;

		if (testCls.replace(clsSelRe, '') != testCls)
		{
			this.isSelected = true;
		}

		this.baseCls = testCls.replace(clsSwRe, '');

		this.el.hover(
			function(ev, el)
			{
				var wrp = this.el;
				var wrpCls = wrp.dom.className.replace(clsSwRe, '') + this.elHoverClsSuffix;

				wrp.dom.className = wrpCls;
				this.fireEvent('mouseover', ev, el);
			},
			function(ev, el)
			{
				var wrp = this.el;
				var wrpCls = this.baseCls + (this.isSelected? this.elSelectedClsSuffix : '');

				wrp.dom.className = wrpCls;
				this.fireEvent('mouseout', ev, el);
			},
			this
		);

		this.el.on('click', function(ev)
		{
			this.fireEvent('click', ev);
		}, this);
	}
});

Ext.ux.MotionCardMenu.Arrow = Ext.extend(Ext.util.Observable, {
	el: null,
	xy: [],
	itemId: '',
	containerEl: null,
	constructor: function(el, config)
	{
		config = config || {};
		Ext.apply(this, config);
		this.el = el;

		Ext.ux.MotionCardMenu.Arrow.superclass.constructor.call(this, config);

		this.addEvents(
			'beforefold',
			'folded',
			'beforeunfold',
			'unfolded'
		);

		this.initMarkup();
	},

	initMarkup: function()
	{
		this.xy = this.el.getXY();
		this.el.setXY(this.xy);
	},

	fold: function()
	{
		var xy = this.xy;
		this.fireEvent('beforefold', this);
		this.el.moveTo(this.containerEl.getX() - this.el.getWidth(), xy[1], {
			duration: 0.5,
			callback: function()
			{
				this.fireEvent('folded', this);
			},
			scope: this
		});
	},

	unfold: function()
	{
		var xy = this.xy;
		this.fireEvent('beforeunfold', this);
		this.el.moveTo(xy[0], xy[1], {
			duration: 0.5,
			callback: function()
			{
				this.fireEvent('unfolded', this);
			},
			scope: this
		});
	}
});

Ext.ux.MotionCardMenu.Button = Ext.extend(Ext.util.Observable, {
	elHoverClsSuffix: '-hover',
	elSelectedClsSuffix: '-selected',
	el: null,
	activatorEl: null,
	midPlaceEl: null,
	midPlaceELQuery: '.x-mcm-button-wrapBody',
	activatorElQuery: '.x-mcm-button-wrapBody a',
	isSelected: false,
	baseCls: '',
	containerEl: null,
	xy: [],
	itemId: '',
	hovered: false,
	constructor: function(el, config)
	{
		config = config || {};
		Ext.apply(this, config);
		this.el = el;

		Ext.ux.MotionCardMenu.Button.superclass.constructor.call(this, config);

		this.addEvents(
			'mouseover',
			'mouseout',
			'click',
			'beforefold',
			'folded',
			'beforeunfold',
			'unfolded'
		);

		this.initMarkup();
	},

	initMarkup: function()
	{
		var clsSwRe = new RegExp('(' + this.elHoverClsSuffix + '|' + this.elSelectedClsSuffix + ')$');
		var clsSelRe = new RegExp(this.elSelectedClsSuffix + '$');
		var testCls = this.el.dom.className;

		if (testCls.replace(clsSelRe, '') != testCls)
		{
			this.isSelected = true;
		}

		this.baseCls = testCls.replace(clsSwRe, '');

		this.el.hover(
			function(ev, el)
			{
				if (!this.hovered)
				{
					var wrp = this.el;
					var wrpCls = wrp.dom.className.replace(clsSwRe, '') + this.elHoverClsSuffix;

					wrp.dom.className = wrpCls;
					this.fireEvent('mouseover', ev, el);
					this.hovered = true;
				}
			},
			function(ev, el)
			{
				if (this.hovered)
				{
					var wrp = this.el;
					var wrpCls = this.baseCls + (this.isSelected? this.elSelectedClsSuffix : '');

					wrp.dom.className = wrpCls;
					this.fireEvent('mouseout', ev, el);
					this.hovered = false;
				}
			},
			this
		);

		this.activatorEl = this.el.child(this.activatorElQuery);
		this.midPlaceEl = this.el.child(this.midPlaceELQuery);

		this.activatorEl.on('click', function(ev)
		{
			this.fireEvent('click', ev);
		}, this);

		this.xy = this.el.getXY();
		this.el.setXY(this.xy);
	},

	fold: function()
	{
		var xy = this.xy;
		this.fireEvent('beforefold', this);
		this.el.moveTo(this.containerEl.getX() - this.el.getWidth(), xy[1], {
			duration: 1,
			callback: function()
			{
				this.fireEvent('folded', this);
			},
			scope: this
		});
	},

	unfold: function()
	{
		var xy = this.xy;
		this.fireEvent('beforeunfold', this);
		this.el.moveTo(xy[0], xy[1], {
			duration: 1,
			callback: function()
			{
				this.fireEvent('unfolded', this);
			},
			scope: this
		});
	}
});

