function ActivityObjective (
			Identifier,
			ProgressStatus,
			SatisfiedStatus,
			MeasureStatus,
			NormalizedMeasure,
			Primary,
			PrevProgressStatus,
			PrevSatisfiedStatus,
			PrevMeasureStatus,
			PrevNormalizedMeasure,
			FirstSuccessTimestampUtc,
			FirstNormalizedMeasure){
			
	this.Identifier = Identifier;
	this.ProgressStatus = ProgressStatus;
	this.SatisfiedStatus = SatisfiedStatus;
	this.MeasureStatus = MeasureStatus;
	this.NormalizedMeasure = NormalizedMeasure;
	this.Primary = Primary;
	
	this.PrevProgressStatus = PrevProgressStatus;
	this.PrevSatisfiedStatus = PrevSatisfiedStatus;
	this.PrevMeasureStatus = PrevMeasureStatus;
	this.PrevNormalizedMeasure = PrevNormalizedMeasure;
	
	this.FirstSuccessTimestampUtc = FirstSuccessTimestampUtc;
	this.FirstNormalizedMeasure = FirstNormalizedMeasure;
	
	//initialize with these deafults since we need to simulate a primary objective but we don't insert one into the static data
	this.SatisfiedByMeasure = false;
	this.MinNormalizedMeasure = 1.0;

	this.Maps = new Array();
	
	this.DataState = DATA_STATE_CLEAN;
	
	this.Sequencer = null;
}


ActivityObjective.prototype.GetXml = ActivityObjective_GetXml;
ActivityObjective.prototype.toString = ActivityObjective_toString;
ActivityObjective.prototype.ResetAttemptState = ActivityObjective_ResetAttemptState;

ActivityObjective.prototype.GetContributesToRollup = ActivityObjective_GetContributesToRollup;
ActivityObjective.prototype.GetMeasureStatus = ActivityObjective_GetMeasureStatus;
ActivityObjective.prototype.GetNormalizedMeasure = ActivityObjective_GetNormalizedMeasure;

ActivityObjective.prototype.SetMeasureStatus = ActivityObjective_SetMeasureStatus;
ActivityObjective.prototype.SetNormalizedMeasure = ActivityObjective_SetNormalizedMeasure;
ActivityObjective.prototype.SetProgressStatus = ActivityObjective_SetProgressStatus;
ActivityObjective.prototype.SetSatisfiedStatus = ActivityObjective_SetSatisfiedStatus;

ActivityObjective.prototype.GetSatisfiedByMeasure = ActivityObjective_GetSatisfiedByMeasure;
ActivityObjective.prototype.GetMinimumSatisfiedNormalizedMeasure = ActivityObjective_GetMinimumSatisfiedNormalizedMeasure;

ActivityObjective.prototype.GetProgressStatus = ActivityObjective_GetProgressStatus;
ActivityObjective.prototype.GetSatisfiedStatus = ActivityObjective_GetSatisfiedStatus;

ActivityObjective.prototype.GetIdentifier = ActivityObjective_GetIdentifier;

ActivityObjective.prototype.GetMaps = ActivityObjective_GetMaps;

ActivityObjective.prototype.SetDirtyData = ActivityObjective_SetDirtyData;

ActivityObjective.prototype.SetSequencer = ActivityObjective_SetSequencer;
ActivityObjective.prototype.Clone = ActivityObjective_Clone;
ActivityObjective.prototype.TearDown = ActivityObjective_TearDown;

function ActivityObjective_GetXml(activityId, index){

	var ServerFormat = new ServerFormater();
	
	var xml = new XmlElement("ActivityObjective");
	
	xml.AddAttribute("ActivityId", activityId);
	xml.AddAttribute("ActivityObjectiveId", index);
	
	xml.AddAttribute("Identifier", this.Identifier);
	xml.AddAttribute("ProgressStatus", ServerFormat.ConvertBoolean(this.ProgressStatus));
	xml.AddAttribute("SatisfiedStatus", ServerFormat.ConvertBoolean(this.SatisfiedStatus));
	xml.AddAttribute("MeasureStatus", ServerFormat.ConvertBoolean(this.MeasureStatus));
	xml.AddAttribute("NormalizedMeasure", this.NormalizedMeasure);

	xml.AddAttribute("PrevProgressStatus", ServerFormat.ConvertBoolean(this.PrevProgressStatus));
	xml.AddAttribute("PrevSatisfiedStatus", ServerFormat.ConvertBoolean(this.PrevSatisfiedStatus));
	xml.AddAttribute("PrevMeasureStatus", ServerFormat.ConvertBoolean(this.PrevMeasureStatus));
	xml.AddAttribute("PrevNormalizedMeasure", this.PrevNormalizedMeasure);
	
	if (this.FirstSuccessTimestampUtc !== null) {
		xml.AddAttribute("FirstSuccessTimestampUtc", ServerFormat.ConvertTime(this.FirstSuccessTimestampUtc));
	}
	
	if (this.FirstNormalizedMeasure !== null) {
		xml.AddAttribute("FirstNormalizedMeasure", this.FirstNormalizedMeasure);
	}
	
	xml.AddAttribute("Primary", ServerFormat.ConvertBoolean(this.Primary));
	
	return xml.toString();
}


