/**
 * var config = { baseUrl : "/Community", startIndex : 1, pageSize : 12 };
 */
HD.CommunityDAO = function(config) {
	this.config = config || {};

	// {boolean/string} secure: Converts KickApps URL's to
	// https://www.harley-davidson.com/ redirect (or custom URL if specified).
	this.config.secure = this.config.secure || false;
	if (this.config.secure && typeof this.config.secure == 'boolean') {
		this.config.secure = 'https://www.harley-davidson.com/';
	}

	this.mediaBaseUrl = 'http://media.kickstatic.com/';
	this.mediaUrlFields = [ 'thumbUrl', 'url' ];
	this.pageNumber = config.startIndex;
	this.initialPageIndex = config.startIndex;
	this.totalPages = config.startIndex;
	this.totalMedia = 0;
	this.activeItem = null;
	this.filters = config.filters || {};
	this.activeItemIndexOnPage = 0;
	this.activeItemPage = config.startIndex;
	this.observers = [];
	this.ratings = [];
	
	/** REST client (if available) */
	this.rest = HD.util.REST || null;
	if (this.rest && !HD.util.Common.getServerUrl().match(/^https?:\/\/[^/]*?\.harley-davidson\.com.*/)) {
		this.rest.useProxy = true;
	}
	this.restAuth = {};

	if (!!this.config.restoreState) {
		this.restoreState(typeof this.config.restoreState == 'string' ? this.config.restoreState : null, true);
	}
};

