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

// note that all of these paths _must not_ end with "/".
var tpMediaDataServicePath = "data/Media";
var tpRatingMetadataServicePath = "metadata/Rating";
var tpTotalRatingMetadataServicePath = "metadata/TotalRating";
var tpTagMetadataServicePath = "metadata/Tag";
var tpTotalTagMetadataServicePath = "metadata/TotalTag";
var tpCommentDataServicePath = "data/Comment";
var tpUserListDataServicePath = "data/UserList";
var tpUserProfileMetadataServicePath = "metadata/UserProfile";
var tpUserDataServicePath = "data/User";

// create a mapping for the jQuery "$" operator, to avoid conflicts with other
// frameworks that are also trying to map "$"
var j$ = jQuery.noConflict();

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

CommunityManager.index = 1;

CommunityManager.prototype = {
	_initialize: function(accountURI, userContext, ratingDivID, commentsDivID, tagsDivID, profileDivID) {
		// validate the accountURI
		if(accountURI == null || accountURI.length == 0) {
			alert("You need to provide the Account URI.");
			return false;
		} else {
			this.accountURI = accountURI;
		}
	
		// validate the userContext. It describes which adapter the identity service will use to authenticate the user.
		if(userContext == null || userContext.length == 0) {
			this.anonymousUser = true;
			this.userContext = null;
		} else {
			// add a trailing "/" if it's missing
			if (userContext.lastIndexOf("/") < (userContext.length-1)) {
  				userContext += "/";
			}
			this.anonymousUser = false;
			this.userContext = userContext;
		}
		
		// determine the ID for this script
		this.scriptID = "CommunityManager" + CommunityManager.index++;
		
		// remember various control div IDs
		this.ratingID = ratingDivID;
		this.commentsID = commentsDivID;
		this.tagsID = tagsDivID;
		this.profileID = profileDivID;
		
		// track whether the user is signed in or not
		this.isAuthenticated = false;		
		
		//MODIFICATION (8-07-2008, P.KAROLEWSKI)
		try{
			cookieToken = getCTToken();
			if(cookieToken != '') {
				this.isAuthenticated = true;
				this.token = cookieToken;
			}
		} catch(error){
			alert(error)
		}; 
				
	},
	
	getToken: function () {
		return this.token;
	},
	//get div selectors
	getRatingDivID: function () {
		return this.ratingID;
	},
	getCommentsDivID: function () {
		return this.commentsID;
	},
	getTagsDivID: function () {
		return this.tagsID;
	},
	getProfileDivID: function(){
		return this.profileID;
	},
	
	//profile events
	_userProfile: undefined,
	_setProfileEvents: [],
	registerForProfileChange: function(handler) {
		this._setProfileEvents.push(handler);
	},
	getProfile: function() {
		return this._userProfile;
	},
	setProfile: function(profile) {
		this._userProfile = profile;
		if (this._setProfileEvents.length > 0) {
			for (var h=0; h<this._setProfileEvents.length; h++) {
				this._setProfileEvents[h](profile);
			}
		}
	},
	clearProfile: function() {
		this.setProfile(undefined);
	},
		
	//authentication functions	
	_signInEvents: [],
	_signOutEvents: [],
	registerForAuthentication: function(handler, authEvent){
		switch(authEvent||"") {
			case "signIn":
				this.registerForSignIn(handler);
				break;
			case "signOut":
				this.registerForSignOut(handler);
				break;
			default:
				this.registerForSignIn(handler);
				this.registerForSignOut(handler);
				break;
		}
	},
	registerForSignIn: function(handler){
		this._signInEvents.push(handler);
	},
	registerForSignOut: function(handler) {
		this._signOutEvents.push(handler);
	},
	signIn: function(userName, password, callback) {
		// make the sign-in call
		var params = {
			username: this.userContext+userName,
			password: password
		}
		if (callback) {
			this.secondarySignInCallback = callback;
		} else {
			this.secondarySignInCallback = undefined;
		}
		// create a timer in case we don't hear back from the sign-in service
		this._signInTimeoutInterval = setInterval(this._signInTimeout.bindTo(this), 5000);
		this._makeJsonServiceCall(params, tpIdentityServicePrefix + "JSON/Authentication/1.0/signIn", "1.0", null, this._signInCallback.bindTo(this));
	},
	_signInTimeout: function() {
		// the sign in JSON call didn't fire a callback.  this can happen when the
		// sign-in servers are offline or refusing connection.  generate a exception
		// message, and make the callback
		clearInterval(this._signInTimeoutInterval);
		if (this.secondarySignInCallback) {
			this.secondarySignInCallback({isException:true,message:"Sign in is not currently available."});
		}	
	},
	_signInCallback: function(response) {
		clearInterval(this._signInTimeoutInterval);
		// if sign in was successful, get the canonical user name
		if (this.isException(response) != true) {
			this.isAuthenticated = true;
			this.token = response.token;
			if (response.idleTimeout > 0) {
				this.tokenRefreshInterval = setInterval(this._refreshToken.bindTo(this), response.idleTimeout);
			} else {
				clearInterval(this.tokenRefreshInterval);
			}
			this._getSelfID(this._getSelfIDCallback.bindTo(this));
		// if sign in failed, send the exception message to the immediate caller
		} else {
			if(this.secondarySignInCallback) {
				this.secondarySignInCallback(response);
			}
		}
	},			
	_getSelfID: function(callback) {
		var params = {
			token: this.token
		};
		this._makeJsonServiceCall(params, tpIdentityServicePrefix + "JSON/Self/1.0/getSelfID", "1.0", null, callback||this.errorHandler.bindTo(this));
	},
	extractUserName: function(ID) {
		// utility function for getting the last part of an ID
		return ID.substring(ID.lastIndexOf("/") + 1, ID.length);
	},
	_getSelfIDCallback: function(response){
		// if we could get the self ID, update info on the current user, and send this
		// response out to all event subscribers
		if (!this.isException(response)) {
			this.selfID = response.userID;
			this.userName = this.extractUserName(this.selfID);
			if(this._signInEvents.length > 0) {
				for(var h=0; h<this._signInEvents.length; h++) {
					this._signInEvents[h](response);
				}
			}
		}
		// if get self ID failed, send that message back to the caller
		if(this.secondarySignInCallback) {
			this.secondarySignInCallback(response);
		}
	},	
	_refreshToken: function(){
		this.getSelfID()
	},
	signInWithToken: function(token) {
		this.token = token;
	},
	signOut: function(callback) {
		// clear local sign-in info immediately.  even if the call below fails, we still want
		// to clear out the user's info
		var params = {
			token: this.token
		}
		this.token = undefined;
		this.selfID = undefined;
		this.isAuthenticated = false;
		this.clearProfile();
		if(typeof callback != "undefined") {
			this.secondarySignOutCallback = callback;
		} else {
			this.secondarySignOutCallback = undefined;
		}
		this._makeJsonServiceCall(params, tpIdentityServicePrefix + "JSON/Authentication/1.0/signOut", "1.0", null, this._signOutCallback.bindTo(this));
		clearInterval(this.tokenRefreshInterval);
	},
	_signOutCallback: function(response){
		if (!this.isException(response)) {
			if(this._signOutEvents.length > 0) {
				for(var h=0; h<this._signOutEvents.length; h++) {
					this._signOutEvents[h](response);
				}
			}
		}
		if(this.secondarySignOutCallback) {
			this.secondarySignOutCallback(response);
		}
	},
		
	// Check the permissions of the user.
	// the serviceUrl is that of an Access service.
	authorize: function( operation, serviceUrl, callback )
	{
		var params = {
			"operations[0].instance": operation.instance||"*",
			"operations[0].service": operation.service||"Community Data Service",
			"operations[0].method": operation.method||"*",
			"operations[0].endpoint": operation.endpoint||"*"		
		};
		
		// If the user is logged in, we need to include the account, if they aren't we shouldn't
		if ( typeof this.token != "undefined" ) {
			this._makeJsonServiceCall(params, serviceUrl + "JSON/Authorization/1.0/authorize", null, "", callback, true);	
		} else {
			this._makeJsonServiceCall(params, serviceUrl + "JSON/Authorization/1.0/authorize", null, "", callback, false);
		}
	},
	
	// add
	addTag: function(aboutID, tag, schemaVersion, serviceUrl, errorCallback) {
		var params = {
			aboutID: aboutID,
			value: tag
		}		
		this._makeJsonServiceCall(params, serviceUrl + tpTagMetadataServicePath, null, "create", errorCallback||this.errorHandler.bindTo(this));
	},
	addRating: function(aboutID, rating, schemaVersion, serviceUrl, errorCallback) {
		var params = {
			aboutID: aboutID,
			value: rating
		}
		this._makeJsonServiceCall(params, serviceUrl + tpRatingMetadataServicePath, null, "create", errorCallback||this.errorHandler.bindTo(this));
	},
	addComment: function(aboutID, name, text, url, schemaVersion, serviceUrl, errorCallback) {
		var params = {
			aboutID: aboutID,
			text: text,
			userName: name
		}
		if (url != null && url.length > 0) {
			params.url = url;
		}
		this._makeJsonServiceCall(params, serviceUrl + tpCommentDataServicePath, null, "create", errorCallback||this.errorHandler.bindTo(this));
	},
	addUserList: function ( name, context, itemIDs, schemaVersion, serviceUrl, errorCallback)
	{
		var params = {
			itemIDs: itemIDs,
			name: name,
			context: context
		}
		this._makeJsonServiceCall(params, serviceUrl + tpUserListDataServicePath, null, "create", errorCallback||this.errorHandler.bindTo(this));
	},	
	addUserPlaylist: function ( name, description, context, itemIDs, schemaVersion, serviceUrl, errorCallback)
	{
		var params = {
			itemIDs: itemIDs,
			name: name,
			description: description,
			context: context
		}
		this._makeJsonServiceCall(params, serviceUrl + tpUserListDataServicePath, null, "create", errorCallback||this.errorHandler.bindTo(this));
	},
	addUserProfile: function ( displayName, website, avatar,  schemaVersion, serviceUrl, errorCallback)
	{
		var params = {
			avatar: avatar,
			displayName: displayName,
			publicData: "{url:'" +  website +"'}"
		}
		this._makeJsonServiceCall(params, serviceUrl + tpUserProfileMetadataServicePath, null, "create", errorCallback||this.errorHandler.bindTo(this));
	},	

	// update
	updateUserProfile: function ( displayName, website, avatar,  schemaVersion, serviceUrl, errorCallback)
	{
		var params = {
			avatar: avatar,
			displayName: displayName,
			publicData: "{url:'" +  website +"'}"
		}
		this._makeJsonServiceCall(params, serviceUrl + tpUserProfileMetadataServicePath, null, "update", errorCallback||this.errorHandler.bindTo(this));
	},	
	updateUserList: function ( objectURI, name, context, itemIDs, schemaVersion, serviceUrl, errorCallback)
	{
		var params = {
			ID: objectURI,
			itemIDs: itemIDs,
			name: name,
			context: context
		}
		this._makeJsonServiceCall(params, serviceUrl + tpUserListDataServicePath, null, "update", errorCallback||this.errorHandler.bindTo(this));
	},
	updateUserListName: function ( objectURI, pName, schemaVersion, serviceUrl, errorCallback)
	{
		var params = {
			ID: objectURI,
			name: pName
		}
		this._makeJsonServiceCall(params, serviceUrl + tpUserListDataServicePath, null, "update", errorCallback||this.errorHandler.bindTo(this));
	},
	
	// get
	getTags: function(aboutID, schemaVersion, serviceUrl, callback) {
		var params = {
			byAboutID: aboutID,
			fields: "value",
			sortFields: "value"
		}
		this._makeJsonServiceCall(params, serviceUrl + tpTagMetadataServicePath, schemaVersion, null, callback);
	},
	getRating: function(aboutID, schemaVersion, serviceUrl, callback) {
		var params = {
			byAboutID: aboutID,
			fields: "value"
		}
		this._makeJsonServiceCall(params, serviceUrl + tpRatingMetadataServicePath, schemaVersion, null, callback);
	},
	getComment: function(URI, schemaVersion, callback) {
		var params = {
			fields: "ID,lastModified,userName,url,text,addedByUserID,approved"
		};		
		this._makeJsonServiceCall(params, URI, schemaVersion, null, callback);
	},
	getComments: function(aboutID, schemaVersion, serviceUrl, callback, startIndex, endIndex) {
		var params = {
			byAboutID: aboutID,
			byApproved: "true",
			fields: "ID,added,userName,url,text,addedByUserID",
			sortFields: "added",
			sortDescending: "true"
		}		
		if(typeof startIndex != "undefined" && startIndex != null) {
			params.startIndex = startIndex;
			params.listInfo = true;
		}
		if(typeof endIndex != 'undefined') {
			params.endIndex = endIndex;
			params.listInfo = true;
		}		
		this._makeJsonServiceCall(params, serviceUrl + tpCommentDataServicePath, schemaVersion, null, callback);
	},
	getUserComments: function(userID, schemaVersion, serviceUrl, callback, startIndex, endIndex) {
		var params = {
			byUserID: userID,
			fields: "ID,added,userName,url,text,approved",
			sortFields: "added",
			sortDescending: "true"
		}		
		if(typeof startIndex != "undefined" && startIndex != null) {
			params.startIndex = startIndex;
			params.listInfo = true;
		}
		if(typeof endIndex != 'undefined') {
			params.endIndex = endIndex;
			params.listInfo = true;
		}		
		this._makeJsonServiceCall(params, serviceUrl + tpCommentDataServicePath, schemaVersion, null, callback);
	},
	getUserCommentsAboutContent: function(userID, aboutID, schemaVersion, serviceUrl, callback, startIndex, endIndex) {
		var params = {
			byUserID: userID,
			byAboutID: aboutID,
			fields: "ID,added,userName,url,text,approved",
			sortFields: "added",
			sortDescending: "true"
		}		
		if(typeof startIndex != "undefined" && startIndex != null) {
			params.startIndex = startIndex;
			params.listInfo = true;
		}
		if(typeof endIndex != 'undefined') {
			params.endIndex = endIndex;
			params.listInfo = true;
		}		
		this._makeJsonServiceCall(params, serviceUrl + tpCommentDataServicePath, schemaVersion, null, callback);
	},
	getTotalTags: function(aboutID, schemaVersion, serviceUrl, callback) {
		var params = {
			byAboutID: aboutID,
			fields: "count,value,lastModified",
			sortFields: "value"
		}
		this._makeJsonServiceCall(params, serviceUrl + tpTotalTagMetadataServicePath, schemaVersion, null, callback);
	},
	getTotalTagsByValue: function(value, schemaVersion, serviceUrl, callback) {
		var params = {
			byValue: this.unsanitize(value, true),
			fields: "aboutID",
			sortFields: "lastModified",
			sortDescending: true,
			startIndex: 1,
			endIndex: 500
		}
		this._makeJsonServiceCall(params, serviceUrl + tpTotalTagMetadataServicePath, schemaVersion, null, callback);
	},
	getTotalRating: function(aboutID, schemaVersion, serviceUrl, callback) {
		var params = {
			byAboutID: aboutID,
			fields: "average,count"
		}
		this._makeJsonServiceCall(params, serviceUrl + tpTotalRatingMetadataServicePath, schemaVersion, null, callback);
	},
	getTopRatings: function(schemaVersion, serviceUrl, callback) {
		var params = {
			fields: "aboutID",
			sortFields: "average",
			sortDescending: true,
			startIndex: 1,
			endIndex: 500
		}
		this._makeJsonServiceCall(params, serviceUrl + tpTotalRatingMetadataServicePath, schemaVersion, null, callback);
	},
	getUserList: function(contextString, schemaVersion, serviceUrl, callback) {
		var params = {
			byContext: contextString,
			fields: "ID,itemIDs"
		};
		this._makeJsonServiceCall(params, serviceUrl + tpUserListDataServicePath, schemaVersion, null, callback);
	},
	getUserListWithSpecifiedFields: function(fields,contextString, schemaVersion, serviceUrl, callback) {
		var params = {
			byContext: contextString,
			fields: fields
		};
		this._makeJsonServiceCall(params, serviceUrl + tpUserListDataServicePath, schemaVersion, null, callback);
	},
	getUserProfile: function(userName, schemaVersion, serviceUrl, callback) {	
		var params = {
			byAboutID: userName,
			fields: "avatar,displayName,publicData,aboutID"
		};
		this._makeJsonServiceCall(params, serviceUrl + tpUserProfileMetadataServicePath, schemaVersion, null, callback);
	},
	getUserProfiles: function(userIDQuery, schemaVersion, serviceUrl, callback) {	
		// note that userIDQuery will be "byAboutID=abc&byAboutID=def&byAboutID=ghi", etc.
		var params = {
			fields: "avatar,displayName,publicData,aboutID"
		};
		this._makeJsonServiceCall(params, serviceUrl + tpUserProfileMetadataServicePath + "?" + userIDQuery, schemaVersion, null, callback);
	},
	
	// delete
	deleteTag: function(aboutID, tag, serviceUrl, errorCallback) {
		var params = {
			byValue: tag,
			byAboutID: aboutID
		}
		this._makeJsonServiceCall(params, serviceUrl + tpTagMetadataServicePath, null, "delete", errorCallback||this.errorHandler.bindTo(this));
	},
	deleteComment: function(objectURI, schemaVersion, serviceUrl, errorCallback) {
		var params = {
		}
		this._makeJsonServiceCall(params, objectURI, null, "delete", errorCallback||this.errorHandler.bindTo(this));
	},
	deleteUserList: function(objectURI, schemaVersion, serviceUrl, errorCallback) {
		var params = {
		}
		this._makeJsonServiceCall(params, objectURI, null, "delete", errorCallback||this.errorHandler.bindTo(this));
	},
	
	// make a JSON call
	_makeJsonServiceCall: function(params, serviceUrl, version, method, callback, includeAccount) {	
		if ( typeof includeAccount == "undefined" ) {
			includeAccount = true;
		}
		// set the token if available
		if (!this.anonymousUser && typeof this.token != "undefined") {
			params.token = this.token;
		}
		
		if (includeAccount ) {
			// set the account
			params.account = this.accountURI;
		}
		
		// specify JSON
		params.type = "json";
		
		// specify the version, if provided
		if (version != null && version.length > 0) {
			params.version = version;
		}
		
		// specify the method, if provided.  note in JSON the HTTP method is always "get", so
		// to allow for deletes, etc., we allow the action to be passed in via a parameter
		if (method != null && method.length > 0) {
			params.method = method;
		}		
				
		// make the call using the jQuery library
		serviceUrl += (serviceUrl.indexOf("?") != -1 ? "&" : "?") + "callback=?";
		return j$.getJSON(serviceUrl, params, callback);			
	},
	
	// error handling
	_errors: [],
	errorHandler: function(response) {
		if(response != null )
		{
			if ( response.isException == true) {
				this._errors.push(response);
				if(typeof this._customErrorHandler == "undefined") {
					alert(response.type+": "+response.message);
				} else {
					this._customErrorHandler(response);
				}
			} else if(typeof response == "string") {
				alert(response);
			}
		}
	},
	isException: function(response){
		return (response != null && typeof response.isException != 'undefined')?Boolean(response.isException):false;
	},
	
	// helpers
	sanitize: function(originalText, useNBSPs){
		var sanitizedText = originalText.replace(/&/g, "&amp;")
		var sanitizedText = sanitizedText.replace(/>/g, "&gt;");
		var sanitizedText = sanitizedText.replace(/</g, "&lt;");
		if (useNBSPs) {
			sanitizedText = sanitizedText.replace(/ /g, "&nbsp;");
		}
		return sanitizedText;
	},
	unsanitize: function(sanitizedText, useNBSPs){
		var unsanitizedText = sanitizedText.replace(/&amp;/g, "&")
		var unsanitizedText = unsanitizedText.replace(/&gt;/g, ">");
		var unsanitizedText = unsanitizedText.replace(/&lt;/g, "<");
		if (useNBSPs) {
			unsanitizedText = unsanitizedText.replace(/&nbsp;/g, " ");
		}
		return unsanitizedText;
	},
	// returns the index of the first non-ad clip in the playlist.  if all
	// the clips are ads, returns -1.
	getContentIndex: function(evt){
		if (typeof evt.data.clips != "undefined") {
			for(var i=0; i<evt.data.clips.length; i++) {
				if(evt.data.baseClips[i].isAd == false) {
					return i;
				}
			}
		}
		return -1;	
	},
	setContentIDs: function(items){
		var contentIDs = "";
		var prefix = tpMediaDataServicePrefix + "data/Media/";
		if (typeof items != "undefined" && typeof items.length != "undefined" && items.length > 0) {
			contentIDCount = 0;
			for (var item in items) {
				var aboutID = items[item].aboutID;
				var	IDStart = aboutID.indexOf(prefix);
				if (IDStart == 0) {
					var ID = aboutID.substr(IDStart + prefix.length, aboutID.length - prefix.length);
					var isNumeric = true;
					for (i = 0; i < ID.length; i++) {
						if (ID.charAt(i) < '0' || ID.charAt(i) > '9') {
							isNumeric = false;
							break;
						}
					}					
					if (isNumeric) {
						if (contentIDs.length == 0) {
							contentIDs = ID;
						} else {
							contentIDs += "," + ID;
						}
						// because of URL length limits, cap the total # of content IDs at 100
						if (++contentIDCount == 100) {
							break;
						}
					}
				}
			}
		} else {
			contentIDs = "0";		
		}
		tpController.refreshReleaseModel("", "", null, null, null, ["query=ContentIDs|" + contentIDs]);	
	},
	_uriPattern: undefined,
	isUri: function(uri) {
		// a valid URL starts with "http://" or "https://", and then has at least one alphanumeric character
		if (this._uriPattern == undefined) {
			this._uriPattern = new RegExp();
			this._uriPattern.compile("^(http|https):\/\/[A-Za-z0-9]+");
		}
		return this._uriPattern.test(uri);
	}
}