function ActivityObjective_toString(){
	return this.Identifier;
}

function ActivityObjective_ResetAttemptState(){
	
	this.PrevProgressStatus = this.ProgressStatus;
	this.PrevSatisfiedStatus = this.SatisfiedStatus;
	this.PrevMeasureStatus = this.MeasureStatus;
	this.PrevNormalizedMeasure = this.NormalizedMeasure;
	
	this.ProgressStatus = false;
	this.SatisfiedStatus = false;
	this.MeasureStatus = false;
	this.NormalizedMeasure = 0;
	
	this.SetDirtyData();
}

function ActivityObjective_GetContributesToRollup(){
	var contributes = this.Primary;
	
	return contributes;
}

//TODO - in final version
//Q-A with Angelo 1/28/05
//How are read maps affected by the UseCurrentAttemptObjectiveInformation setting?
//If UseCurrentAttemptObjectiveInformation is set to true then the status of child activities should not be used 
//(regardless if that status was 'read' from a shared global objective) unless that child has been attempted 
//during the current attempt of its parent.  Applying UseCurrentAttemptObjectiveInformation essentially turns 
//off all 'read' maps prior to those activities actually being attempted.
//to do this, we'll somehow need to set a flag in here that indicates whether or not a read map
//may be accessed, then in ResetState, this will need to be set to false if the parent has UseCurrentAttempt=true
//then when the activity is attempted, it will need to set back to true


function ActivityObjective_GetMeasureStatus(activity, canLookAtPreviousAttempt){

	if (canLookAtPreviousAttempt === null || canLookAtPreviousAttempt === undefined){
		Debug.AssertError("ERROR - canLookAtPreviousAttempt must be passed into GetMeasureStatus");
		//canLookAtPreviousAttempt = false;
	}
	
	//if unknown, and there is a read map, read from the global objective

	var measureStatus;

	//when evaluating sequencing rules, if there was a previous attempt, and the current activity hasn't been
	//attempted during the current attempt on the parent, use the previous attempt's data
	if (canLookAtPreviousAttempt === true && 
		(activity != null && activity != undefined) &&			//note use of short circuit AND (be careful that activity is always passed in)
		activity.WasAttemptedDuringThisAttempt() === false
		){
		measureStatus = this.PrevMeasureStatus;
	}
	else{
		measureStatus = this.MeasureStatus;
	}

	//In SCORM 2004 2nd Edition, a local status overrides a global status. In 3rd Edition and later
	//the global value is always used, even if a local value is known.
	var useGlobalStatus = (measureStatus === false) || (Control.Package.LearningStandard == STANDARD_SCORM_2004);
	
	if (useGlobalStatus === true){
		
		var maps = this.Maps;
		
		for (var i=0; i < maps.length; i++){
			
			if (maps[i].ReadNormalizedMeasure === true){
				
				var globalObjective = this.Sequencer.GetGlobalObjectiveByIdentifier(maps[i].TargetObjectiveId);
				
				if (globalObjective !== null){
					measureStatus = globalObjective.MeasureStatus;
				}
				
			}
		}
	}
	
	return measureStatus;
}