HD.CommunityDAO.prototype = {
	adapter: {
		// Media requests.
		getMedia: function(req, cb) { CommunityService.getMedia(req, cb); },
		getPopularMedia: function(req, cb) { CommunityService.getPopularMedia(req, cb); },
		getMedium: function(req, cb) { CommunityService.getMedium(req, cb); },
		getMultipleMedium: function(req, cb) { CommunityService.getMultipleMedium(req, cb); },
		getComments: function(req, cb) { CommunityService.getComments(req, cb); },

		// Content requests.
		getFaceoff: function(req, cb) { CommunityService.getFaceoff(req, cb); },
		getTags: function(req, cb) { CommunityService.getTags(req, cb); },
		getRatings: function(req, cb) { CommunityService.getRatings(req, cb); },
		getMonthly: function(req, cb) { CommunityService.getMonthly(req, cb); },
		getAllBlogAuthors: function(req, cb) { CommunityService.getAllBlogAuthors(cb); },
		getMemberProfile: function(req, cb) { CommunityService.getMemberProfile(req, cb); },

		// Submission requests.
		submitBlogEntry: function(req, cb) { CommunityService.submitBlogEntry(req, cb); },
		submitComment: function(req, cb) { CommunityService.submitComment(req, cb); },
		rateMedia: function(req, cb) { CommunityService.rateMedia(req, cb); },
		
		// Poll requests
		getPollsFeed: function(req, cb) { CommunityService.getPollsFeed(req, cb); },

		// Social media requests.
		getAllFacebookEvents: function(req, cb) { CommunityService.getAllFacebookEvents(req, cb); },
		getAllFacebookEventsAfterDate: function(req, cb) { CommunityService.getAllFacebookEventsAfterDate(req, cb); },
		getFutureFacebookEvents: function(req, cb) { CommunityService.getFutureFacebookEvents(req, cb); },
		getAllFacebookAttendeesForEvent: function(req, cb) { CommunityService.getAllFacebookAttendeesForEvent(req, cb); },
		getTwitterFeed: function(req, cb) { CommunityService.getTwitterFeed(cb); },
		getYoutubeMedia: function(req, cb) { CommunityService.getYoutubeMedia(req, cb); }
	},
  
	getMedia : function(pageNumber, isLastIndexActive, preventSetActiveItem,
			setThisIndex) {

		this.notifyObservers("getMedia_Start");

		this.pageIndex = pageNumber;

		var mediaRequest = {
			pageNumber : pageNumber
		};

		this.setFilters(mediaRequest);

		var cb = this;
		var isLastCb = isLastIndexActive;
		var preventSetActiveItem = preventSetActiveItem || false;

		var callMetadata = {
			callback : function(mediaResponse) {

				var eventName = mediaResponse.success ? "getMedia_Finish"
						: "getMedia_Error";

				var media = mediaResponse.media;

				var filteredMedia = [];

				var prevMedium = null;
				for ( var i = 0, len = media.length; i < len; i++) {
					var medium = media[i];
					if (medium != null) {
						if (prevMedium != null) {
							medium.previous = prevMedium;
						}
						if (i < len - 1) {
							medium.next = media[i + 1];
						}

						cb.setFacade.call(cb, medium);

						filteredMedia.push(medium);
					}
					prevMedium = medium;
				}

				var activeIndex = setThisIndex
						|| (isLastCb ? media.length - 1 : 0);

				// TODO
				if (filteredMedia.length > 0 && !preventSetActiveItem) {
					cb.activeItem = filteredMedia[activeIndex];
				}

				cb.totalPages = mediaResponse.totalPages;
				cb.pageNumber = mediaResponse.pageNumber;
				cb.totalMedia = mediaResponse.totalMedia;

				cb.media = filteredMedia;

				mediaResponse.media = filteredMedia;
				cb.notifyObservers.call(cb, eventName, mediaResponse);

				if (filteredMedia.length > 0) {
					// !!! do not remove this,
					// otherwise 'activeItem_Change' event won't fire
					var itemToSetActive = filteredMedia[activeIndex];

					if (!preventSetActiveItem) {
						cb.activeItem = null;
						cb.setActiveItem.call(cb, itemToSetActive);
					}
				}
			},
			parameters : {
				siteName : this.config.siteName
			}
		};

		if (this.config.preloadedMedia == null) {
			this.adapter.getMedia(mediaRequest, callMetadata);
		} else {
			callMetadata.callback(this.config.preloadedMedia.getMedia());
			this.config.preloadedMedia = null;
		}
	},

	// Convert URL's to secure URL's if needed.
	applySecureUrl : function(medium) {
		if (this.config.secure) {
			for ( var i = 0; i < this.mediaUrlFields.length; i++) {
				var field = [ this.mediaUrlFields[i] ];
				if (medium[field]) {
					medium[field] = medium[field].replace(this.mediaBaseUrl,
							this.config.secure);
				}
			}
		}
		return medium;
	},

	hasNextPage : function() {
		return this.pageNumber < this.totalPages;
	},

	hasPreviousPage : function() {
		return this.pageNumber > this.initialPageIndex;
	},

	getNextPage : function(preventSetActiveItem) {
		if (this.hasNextPage()) {
			this.getMedia(++this.pageNumber, null, preventSetActiveItem);
		}
	},

	getSamePage : function() {
		this.getMedia(this.pageNumber);
	},

	getPreviousPage : function(isLastIndexActive, preventSetActiveItem) {
		if (this.hasPreviousPage()) {
			this.getMedia(--this.pageNumber, isLastIndexActive,
					preventSetActiveItem);
		}
	},

	getActiveItem : function() {
		return this.activeItem;
	},

	hasNextItem : function() {
		if (this.activeItem && this.activeItem.next != null) {
			return true;
		}
		return this.hasNextPage();
	},

	hasPreviousItem : function() {
		if (this.activeItem && this.activeItem.previous != null) {
			return true;
		}
		return this.hasPreviousPage();
	},

	getNextItem : function() {
		if (this.activeItem.next != null) {
			this.setActiveItem(this.activeItem.next);
		} else if (this.hasNextPage()) {
			this.getNextPage();
			this.notifyObservers("activeItem_PageChange");
		}
	},

	getPreviousItem : function() {
		if (this.activeItem.previous != null) {
			this.setActiveItem(this.activeItem.previous);
		} else if (this.hasPreviousPage()) {
			this.getPreviousPage(true);
			this.notifyObservers("activeItem_PageChange");
		}
	},

	setActiveItem : function(item) {

		if (this.activeItem != null && this.activeItem.mediaId == item.mediaId) {
			return;
		}
		this.activeItem = item;
		this.notifyObservers("activeItem_Change", item);
	},

	setFacade : function(medium) {
		if (medium != null) {
			// Apply secure URL if necessary.
			this.applySecureUrl(medium);

			// Extract meta tags.
			var isMetaTag = /^hd:([a-zA-Z0-9_]+?)(=(.+))?$/;
			if (medium.tags && medium.tags.length > 0) {
				medium.metaTags = {};
				for ( var i = medium.tags.length - 1; i >= 0; i--) {
					var metaTag = medium.tags[i].match(isMetaTag);
					if (metaTag) {
						medium.tags.splice(i, 1);
						medium.metaTags[metaTag[1]] = metaTag[3] || true;
					}
				}
			}

			if (HD.community.isBlog(medium.contentType)) {
				medium.facade = new HD.community.Blog(medium);
			} else if (HD.community.isPhoto(medium.contentType)) {
				medium.facade = new HD.community.Photo(medium);
			} else if (HD.community.isVideo(medium.contentType)) {
				medium.facade = new HD.community.Video(medium);
			}
		}
	},

	getMedium : function(mediaId, callback, contentType) {
		this.notifyObservers("getMedium_Start");
		var mediaRequest = {
			mediaId : mediaId
		};

		this.setFilters(mediaRequest);

		if (contentType != null) {
			mediaRequest.contentType = contentType;
		}

		var cb = this;
		var cbCb = callback;

		var callMetadata = {
			callback : function(mediaResponse) {
				var media = mediaResponse.media;
				var eventName = mediaResponse.success ? "getMedium_Finish"
						: "getMedium_Error";
				var medium = media[0];
				cb.setFacade.call(cb, medium);

				cb.insertItem.call(cb, medium);

				if (cbCb != null) {
					cbCb(medium);
				}

				cb.addCachedMedium.call(cb, medium);

				cb.setActiveItem.call(cb, medium);
				cb.notifyObservers.call(cb, eventName, medium);
			},
			parameters : {
				siteName : this.config.siteName
			}
		};

		this.adapter.getMedium(mediaRequest, callMetadata);
	},
	
	getMultipleMedium : function(mediaIds, callback, contentType) {
		this.notifyObservers("getMultipleMedium_Start");
		var mediaRequest = { mediaId: (mediaIds || []).join(','), contentType: contentType || this.config.contentType }; 

		this.setFilters(mediaRequest);

		if (contentType != null) {
			mediaRequest.contentType = contentType;
		}

		var cb = this;
		var cbCb = callback;

		var callMetadata = {
			callback : function(mediaResponse) {
				var media = mediaResponse.media;
				var eventName = mediaResponse.success ? "getMultipleMedium_Finish" : "getMultipleMedium_Error";
				
				for (var i = 0; i < media.length; i++) {
					cb.setFacade.call(cb, media[i]);
					cb.insertItem.call(cb, media[i]);
					cb.addCachedMedium.call(cb, media[i]);
				}

				if (!!cbCb) {
					cbCb(media);
				}
				
				cb.notifyObservers.call(cb, eventName, media);
			},
			parameters : {
				siteName : this.config.siteName
			}
		};

		this.adapter.getMultipleMedium(mediaRequest, callMetadata);
	},

	getTags : function(itemsLimit) {
		this.notifyObservers("getTags_Start");

		var mediaRequest = {
			itemsLimit : itemsLimit
		};

		this.setFilters(mediaRequest);
		// Using tags with this call results in bad data coming back.
		if (mediaRequest.tags) {
			delete mediaRequest.tags;
		}

		var cb = this;

		var callMetadata = {
			callback : function(mediaResponse) {
				var eventName = mediaResponse.success ? "getTags_Finish"
						: "getTags_Error";

				// Remove meta tags.
				var isMetaTag = /^hd:([a-zA-Z0-9_]+?)(=(.+))?$/;
				for ( var i = mediaResponse.tags.length - 1; i >= 0; i--) {
					if (mediaResponse.tags[i].tagName.match(isMetaTag)) {
						mediaResponse.tags.splice(i, 1);
					}
				}

				cb.notifyObservers.call(cb, eventName, mediaResponse);
			},
			parameters : {
				siteName : this.config.siteName
			}
		};

		this.adapter.getTags(mediaRequest, callMetadata);
	},

	getMonthly : function(itemsLimit) {
		this.notifyObservers("getMonthly_Start");

		var mediaRequest = {
			itemsLimit : itemsLimit
		};

		this.setFilters(mediaRequest);

		var cb = this;

		var callMetadata = {
			callback : function(mediaResponse) {
				var eventName = mediaResponse.success ? "getMonthly_Finish"
						: "getMonthly_Error";
				cb.notifyObservers.call(cb, eventName, mediaResponse);
			},
			parameters : {
				siteName : this.config.siteName
			}
		};

		this.adapter.getMonthly(mediaRequest, callMetadata);
	},

	getAllBlogAuthors : function(itemsLimit) {
		this.notifyObservers("getAllBlogAuthors_Start");

		var mediaRequest = {
			itemsLimit : itemsLimit
		};

		this.setFilters(mediaRequest);
		var cb = this;

		var callMetadata = {
			callback : function(mediaResponse) {
				var eventName = "getAllBlogAuthors_Finish";
				cb.notifyObservers.call(cb, eventName, mediaResponse);
			},
			parameters : {
				siteName : this.config.siteName
			}
		};

		this.adapter.getAllBlogAuthors(callMetadata);
	},

	getFacebookEvents : function() {
		this.notifyObservers("getFacebookEvents_Start");

		var cb = this;

		var callMetadata = {
			callback : function(mediaResponse) {
				// var eventName = mediaResponse.success ? "getFBEvents_Finish"
				// : "getFBEvents_Error";
			var eventName = "getFacebookEvents_Finish";
			cb.notifyObservers.call(cb, eventName, mediaResponse);
		},
		parameters : {
			siteName : this.config.siteName,
			userId : "87949232233",//Dark Custom is the default 
			eventsToReturn: 8
		}
		};

		this.adapter.getAllFacebookEvents(parameters, callMetadata);
	},
	
	getFutureFacebookEvents : function() {
		this.notifyObservers("getFutureFacebookEvents_Start");

		var cb = this;

		var callMetadata = {
				callback : function(mediaResponse) {
			// var eventName = mediaResponse.success ? "getFBEvents_Finish"
			// : "getFBEvents_Error";
			var eventName = "getFutureFacebookEvents_Finish";
			cb.notifyObservers.call(cb, eventName, mediaResponse);
		}
		};

		var facebookEventCall = {
				userId : "87949232233",//Dark Custom set as default
				eventsToReturn: 8,
				startDate: "now",
				endDate: ""
		};

		this.adapter.getFutureFacebookEvents(facebookEventCall, callMetadata);
	},

	getAllFacebookAttendeesForEvent : function(eventId, limit) {
		this.notifyObservers("getFacebookAttendeesForEvent_Start");

		var cb = this;

		var callMetadata = {
			callback : function(mediaResponse) {
			//var eventName = mediaResponse.success ? "getFacebookAttendeesForEvent_Finish" : "getFacebookAttendeesForEvent_Error";
			var eventName = "getFacebookAttendeesForEvent_Finish";
			cb.notifyObservers.call(cb, eventName, mediaResponse);
		},
		parameters : {
			siteName : this.config.siteName
		}
		};

    var params = {
      userId: "1047443325",
      eventId: eventId,
      numberOfUsersToReturn: limit
    }

		//this.adapter.getAllFacebookAttendeesForEvent("87949232233", eventId, limit, callMetadata);//dark custom: remmed for testing
		this.adapter.getAllFacebookAttendeesForEvent(params, callMetadata);
	},

	getYoutubeMedia : function(numberToReturn) {
		this.notifyObservers("getYoutube_Start");

		var youtubeRequest = {
			numberToReturn : numberToReturn
		};

		// this.setFilters(youtubeRequest);

		var cb = this;

		var callMetadata = {
			callback : function(mediaResponse) {
				var eventName = "getYoutube_Finish";
				cb.notifyObservers.call(cb, eventName, mediaResponse);
			},
			parameters : {
				siteName : this.config.siteName
			}
		};
		this.adapter.getYoutubeMedia(youtubeRequest, callMetadata);
	},

	getTwitterFeed : function() {
		this.notifyObservers("getTwitterFeed_Start");

		var cb = this;

		var callMetadata = {
			callback : function(mediaResponse) {
				var eventName = "getTwitterFeed_Finish";
				cb.notifyObservers.call(cb, eventName, mediaResponse);
			},
			parameters : {
				siteName : this.config.siteName
			}
		};

		this.adapter.getTwitterFeed(callMetadata);
	},
	
	getPollsFeed : function() {
		this.notifyObservers("getPollsFeed_Start");

		var cb = this;

		var callMetadata = {
			callback : function(mediaResponse) {
				var eventName = "getPollsFeed_Finish";
				cb.notifyObservers.call(cb, eventName, mediaResponse);
			},
			parameters : {
				siteName : this.config.siteName
			}
		};

		this.adapter.getPollsFeed(callMetadata);
	},

	getPopular : function(itemsLimit, sortType) {
		this.notifyObservers("getPopular_Start");

		var mediaRequest = {
			itemsLimit : itemsLimit
		};

		this.setFilters(mediaRequest);
		// if sort type wasn't passed in, default to highest rated
		if (!HD.util.Common.hasValue(sortType)) {
			sortType = HD.SORTS.HIGHEST_RATED;
		}

		mediaRequest.sortType = sortType;

		var cb = this;

		var callMetadata = {
			callback : function(mediaResponse) {
				var eventName = mediaResponse.success ? "getPopular_Finish"
						: "getPopular_Error";

				var media = mediaResponse.media;

				var prevMedium = null;
				for ( var i = 0, len = media.length; i < len; i++) {
					var medium = media[i];
					if (medium != null) {
						if (prevMedium != null) {
							medium.previous = prevMedium;
						}
						if (i < len - 1) {
							medium.next = media[i + 1];
						}
					}
					cb.setFacade.call(cb, medium);
					prevMedium = medium;
				}

				mediaResponse.media = media;

				cb.notifyObservers.call(cb, eventName, mediaResponse);
			},
			parameters : {
				siteName : this.config.siteName
			}
		};

		this.adapter.getPopularMedia(mediaRequest, callMetadata);
	},

	getComments : function(mediaId, contentType) {

		this.notifyObservers("getComments_Start");
		var mediaRequest = {
			mediaId : mediaId
		};

		this.setFilters(mediaRequest);

		if (HD.util.Common.hasValue(contentType)) {
			mediaRequest.contentType = contentType;
		}

		var cb = this;

		var callMetadata = {
			callback : function(mediaResponse) {
				var eventName = mediaResponse.success ? "getComments_Finish"
						: "getComments_Error";
				var media = mediaResponse.media;				
				var medium = media[0];
				var comments = medium.comments;
				
				// Replace the anonymous submitter label
				for (var i=0; i<comments.length; i++){
					var submitter = comments[i].submittedBy;
					if (submitter.match(/^anonymoususer/i)){
				
						comments[i].submittedBy = 'anonymous';
					}
				}
				
				
				// TODO insert into cache setting previous and next
				cb.notifyObservers.call(cb, eventName, medium);
			},
			parameters : {
				siteName : this.config.siteName
			}
		};
		this.adapter.getComments(mediaRequest, callMetadata);
	},
	
	// getFaceoff aggregates getComments(getMedium) and getMedium calls.
	getFaceoff : function(mediaId) {
		this.notifyObservers("getFaceoff_Start");
		this.notifyObservers("getComments_Start");
		var cb = this;
		var request = { mediaId: mediaId };
		this.setFilters(request);
		
		// Use the back-end implementation of getFaceoff if available.
		var metadata = {
			callback : function(response) {
				// Set media facades.
				if (response.success) {
					cb.setFacade(response.faceoff);
					for (var i = 0; i < response.media.length; i++) {
						cb.setFacade(response.media[i]);	
					}
				}
				
				var eventName = response.success ? "_Finish" : "_Error";
				cb.notifyObservers('getComments' + eventName, response.faceoff || null);
				cb.notifyObservers('getFaceoff' + eventName, response);
			},
			parameters : {
				siteName : this.config.siteName
			}
		};
		this.adapter.getFaceoff(request, metadata);
	},
	
	/**
	 * "formId" or HTML Form element
	 */
	submitMedium : function(form) {
		this.notifyObservers("submitMedium_Start");
		var type = "";
		var formEl = form;

		if (form.type.value != null && form.type.value != "") {
			type = "?type=" + form.type.value;
		}

		var cb = this;

		return HD.util.Common.uploadFile(
						form,
						this.config.baseUrl + "/fileUpload" + type,
						function(uploadResponse) {
							var eventName = (uploadResponse.indexOf("success") >= 0) ? "submitMedium_Finish"
									: "submitMedium_Error";
							var eventData = new Array(5);
							eventData[0] = uploadResponse;
							eventData[1] = formEl.title.value;
							eventData[2] = formEl.story.value;
							eventData[3] = formEl.type.value || '';
							eventData[4] = (formEl.category && formEl.category.value) || '';
							clearTimeout(HD.UploadWidget.progressTimer);
							cb.notifyObservers.call(cb, eventName, eventData);
						});
	},

	submitComment : function(mediaId, contentType, comment) {
		this.notifyObservers("submitComment_Start", comment);

		var mediaRequest = {
			mediaId : mediaId,
			comment : comment,
			contentType : contentType
		};

		this.setFilters(mediaRequest);
		var cb = this;

		var callMetadata = {
			callback : function(mediaResponse) {
				var eventName = mediaResponse.success ? "submitComment_Finish"
						: "submitComment_Error";
				var response = null;
				if (mediaResponse.success) {
					// TODO insert into cache setting previous and next
					response = mediaResponse.media[0];
					cb.setFacade.call(cb, response);
				} else {
					response = mediaResponse.errors;
				}

				HD.util.Analytics.track(cb.analyticsCommentString.call(cb,
						response));

				cb.notifyObservers.call(cb, eventName, response);
			},
			parameters : {
				siteName : this.config.siteName
			}
		};

		this.adapter.submitComment(mediaRequest, callMetadata);
	},

	rateMedia : function(mediaId, contentType, rating) {
		this.notifyObservers("rateMedia_Start");

		var mediaRequest = {
			mediaId : mediaId,
			rating : rating,
			contentType : contentType
		};

		this.setFilters(mediaRequest);
		var cb = this;

		var callMetadata = {
			callback : function(mediaResponse) {
				var eventName = mediaResponse.success
						&& mediaResponse.media != null ? "rateMedia_Finish"
						: "rateMedia_Error";

				var medium = null;
				var media = mediaResponse.media;
				if (media != null) {
					medium = media[0];

					cb.setFacade.call(cb, medium);
					cb.insertItem.call(cb, medium);

					cb.addCachedMedium.call(cb, medium);

					HD.util.Analytics.track(cb.analyticsRatingString.call(cb,
							medium));
				}

				// TODO insert into cache setting previous and next
				cb.notifyObservers.call(cb, eventName, medium);
			},
			parameters : {
				siteName : this.config.siteName
			}
		};
		this.adapter.rateMedia(mediaRequest, callMetadata);
	},
	
	/**
	 * Enhances a tasklist object for widget usage
	 * @param {object} [tasklist]
	 *				   A tasklist object
	 * @returns {object} The resulting tasklist
	 */
	_parseTasks: function(tasklist) {		
		var steps = tasklist.steps;
		for (var i = 0; i < steps.length; i++) {
			steps[i].createDate = new Date(steps[i].createDate);
			steps[i].modifiedDate = new Date(steps[i].modifiedDate);
			steps[i]._stepIndex = i;
			for (var j = 0; j < steps[i].tasks.length; j++) {
				steps[i].tasks[j]._stepIndex = i;
				steps[i].tasks[j]._taskIndex = j;
				steps[i].tasks[j].createDate = new Date(steps[i].tasks[j].createDate);
				steps[i].tasks[j].modifiedDate = new Date(steps[i].tasks[j].modifiedDate);
			}
		}
		return tasklist;
	},
	
	/**
	 * Retrieves a list of tasks for a given type/name
	 * @param {string} [type]
	 *				   The tasklist type
	 * @param {string} [name]
	 *				   The tasklist collection name
	 */
	getTasks: function(type, name) {
		var self = this, options = {
			type: type || 'roadmap',
			name: name || 'test'
		};
		this.notifyObservers('getTasks_Start', options);
		if (options.type === 'roadmap') {
			this.restAuthenticate(options.type, null, function(auth) {
				// If authenticated, get the user's roadmap, but otherwise get an empty one.
				var url = '/roadmap/services/retrieve/' + options.name + '.json';
				self.rest.request(
					'GET',
					self.rest.useProxy ? '/Community/services/hd/hd_rest/assets/proxy.jsp?call=' + encodeURIComponent('http://hdgisscwasd01:9202'+url) : url,
					auth.success ? { ilticket: auth.ilTicket } : null,
					function(result) {
						var eventName = 'getTasks_' + (result.success ? 'Finish' : 'Error');
						if (result.success) {
							result = self._parseTasks(result.usermap);
						}
						self.notifyObservers(eventName, result);
					}
				);
			});
		}
	},
	
	/**
	 * Updates a task's status
	 * @param {string} [type]
	 *				   The tasklist type
	 * @param {string} [name]
	 *				   The tasklist collection name
	 * @param {number} taskId
	 *				   The ID of the task to update
	 * @param {string} status
	 *				   The new task status ('C' for completed, 'I' for incomplete, 'S' for skipped)
	 */
	updateTask: function(type, name, taskId, status) {
		var self = this, options = {
			type: type || 'roadmap',
			name: name || 'test',
			taskId: taskId || '',
			status: status || 'I'
		};
		this.notifyObservers('updateTask_Start', options);
		if (options.type === 'roadmap') {
			this.restAuthenticate(options.type, null, function(auth) {
				// Require an authenticated user.
				if (auth.success) {
					var url = '/roadmap/services/updateTask/' + options.name + '/' + options.taskId + '/' + options.status + '.json';
					self.rest.request(
						'GET',
						self.rest.useProxy ? '/Community/services/hd/hd_rest/assets/proxy.jsp?call=' + encodeURIComponent('http://hdgisscwasd01:9202'+url) : url,
						{ ilticket: auth.ilTicket },
						function(result) {
							var eventName = 'updateTask_' + (result.success ? 'Finish' : 'Error');
							if (result.success) {
								result = self._parseTasks(result.usermap);
							}
							self.notifyObservers(eventName, result);
						}
					);
				}
				else {
					self.notifyObservers('updateTask_Error', auth);	
				}
			});
		}
	},
	
	/**
	 * Updates a tasklist's fast track state
	 * @param {string} [type]
	 *				   The tasklist type
	 * @param {string} [name]
	 *				   The tasklist collection name
	 * @param {boolean} isFastTrack
	 *				   Whether to fast track a tasklist
	 */
	setTasksFastTrack: function(type, name, isFastTrack) {
		var self = this, options = {
			type: type || 'roadmap',
			name: name || 'test',
			isFastTrack: isFastTrack || false
		};
		this.notifyObservers('setTasksFastTrack_Start', options);
		if (options.type === 'roadmap') {
			this.restAuthenticate(options.type, null, function(auth) {
				// Require an authenticated user.
				if (auth.success) {
					var url = '/roadmap/services/fastTrack/' + options.name + '/' + options.isFastTrack.toString() + '.json';
					self.rest.request(
						'GET',
						self.rest.useProxy ? '/Community/services/hd/hd_rest/assets/proxy.jsp?call=' + encodeURIComponent('http://hdgisscwasd01:9202'+url) : url,
						{ ilticket: auth.ilTicket },
						function(result) {
							var eventName = 'setTasksFastTrack_' + (result.success ? 'Finish' : 'Error');
							if (result.success) {
								result = self._parseTasks(result.usermap);
							}
							self.notifyObservers(eventName, result);
						}
					);
				}
				else {
					self.notifyObservers('setTasksFastTrack_Error', auth);	
				}
			});
		}
	},
	
	/**
	 * Checks authentication for a REST service
	 * @param {string} [type]
	 *				   The REST service type
	 * @param {object} [params]
	 *				   A collection of options to pass to the REST service
	 * @param {function} callback
	 *				   A callback to execute after checking authentication
	 */
	restAuthenticate: function(type, params, callback) {
		var self = this, options = {
			type: type || 'roadmap',
			params: params || {}
		};
		this.notifyObservers('restAuthenticate_Start', options);
		if (type === 'roadmap') {
			if (login.model.ilTicket) {
				var result = { success: true, ilTicket: login.model.ilTicket };
				this.notifyObservers('restAuthenticate_Finish', result);
				callback(result);
			}
			else {
				var result = { success: false, ilTicket: null };
				this.notifyObservers('restAuthenticate_Error', result);
				callback(result);
			}
		}
	},

	insertItem : function(medium) {
		var cachedMedia = this.media;
		if (cachedMedia != null) {
			for ( var i = 0, len = cachedMedia.length; i < len; i++) {
				if (cachedMedia[i] != null
						&& cachedMedia[i].mediaId == medium.mediaId) {
					// delete cachedMedia[i];
					if (i > 0) {
						medium.previous = cachedMedia[i - 1];
					}
					if (i < len - 1) {
						medium.next = cachedMedia[i + 1];
					}
					cachedMedia[i] = medium;
				}
			}
		}
		this.media = cachedMedia;
	},

	getMemberProfile : function(memberId) {
		this.notifyObservers("getMember_Start");

		var profileRequest = {
			memberId : memberId
		};

		this.setFilters(profileRequest);

		var cb = this;

		var callMetadata = {
			callback : function(memberResponse) {
				var profile = memberResponse.profile;
				var eventName = memberResponse.success ? "getMember_Finish"
						: "getMember_Error";

				cb.notifyObservers.call(cb, eventName, profile);
			},
			parameters : {
				siteName : this.config.siteName
			}
		};

		this.adapter.getMemberProfile(profileRequest, callMetadata);
	},

	getRatings : function(media) {
		this.notifyObservers("getRatings_Start");

		// if no media explicitly passed in, assume user wants to get
		// ratings for current media items
		if (media == null) {
			media = this.media;
		}

		var siteName = this.config.siteName;
		var ratings = [];
		for ( var i = 0, len = media.length; i < len; i++) {
			var medium = media[i];
			ratings.push( {
				mediaId : medium.mediaId,
				contentType : medium.contentType,
				siteName : siteName
			});
		}

		var ratingRequest = {
			ratings : ratings
		};

		this.setFilters(ratingRequest);

		var cb = this;
		var mediaCb = media;

		var callMetadata = {
			callback : function(ratingResponse) {
				var eventName = ratingResponse.success ? "getRatings_Finish"
						: "getRatings_Error";

				var ratings = ratingResponse.ratings;
				var media = mediaCb;

				for ( var i = 0, len = media.length; i < len; i++) {
					var medium = media[i];
					var rating = ratings[i];

					if (medium != null && rating != null) {
						medium.currentUserRating = rating.rating;
						cb.addCachedMedium(medium);
						medium.facade.updateRatingWidgets(medium);
					}
				}
			},
			parameters : {
				siteName : this.config.siteName
			}
		};

		this.adapter.getRatings(ratingRequest, callMetadata);
	},

	getCachedMedium : function(mediaId) {
		var medium = this.ratings[mediaId];

		if (medium == null && this.media != null) {
			var media = this.media;
			for ( var i = 0, len = media.length; i < len; i++) {
				var mediumTemp = media[i];
				if (mediumTemp != null && mediumTemp.mediaId == mediaId) {
					medium = mediumTemp;
					break;
				}
			}
		}

		return medium;
	},

	addCachedMedium : function(medium) {
		this.ratings[medium.mediaId] = medium;
	},

	setFilters : function(request) {
		var filters = this.filters;
		var config = this.config;

		request.siteName = config.siteName;

		if (filters.startDate != null) {
			request.startDate = filters.startDate;
		}
		if (filters.endDate != null) {
			request.endDate = filters.endDate;
		}
		if (filters.sortType != null) {
			request.sortType = filters.sortType;
		}
		if (filters.tags != null) {
			request.tags = filters.tags;
		}
		if (filters.members != null) {
			request.members = filters.members;
		}
		if (filters.metaTags != null) {
			request.tags = (request.tags || []).concat(filters.metaTags);
		}
		if (filters.author != null) {
			request.author = filters.author;
		}
		if (filters.contentSubtype != null) {
			request.contentSubtype = filters.contentSubtype;
		}
		if (filters.numberToReturn != null) {// newksl: youtube related
			request.numberToReturn = filters.numberToReturn;
		}
		if (config.categories != null) {
			request.categories = config.categories;
		}
		if (config.contentType != null && request.contentType == null) {
			request.contentType = config.contentType;
		}
		if (config.pageSize != null) {
			request.pageSize = config.pageSize;
		}
		if (config.thumbWidth != null) {
			request.thumbWidth = config.thumbWidth;
		}
		if (config.mediaWidth != null) {
			request.mediaWidth = config.mediaWidth;
		}

	},

	setDateRange : function(dateRange, skipUpdate, setActive) {
		this.notifyObservers("dateRange_Set", dateRange);
		this.filters.startDate = dateRange.startDate;
		this.filters.endDate = dateRange.endDate;
		if (!skipUpdate) {
			this.getMedia(1, null, !setActive);
		}
	},

	clearDateRange : function(skipUpdate, setActive) {
		this.notifyObservers("dateRange_Clear");
		delete this.filters.startDate;
		delete this.filters.endDate;
		if (!skipUpdate) {
			this.getMedia(1, null, !setActive);
		}
	},

	setMetaTags : function(tags, skipUpdate, setActive) {
		this.filters.metaTags = typeof tags == 'string' ? [ tags ] : tags;
		if (this.filters.metaTags.length == 0) {
			return this.clearMetaTags(skipUpdate);
		}
		this.notifyObservers("metaTags_Set", this.filters.metaTags);
		if (!skipUpdate) {
			this.getMedia(1, null, !setActive);
		}
	},

	clearMetaTags : function(skipUpdate, setActive) {
		delete this.filters.metaTags;
		this.notifyObservers("metaTags_Clear", []);
		if (!skipUpdate) {
			this.getMedia(1, null, !setActive);
		}
	},

	setTags : function(tags, skipUpdate, setActive) {
		this.filters.tags = typeof tags == 'string' ? [ tags ] : tags;
		if (this.filters.tags.length == 0) {
			return this.clearTags(skipUpdate);
		}
		this.notifyObservers("tags_Set", this.filters.tags);
		if (!skipUpdate) {
			this.getMedia(1, null, !setActive);
		}
	},

	clearTags : function(skipUpdate, setActive) {
		delete this.filters.tags;
		this.notifyObservers("tags_Clear", []);
		if (!skipUpdate) {
			this.getMedia(1, null, !setActive);
		}
	},

	setAuthor : function(author, skipUpdate, setActive) {
	
		this.filters.author = author.userName;
		if (this.filters.author.length == 0) {
			return this.clearAuthor(skipUpdate);
		}
		this.notifyObservers("author_Set", author);
		if (!skipUpdate) {
			this.getMedia(1, null, !setActive);
		}
	},

	clearAuthor : function(skipUpdate, setActive) {
		delete this.filters.author;
		this.notifyObservers("author_Clear", []);
		if (!skipUpdate) {
			this.getMedia(1, null, !setActive);
		}
	},

	setContentSubtype : function(contentSubtype, skipUpdate, setActive) {
		this.filters.contentSubtype = contentSubtype;
		if (this.filters.contentSubtype.length == 0) {
			return this.clearContentSubtype(skipUpdate);
		}
		this.notifyObservers("contentSubtype_Set", this.filters.contentSubtype);
		if (!skipUpdate) {
			this.getMedia(1, null, !setActive);
		}
	},

	clearContentSubtype : function(skipUpdate, setActive) {
		delete this.filters.contentSubtype;
		this.notifyObservers("contentSubtype_Clear", []);
		if (!skipUpdate) {
			this.getMedia(1, null, !setActive);
		}
	},

	setCategories : function(categories, skipUpdate, setActive) {
		this.config.categories = categories.slice(0);
		this.notifyObservers("categories_Set", categories);
		if (!skipUpdate) {
			this.getMedia(1, null, !setActive);
		}
	},

	setSort : function(sortType) {
		this.notifyObservers("sortType_Change", sortType);
		this.filters.sortType = sortType;
		this.pageNumber = this.initialPageIndex;
		this.getSamePage();
	},

	getSort : function(sortType) {
		return this.filters.sortType;
	},

	isInCurrentPage : function(itemId) {
		var itemExistsInPage = false;
		var media = this.media;

		for ( var i = 0; i < media.length; i++) {

			if (media[i].mediaId == itemId) {

				itemExistsInPage = true;
				break;
			}

		}
		return itemExistsInPage;
	},

	_generateState : function() {
		// Only include properties that are valid.
		var state = {
			categories : this.config.categories.join(';')
		};
		if (this.filters.tags) {
			state.tags = this.filters.tags.join(';');
		}
		if (this.filters.members) {
			state.members = this.filters.members.join(';');
		}
		if (this.filters.author) {
			state.author = this.filters.author.join(';');
		}
		if (this.filters.contentSubtype) {
			state.contentSubtype = this.filters.contentSubtype.join(';');
		}
		if (this.filters.startDate) {
			state.startDate = this.filters.startDate;
		}
		if (this.filters.endDate) {
			state.startDate = this.filters.startDate;
		}
		if (this.filters.sortType) {
			state.sortType = this.filters.sortType;
		}
		return state;
	},

	_applyState : function(state, skipUpdate) {
		if (!state) {
			return false;
		}
		if (typeof state == 'string') {
			state = YAHOO.util.Cookie._parseCookieHash(state);
		}
		if (state.categories) {
			this.setCategories(state.categories.split(';'), true);
		}
		if (state.tags) {
			this.setTags(state.tags.split(';'), true);
		}
		if (state.author) {
			this.setAuthor(state.author);
		}
		if (state.contentSubtype) {
			this.setContentSubtype(state.contentSubtype);
		}
		if (state.startDate) {
			this.filters.startDate = state.startDate;
		}
		if (state.endDate) {
			this.filters.endDate = state.endDate;
		}
		if (state.sortType) {
			this.filters.sortType = state.sortType;
		}
		if (!skipUpdate) {
			this.getMedia(1);
		}
		return true;
	},

	// Manage state using strings.
	exportState : function() {
		return YAHOO.util.Cookie._createCookieHashString(this._generateState());
	},
	importState : function(stateString, skipUpdate) {
		return this._applyState(stateString, skipUpdate);
	},

	// Manage state using cookies.
	storeState : function(name) {
		return YAHOO.util.Cookie.setSubs(name || this.config.siteName, this
				._generateState());
	},
	restoreState : function(name, skipUpdate) {
		return this._applyState(YAHOO.util.Cookie.getSubs(name
				|| this.config.siteName), skipUpdate);
	},
	clearState : function(name) {
		return YAHOO.util.Cookie.remove(name || this.config.siteName);
	},

	analyticsRatingString : function(item) {
		return "default_analyticsRatingString";
	},

	analyticsCommentString : function(item) {
		return "default_analyticsCommentString";
	}
};

HD.extend(HD.CommunityDAO, [ HD.util.Observable ]);

HD.register('hd_community_model', 'HD.CommunityDAO', {
	version : "1.0",
	build : "1"
});