
//TODO: improvement - make the function names in the Sequencers be named Sequencer2004_xxx, etc?..will make it clear where you are when doing Finds and such

function Sequencer(lookAhead, activities){
	
	this.LookAhead = lookAhead;
	this.Activities = activities;
	
	this.NavigationRequest = null;
	this.SuspendedActivity = null;
	this.CurrentActivity = null;
	
	this.ExceptionText = "";
	
	this.AtEndOfCourse = false;
	this.AtStartOfCourse = false;
}

Sequencer.prototype.OverallSequencingProcess = Sequencer_OverallSequencingProcess;
Sequencer.prototype.SetSuspendedActivity = Sequencer_SetSuspendedActivity;
Sequencer.prototype.GetSuspendedActivity = Sequencer_GetSuspendedActivity;
Sequencer.prototype.Start = Sequencer_Start;
Sequencer.prototype.InitialRandomizationAndSelection = Sequencer_InitialRandomizationAndSelection;
Sequencer.prototype.GetCurrentActivity = Sequencer_GetCurrentActivity;
Sequencer.prototype.GetExceptionText = Sequencer_GetExceptionText;
Sequencer.prototype.GetExitAction = Sequencer_GetExitAction;
Sequencer.prototype.IsActivityLastOverall = Sequencer_IsActivityLastOverall;
Sequencer.prototype.IsActivityFirstOverall = Sequencer_IsActivityFirstOverall;
Sequencer.prototype.EvaluatePossibleNavigationRequests = Sequencer_EvaluatePossibleNavigationRequests;
Sequencer.prototype.InitializePossibleNavigationRequestAbsolutes = Sequencer_InitializePossibleNavigationRequestAbsolutes;
Sequencer.prototype.ContentDeliveryEnvironmentActivityDataSubProcess = Sequencer_ContentDeliveryEnvironmentActivityDataSubProcess;

Sequencer.prototype.LogSeq = Sequencer_LogSeq;
Sequencer.prototype.LogSeqAudit = Sequencer_LogSeqAudit;
Sequencer.prototype.LogSeqReturn = Sequencer_LogSeqReturn;