function ActivityObjective_GetNormalizedMeasure(activity, canLookAtPreviousAttempt){
	
	if (canLookAtPreviousAttempt === null || canLookAtPreviousAttempt === undefined){
		Debug.AssertError("ERROR - canLookAtPreviousAttempt must be passed into GetNormalizedMeasure");
		//canLookAtPreviousAttempt = false;
	}
	
	//if unknown, and there is a read map, read from the global objective

	var measureStatus;
	var normalizedMeasure;

	//when evaluating sequencing rules, if there was a previous attempt, and the current activity hasn't been
	//attempted during the current attempt on the parent, use the previous attempt's data
	if (canLookAtPreviousAttempt === true && 
		(activity != null && activity != undefined) &&			//note use of short circuit AND (be careful that activity is always passed in)
		activity.WasAttemptedDuringThisAttempt() === false){
		
		measureStatus = this.PrevMeasureStatus;
		normalizedMeasure = this.PrevNormalizedMeasure;
	}
	else{
		measureStatus = this.MeasureStatus;
		normalizedMeasure = this.NormalizedMeasure;
	}	
	
	//In SCORM 2004 2nd Edition, a local status overrides a global status. In 3rd Edition and later
	//the global value is always used, even if a local value is known.
	var useGlobalStatus = (measureStatus === false) || (Control.Package.LearningStandard == STANDARD_SCORM_2004);
	
	if (useGlobalStatus === true){
		
		var maps = this.Maps;
		
		for (var i=0; i < maps.length; i++){
			
			if (maps[i].ReadNormalizedMeasure === true){
				
				var globalObjective = this.Sequencer.GetGlobalObjectiveByIdentifier(maps[i].TargetObjectiveId);
				
				if (globalObjective !== null && globalObjective.MeasureStatus === true){
					normalizedMeasure = globalObjective.NormalizedMeasure;
				}
				
			}
		}
	}	
		
	return normalizedMeasure;
}


//TODO - improvement - should we consolidate the reading and writing of these pairs? that might simplify the global objectives code and be more logical,
//this would also ensure that the unknown flag is always set before the data value (necessary for maintaining global data properly)

function ActivityObjective_SetMeasureStatus(status, activity){
	
	if (activity === null || activity === undefined){
		Debug.AssertError("ERROR - activity must be passed into SetMeasureStatus");
	}
	
	//if not unknown, and there is a write map, write to the global objective
	
	this.MeasureStatus = status;
	
	if (status === true){
		
		activity.SetAttemptedDuringThisAttempt();
		
		var maps = this.Maps;

		for (var i=0; i < maps.length; i++){
		
			if (maps[i].WriteNormalizedMeasure === true){
				
				var globalObjective = this.Sequencer.GetGlobalObjectiveByIdentifier(maps[i].TargetObjectiveId);
				
				if (globalObjective === null){
					this.Sequencer.AddGlobalObjective(maps[i].TargetObjectiveId, false, false, true, 0);
				}
				else{
					globalObjective.MeasureStatus = true;
					globalObjective.SetDirtyData();
				}
				
			}
		}		
	}
	this.SetDirtyData();
}


function ActivityObjective_SetNormalizedMeasure(measure, activity){
	
	//if not unknown, and there is a write map, write to the global objective
	
	this.NormalizedMeasure = measure;
	
	if (this.MeasureStatus === true){		//only overwrite global data if the local data is known
		
		var maps = this.Maps;
		
		for (var i=0; i < maps.length; i++){
			
			if (maps[i].WriteNormalizedMeasure === true){
				
				var globalObjective = this.Sequencer.GetGlobalObjectiveByIdentifier(maps[i].TargetObjectiveId);
				
				if (globalObjective === null){
					this.Sequencer.AddGlobalObjective(maps[i].TargetObjectiveId, false, false, true, measure);
				}
				else {
					globalObjective.NormalizedMeasure = measure;
					globalObjective.SetDirtyData();
				}
			}
		}		
	}
	
	//if satisfied by measure is true, then the only way the objective can be satisifed is through a
	//score exceeding the mastery score, so make sure that when this happens, we set the progress and success status
	
	if (activity === null || activity === undefined){
		Debug.AssertError("ERROR - activity must be passed into SetNormalizedMeasure");
	}
	
	if (this.GetSatisfiedByMeasure() === true && 
		(activity.IsActive() === false || activity.GetMeasureSatisfactionIfActive() === true)){
		
		var progressStatus = true;
		var satisfiedStatus;
		
		if (this.GetNormalizedMeasure(activity, false) >= this.GetMinimumSatisfiedNormalizedMeasure()){
			satisfiedStatus = true;
		}
		else{
			satisfiedStatus = false;
		}
		
		this.SetProgressStatus(progressStatus, true, activity);
		this.SetSatisfiedStatus(satisfiedStatus, true);		
	}
	
	if (this.ProgressStatus === true && this.FirstNormalizedMeasure == 0) {
		this.FirstNormalizedMeasure = measure;
	}
	
	this.SetDirtyData();
}



