//****************************************************************************
// Copyright (C) thePlatform for Media, Inc. All Rights Reserved.
//****************************************************************************

if (window.addEventListener){
	window.addEventListener("load", setupTagWidget, true);
} else if (window.attachEvent){
	window.attachEvent("onload", setupTagWidget );
}

var tpTaggingWidget;

function setupTagWidget(evt) {
	if (tpCommunityManager.getTagsDivID() != null && tpCommunityManager.getTagsDivID().length > 0) {
		tpTaggingWidget = new CommunityManagerTagging(tpCommunityManager.getTagsDivID(), tpCommunityManager, tpMediaDataServicePrefix + "data/Media/", "1.0", tpTagDataServicePrefix, tpTotalTagDataServicePrefix);
		tpCommunityManager.authorize( { endpoint: "Tag", method: "*"}, tpAccessServicePrefix, tpTaggingWidget.handleAuthorizeResponse.bindTo(tpTaggingWidget) );
		tpCommunityManager.registerForAuthentication(tpTaggingWidget.signInRefresh.bindTo(tpTaggingWidget));
		tpController.addEventListener("OnMediaStart", loadTags);
		tpController.addEventListener("OnReleaseStart", loadTags);
	}
}
function loadTags(evt){
	tpTaggingWidget.activate(evt);
}