function Sequencer_OverallSequencingProcess(){

	var logParent = this.LogSeqAudit("OverallSequencingProcess for SCORM 1.1 / SCORM 1.2");
	
	this.ExceptionText = "";
	
	this.LogSeq("Transferring RTE data to Activity data", logParent);
	this.CurrentActivity.TransferRteDataToActivity();

	if ( (this.CurrentActivity.LearningObject.ScormType === SCORM_TYPE_ASSET) && this.CurrentActivity.WasLaunchedThisSession() ) {
			this.LogSeq("This activity utilized a launchable Asset, so automatically complete it", logParent);
			this.CurrentActivity.SetAttemptProgressStatus(true);			
			this.CurrentActivity.SetAttemptCompletionStatus(true);
	}
	
	this.LogSeq("Rolling up activity data", logParent);
	this.RollupData(this.CurrentActivity);
	
	this.LogSeq("Checking for first SCO pretest", logParent);
	if (Control.Package.Properties.FirstScoIsPretest === true){
		if (this.IsActivityFirstOverall(this.CurrentActivity)){
			if (this.CurrentActivity.IsSatisfied() === true){
				this.LogSeq("Pretest satisfied, marking all activities complete", logParent);
				this.MarkAllActivitiesComplete();
			}
		}
	}

	if (this.NavigationRequest === null){
		
		var exitAction = this.GetExitAction(this.GetCurrentActivity(), false, logParent);
		this.LogSeq("No API Runtime Nav Request, exit action=" + exitAction, logParent);
		
		//TODO: add get text to integration layer
		var messageText = "";
		
		if (exitAction == EXIT_ACTION_EXIT_CONFIRMATION ||
		    exitAction == EXIT_ACTION_DISPLAY_MESSAGE){
		
			var rootActivity = Control.Activities.GetRootActivity();
			var courseIsSatisfied = (rootActivity.IsCompleted() || rootActivity.IsSatisfied());
			
			if (courseIsSatisfied === true){
				messageText = IntegrationImplementation.GetString("The course is now complete. Please make a selection to continue.");
			}
			else{
				messageText = IntegrationImplementation.GetString("Please make a selection to continue.");
			}
		}
		
		switch (exitAction){

			case (EXIT_ACTION_EXIT_NO_CONFIRMATION):
				this.NavigationRequest = new NavigationRequest(NAVIGATION_REQUEST_EXIT_ALL, null, "");
			break;
			
			case (EXIT_ACTION_EXIT_CONFIRMATION):
				
				
				if (confirm(IntegrationImplementation.GetString("Would you like to exit the course now?"))){
					this.NavigationRequest = new NavigationRequest(NAVIGATION_REQUEST_EXIT_ALL, null, "");
				}
				else{
					this.NavigationRequest = new NavigationRequest(NAVIGATION_REQUEST_DISPLAY_MESSAGE, null, messageText);
				}
			break;
			
			case (EXIT_ACTION_GO_TO_NEXT_SCO):
				this.NavigationRequest = new NavigationRequest(NAVIGATION_REQUEST_CONTINUE, null, "");
			break;
			
			case (EXIT_ACTION_DISPLAY_MESSAGE):
				
				this.NavigationRequest = new NavigationRequest(NAVIGATION_REQUEST_DISPLAY_MESSAGE, null, messageText);
			break;
			
			case (EXIT_ACTION_DO_NOTHING):
				this.NavigationRequest = null;
			break;
			
			case (EXIT_ACTION_REFRESH_PAGE):
				Control.RefreshPage();
			break;
		}		
	}
	
	if (this.NavigationRequest == null){
		this.LogSeqReturn("No navigation request, exiting", logParent);
		return;
	}
	
	switch (this.NavigationRequest.Type){
		
		case NAVIGATION_REQUEST_CONTINUE:
			this.DoContinue();
		break;
		
		case NAVIGATION_REQUEST_PREVIOUS:
			this.DoPrevious();
		break;
		
		case NAVIGATION_REQUEST_CHOICE:
			this.DoChoice(this.NavigationRequest.TargetActivity);
		break;
		
		case NAVIGATION_REQUEST_EXIT:
			//sco should already be unloaded before this gets executed
			//Control.ExitSco();
		break;
		
		case NAVIGATION_REQUEST_EXIT_ALL:
			Control.ExitScormPlayer();
		break;
		
		case NAVIGATION_REQUEST_SUSPEND_ALL:
			Control.ExitScormPlayer();
		break;
		
		case NAVIGATION_REQUEST_ABANDON:
			//sco should already be unloaded before this gets executed
			//Control.ExitSco();
		break;
		
		case NAVIGATION_REQUEST_ABANDON_ALL:
			Control.ExitScormPlayer();
		break;
		
		case NAVIGATION_REQUEST_DISPLAY_MESSAGE:
			//do nothing
		break;
		
		case NAVIGATION_REQUEST_EXIT_PLAYER:
			Control.ExitScormPlayer();
		break;
		
		default:
			Debug.AssertError("Recieved an unrecognized navigation request - " + this.NavigationRequest);
			break;
	}
	
	this.LogSeqReturn("", logParent);
}


function Sequencer_SetSuspendedActivity(activity){
	this.SuspendedActivity = activity;
}

function Sequencer_GetSuspendedActivity(){
	return this.SuspendedActivity;
}

function Sequencer_Start(){

	var activityToDeliver;
	
	if (this.SuspendedActivity !== null){
		activityToDeliver = this.SuspendedActivity;
	}
	else{
		activityToDeliver = this.GetFirstIncompleteActivity(this.Activities.SortedActivityList);
	}
		
	if (Control.Package.Properties.AlwaysFlowToFirstSco === true){
		this.DeliverThisActivity(activityToDeliver);
	}
	else{
		var messageText = IntegrationImplementation.GetString("Please make a selection to continue.");
		this.CurrentActivity = activityToDeliver;
		this.NavigationRequest = new NavigationRequest(NAVIGATION_REQUEST_DISPLAY_MESSAGE, null, messageText);
	}
		
}


function Sequencer_InitialRandomizationAndSelection(){
//nothing to do here in 1.2
}