DomFragment = function(fragmentType, propertiesObject) {
	if(typeof fragmentType == "string") {
		var fragment = document.createElement(fragmentType);
	} else {
		var fragment = fragmentType;
	}
	if(typeof propertiesObject != "undefined") {
		for(p in propertiesObject) {
			if(typeof propertiesObject[p] == "object") {
				if(typeof fragment[p] == "undefined" && p != "toAppend") {
					fragment[p] = propertiesObject[p];
				} else if(p == "toAppend") {
					fragment._cFrag = {};
					for(ta in propertiesObject[p]) {
						if(typeof propertiesObject[p][ta].appendChild != "undefined") {
							fragment.appendChild(propertiesObject[p][ta]);
							fragment._cFrag[ta] = propertiesObject[p][ta];
						} else if(typeof propertiesObject[p][ta][0] != "undefined") {
							for(i=0; i<propertiesObject[p][ta].length; i++) {
								if(typeof propertiesObject[p][ta][0].appendChild != "undefined") {
									fragment.appendChild(propertiesObject[p][ta][0]);
									fragment._cFrag[ta] = propertiesObject[p][ta][0];
								}
							}
						}
					}
				} else {
					for(np in propertiesObject[p]) {
						fragment[p][np] = propertiesObject[p][np];
					}
				}
			} else {
				if(p.toLowerCase() != "class") {
					fragment[p] = propertiesObject[p];
				} else {
					fragment.className = propertiesObject[p];
				}
			}
		}
	}
	return fragment;
}

Function.prototype.bindTo = function (object) {
	var method = this;
	return function () {
		return method.apply(object, arguments);
	};
}

function getCTToken(){
	var token = getRealCookie("ctToken");
	if (token == ''){
		//get token from backend
		var html = j$.ajax({
	 		  type: "GET",
			  url: "/SignIn/ctToken",
			  async: false
		}).responseText;
		token = getRealCookie("ctToken");
	}
	return token;
}


