// -----------------------------------------------------------------------------

function Factor(
            Name,
            GroupName,
            SelectorName,
            RiskLevel_Real,
            RiskLevel_Perceived,
            OptionData,
            LogicNotes) {
// Purpose :  Define the "Factor" object
// Input :
//    Name :  The factor's name. Examples :  Wing DHV level, Age, ...
//    GroupName :  The name of the factor's category.  Examples :  Gear, Conditions, Social, Attitude.
//    SelectorName :  Label for the <SELECT> HTML tag.
//    RiskLevel_Real :  Maximum value this Factor can take for the real 12-month partial injury risk.
//    RiskLevel_Perceived :  Maximum value this Factor can take for the perceived 12-month partial injury risk.
//    OptionData :  String containing data on options user will be able to select.  Rules :
//       |  is used to delimit options.
//       ,  delimits option data :  Label (for user selection),
//                                  Real and Perceived relative (between options) risk proportions (0-100 range).
//       For real and perceived risk levels :
//          You must use 0-100 range.  Values will be scaled to match if full range not used.
//       Example (for a Wing's DHV level factor) :
//          "1,22,20|1.5,35,30|2,45,40|2.5,65,80|3,100,100"
//             3,100,100  --> A DHV 3 wing will have maximum real and perceived
//                            12-month partial injury risk.
//    LogicNotes :  Comments on the usefulness of this factor and how it is used.
// Output :
//    New Factor object returned.
//    Member variables :
//       Name :  (same as input).
//       GroupName :  (same as input).
//       SelectorName :  (same as input).
//       Option_Label[0..this.Option_Label.length-1] :  Label (for user selection).
//       Option_RiskReal[0..this.Option_Label.length-1] :  Real 12-month partial injury risk.
//       Max_RiskReal = Maximum value stored in Option_RiskReal[...]
//       Option_RiskPerceived[0..this.Option_Label.length-1] :  Perceived 12-month partial injury risk.
//       Max_RiskPerceived = Maximum value stored in Option_RiskPerceived[...]
//       Option_ChosenIndex :  The index of the option chosen by the user.
//          -1 if none chosen yet.
//       LogicNotes :  (same as input).
//       Diagnostic :  Comments on pilot profile based on Option_ChosenIndex.
//          Null string of no comment yet.
// Author :  Jerome Daoust, 2003/12/9.

   // Set function name
   var c_fn = "Factor"

   var Attrib = ""
   var c_split_Option_char = "|"
   var c_split_OptData_char = ","

   // Create object variables.
   this.Name = Name
   this.GroupName = GroupName
   this.SelectorName = SelectorName 

   // Setup the array for the user menu options.
   this.Option_Label = new Array()
   this.Option_RiskReal = new Array()
   this.Option_RiskPerceived = new Array()

   // Get the array of points
   ac_Option = OptionData.split( c_split_Option_char)
   // Loop on each option
   for ( i_Option=0 ; i_Option<ac_Option.length ; i_Option++ ) {
      // Get the array of data
      ac_OptData = ac_Option[i_Option].split( c_split_OptData_char)

      // Skip data points with either zero length option data.
      if ( ( ac_OptData.length < 3 ) ||
           ( ac_OptData[0].length <= 0 ) ||
           ( ac_OptData[1].length <= 0 ) ||
           ( ac_OptData[2].length <= 0 ) ) {
         alert("Error with Option in " + c_fn + "()."
                        + "  Option='" + ac_Option[i_Option] + "'")
         return -1
      }

      // Store the option data.
      j_Option = this.Option_Label.length
      this.Option_Label[j_Option] = ac_OptData[0]
      this.Option_RiskReal[j_Option] = parseFloat( ac_OptData[1])
      this.Option_RiskPerceived[j_Option] = parseFloat( ac_OptData[2])
   }

   // Get range for supplied risk proportions.
   Risk_Real_Relative_Min = 1.0E30
   Risk_Real_Relative_Max = -1.0E30
   Risk_Perceived_Relative_Min = 100.0
   Risk_Perceived_Relative_Max = 0.0
   for ( i_Option=0 ; i_Option<this.Option_Label.length ; i_Option++ ) {
      if ( this.Option_RiskReal[i_Option] < Risk_Real_Relative_Min ) {
         Risk_Real_Relative_Min = this.Option_RiskReal[i_Option]
      }
      if ( Risk_Real_Relative_Max < this.Option_RiskReal[i_Option] ) {
         Risk_Real_Relative_Max = this.Option_RiskReal[i_Option]
      }
      if ( this.Option_RiskPerceived[i_Option] < Risk_Perceived_Relative_Min ) {
         Risk_Perceived_Relative_Min = this.Option_RiskPerceived[i_Option]
      }
      if ( Risk_Perceived_Relative_Max < this.Option_RiskPerceived[i_Option] ) {
         Risk_Perceived_Relative_Max = this.Option_RiskPerceived[i_Option]
      }
   }
   // Verify that min and max values are not the same (so we can divide by range later).
   if ( Math.abs(Risk_Real_Relative_Max-Risk_Real_Relative_Min) <= 0.0 ) {
      alert("Error in " + c_fn + "()."
                     + "  Supplied real risk proportions have no range.")
      return -1
   }
   if ( Math.abs(Risk_Perceived_Relative_Max-Risk_Perceived_Relative_Min) <= 0.0 ) {
      alert("Error in " + c_fn + "()."
                     + "  Supplied perceived risk proportions have no range.")
      return -1
   }

   // Scale risk value to match 0-100 range.
   for ( i_Option=0 ; i_Option<this.Option_Label.length ; i_Option++ ) {
      this.Option_RiskReal[i_Option] =
         100.0 *
         ( this.Option_RiskReal[i_Option] - Risk_Real_Relative_Min) /
         ( Risk_Real_Relative_Max - Risk_Real_Relative_Min )
      this.Option_RiskPerceived[i_Option] =
         100.0 *
         ( this.Option_RiskPerceived[i_Option] - Risk_Perceived_Relative_Min) /
         ( Risk_Perceived_Relative_Max - Risk_Perceived_Relative_Min )
   }

   // Apply Risk levels.
   for ( i_Option=0 ; i_Option<this.Option_Label.length ; i_Option++ ) {
      this.Option_RiskReal[i_Option] *= RiskLevel_Real/100.0
      this.Option_RiskPerceived[i_Option] *= RiskLevel_Perceived/100.0
   }

   // Find maximums for risk levels.
   this.Max_RiskReal = -1.0
   this.Max_RiskPerceived = -1.0
   for ( i_Option=0 ; i_Option<this.Option_Label.length ; i_Option++ ) {
      if ( this.Max_RiskReal < this.Option_RiskReal[i_Option] ) this.Max_RiskReal = this.Option_RiskReal[i_Option]
      if ( this.Max_RiskPerceived < this.Option_RiskPerceived[i_Option] ) this.Max_RiskPerceived = this.Option_RiskPerceived[i_Option]
   }
   // Verify that min and max values are not the same (so we can divide by range later).
   if ( this.Max_RiskReal < 0.0 ) {
      alert("Error in " + c_fn + "()."
                     + "  Max_RiskReal could not be established.")
      return -1
   }
   if ( this.Max_RiskPerceived < 0.0 ) {
      alert("Error in " + c_fn + "()."
                     + "  Max_RiskPerceived could not be established.")
      return -1
   }

   // Create object variable.
   Option_ChosenIndex = -1
      // Negative indicates no option chosen yet.
   this.LogicNotes = LogicNotes
   this.Diagnostic = ""
      // None yet.

   // Add method to this object
   this.SetOptionChosenIndex = Factor_Method_SetOptionChosenIndex

   return this
}
// -----------------------------------------------------------------------------

function Factor_Method_SetOptionChosenIndex(
            OptionChosenIndex) {
// Purpose :  Set the index for the option chosen by the user.
// Input :
//    this :  "Factor" object.
//    OptionChosenIndex :   0..this.Option_Label.length-1.
// Output :
//    this.Option_ChosenIndex :  The index of the option chosen by the user.
//          -1 if none chosen yet.
// Author :  Jerome Daoust, 2002/12/15.

   // Validate range.
   if ( OptionChosenIndex < 0 ) return -1
   if ( (this.Option_Label.length-1) < OptionChosenIndex ) return -1

   // Save the value.
   this.Option_ChosenIndex = OptionChosenIndex

   // Exit sucessfully.
   return 0
}
// -----------------------------------------------------------------------------