function Sequencer_GetCurrentActivity(){
	return this.CurrentActivity;
}

function Sequencer_GetExceptionText(){
	return this.ExceptionText;
}


function Sequencer_GetExitAction(activity, scoIsStillActive, logEntry){

	var exitType = activity.RunTime.Exit;
	
	//translate the exit type into SCORM 1.2
	if (exitType == SCORM_EXIT_UNKNOWN){
		exitType = SCORM_EXIT_NORMAL;
	}
	
	var isLastActivity = this.IsActivityLastOverall(activity, logEntry);
	
	var activityIsComplete;
	
	if (scoIsStillActive){
		activityIsComplete = ((activity.RunTime.CompletionStatus == SCORM_STATUS_COMPLETED) || (activity.RunTime.SuccessStatus == SCORM_STATUS_PASSED));
	}
	else{
		activityIsComplete = (activity.IsCompleted() == true || activity.IsSatisfied() == true);
	}
	
	var rootActivity = Control.Activities.GetRootActivity();
	var courseIsSatisfied = (rootActivity.IsCompleted() == true || rootActivity.IsSatisfied() == true);
	
	var exitAction;
	
	if (isLastActivity){
	
		if (courseIsSatisfied === true){
			
			switch(exitType){
			
				case SCORM_EXIT_NORMAL:
					logEntry.write("Using finalScoCourseSatisfiedNormalExitAction parameter");
					exitAction = RegistrationToDeliver.Package.Properties.FinalScoCourseSatisfiedNormalExitAction;
				break;				
				case SCORM_EXIT_SUSPEND:
					logEntry.write("Using finalScoCourseSatisfiedSuspendExitAction parameter");
					exitAction = RegistrationToDeliver.Package.Properties.FinalScoCourseSatisfiedSuspendExitAction;
				break;					
				case SCORM_EXIT_TIME_OUT:
					logEntry.write("Using finalScoCourseSatisfiedTimeoutExitAction parameter");
					exitAction = RegistrationToDeliver.Package.Properties.FinalScoCourseSatisfiedTimeoutExitAction;
				break;
				case SCORM_EXIT_LOGOUT:
					logEntry.write("Using finalScoCourseSatisfiedLogoutExitAction parameter");
					exitAction = RegistrationToDeliver.Package.Properties.FinalScoCourseSatisfiedLogoutExitAction;
				break;
			}
			
		}
		else{
			switch(exitType){
				case SCORM_EXIT_NORMAL:
					logEntry.write("Using finalScoCourseNotSatisfiedNormalExitAction parameter");
					exitAction = RegistrationToDeliver.Package.Properties.FinalScoCourseNotSatisfiedNormalExitAction;
				break;				
				case SCORM_EXIT_SUSPEND:
					logEntry.write("Using finalScoCourseNotSatisfiedSuspendExitAction parameter");
					exitAction = RegistrationToDeliver.Package.Properties.FinalScoCourseNotSatisfiedSuspendExitAction;
				break;					
				case SCORM_EXIT_TIME_OUT:
					logEntry.write("Using finalScoCourseNotSatisfiedTimeoutExitAction parameter");
					exitAction = RegistrationToDeliver.Package.Properties.FinalScoCourseNotSatisfiedTimeoutExitAction;
				break;
				case SCORM_EXIT_LOGOUT:
					logEntry.write("Using finalScoCourseNotSatisfiedLogoutExitAction parameter");
					exitAction = RegistrationToDeliver.Package.Properties.FinalScoCourseNotSatisfiedLogoutExitAction;
				break;
	
			}
		}
	}
	else{
	
		if (activityIsComplete === true){
		
			switch(exitType){
				case SCORM_EXIT_NORMAL:
					logEntry.write("Using intermediateScoSatisfiedNormalExitAction parameter");
					exitAction = RegistrationToDeliver.Package.Properties.IntermediateScoSatisfiedNormalExitAction;
				break;				
				case SCORM_EXIT_SUSPEND:
					logEntry.write("Using intermediateScoSatisfiedSuspendExitAction parameter");
					exitAction = RegistrationToDeliver.Package.Properties.IntermediateScoSatisfiedSuspendExitAction;
				break;					
				case SCORM_EXIT_TIME_OUT:
					logEntry.write("Using intermediateScoSatisfiedTimeoutExitAction parameter");
					exitAction = RegistrationToDeliver.Package.Properties.IntermediateScoSatisfiedTimeoutExitAction;
				break;
				case SCORM_EXIT_LOGOUT:
					logEntry.write("Using intermediateScoSatisfiedLogoutExitAction parameter");
					exitAction = RegistrationToDeliver.Package.Properties.IntermediateScoSatisfiedLogoutExitAction;
				break;
			}
		}
		else{
			switch(exitType){
				case SCORM_EXIT_NORMAL:
					logEntry.write("Using intermediateScoNotSatisfiedNormalExitAction parameter");
					exitAction = RegistrationToDeliver.Package.Properties.IntermediateScoNotSatisfiedNormalExitAction;
				break;				
				case SCORM_EXIT_SUSPEND:
					logEntry.write("Using intermediateScoNotSatisfiedSuspendExitAction parameter");
					exitAction = RegistrationToDeliver.Package.Properties.IntermediateScoNotSatisfiedSuspendExitAction;
				break;					
				case SCORM_EXIT_TIME_OUT:
					logEntry.write("Using intermediateScoNotSatisfiedTimeoutExitAction parameter");
					exitAction = RegistrationToDeliver.Package.Properties.IntermediateScoNotSatisfiedTimeoutExitAction;
				break;
				case SCORM_EXIT_LOGOUT:
					logEntry.write("Using intermediateScoNotSatisfiedLogoutExitAction parameter");
					exitAction = RegistrationToDeliver.Package.Properties.IntermediateScoNotSatisfiedLogoutExitAction;
				break;
			}
		}
	}
	
	return exitAction;
}

