TagSelector = function(oConfig)
{
	return this.init(oConfig);
};

TagSelector.prototype = {
	
	/* props */
	oConfig: null,
	recs:		[],			// recommended tag array
	cats:		[],			// category tag array
	users:		[],			// user registered tag array
	selected:	[],		// array of selected tag ids
	tagcnt:		0,
	tagMax:		20,
	btn:	{
		add: null
	},
	form:	{
		tag: null
	},
	view: 	{
		selected: null,
		recs: null,
		cats: null,
		hidden: null
	},
	
	/* methods */
	init: function(oConfig)
	{
		this.oConfig	= oConfig;
		
		/* view area */
		this.view.selected	= YAHOO.util.Dom.get(oConfig.selectedViewId);
		this.view.recs		= YAHOO.util.Dom.get(oConfig.recViewId);
		this.view.cats		= YAHOO.util.Dom.get(oConfig.catViewId);
		this.btn.add		= YAHOO.util.Dom.get(oConfig.tagSubmitId);
		this.form.tag		= YAHOO.util.Dom.get(oConfig.tagFormId);
		this.view.hidden	= YAHOO.util.Dom.get(oConfig.prvTagHiddenId);
		
		this.initAddTag();
		this.parsePresets();
		this.parseUsers();
	},
	
	initAddTag: function()
	{
		YAHOO.util.Event.addListener(
					this.btn.add,
					'click',
					this.handlerUPush,
					this
					);
		kL	= new YAHOO.util.KeyListener(
					this.form.tag,
					{ keys: [13,108] },
					{
						fn: this.handlerEnterKey,
						scope:this,
						correctScope:true}
					);
		kL.enable();
	},
	
	/* parse and display selectable tags */
	parsePresets: function()
	{
		var tags	= this.oConfig.tags;
		for(idx in tags.presets)
		{
			var tag	= tags.presets[idx];
			
			var el	= document.createElement('li');
			el.id			= tag.id;
			el.innerHTML	= tag.name;
			
			// set tag type
			if (tag.type == tags.recTagTypeId)
			{
				tag.classname	= 'recommend_tag';
				el.className	= 'recommend_tag';
			}
			else if (tag.type == tags.catTagTypeId)
			{
				tag.classname	= 'category_tag';
				el.className	= 'category_tag';
			}
			
			var cHandler	= null; // click handler
			var view		= null; // view area
			
			if (!this.in_array(tag.id, tags.selected))
			{
				if (tag.type == tags.recTagTypeId)
				{
//					this.recs.push(tag);
					cHandler	= this.handlerPush;
					view		= this.view.recs;
				}
				else if (tag.type == tags.catTagTypeId)
				{
//					this.cats.push(tag);
					cHandler	= this.handlerPush;
					view		= this.view.cats;
				}
			}
			else
			{
				this.selected.push(tag.id);
				this.tagcnt++;
				
				cHandler	= this.handlerPop;
				view		= this.view.selected;
			}
			
			YAHOO.util.Dom.setStyle(el, 'cursor', 'pointer');
//			YAHOO.util.Dom.setStyle(el, 'border', 'solid 1px white');
			YAHOO.util.Event.addListener(
								el,
								'mouseover',
								this.handlerMOver,
								this);
			YAHOO.util.Event.addListener(
								el,
								'mouseout',
								this.handlerMOut,
								this);
			YAHOO.util.Event.addListener(
								el,
								'click',
								cHandler,
								this
							);
			view.appendChild(el);
		}
	},
	
	/* create user added tag elements */
	parseUsers: function()
	{
		var users	= this.oConfig.tags.userTags;
		for (idx in users)
		{
			var tag	= users[idx];
			var el	= document.createElement('li');
			el.id	= tag;
			el.className = 'tag';
			el.innerHTML = tag;
			
			this.users.push(tag);
			this.tagcnt++;

			YAHOO.util.Dom.setStyle(el, 'cursor', 'pointer');
//			YAHOO.util.Dom.setStyle(el, 'border', 'solid 1px white');
			YAHOO.util.Event.addListener(
					el,
					'mouseover',
					this.handlerMOver,
					this);
			YAHOO.util.Event.addListener(
					el,
					'mouseout',
					this.handlerMOut,
					this);
			YAHOO.util.Event.addListener(
					el,
					'click',
					this.handlerUPop,
					this
				);
			this.view.selected.appendChild(el);
		}
	},
	
	/* enter keydown handler */
	handlerEnterKey: function(type, args, me)
	{
		me.handlerUPush(args[1], me);
	},
	
	/* move as selected */
	handlerPush: function(e, me)
	{
		if (me.tagcnt > me.tagMax)
		{
			alert('追加できるタグは' + me.tagMax + '個までです。');
			return;
		}
		var target	= YAHOO.util.Event.getTarget(e);
		me.selected.push(target.id);
		me.tagcnt++;
		
//		YAHOO.util.Dom.setStyle(target, 'border', 'solid 1px white');
		YAHOO.util.Event.purgeElement(target, false, 'click');
		YAHOO.util.Event.addListener(
				target,
				'click',
				me.handlerPop,
				me);
		me.view.selected.appendChild(target);
		me.animAppear(target);
	},
	
	/* remove from selected, and return where it belong */
	handlerPop: function(e, me)
	{
		var target = YAHOO.util.Event.getTarget(e);
		for(i = 0; i < me.selected.length; i++)
		{
			if (me.selected[i] == target.id)
			{
				me.selected.splice(i, 1);
			}
		}
		
		var view	= null;
		if (target.className == 'recommend_tag')
		{
			view	= me.view.recs;
		}
		else if (target.className == 'category_tag')
		{
			view	= me.view.cats;
		}
		me.tagcnt--;
		
//		YAHOO.util.Dom.setStyle(target, 'border', 'solid 1px white');
		YAHOO.util.Event.purgeElement(target, false, 'click');
		YAHOO.util.Event.addListener(
				target,
				'click',
				me.handlerPush,
				me);
		view.appendChild(target);
		me.animAppear(target);
	},
	
	/* handle user tag submission */
	handlerUPush: function(e, me)
	{
		if (me.tagcnt > me.tagMax)
		{
			alert('追加できるタグは' + me.tagMax + '個までです。');
			return;
		}
		
		var tag	= me.form.tag;
		if (tag.value !== '' && !me.in_array(tag.value, me.users))
		{
			var el		= document.createElement('li');
			var input	= tag.value.replace(/<\/?[^>]+>/gi, '');
			el.id	= input;
			el.className = 'tag';
			el.innerHTML = input;
			
			me.users.push(input);
			me.tagcnt++;

			YAHOO.util.Dom.setStyle(el, 'cursor', 'pointer');
//			YAHOO.util.Dom.setStyle(el, 'border', 'solid 1px white');
			YAHOO.util.Event.addListener(
					el,
					'mouseover',
					me.handlerMOver,
					me);
			YAHOO.util.Event.addListener(
					el,
					'mouseout',
					me.handlerMOut,
					me);
			YAHOO.util.Event.addListener(
					el,
					'click',
					me.handlerUPop,
					me);
			me.view.selected.appendChild(el);
			
		}
		tag.value = '';
	},
	
	/* delete from user added tags */
	handlerUPop: function(e, me)
	{
		var target = YAHOO.util.Event.getTarget(e);
		for(i = 0; i < me.users.length; i++)
		{
			if (me.users[i] == target.id)
			{
				me.users.splice(i, 1);
			}
		}
		me.tagcnt--;
		me.view.selected.removeChild(target);
	},
	
	/* tag mouse over handler */
	handlerMOver: function(e, me)
	{
//		YAHOO.util.Dom.setStyle(
//			YAHOO.util.Event.getTarget(e),
//			'background',
//			'yellow');
	},
	
	/* tag mouse out handler */
	handlerMOut: function(e, me)
	{
//		var target	= YAHOO.util.Event.getTarget(e);
//		YAHOO.util.Dom.setStyle(
//			target,
//			'background-image',
//			'url(../img/icon_site2.gif)');
	},
	
	/* tag appearance animation */
	animAppear : function(el)
	{
		var anim1	= new YAHOO.util.ColorAnim(
							el,
							{ backgroundColor: { from: '#fff', to: '#ff0'} },
							0.1
						);
		var anim2	= new YAHOO.util.ColorAnim(
							el,
							{ backgroundColor: { from: '#ff0', to: '#fff'} },
							0.5
						);
		anim1.animate();
		anim2.animate();
	},
	
	/* utility class */
	in_array: function(needle, haystack)
	{
		var hLength	= haystack.length;
		for (var i = 0; i < hLength; i++)
		{
			if (haystack[i] == needle) 
			{
				return true;
			}
		}
		return false;
	},
	
	/* set selected tags as hidden fields array */
	setPrvHiddens: function()
	{
		var tags	= this.view.selected.childNodes;
		this.view.hidden.innerHTML = '';
		if (tags.length > 0)
		{
			for (i = 0; i < tags.length; i++)
			{
				var tag	= tags[i];
				var el	= document.createElement('input');
				el.setAttribute( 'type', 'hidden' );
				el.setAttribute( 'name', 'tags[' + i + ']' );
				el.setAttribute( 'value', tag.innerHTML );
				this.view.hidden.appendChild( el );
			}
		}
	},
	
	setHiddens: function()
	{
		var form	= YAHOO.util.Dom.get(this.oConfig.formId);
		
		if (this.selected.length > 0)
		{
			for(idx in this.selected)
			{
				h	= document.createElement('input');
				h.setAttribute( 'type', 'hidden' );
				h.setAttribute( 'name', this.oConfig.selectedHiddenId + '[' + idx + ']' );
				h.setAttribute( 'value', this.selected[idx] );
				form.appendChild( h );
			}
		}
		
		if (this.users.length > 0)
		{
			for (idx in this.users)
			{
				uh	= document.createElement('input');
				uh.setAttribute( 'type', 'hidden' );
				uh.setAttribute( 'name', this.oConfig.userHiddenId + '[' + idx + ']' );
				uh.setAttribute( 'value', this.users[idx] );
				form.appendChild( uh );
			}
		}

	}
};