CommunityManagerTagging = function() {
	this._initialize.apply(this, arguments);
}
CommunityManagerTagging.prototype = {

	// This method does basic initialization of variables. It is called whenever the object is constructed ( "new CommunityManagerTagging", e.g.)
	_initialize: function(widgetSelector, communityManagerInstance, objectURIPrefix, schemaVersion, tagsInstance, totalTagsInstance, optionalArgs) {
		//get a dom reference to the container element for the tagging widget
		this.widget = j$(widgetSelector).eq(0);
		
		// hide it until it goes active
		this.widget.hide();
		
		this.widget.addClass("communityManagerTagWidget");
		//reference to the CommunityManager instance that this is attached to
		this.cmInstance = communityManagerInstance;
		//base of the URL for all tag endpoints
		this.tagsInstance = tagsInstance;
		//base of the URL for all totalTag endpoints
		this.totalTagsInstance = totalTagsInstance;
		//version number of the API for calls to CommunityManager methods
		this.schemaVersion = schemaVersion;
		//the prefix for the unique identifier of the object being interacted with
		this.objectURIPrefix = objectURIPrefix;
		//quick reference points for number of totalTags and myTags
		this.totalTagCount = 0;
		this.myTagCount = 0;
		//boolean indication of whether the initial ui assembly been completed for each section or not
		this.totalTagsLoaded = false;
		this.myTagsLoaded = false;
		//set default number of rows for totalTag cloud
		this.totalTagRows = 2;
		
		this.activated = false;
		
		this.additionalTotalTagCount = 0;
				
		this._myTags = new this._tagCollection("tag");
		this._totalTags = new this._tagCollection("totalTag");
		
		if(typeof optionalArgs != "undefined") {
			if(typeof optionalArgs.totalTagRows != "undefined") {
				this.totalTagRows = optionalArgs.totalTagRows;
			}
		}
		
		this._prepareWidgetSpace();
	},
	activate: function(evt) {
		if ( typeof evt == "undefined" ) {
			if (this.objectURI) {
				this.refreshTags();
			}
		} else if (evt.type == "OnReleaseStart" ) {
			this._clearTags();
			var contentIndex = this.cmInstance.getContentIndex(evt);
			if (contentIndex >= 0) {
				this.contentID = evt.data.baseClips[contentIndex].contentID;
				this.objectURI = this.objectURIPrefix + this.contentID;
				this.refreshTags();
			} else {
				this.objectURI = undefined;
				this.contentID = undefined;
			}				
		} else if (evt.type == "OnMediaStart") {
			if (!evt.data.baseClip.isAd) {
				var oldContentID = this.contentID;				
				if(oldContentID !=  evt.data.baseClip.contentID) {
					this._clearTags();
					this.contentID = evt.data.baseClip.contentID;
					this.objectURI = this.objectURIPrefix + this.contentID;
					this.refreshTags();
				}
			}
		}
	},
	refreshTags: function () {
		this.widget.show();
		this.cmInstance.getTotalTags(this.objectURI, "1.0", tpTotalTagDataServicePrefix, this._createTotalTags.bindTo(this));
		if ( this._rights == "read_write" ) {
			this.cmInstance.getTags(this.objectURI, "1.0", tpTagDataServicePrefix, this._createMyTags.bindTo(this));
		} else {
			j$(".communityManagerMyTags").hide();
		}
	},
	signInRefresh: function(){
		this.cmInstance.authorize( { endpoint: "Tag", method: "*"}, tpAccessServicePrefix, this.handleAuthorizeResponse.bindTo(this));
	},
	_rights: "read",
	handleAuthorizeResponse: function (evt) {
		if(this.cmInstance.isException(evt)) {
			this.cmInstance.errorHandler(evt);
			return false;
		}
		if ( jQuery.grep(evt.accountIDs, function(n, i){ return (n == tpCommunityManager.accountURI);}).length > 0 ) {
			this._rights = "read_write";
		} else {
			this._rights = "read";
		}
		this._clearTags();
		this.activate();
	},
	_clearTags: function () {
		this.widget.hide();
		this.activated = false;
		
		this.addTags = undefined;
		this._myTags = undefined;
		this._myTags = new this._tagCollection("tag");
		this._totalTags = undefined;
		this._totalTags = new this._tagCollection("totalTag");
		this.additionalTotalTagCount = 0;
		//this.contentID = undefined;
		this.topLog = undefined;

		this.sortedTotalTags = undefined;
		this.myTags = undefined;
		
		for(var t=this.totalTagsContainer.childNodes.length-1; t>=0; t--) {
			this.totalTagsContainer.removeChild(this.totalTagsContainer.childNodes[t])
		}
		for(var m=this.myTagsContainer.childNodes.length-1; m>=0; m--) {
			this.myTagsContainer.removeChild(this.myTagsContainer.childNodes[m])
		}
	},
	sortedTotalTags: [],
	_prepareWidgetSpace: function(){
		//create and attach containers for the two main portions of the tagging widget
		this.totalTagsContainer = DomFragment("div", { className: "communityManagerTotalTags" });
		this.widget[0].appendChild(this.totalTagsContainer);		
		this.myTagsContainer = DomFragment("div", { className: "communityManagerMyTags" });
		this.widget[0].appendChild(this.myTagsContainer);
	},
	_createTotalTags: function(tagObject) {
		this.topLog = 0;
		j$(".communityManagerTotalTags").show();
		var totalTagsContainer = DomFragment(this.totalTagsContainer, {
			toAppend: {
				noTags: DomFragment("span", { className: "noTotalTags", innerHTML: "No tags for this video" }),
				moreTagsLink: DomFragment("span", {
					className: "totalTagsItem moreTagsLink",
					toAppend: {
						moreTagsLink: j$(DomFragment("span", { innerHTML: "And&nbsp;00000&nbsp;more&#8230;" })).bind("click", this, this._showMoreTags)
					}
				}),
				lessTagsLink: DomFragment("span", {
					className: "totalTagsItem lessTagsLink",
					toAppend: {
						lessTagsLink: j$(DomFragment("span", { innerHTML: "Show&nbsp;less&#8230;" })).bind("click", this, this._showLessTags)
					}
				})
			}
		});
		var moreTagsLink = totalTagsContainer._cFrag.moreTagsLink;
		var lessTagsLink = totalTagsContainer._cFrag.lessTagsLink;
		var noTags = totalTagsContainer._cFrag.noTags;
		
		// tags will come back sorted
		if(typeof tagObject.items != "undefined" && typeof tagObject.items.length != "undefined" && tagObject.items.length > 0) {
			this.sortedTotalTags = tagObject.items;
			this.totalTagCount = this.sortedTotalTags.length;
			var currentLog;
			for(t in this.sortedTotalTags) {
				currentLog = Math.round(Math.log(this.sortedTotalTags[t].totalTag.count));
				if(currentLog > this.topLog) {
					this.topLog = currentLog;
				}
			}
			
			var tagRowCount = 0;
			var newTotalTag;
			var additionalTags = false;
			var oldMoreLinkOffset = 200000;
			var moreLinkDropped = false;
			var tagSizeClass;
			var tagColorClass;
			var modifiedAgoDays;
			var currentTime = new Date().getTime();
			for(t=0; t<this.sortedTotalTags.length; t++) {
				currentLog = Math.round(Math.log(this.sortedTotalTags[t].totalTag.count));
				tagSizeClass = this._getTagSizeClass(currentLog);
				modifiedAgoDays = (currentTime - this.sortedTotalTags[t].lastModified) / (1000*60*60*24);
				if(modifiedAgoDays <= 1) {
					tagColorClass = "recentTextColor";
				} else if(modifiedAgoDays <= 30) {
					tagColorClass = "textColor";
				} else {
					tagColorClass = "oldTextColor";
				}
				
				newTotalTag = this._createTotalTag(this.sortedTotalTags[t].totalTag.value, tagSizeClass, tagColorClass, { positionBefore: moreTagsLink });
				this._totalTags.addTag(this.sortedTotalTags[t], newTotalTag, t);

				if(moreTagsLink.offsetLeft <= newTotalTag.offsetLeft && oldMoreLinkOffset != moreTagsLink.offsetLeft) {
					tagRowCount++;
				}
				if(oldMoreLinkOffset != moreTagsLink.offsetLeft && additionalTags == false) {
					oldMoreLinkOffset = moreTagsLink.offsetLeft;
					if(tagRowCount >= this.totalTagRows) {
						additionalTags = true;
					}
				}
				if(additionalTags == true) {
					this.additionalTotalTagCount++;
					this._toAdditionalTag(newTotalTag);
				}
			}
			this._setMoreTotalTagsCount();
		} else {
			this._changeDisplayMode(this.totalTagsContainer, "noTags")
		}
	},
	_createMyTags: function(tagObject) {
		if(this.cmInstance.isException(tagObject) == true) {
			this.cmInstance.errorHandler(tagObject);
			return false;
		}
		j$(".communityManagerMyTags").show();
		
		this.myTags = tagObject.items;
		
		var myTagsData = tagObject.items;
		
		this.myTagsControls = DomFragment("div", {
			className: "myTagsControls",
			toAppend: [
				DomFragment("div", { className: "myTagsHeader", innerHTML: "Your Tags:" }),
				DomFragment("div", { 
					className: "myTagsList", 
					toAppend: {
						myTagsList: DomFragment("div", {
							toAppend: {
								noTotalTags: DomFragment("span", { className: "myTagsLink noTotalTags", innerHTML: "You have no tags for this video" }),
								addTags: DomFragment("span", {
									className: "myTagsLink addTagsLink",
									toAppend: [
										j$(DomFragment("span", { innerHTML: "Add&nbsp;tag&nbsp;+"})).bind("click", this, this._showAddEvent)
									]
								})
							}
						})
					}
				})
			]
		});
		this.myTagsContainer.appendChild(this.myTagsControls);
		
		var addTags = this.myTagsControls._cFrag[1]._cFrag.myTagsList._cFrag.addTags;
		
		var tagRowCount = 0;
		var newMyTag;
		for(t=0; t<myTagsData.length; t++) {
			newMyTag = this._createMyTag(myTagsData[t].tag.value, { positionBefore: addTags });
			this._myTags.addTag(myTagsData[t], newMyTag, t);
		}
		if(tagObject.items.length == 0) {
			this._changeDisplayMode(this.myTagsContainer, "noTags");
		} else {
			this._changeDisplayMode(this.myTagsContainer, "");
		}
		
		this._setMoreMyTagsCount();
		
		this.addTags = DomFragment("div", {
			className: "addTagsControls",
			style: {
				display: "none"
			},
			toAppend: [
				DomFragment("div", { className: "myTagsHeader", innerHTML: "Add Tags:" }),
				DomFragment("div", {
					className: "myTagsForm",
					toAppend: [
						j$(DomFragment("form", {
							toAppend: [
								DomFragment("input", { type: "text", id: "", name: "", className: "addTagsField" }),
								DomFragment("input", { type: "submit", name: "submit", value: "Add", style: { display:"none" } }),
								j$(DomFragment("span", { innerHTML: "Add", className: "addTagLink" })).bind("click", {}, this._addTagClick.bindTo(this)),
								j$(DomFragment("span", { innerHTML: "Done", className: "doneTaggingLink" })).bind("click", this, this._hideAddEvent.bindTo(this))
							],
							onsubmit: "return false;"
						})).bind("submit", this._addTagClick.bindTo(this))
					]
				})
			]
		});
		
		this.addTagsField = j$(this.addTags._cFrag[1]._cFrag[0]._cFrag[0]);
		this.addTagsField[0].setAttribute("maxLength", 32)
		this.addTagsField.val(this.tagFieldLastVal||"");
		this.myTagsContainer.appendChild(this.addTags);
		
		this.widget[0].appendChild(this.myTagsContainer);
	},
	_tagCollection: function(tagType) {
		if(typeof tagType == "undefined")
			throw("You must provide a tagType argument when creating a new _tagCollection. Please use 'tag' or 'totalTag' for this argument.");
		
		this.tagType = tagType;
		this.DOMElements = [];
		this.tagData = [];
		this.tagMappings = [];
		this.length = 0;
		
		this.addTag = function(tagObject, tagElement, tagIndex) {
			//console.log("tagObject=" + (tagObject.totalTag ? tagObject.totalTag.value : tagObject.tag.value) + ", tagElement=" + tagElement + ", tagIndex=" + (tagIndex == undefined ? this.length : tagIndex));
			if(this.DOMElements.length != this.tagData.length) {
				throw("The number of items in CommunityManagerTagging._myTags groups does not match!")
			} else {
				if(typeof tagIndex == "undefined")
					var tagIndex = this.length;
				if(typeof this.tagData[tagIndex] != "undefined") {
					this.tagData.splice(tagIndex, 0, tagObject);
					this.DOMElements.splice(tagIndex, 0, tagElement);
				} else {
					this.tagData[tagIndex] = tagObject;
					this.DOMElements[tagIndex] = tagElement;
				}
				this.tagMappings[tagObject[this.tagType].value.toLowerCase()] = tagIndex;
				this.length++;
			}
		}
		this.getElementByTagText = function(tag) {
			return this.DOMElements[this.tagMappings[tag.toLowerCase()]]||false;
		}
		this.getDataByTagText = function(tag) {
			return this.tagData[this.tagMappings[tag.toLowerCase()]]||false;
		}
		this.removeTag = function(tag) {
			//Make the totalTag delete only delete if count == 0 otherwise, count--
			tag = tag.toLowerCase();
			var tagIndex = this.tagMappings[tag];
			if(typeof tagIndex != "undefined") {
				if((this.tagType == "totalTag" && this.tagData[tagIndex].totalTag.count <= 1) || this.tagType == "tag") {
					var DOMElement = this.DOMElements[tagIndex];
					this.DOMElements.splice(tagIndex, 1);
					
					// remove the spacing element that we add for tags.
					var spacer = DOMElement.nextSibling;
					spacer.parentNode.removeChild(spacer);				
					
					// remove the actual tag
					DOMElement.parentNode.removeChild(DOMElement);
					
					this.tagData.splice(tagIndex, 1);
					delete this.tagMappings[tag];
					for(t in this.tagMappings) {
						if(this.tagMappings[t] > tagIndex)
							this.tagMappings[t]--;
					}
					this.length--;
				} else if(this.tagType == "totalTag") {
					this.tagData[tagIndex].totalTag.count--;
				}
				return true;
			} else {
				return false;
			}
		}
		this.getInsertionPoint = function(tag) {
			return this.DOMElements[this.getInsertionPointIndex(tag)]||false;
		}
		this.getInsertionPointIndex = function(tag) {
			for(t=0; t<this.length; t++) {
				if(this.tagData[t][this.tagType].value.toLowerCase() > tag.toLowerCase())
					return t;
			}
			return false;
		}
	},
	// used to get an element for introducing a potential line break in a
	// run of tags.  in IE, we need to use an empty img tag, otherwise all the
	// spaces for "hidden" tags will accumulate at the end of the tag list.  in
	// other browsers, use a space, since in firefox using an img tag won't allow
	// for line breaks
	_getSpacer: function() {
		if (navigator.userAgent.toLowerCase().indexOf("msie") != -1) {
			return DomFragment("img", {height:0, width:0});
		} else {
			return document.createTextNode(" ");
		}
	},
	_createTotalTag: function(tag, tagSizeClass, tagColorClass, optionalArgs) {
		var tagProperties = {
			innerHTML: this.cmInstance.sanitize(tag, true),
			className: "totalTagsItem "+tagSizeClass+" "+tagColorClass
		};
		
		if(typeof optionalArgs != "undefined") {
			var positionBefore = optionalArgs.positionBefore||undefined;
			if(optionalArgs.additionalTag == true) {
				tagProperties.className += " additionalTag";
				tagProperties.style = {display: "none"};
			}
		}
		
		var tagElement = DomFragment("span", tagProperties);
		j$(tagElement).bind("click", this, this._searchByTag)
		var spacer = this._getSpacer();
		if(typeof positionBefore == "undefined" || positionBefore.parentNode == null) {
			this.totalTagsContainer.appendChild(tagElement);
			this.totalTagsContainer.appendChild(spacer);
		} else {
			positionBefore.parentNode.insertBefore(tagElement, positionBefore);
			positionBefore.parentNode.insertBefore(spacer, positionBefore);
		}
		
		return tagElement;
	},
	_createMyTag: function(tag, optionalArgs) {
		var myTagsControls = j$(".myTagsList", this.myTagsControls).eq(0)[0];
		
		var tagClassName = "myTagsItem tagElement"
		if(typeof optionalArgs != "undefined") {
			var positionBefore = optionalArgs.positionBefore||undefined;
		}
		
		var tagElement = DomFragment("span", {
			className: tagClassName,
			toAppend: [
				document.createTextNode("["),
				j$(DomFragment("span", { innerHTML: "x", title: "Remove tag", className: "deleteTagLink" })).bind("click", {tag: tag}, this._deleteTagClick.bindTo(this)),
				DomFragment("span", { innerHTML: "]&nbsp;" + this.cmInstance.sanitize(tag, true) }),
			]
		});
		
		var spacer = this._getSpacer();
		if(typeof positionBefore == "undefined") {
			myTagsControls.appendChild(tagElement);
			myTagsControls.appendChild(spacer);
		} else {
			positionBefore.parentNode.insertBefore(tagElement, positionBefore);
			positionBefore.parentNode.insertBefore(spacer, positionBefore);
		}
		
		return tagElement;
	},
	_addTagClick: function(evt) {
		var tagField = j$(".addTagsField", this.addTags)[0];
		var tag = j$.trim(tagField.value);
		var isValid = true;
		var errorMessage = "";
		if(tag == "") {
			isValid = false;
			errorMessage += "- You must enter text for the tag you would like to add"
		}
		if(tag.length > 32) {
			isValid = false;
			errorMessage += "- Tags can not be more than 32 characters"
		}
		if(isValid == true) {
			this._changeDisplayMode(this.myTagsContainer, "tagsCollapsed");
			var tag = j$(".addTagsField", this.addTags)[0].value;

			var matchedMyTag = this._myTags.getDataByTagText(tag);
			if(matchedMyTag != false) {
				// alert('You have already added the tag "'+matchedMyTag.tag.value+'" to this item.');
				matchedMyTag.tag.value = tag;
				var totalTags = j$(".totalTagsItem", this.totalTags);
				for(t=0; t<totalTags.length; t++) {
					if(j$.trim(totalTags[t].innerHTML).toLowerCase() == tag.toLowerCase()) {
						totalTags.eq(t).html(tag);
						t=totalTags.length;
					}
				}
			} else {
				var matchedTotalTag = this._totalTags.getDataByTagText(tag);
				this.myTags.push({
					tag: {
						value: tag,
						count: 1
					},
					lastModified: new Date().getTime()
				});
				if(matchedTotalTag == false) {
					var totalTagsItems = j$(".totalTagsItem", this.totalTagsContainer);
					var totalTagBefore = this._totalTags.getInsertionPoint(tag);
					var totalTagIndex = this._totalTags.getInsertionPointIndex(tag);
					
					// this._totalTags.addTag();
					var totalTagObject = {
						totalTag: {
							value: tag,
							count: 1
						},
						lastModified: new Date().getTime()
					}
					if(totalTagBefore == false) {
						var additionalTag =	(this.additionalTotalTagCount > 0)?true:false;
						var moreTagsLink = j$(".moreTagsLink", this.totalTagsContainer)[0];
						var tagSizeClass = this._getTagSizeClass(Math.round(Math.log(1)));
						var newTotalTag = this._createTotalTag(tag, tagSizeClass, "recentTextColor", {
							additionalTag: additionalTag,
							positionBefore: moreTagsLink
						});
						this._totalTags.addTag(totalTagObject, newTotalTag);
					} else {
						var additionalTag = (j$(totalTagBefore).eq(0).hasClass("additionalTag"))?true:false;
						var tagSizeClass = this._getTagSizeClass(Math.round(Math.log(1)))
						var newTotalTag = this._createTotalTag(tag, tagSizeClass, "recentTextColor", {
							additionalTag:  additionalTag,
							positionBefore: totalTagBefore
						});
						this._totalTags.addTag(totalTagObject, newTotalTag, totalTagIndex);
					}
				} else {
					matchedTotalTag.totalTag.count++;
				}

				// var myTagsItems = j$(".tagElement", this.myTagsContainer);
				if(this._myTags.length > 0) {
					for(t=0; t<this._myTags.length; t++) {
						if(this._myTags.tagData[t].tag.value.toLowerCase() > tag.toLowerCase()) {
							var myTagBefore = this._myTags.DOMElements[t];
							t = this._myTags.length;
						}
					}
				}
				var newMyTag = this._createMyTag(tag, { positionBefore: j$(".addTagsLink", this.myTagsContainer)[0] });
				this._myTags.addTag({
					tag: {
						value: tag,
						count: 1
					},
					lastModified: new Date().getTime()
				}, newMyTag);
				this._setMoreTotalTagsCount();
				this.cmInstance.addTag(this.objectURI, tag, this.apiVersion, this.tagsInstance);
			}
			
			tagField.value = "";
			tagField.focus();
		} else {
			this.cmInstance.errorHandler(errorMessage);
		}
		return false;
	},
	_getTagSizeClass: function(tagLog){
		switch(tagLog) {
			case this.topLog:
				return "totalTagsLarge";
				break;
			case (this.topLog-1):
				return "totalTagsMedium";
				break;
			default:
				return "totalTagsSmall";
				break;
		}
	},
	_changeDisplayMode: function(tagContainer, displayMode) {
		tagContainer = j$(tagContainer);
		switch(displayMode) {
			case "noTags":
				tagContainer.addClass("noTags").removeClass("tagsExpanded");
				break;
			case "tagsExpanded":
				tagContainer.addClass("tagsExpanded").removeClass("noTags");
				break;
			default:
				tagContainer.removeClass("tagsExpanded").removeClass("noTags");
				break;
		}
	},
	_toAdditionalTag: function(tagEl) {
		j$(tagEl).addClass("additionalTag");
	},
	_showMoreTags: function(evt){
		var self = evt.data;
		var target = evt.currentTarget||evt.target;
		self._changeDisplayMode(target.parentNode.parentNode, "tagsExpanded");
		return false;
	},
	_showLessTags: function(evt){
		var self = evt.data;
		var target = evt.currentTarget||evt.target;
		self._changeDisplayMode(target.parentNode.parentNode, "tagsCollapsed");
		return false
	},
	_deleteTagClick: function(evt) {
		var tag = evt.data.tag;
		//Get a tag Object for the tag being removed if it exists
		var matchedMyTag = this._myTags.getDataByTagText(tag);
		//If a match was found for this tag, remove it
		if(matchedMyTag != false) {
			matchedMyTag.tag.count--;
			this._myTags.removeTag(tag);
			var matchedTotalTag = this._totalTags.getDataByTagText(tag);
			if(matchedTotalTag != false)
				this._totalTags.removeTag(tag);
		}
		if(this._myTags.length == 0)
			this._changeDisplayMode(this.myTagsContainer, "noTags");
		if(this._totalTags.length == 0)
			this._changeDisplayMode(this.totalTagsContainer, "noTags");
		this._setMoreTotalTagsCount();
		this._setMoreMyTagsCount();
		this.cmInstance.deleteTag(this.objectURI, evt.data.tag, this.tagsInstance);
		return false;
	},
	_showAddEvent: function(evt) {
		var self = evt.data;
		j$(".myTagsControls", self.myTagsContainer).hide();
		j$(".addTagsControls", self.myTagsContainer).show();
		j$(".addTagsField", self.myTagsContainer).focus();
		j$(".addTagsField", self.myTagsContainer).select();
		tpController.suspendPlayAll(true);
		return false;
	},
	_hideAddEvent: function(evt) {
		var self = evt.data;
		j$(".addTagsControls", self.myTagsContainer).hide();
		j$(".myTagsControls", self.myTagsContainer).show();
		tpController.suspendPlayAll(false);
		return false;
	},
	_setMoreTotalTagsCount: function(evt) {
		var moreTagsLink = j$(".moreTagsLink span", this.totalTagsContainer).eq(0);
		var tagCount = this._totalTags.length;
		var additionalTagCount = j$(".additionalTag", this.totalTagsContainer).length;
		moreTagsLink.html("And&nbsp;"+additionalTagCount+"&nbsp;more&#8230;");
		if(tagCount == 0)
			j$(this.totalTagsContainer).addClass("noTags").removeClass("tagsExpanded");
		else
			j$(this.totalTagsContainer).removeClass("noTags")
		if(additionalTagCount == 0)
			moreTagsLink.hide();
		else
			moreTagsLink.show();
	},
	_setMoreMyTagsCount: function(evt) {
		var moreTagsLink = j$(".moreTagsLink a", this.myTagsContainer).eq(0);
		var tagCount = this._myTags.length;
		var additionalTagCount = j$(".additionalTag", this.myTagsContainer).length
		moreTagsLink.html("And&nbsp;"+additionalTagCount+"&nbsp;more&#8230;");
		if(additionalTagCount == 0)
			moreTagsLink.hide();
		else
			moreTagsLink.show();
	},
	_searchByTag: function(evt)	{
		var self = evt.data;
		var target = evt.currentTarget||evt.target;
		var tag = self.cmInstance.unsanitize(target.innerHTML, true);
		self.cmInstance.getTotalTagsByValue(tag, "1.0", tpTotalTagDataServicePrefix, self._updateReleaseList.bindTo(self));
	},
	_updateReleaseList: function(tags) {
		tpController.clearCategorySelection(null);
		this.cmInstance.setContentIDs(tags.items);	
	}	
}

Function.prototype.r = function(rangeString) {
    var splitRange = rangeString.split("..");
    for(i=Number(splitRange[0]); i<=Number(splitRange[1]); i++)
        this(i);
}