//private to this sequencer

Sequencer.prototype.LogSeq = Sequencer_LogSeq;
Sequencer.prototype.LogSeqAudit = Sequencer_LogSeqAudit;

Sequencer.prototype.DeliverThisActivity = Sequencer_DeliverThisActivity;
Sequencer.prototype.GetFirstIncompleteActivity = Sequencer_GetFirstIncompleteActivity;
Sequencer.prototype.DoContinue = Sequencer_DoContinue;
Sequencer.prototype.DoPrevious = Sequencer_DoPrevious;
Sequencer.prototype.DoChoice = Sequencer_DoChoice;
Sequencer.prototype.RollupData = Sequencer_RollupData;
Sequencer.prototype.ActivityRollupProcess = Sequencer_ActivityRollupProcess;
Sequencer.prototype.MarkAllActivitiesComplete = Sequencer_MarkAllActivitiesComplete;

function Sequencer_LogSeq(str){

	if (this.LookAhead === true){
		Debug.WriteLookAheadDetailed(str);
	}
	else{
		Debug.WriteSequencingDetailed(str);
	}
}

function Sequencer_LogSeqAudit(str){
	
	if (this.LookAhead === true){
		Debug.WriteLookAheadAudit(str);
	}
	else{
		Debug.WriteSequencingAudit(str);
	}
}

function Sequencer_DeliverThisActivity(activityToDeliver){

	if (Control.Package.Properties.ScoLaunchType !== LAUNCH_TYPE_POPUP_AFTER_CLICK) {
		this.ContentDeliveryEnvironmentActivityDataSubProcess(activityToDeliver);
	}

	this.CurrentActivity = activityToDeliver;
	
	var sortedActivityList = this.Activities.SortedActivityList;	
	for (var i=0; i < sortedActivityList.length; i++){
		sortedActivityList[i].SetActive(false);		
	}
	
	var activeParents = this.Activities.GetActivityPath(activityToDeliver, true);
	for (var i=0; i < activeParents.length; i++){
		activeParents[i].SetActive(true);
	}
	
	Control.DeliverActivity(activityToDeliver);	
}