function ActivityObjective_SetProgressStatus(status, overrideSatByMeasureCheck, activity){

	if (activity === null || activity === undefined){
		Debug.AssertError("ERROR - activity must be passed into SetMeasureStatus");
	}
	
	//if not unknown, and there is a write map, write to the global objective
	
	//if an objective is satisfied by measure, then it can ONLY be satisfied by measure
	if (this.GetSatisfiedByMeasure() === false || overrideSatByMeasureCheck === true){
	
		this.ProgressStatus = status;
		
		if (status === true){
			
			activity.SetAttemptedDuringThisAttempt();
			
			var maps = this.Maps;
			
			for (var i=0; i < maps.length; i++){
				
				if (maps[i].WriteSatisfiedStatus === true){
					
					var globalObjective = this.Sequencer.GetGlobalObjectiveByIdentifier(maps[i].TargetObjectiveId);
					
					if (globalObjective === null){
						this.Sequencer.AddGlobalObjective(maps[i].TargetObjectiveId, true, false, false, 0);
					}
					else{
						globalObjective.ProgressStatus = true;
						globalObjective.SetDirtyData();
					}
					
				}
			}		
		}
		
		this.SetDirtyData();
	}
}


function ActivityObjective_SetSatisfiedStatus(status, overrideSatByMeasureCheck){
	
	//if not unknown, and there is a write map, write to the global objective
	
	//if an objective is satisfied by measure, then it can ONLY be satisfied by measure
	if (this.GetSatisfiedByMeasure() === false || overrideSatByMeasureCheck === true){
	
		this.SatisfiedStatus = status;
		
		if (this.ProgressStatus === true){		//only overwrite global data if the local data is known
			
			if (this.FirstSuccessTimestampUtc === null && status === true) {
				this.FirstSuccessTimestampUtc = ConvertDateToIso8601String(new Date());
			}
			
			var maps = this.Maps;
			
			for (var i=0; i < maps.length; i++){
				
				if (maps[i].WriteSatisfiedStatus === true){
					
					var globalObjective = this.Sequencer.GetGlobalObjectiveByIdentifier(maps[i].TargetObjectiveId);
					
					if (globalObjective === null){
						this.Sequencer.AddGlobalObjective(maps[i].TargetObjectiveId, true, status, false, 0);
					}
					else{
						globalObjective.SatisfiedStatus = status;
						globalObjective.SetDirtyData();
					}
				}
			}		
		}
		
		this.SetDirtyData();
	}	
}

function ActivityObjective_GetSatisfiedByMeasure(){
	var satisfiedByMeasure = this.SatisfiedByMeasure;
	return satisfiedByMeasure;
}

function ActivityObjective_GetMinimumSatisfiedNormalizedMeasure(){
	var minimumMeasure = this.MinNormalizedMeasure;
	minimumMeasure = parseFloat(minimumMeasure);
	return minimumMeasure;
}


function ActivityObjective_GetProgressStatus(activity, canLookAtPreviousAttempt){

	if (canLookAtPreviousAttempt === null || canLookAtPreviousAttempt === undefined){
		Debug.AssertError("ERROR - canLookAtPreviousAttempt must be passed into GetProgressStatus");
	}

	//if unknown, and there is a read map, read from the global objective
	//activity is passed in to help determine if we should be overriding the satisfaction status using the measure value
		
	var progressStatus;
	
	//when evaluating sequencing rules, if there was a previous attempt, and the current activity hasn't been
	//attempted during the current attempt on the parent, use the previous attempt's data
	if (canLookAtPreviousAttempt === true && activity.WasAttemptedDuringThisAttempt() === false){
		progressStatus = this.PrevProgressStatus;
	}
	else{
		progressStatus = this.ProgressStatus;
	}

	//In SCORM 2004 2nd Edition, a local status overrides a global status. In 3rd Edition and later
	//the global value is always used, even if a local value is known.
	var useGlobalStatus = (progressStatus === false) || (Control.Package.LearningStandard == STANDARD_SCORM_2004);
	
	if (useGlobalStatus === true){
		
		var maps = this.Maps;
		
		for (var i=0; i < maps.length; i++){
			
			if (maps[i].ReadSatisfiedStatus === true){
				
				var globalObjective = this.Sequencer.GetGlobalObjectiveByIdentifier(maps[i].TargetObjectiveId);
				
				if (globalObjective !== null){
					progressStatus = globalObjective.ProgressStatus;
				}
			}
		}
	}	

	//if SatisfiedByMeasure && (activity.Active == false or activity.MeasureSatisfactionIfActive == true)
	//	override the objective's satisfied status based on the measure value
	
	if (activity === null || activity === undefined){
		Debug.AssertError ("ERROR - activity must be passed into ActivityObjective_GetProgressStatus");
	}
	else{
		if (this.GetSatisfiedByMeasure() === true && 
			(activity.IsActive() === false || activity.GetMeasureSatisfactionIfActive() === true)){
			
			if (this.GetMeasureStatus(activity, canLookAtPreviousAttempt) === true){
				progressStatus = true;
			}
			else{
				progressStatus = false;
			}
		}
	}
	
	return progressStatus;
}