function Sequencer_GetFirstIncompleteActivity(sortedActivityList){
	
	//looks for the first activity that is not completed or passed and returns it.
	//if all activities are completed or passed, returns the first deliverable activity
	
	var firstDeliverableActivity = null;
	
	var satisfied;
	var completed;
	
	for (var i=0; i < sortedActivityList.length; i++){

		if (sortedActivityList[i].IsDeliverable() === true){
			
			if (firstDeliverableActivity === null){
				firstDeliverableActivity = sortedActivityList[i];
			}
			
			satisfied = sortedActivityList[i].IsSatisfied();
			completed = sortedActivityList[i].IsCompleted();
			
			if (completed == false || completed == RESULT_UNKNOWN || (completed == true && satisfied == false)){
				
				//If the SCO is browsed, then skip it as well (this is essentially "complete" in no-credit/browse mode, but we don't 
				//record that as such in the activity data
				//This is mostly here for the 1.2 Test Suite. In a real deployment, the no-credit mode likely won't even be persisting data.
				
				if (sortedActivityList[i].RunTime !== null && sortedActivityList[i].RunTime.CompletionStatus != SCORM_STATUS_BROWSED){
					return sortedActivityList[i];
				}
			}
		}
	}
	
	if (firstDeliverableActivity !== null){
		return firstDeliverableActivity;
	}
	else{
		Debug.AssertError("No Deliverable Activities Found");
	}
}


function Sequencer_DoContinue(){
	
	if (this.AtEndOfCourse === true){
		return;
	}
	
	var currentActivityIndex;
	
	if (this.AtStartOfCourse === true){
		currentActivityIndex = -1;
	}
	else{
		currentActivityIndex = this.Activities.GetSortedIndexOfActivity(this.CurrentActivity);
	}
	
	var nextActivity = null;

	for (var i = (currentActivityIndex + 1); i < this.Activities.SortedActivityList.length; i++){
		if (this.Activities.SortedActivityList[i].IsDeliverable() === true){
			nextActivity = this.Activities.SortedActivityList[i];
			break;
		}
	}

	if (nextActivity !== null){
		this.AtEndOfCourse = false;
		this.AtStartOfCourse = false;
		this.DeliverThisActivity(nextActivity);
	}
	else{
		this.AtEndOfCourse = true;
		this.ExceptionText = IntegrationImplementation.GetString("You have reached the end of the course.");
	}
}


function Sequencer_DoPrevious(){

	if (this.AtStartOfCourse === true){
		return;
	}
	
	var currentActivityIndex;
	
	if (this.AtEndOfCourse === true){
		currentActivityIndex = this.Activities.SortedActivityList.length;
	}
	else{
		currentActivityIndex = this.Activities.GetSortedIndexOfActivity(this.CurrentActivity);
	}
	
	var previousActivity = null;

	for (var i = (currentActivityIndex - 1); i >= 0; i--){
		if (this.Activities.SortedActivityList[i].IsDeliverable() === true){
			previousActivity  = this.Activities.SortedActivityList[i];
			break;
		}
	}

	if (previousActivity !== null){
		this.AtEndOfCourse = false;
		this.AtStartOfCourse = false;
		this.DeliverThisActivity(previousActivity );
	}
	else{
		this.AtStartOfCourse = true;
		this.ExceptionText = IntegrationImplementation.GetString("You have reached the beginning of the course.");
	}
}

function Sequencer_DoChoice(targetItemIdentifier){
	
	var chosenActivity = null;
	
	chosenActivity = this.Activities.GetActivityFromIdentifier(targetItemIdentifier);
	
	if (chosenActivity !== null){
		if (chosenActivity.IsDeliverable() === true){
			
			this.AtEndOfCourse = false;
			this.AtStartOfCourse = false;
			
			this.DeliverThisActivity(chosenActivity);
		}
		else{
			Debug.AssertError("Chosen activity is not deliverable.");
		}
	}
	else{
		//already asserted an error in GetActivityFromIdentifier
	}
}

function Sequencer_RollupData(startActivity){

	var aryParentActivities = this.Activities.GetActivityPath(startActivity);

	for (var i=0; i < aryParentActivities.length; i++){
		
		this.ActivityRollupProcess(aryParentActivities[i]);
	}	
}

function Sequencer_ActivityRollupProcess(activity){

	var applicableChildren = activity.GetChildren();
	
	var anyAttempted = false;
	
	var allNotSatisfied = true;
	var allSatisfied = true;
	
	var allIncomplete = true;
	var allCompleted = true;
	
	var allSatisfactorilyCompleted = true;
	
	var attempted;
	var satisfied;
	var notSatisfied;
	var completed;
	var incomplete;
	var satisfactorilyCompleted;
	
	var numActivitiesWithScores = 0;
	var totalScoreValue = null;
	var actualScore;
	
	//TODO: do we want to try to roll up time in 1.2? - no fields for time in the db right now
	//TODO: is attempt count updated appropriately?
	
	var targetObjective = activity.GetPrimaryObjective();
	
	//reset the status
	targetObjective.SetProgressStatus(false, false, activity);
	targetObjective.SetSatisfiedStatus(false);
	
	targetObjective.SetMeasureStatus(false, activity);
	
	activity.SetAttemptProgressStatus(false);
	activity.SetAttemptCompletionStatus(false);
	
	//aggregate the status of all the children
	var childTargetObjective;
	for (var i=0; i < applicableChildren.length; i++){
		
		attempted = (applicableChildren[i].IsAttempted() === true);	
		
		satisfied = applicableChildren[i].IsSatisfied();
		notSatisfied = (satisfied === false && attempted === true);
		
		completed = applicableChildren[i].IsCompleted();
		incomplete = (completed === false || attempted === true);
		
		satisfactorilyCompleted = (completed === true && (notSatisfied !== true) );		//completed and not failed
		
		anyAttempted = (anyAttempted === true || attempted === true);
		
		allSatisfied = (allSatisfied === true && (satisfied === true));		
		allNotSatisfied = (allNotSatisfied === true && notSatisfied === true);
		
		allCompleted = (allCompleted === true && (completed === true));
		allIncomplete = (allIncomplete === true && incomplete === true);
		
		allSatisfactorilyCompleted = (allSatisfactorilyCompleted === true && (satisfactorilyCompleted === true));
		
		childTargetObjective = applicableChildren[i].GetPrimaryObjective();
		if (childTargetObjective.GetMeasureStatus(applicableChildren[i], false) === true){
			
			numActivitiesWithScores++;
			
			if (totalScoreValue === null){totalScoreValue = 0;}
			
			totalScoreValue = totalScoreValue + childTargetObjective.GetNormalizedMeasure(applicableChildren[i], false);
		}
	}
	
	//rollup and normalize the children's scores into this score
	if (totalScoreValue !== null){
	
		switch (Control.Package.Properties.ScoreRollupMode){
		
			case (SCORE_ROLLUP_METHOD_SCORE_PROVIDED_BY_COURSE):
				actualScore = totalScoreValue;
			break;
			
			case (SCORE_ROLLUP_METHOD_AVERAGE_SCORE_OF_ALL_UNITS):
				actualScore = (totalScoreValue / applicableChildren.length);
			break;
			
			case (SCORE_ROLLUP_METHOD_AVERAGE_SCORE_OF_ALL_UNITS_WITH_SCORES):
				actualScore = (totalScoreValue / numActivitiesWithScores);
			break;
			
			case (SCORE_ROLLUP_METHOD_FIXED_AVERAGE):			
				// If it's the root, re-tally up all scores in the whole course, otherwise rollup will be based on children only.
				// The intermediate, non root, rollup data will most likely be inivalid, but this behavior isn't well-defined
				// and the root activity is all that matters in almost all cases.
				if (activity.IsTheRoot()) {
					var totalScoreValue = 0;
					for (var i=0; i < Control.Activities.ActivityList.length; i++) {
						var rt = Control.Activities.ActivityList[i].RunTime;
						if (rt !== null && rt !== undefined && rt.ScoreScaled !== null) {
							totalScoreValue += rt.ScoreScaled;
						}
					}
				} 
				actualScore = (totalScoreValue / Control.Package.Properties.NumberOfScoringObjects);
			break;
			
			default:
				Debug.AssertError("Invalid Score Rollup Mode Detected-" + Control.Package.Properties.ScoreRollupMode);
			break;
		}
		
		actualScore = RoundToPrecision(actualScore, 7);
		
		targetObjective.SetMeasureStatus(true, activity);
		targetObjective.SetNormalizedMeasure(actualScore, activity);
	}
	
	//if anything is attempted, we have a valid completion status
	if (anyAttempted){
		activity.SetAttemptProgressStatus(true);
		activity.SetActivityProgressStatus(true);
	}
	
	//set the status to incomplete if appropriate
	if (allIncomplete === true || anyAttempted){
		activity.SetAttemptProgressStatus(true);
		activity.SetAttemptCompletionStatus(false);
	}
	
	//determine completion based on the the method selected in the package properties		
	switch (Control.Package.Properties.StatusRollupMode){
	
		case (STATUS_ROLLUP_METHOD_STATUS_PROVIDED_BY_COURSE):
			
			if (allCompleted === true){
				activity.SetAttemptProgressStatus(true);
				activity.SetAttemptCompletionStatus(true);
			}

		break;
		
		case (STATUS_ROLLUP_METHOD_COMPLETE_WHEN_ALL_UNITS_COMPLETE):
			
			if (allCompleted === true || allSatisfied === true || allNotSatisfied === true){
				activity.SetAttemptProgressStatus(true);
				activity.SetAttemptCompletionStatus(true);
			}
			
		break;
		
		case (STATUS_ROLLUP_METHOD_COMPLETE_WHEN_ALL_UNITS_SATISFACTORILY_COMPLETE):
		
			if (allSatisfactorilyCompleted === true){
				activity.SetAttemptProgressStatus(true);
				activity.SetAttemptCompletionStatus(true);
			}
			
		break;
		
		case (STATUS_ROLLUP_METHOD_COMPLETE_WHEN_THRESHOLD_SCORE_IS_MET):
		
			if (actualScore >= Control.Package.Properties.ThresholdScore){
				activity.SetAttemptProgressStatus(true);
				activity.SetAttemptCompletionStatus(true);
			}
			
		break;
		
		case (STATUS_ROLLUP_METHOD_COMPLETE_WHEN_ALL_UNITS_COMPLETE_AND_THRESHOLD_SCORE_IS_MET):
			
			if ( (allCompleted === true || allSatisfied === true || allNotSatisfied === true)
				&& (actualScore >= Control.Package.Properties.ThresholdScore) ) {
				
				activity.SetAttemptProgressStatus(true);
				activity.SetAttemptCompletionStatus(true);
			}
			
		break;	
		
		default:
			Debug.AssertError("Invalid Status Rollup Mode Detected-" + Control.Package.Properties.StatusRollupMode);
		break;
	}
	
	
	//set the satisfaction status
	if (allNotSatisfied === true){	
		targetObjective.SetProgressStatus(true, false, activity);
		targetObjective.SetSatisfiedStatus(false);
	}
	
	if (allSatisfied === true){
		targetObjective.SetProgressStatus(true, false, activity);
		targetObjective.SetSatisfiedStatus(true);
	}

	
}