function ActivityObjective_GetSatisfiedStatus(activity, canLookAtPreviousAttempt){

	if (canLookAtPreviousAttempt === null || canLookAtPreviousAttempt === undefined){
		Debug.AssertError("ERROR - canLookAtPreviousAttempt must be passed into GetSatisfiedStatus");
		//canLookAtPreviousAttempt = false;
	}

	//if unknown, and there is a read map, read from the global objective
	//activity is passed in to help determine if we should be overriding the satisfaction status using the measure value
	
	var satisfiedStatus;
	var progressStatus;
	
	//when evaluating sequencing rules, if there was a previous attempt, and the current activity hasn't been
	//attempted during the current attempt on the parent, use the previous attempt's data
	if (canLookAtPreviousAttempt === true && activity.WasAttemptedDuringThisAttempt() === false){
		progressStatus = this.PrevProgressStatus;
		satisfiedStatus = this.PrevSatisfiedStatus;
	}
	else{
		progressStatus = this.ProgressStatus;
		satisfiedStatus = this.SatisfiedStatus;
	}
	
	//In SCORM 2004 2nd Edition, a local status overrides a global status. In 3rd Edition and later
	//the global value is always used, even if a local value is known.
	var useGlobalStatus = (progressStatus === false) || (Control.Package.LearningStandard == STANDARD_SCORM_2004);
	
	if (useGlobalStatus === true){
		
		var maps = this.Maps;
		
		for (var i=0; i < maps.length; i++){
			
			if (maps[i].ReadSatisfiedStatus === true){
				
				var globalObjective = this.Sequencer.GetGlobalObjectiveByIdentifier(maps[i].TargetObjectiveId);
				
				if (globalObjective !== null && globalObjective.ProgressStatus === true){
					satisfiedStatus = globalObjective.SatisfiedStatus;
				}
				
			}
		}
	}		

	//if SatisfiedByMeasure && (activity.Active == false or activity.MeasureSatisfactionIfActive == true)
	//	override the objective's satisfied status based on the measure value
	
	if (activity === null || activity === undefined){
		Debug.AssertError ("ERROR - activity must be passed into ActivityObjective_GetProgressStatus");
	}
	else{
		if (this.GetSatisfiedByMeasure() === true && 
			(activity.IsActive() === false || activity.GetMeasureSatisfactionIfActive() === true)){
			
			if (this.GetMeasureStatus(activity, canLookAtPreviousAttempt) === true){
				if (this.GetNormalizedMeasure(activity, canLookAtPreviousAttempt) >= this.GetMinimumSatisfiedNormalizedMeasure()){
					satisfiedStatus = true;
				}
				else{
					satisfiedStatus = false;
				}
			}
		}
	}
	
	return satisfiedStatus;
}

function ActivityObjective_GetIdentifier(){
	var identifier = this.Identifier;
	return identifier;
}


function ActivityObjective_GetMaps(){
	var maps = this.Maps;
	return maps;
}

function ActivityObjective_SetDirtyData(){
	this.DataState = DATA_STATE_DIRTY;
}

function ActivityObjective_SetSequencer(sequencer){
	this.Sequencer = sequencer;
}

function ActivityObjective_Clone(){

	var clone = new ActivityObjective (this.Identifier,
										this.ProgressStatus,
										this.SatisfiedStatus,
										this.MeasureStatus,
										this.NormalizedMeasure,
										this.Primary);

	clone.SatisfiedByMeasure = this.SatisfiedByMeasure;
	clone.MinNormalizedMeasure = this.MinNormalizedMeasure;

	clone.Maps = this.Maps;
	
	return clone;
}

function ActivityObjective_TearDown(){
	
	this.Identifier = null;
	this.ProgressStatus = null;
	this.SatisfiedStatus = null;
	this.MeasureStatus = null;
	this.NormalizedMeasure = null;
	this.Primary = null;
	this.SatisfiedByMeasure = null;
	this.MinNormalizedMeasure = null;
	this.Maps = null;
	this.DataState = null;
	this.Sequencer = null;
}