function Sequencer_IsActivityLastOverall(activity){
	if (this.Activities.SortedActivityList[this.Activities.SortedActivityList.length - 1] == activity){
		return true;
	}
	else{
		return false;
	}
}

function Sequencer_IsActivityFirstOverall(activity){
	
	var sortedActivityList = this.Activities.SortedActivityList;
	
	for (var i=0; i < sortedActivityList.length; i++){

		if (sortedActivityList[i].IsDeliverable() === true){
			if (activity == sortedActivityList[i]){
				return true;
			}
			else{
				return false;
			}
		}
	}
}


function Sequencer_EvaluatePossibleNavigationRequests(aryPossibleRequests){
	
	//look at package properties to see what should and should not be enabled
	var packageProperties = Control.Package.Properties;

	
	aryPossibleRequests[POSSIBLE_NAVIGATION_REQUEST_INDEX_START].WillSucceed = true;
	aryPossibleRequests[POSSIBLE_NAVIGATION_REQUEST_INDEX_RESUME_ALL].WillSucceed = true;
	aryPossibleRequests[POSSIBLE_NAVIGATION_REQUEST_INDEX_CONTINUE].WillSucceed = (this.AtEndOfCourse === false && packageProperties.EnableFlowNav === true);
	aryPossibleRequests[POSSIBLE_NAVIGATION_REQUEST_INDEX_PREVIOUS].WillSucceed = (this.AtStartOfCourse === false && packageProperties.EnableFlowNav === true);
	aryPossibleRequests[POSSIBLE_NAVIGATION_REQUEST_INDEX_EXIT].WillSucceed = true;
	aryPossibleRequests[POSSIBLE_NAVIGATION_REQUEST_INDEX_EXIT_ALL].WillSucceed = true;
	aryPossibleRequests[POSSIBLE_NAVIGATION_REQUEST_INDEX_SUSPEND_ALL].WillSucceed = true;
	aryPossibleRequests[POSSIBLE_NAVIGATION_REQUEST_INDEX_ABANDON].WillSucceed = true;
	aryPossibleRequests[POSSIBLE_NAVIGATION_REQUEST_INDEX_ABANDON_ALL].WillSucceed = true;
	
	var activity;
	for (var i=POSSIBLE_NAVIGATION_REQUEST_INDEX_CHOICE; i < aryPossibleRequests.length; i++){
		
		activity = this.Activities.GetActivityFromIdentifier(aryPossibleRequests[i].TargetActivityItemIdentifier);
		
		aryPossibleRequests[i].WillSucceed = (activity.IsDeliverable() && packageProperties.EnableChoiceNav === true);
	}
	
	return aryPossibleRequests;
}

function Sequencer_InitializePossibleNavigationRequestAbsolutes(aryPossibleRequests, activityTree, activityList){
	//do nothing, no need to populate the WillAlwaysSucceed and WillNeverSuceed, in the future it might be worth doing for a small optimization
}

function Sequencer_MarkAllActivitiesComplete(){
	
	var sortedActivityList = this.Activities.SortedActivityList;
	var primaryObjective;
	
	for (var i=0; i < sortedActivityList.length; i++){
		primaryObjective = sortedActivityList[i].GetPrimaryObjective();
		
		sortedActivityList[i].SetAttemptProgressStatus(true);
		sortedActivityList[i].SetAttemptCompletionStatus(true);
		
		primaryObjective.SetProgressStatus(true, false, sortedActivityList[i]);
		primaryObjective.SetSatisfiedStatus(true);		
	}
}


function Sequencer_LogSeq(str, logEntry){

	if (logEntry === null || logEntry === undefined){
		Debug.AssertError("failed to pass logEntry");
	}
	
	str = str + "";
	
	if (this.LookAhead === true){
		return Debug.WriteLookAheadDetailed(str, logEntry);
	}
	else{
		return Debug.WriteSequencingDetailed(str, logEntry);
	}
}

function Sequencer_LogSeqAudit(str, logEntry){
	
	str = str + "";
	
	if (this.LookAhead === true){
		return Debug.WriteLookAheadAudit(str, logEntry);
		return "";
	}
	else{
		return Debug.WriteSequencingAudit(str, logEntry);
	}
}

function Sequencer_LogSeqReturn(str, logEntry){
	
	if (logEntry === null || logEntry === undefined){
		Debug.AssertError("failed to pass logEntry");
	}
	
	str = str + "";
	
	if (this.LookAhead === true){
		return logEntry.setReturn(str);
	}
	else{
		return logEntry.setReturn(str);
	}
}

function Sequencer_ContentDeliveryEnvironmentActivityDataSubProcess(activityToDeliver) {

	if (activityToDeliver.IsSuspended() === false){
		activityToDeliver.IncrementAttemptCount();
		activityToDeliver.SetActivityProgressStatus(true);
	}
	
	this.SuspendedActivity = null;
	
	var activeParents = this.Activities.GetActivityPath(activityToDeliver, true);
	for (var i=0; i < activeParents.length; i++){
		
		//we need to record at least one attempt to get a proper rollup
		if (activeParents[i].GetAttemptCount() == 0){
			activeParents[i].SetActivityProgressStatus(true);
			activeParents[i].IncrementAttemptCount();
		}
	}
}
