/// <summary>
        /// Private helper method for GetSensorGasEndPoint(Sensor).
        /// </summary>
        /// <param name="sensor"></param>
        /// <param name="gasEndPoints"></param>
        /// <returns></returns>
        private GasEndPoint GetSensorGasEndPoint(Sensor sensor, List <GasEndPoint> gasEndPoints)
        {
            MeasurementType sensorMeasurementType = ((SensorType)sensor.Type).MeasurementType;

            string sensorGasCode = sensor.CalibrationGas.Code;

            double sensorConcentration = sensor.CalibrationGasConcentration;

            double lelMultiplier = GasType.Cache[sensorGasCode].LELMultiplier;

            int pointNumber = 0;

            Log.Debug("SCAN 1 (find appropriate gas with desired concentration)...");
            foreach (GasEndPoint gasEndPoint in gasEndPoints)
            {
                Cylinder cyl = gasEndPoint.Cylinder;

                LogGasEndPoint(gasEndPoint, ++pointNumber);

                // Ignore already tried cylinders.
                if (_triedGasEndPoints.ContainsKey(gasEndPoint))
                {
                    Log.Debug("...Rejected. Already tried cylinder.");
                    continue;
                }

                // Ignore empty cylinders.
                if (cyl.Pressure == PressureLevel.Empty)
                {
                    _triedGasEndPoints[gasEndPoint] = gasEndPoint;
                    Log.Debug("...Rejected. Cylinder empty.");
                    continue;
                }

                // Check the measurement type for how to multiply the concentration.

                // Make sure we convert sensor's LEL
                // concentration to PPM for matching against cylinders concentrations
                if (sensorMeasurementType == MeasurementType.LEL)
                {
                    // Convert sensor's cal gas concentration from %LEL to PPM
                    sensorConcentration = sensor.CalibrationGasConcentration / lelMultiplier;
                    // We want to round the concentration to the nearest hundred.
                    // e.g., if concentration is 3928, we want to round it to 3900.
                    //
                    // DO NOT DO THE FOLLOWING COMMENTED OUT LINE!  IT NEEDS TO BE KEPT
                    // SEPARATED AS THREE SEPARATE LINES, OTHERWISE IT MIGHT CRASHES WINCE.
                    // SOME BUG IN COMPACT FRAMEWORK?
                    // sensorConcentration = Math.Round( sensorConcentration / 100.0, 0 ) * 100.0;
                    sensorConcentration /= 100.0;
                    sensorConcentration  = Math.Round(sensorConcentration, 0);
                    sensorConcentration *= 100.0;
                    Log.Debug(string.Format("...Sensor concentration of {0}%% LEL equals {1} PPM ({2} multiplier).",
                                            sensor.CalibrationGasConcentration, sensorConcentration, lelMultiplier));
                }

                else if (sensorMeasurementType == MeasurementType.VOL)
                {
                    sensorConcentration = sensor.CalibrationGasConcentration * 10000;
                    Log.Debug(string.Format("...Sensor concentration of {0}%% VOL equals {1} PPM.",
                                            sensor.CalibrationGasConcentration, sensorConcentration));
                }

                // For oxygen sensors, ignore 20.9 concentration end points.
                if ((sensorGasCode == GasCode.O2) && cyl.IsZeroAir)
                {
                    Log.Debug("...Rejected. Can't use ZeroAir for O2.");
                    continue;
                }

                // For oxygen sensors, ignore 20.9 concentration end points.
                if ((sensorGasCode == GasCode.O2) && cyl.IsFreshAir)
                {
                    Log.Debug("...Rejected. Can't use FreshAir for O2.");
                    continue;
                }

                // Ignore cylinders lacking the right gases.
                if (!cyl.ContainsGas(sensorGasCode, sensorConcentration, sensorMeasurementType))
                {
                    Log.Debug("...Rejected. Does not contain " + sensorGasCode + " with concentration " + sensorConcentration);
                    continue;
                }

                // Ensure bump tests for O2 sensors use concentrations of 19% O2 or less.
                if (sensorGasCode == GasCode.O2)
                {
                    // The following Find should always succeed assuming we already did a Cylinder.ContainsGas call earlier.
                    GasConcentration gasConcentration = cyl.GasConcentrations.Find(gc => gc.Type.Code == sensorGasCode);
                    // Parts per million (ppm) of X divided by 10,000 = percentage concentration of X
                    if ((gasConcentration.Concentration / 10000.0) > 19.0)
                    {
                        Log.Debug("...Rejected. Can't use concentrations above 19% for O2.");
                        continue;
                    }
                }

                // Ensure cylinder concentration is not higher than 60% for potentially explosive cal gases
                if (lelMultiplier > 0.0)
                {
                    // We now know this cylinder contains the desired gas concentration. But we don't allow
                    // calibration of combustible sensor using any cylinder that is higher than 60% LEL.
                    // So, find the gas in the cylinder and check it's LEL level.

                    double cylinderPPM = -1.0;
                    foreach (GasConcentration gasConcentration in cyl.GasConcentrations)
                    {
                        if (gasConcentration.Type.Code == sensorGasCode)
                        {
                            cylinderPPM = gasConcentration.Concentration;
                            break;
                        }
                    }

                    if (cylinderPPM < 0) // this should never happen.  Which means we better check.
                    {
                        Log.Debug("...Rejected. Does not contain " + sensorGasCode);
                        continue;
                    }

                    double cylinderLEL = cylinderPPM * lelMultiplier;
                    if (cylinderLEL > 60.0)  // cylinder is higher than 60%?  Don't use it.
                    {
                        Log.Debug(string.Format("...Rejected. Contains {0} with too high LEL concentration ({1}%%).",
                                                sensorGasCode, Math.Round(cylinderLEL, 1)));
                        Log.Debug("...Will not use concentration higher than 60%% LEL.");
                        continue;
                    }
                }

                // Found a cylinder with the correct gas and concentration.
                _triedGasEndPoints[gasEndPoint] = gasEndPoint;

                Log.Debug("...SELECTED. Contains " + sensorGasCode + " with desired concentration " + sensorConcentration);

                return(gasEndPoint);
            }

            Log.Debug("SCAN 2 (find appropriate gas with any concentration)...");

            pointNumber = 0;
            foreach (GasEndPoint gasEndPoint in gasEndPoints)
            {
                LogGasEndPoint(gasEndPoint, ++pointNumber);

                // Ignore already tried cylinders.
                if (_triedGasEndPoints.ContainsKey(gasEndPoint))
                {
                    Log.Debug("...Rejected. Already tried cylinder.");
                    continue;
                }

                // Ignore empty cylinders.
                if (gasEndPoint.Cylinder.Pressure == PressureLevel.Empty)
                {
                    _triedGasEndPoints[gasEndPoint] = gasEndPoint;
                    Log.Debug("...Rejected. Cylinder empty.");
                    continue;
                }

                // For oxygen sensors, ignore 20.9 concentration end points.
                if ((sensorGasCode == GasCode.O2) &&
                    gasEndPoint.Cylinder.IsZeroAir)
                {
                    Log.Debug("...Rejected. Can't use Zero Air for O2.");
                    continue;
                }

                // For oxygen sensors, ignore 20.9 concentration end points.
                if ((sensorGasCode == GasCode.O2) &&
                    gasEndPoint.Cylinder.IsFreshAir)
                {
                    Log.Debug("...Rejected. Can't use FreshAir for O2.");
                    continue;
                }

                // Ignore cylinders lack the right gases.
                if (!gasEndPoint.Cylinder.ContainsGas(sensorGasCode))
                {
                    Log.Debug("...Rejected. Does not contain " + sensorGasCode);
                    continue;
                }

                // Ensure bump tests for O2 sensors use concentrations of 19% O2 or less.
                if (sensorGasCode == GasCode.O2)
                {
                    // The following Find should always succeed assuming we already did a Cylinder.ContainsGas call earlier.
                    GasConcentration gasConcentration = gasEndPoint.Cylinder.GasConcentrations.Find(gc => gc.Type.Code == sensorGasCode);
                    // Parts per million (ppm) of X divided by 10,000 = percentage concentration of X
                    if ((gasConcentration.Concentration / 10000.0) > 19.0)
                    {
                        Log.Debug("...Rejected. Can't use concentrations above 19% for O2.");
                        continue;
                    }
                }

                // SGF  Feb-10-2009  DSW-72
                // Ensure cylinder concentration is not higher than 60% for potentially explosive cal gases

                if (lelMultiplier > 0.0)
                {
                    // We now know this cylinder contains the desired gas concentration. But we don't allow
                    // calibration of combustible sensor using any cylinder that is higher than 60% LEL.
                    // So, find the gas in the cylinder and check it's LEL level.

                    double cylinderPPM = -1.0;
                    foreach (GasConcentration gasConcentration in gasEndPoint.Cylinder.GasConcentrations)
                    {
                        if (gasConcentration.Type.Code == sensorGasCode)
                        {
                            cylinderPPM = gasConcentration.Concentration;
                            break;
                        }
                    }

                    if (cylinderPPM < 0) // this should never happen.  Which means we better check.
                    {
                        Log.Debug("...Rejected. Does not contain " + sensorGasCode);
                        continue;
                    }

                    double cylinderLEL = cylinderPPM * lelMultiplier;
                    if (cylinderLEL > 60.0)  // cylinder is higher than 60%?  Don't use it.
                    {
                        Log.Debug(string.Format("...Rejected. Contains {0} with too high LEL concentration ({1}%%).",
                                                sensorGasCode, Math.Round(cylinderLEL, 1)));
                        Log.Debug("...Will not use concentration higher than 60%% LEL.");
                        continue;
                    }
                }

                // Found a cylinder with the correct gas.
                _triedGasEndPoints[gasEndPoint] = gasEndPoint;

                Log.Debug("...SELECTED. Contains " + sensorGasCode);

                return(gasEndPoint);
            }

            return(null);
        }
    /// <summary>
    /// Get the calibration test gas end point for a sensor.
    /// </summary>
    /// <param name="installedComponent">The sensor to get the gas for.</param>
    /// <returns>The correct gas end point.</returns>
    /// <exception cref="CorrectCalibrationGasUnavailable">
    /// Thrown when no cylinder is provided for the sensor.
    /// </exception>
	protected GasEndPoint GetSensorGasEndPoint( InstalledComponent installedComponent )
    {
        Sensor sensor = null;
        MeasurementType sensorMeasurementType = MeasurementType.Unknown;

        if (installedComponent != null)
        {
            sensor = installedComponent.Component as Sensor;
            sensorMeasurementType = ((SensorType)sensor.Type).MeasurementType;
        }

        #region LogDebug
        if (sensor != null)
        {
            Log.Debug( "Calibration.GetSensorGasEndPoint" );
            Log.Debug( "Finding appropriate cal gas for Sensor: " + sensor.Type
                + ", UID: " + sensor.Uid
                + ", CalGas Code: " + sensor.CalibrationGas.Code
                + ", Conc: " + sensor.CalibrationGasConcentration
                + ", Pos: " + installedComponent.Position );
        }
        #endregion

        // If this is a sensor that uses 20.9 O2 for its calibration gas,
        // then attempt to find a cylinder that offers Zero Air; if 
        // Zero Air is not available, find Fresh Air.  If neither are
        // available, then fall out of this code and proceed to the main
        // processing loop below.
        if ( sensor.CalibrationGas.Code == GasCode.O2 && sensor.CalibrationGasConcentration == 20.9 )
        {
			GasEndPoint air = GetSensorZeroAir( installedComponent, false, true ); 
            if (air != null)
            {
                _triedGasEndPoints[air] = air;
                Cylinder cyl = air.Cylinder;
                if (cyl.IsZeroAir)
                    Log.Debug("...SELECTED GasEndPoint.  Has ZeroAir for O2 at 20.9.");
                else if (cyl.IsFreshAir)
                    Log.Debug("...SELECTED GasEndPoint.  Has FreshAir for O2 at 20.9.");
                else
                    // We do not expect to reach this line of code, but it has been placed here to 
                    // log that GetSensorZeroAir returned a cylinder that was Fresh Air or Zero Air.
                    Log.Debug(string.Format("...SELECTED GasEndPoint: {0}", cyl.ToString()));
                return air;
            }
        }

        double sensorConcentration = sensor.CalibrationGasConcentration;

        double lelMultiplier = GasType.Cache[ sensor.CalibrationGas.Code ].LELMultiplier;

        int pointCount = 0;

        Log.Debug( "SCAN 1 (Find appropriate gas with desired concentration)..." );
		foreach ( GasEndPoint gasEndPoint in GasEndPoints )
        {
            Cylinder cyl = gasEndPoint.Cylinder;

            #region LogDebug
            string msg = "GasEndPoint #" + ++pointCount;
            Log.Debug(msg);

            msg = "...Pos=" + gasEndPoint.Position
                //+ ", ID=" + cyl.ID
                + ", FactID=" + cyl.FactoryId
                + ", Part=" + cyl.PartNumber
                + ", Fresh=" + cyl.IsFreshAir
                + ", ZeroAir=" + cyl.IsZeroAir
                + ", Pressure=" + cyl.Pressure.ToString();
            if ( cyl.Volume != DomainModelConstant.NullInt ) msg += ", Vol=" + cyl.Volume;

            Log.Debug( msg );
            
            msg = "......";
            foreach ( GasConcentration gasCon in cyl.GasConcentrations )
            {
                msg += "[" + gasCon.Type.Code;
                msg += " ";
                msg += ( gasCon.Concentration == DomainModelConstant.NullDouble ) ? "fresh" : gasCon.Concentration.ToString();
                msg += "]";
            }

            Log.Debug( msg );
            #endregion

            // Ignore already tried cylinders.
            if ( _triedGasEndPoints.ContainsKey( gasEndPoint ) )
            {
                Log.Debug( "...Rejected. Already tried cylinder." );
                continue;
            }

            // Ignore empty cylinders.
            if ( cyl.Pressure == PressureLevel.Empty )
            {
                _triedGasEndPoints[ gasEndPoint ] = gasEndPoint;
                Log.Debug( "...Rejected. Cylinder empty." );
                continue;
            }

            // Check the measurement type for how to multiply the concentration.

            // Make sure we convert sensor's LEL 
            // concentration to PPM for matching against cylinders concentrations
            if (sensorMeasurementType == MeasurementType.LEL)
            {
                // Convert sensor's cal gas concentration from %LEL to PPM
                sensorConcentration = sensor.CalibrationGasConcentration / lelMultiplier;
                // We want to round the concentration to the nearest hundred.
                // e.g., if concentration is 3928, we want to round it to 3900.
                //
                // DO NOT DO THE FOLLOWING COMMENTED OUT LINE!  IT NEEDS TO BE KEPT
                // SEPARATED AS THREE SEPARATE LINES, OTHERWISE IT CRASHES WINCE.
                // SOME BUG IN COMPACT FRAMEWORK?
                // sensorConcentration = Math.Round( sensorConcentration / 100.0, 0 ) * 100.0;
                sensorConcentration /= 100.0;
                sensorConcentration = Math.Round( sensorConcentration, 0 );
                sensorConcentration *= 100.0;
                Log.Debug( string.Format( "...Sensor concentration of {0}%% LEL equals {1} PPM ({2} multiplier)",
                    sensor.CalibrationGasConcentration, sensorConcentration, lelMultiplier ) );
            }

            else if (sensorMeasurementType == MeasurementType.VOL)
            {
                sensorConcentration = sensor.CalibrationGasConcentration * 10000;
                Log.Debug( string.Format( "...Sensor concentration of {0}%% VOL equals {1} PPM",
                    sensor.CalibrationGasConcentration, sensorConcentration ) );
            }

            // Ignore cylinders lacking the right gases.
            if (!cyl.ContainsGas(sensor.CalibrationGas.Code, sensorConcentration, sensorMeasurementType))
            {
                Log.Debug( "...Rejected. Does not contain " + sensor.CalibrationGas.Code + " with desired concentration " + sensorConcentration );
                continue;
            }

            // SGF  Feb-10-2009  DSW-72
            // Ensure cylinder concentration is not higher than 60% for potentially explosive cal gases

            if ( lelMultiplier > 0.0 )
            {
                // We now know this cylinder contains the desired gas concentration. But we don't allow
                // calibration of combustible sensor using any cylinder that is higher than 60% LEL.
                // So, find the gas in the cylinder and check it's LEL level.

                double cylinderPPM = -1.0;
                foreach ( GasConcentration gasConcentration in cyl.GasConcentrations )
                {
                    if ( gasConcentration.Type.Code == sensor.CalibrationGas.Code )
                    {
                        cylinderPPM = gasConcentration.Concentration;
                        break;
                    }
                }

                if ( cylinderPPM < 0 ) // this should never happen.  Which means we better check.
                {
                    Log.Debug( "...Rejected. Does not contain " + sensor.CalibrationGas.Code );
                    continue;
                }

                double cylinderLEL = cylinderPPM * lelMultiplier;
                if ( cylinderLEL > 60.0 )  // cylinder is higher than 60%?  Don't use it.
                {
                    Log.Debug( string.Format( "...Rejected. Contains {0} with too high LEL concentration ({1}%%)",
                        sensor.CalibrationGas.Code,  Math.Round( cylinderLEL, 1 ) ) );
                    Log.Debug( "...Will not use concentration higher than 60%% LEL." );
                    continue;
                }
            }

            // Found a cylinder with the correct gas and concentration.
            _triedGasEndPoints[ gasEndPoint ] = gasEndPoint;

            Log.Debug( "...SELECTED. Contains " + sensor.CalibrationGas.Code + " with desired concentration " + sensorConcentration );

            return gasEndPoint;

        }  // end-foreach 1

        Log.Debug( "SCAN 2 (find appropriate gas with any concentration)..." );

        pointCount = 0;
		foreach ( GasEndPoint gasEndPoint in GasEndPoints )
        {
            Cylinder cyl = gasEndPoint.Cylinder;

            #region LogDebug

            string msg = "GasEndPoint #" + ++pointCount;
            Log.Debug(msg);

            msg = "...Pos=" + gasEndPoint.Position
                //+ ", ID=" + cyl.ID
                + ", FactID=" + cyl.FactoryId
                + ", Part=" + cyl.PartNumber
                + ", Fresh=" + cyl.IsFreshAir
                + ", ZeroAir=" + cyl.IsZeroAir
                + ", Pressure=" + cyl.Pressure.ToString();
            if ( cyl.Volume != DomainModelConstant.NullInt ) msg += ", Vol=" + cyl.Volume;

            Log.Debug( msg );
            
            msg = "......";
            foreach ( GasConcentration gasCon in cyl.GasConcentrations )
            {
                msg += "[" + gasCon.Type.Code;
                msg += " ";
                msg += ( gasCon.Concentration == DomainModelConstant.NullDouble ) ? "fresh" : gasCon.Concentration.ToString();
                msg += "]";
            }

            Log.Debug( msg );
            #endregion

            // Ignore already tried cylinders.
            if ( _triedGasEndPoints.ContainsKey( gasEndPoint ) )
            {
                Log.Debug( "...Rejected. Already tried cylinder." );
                continue;
            }

            // Ignore cylinders lack the right gases.
            if ( ! cyl.ContainsGas( sensor.CalibrationGas.Code ) )
            {
                Log.Debug( "...Rejected. Does not contain " + sensor.CalibrationGas.Code  );
                continue;
            }

            // SGF  Feb-10-2009  DSW-72
            // Ensure cylinder concentration is not higher than 60% for potentially explosive cal gases
            if ( lelMultiplier > 0.0 )
            {
                // We now know this cylinder contains the right gas.  But we don't allow 
                // calibration of combustible sensor using any cylinder that is higher than 60% LEL.
                // So, find the gas in the cylinder and check it's LEL level.

                double cylinderPPM = -1.0;
                foreach ( GasConcentration gasConcentration in cyl.GasConcentrations )
                {
                    if ( gasConcentration.Type.Code == sensor.CalibrationGas.Code )
                    {
                        cylinderPPM = gasConcentration.Concentration;
                        break;
                    }
                }

                if ( cylinderPPM < 0 ) // this should never happen.  Which means we better check.
                {
                    Log.Debug( "...Rejected. Does not contain " + sensor.CalibrationGas.Code );
                    continue;
                }

                double cylinderLEL = cylinderPPM * lelMultiplier;
                if ( cylinderLEL > 60.0 )  // cylinder is higher than 60%?  Don't use it.
                {
                    Log.Debug( string.Format( "...Rejected. Contains {0} with too high LEL concentration ({1}%%)",
                        sensor.CalibrationGas.Code,  Math.Round( cylinderLEL, 1 ) ) );
                    Log.Debug( "...Will not use concentration higher than 60%% LEL." );
                    continue;
                }

            } // end-if MeasurementTypes.LEL

            // Found a cylinder with the correct gas.
            _triedGasEndPoints[ gasEndPoint ] = gasEndPoint;
            
            Log.Debug( "...SELECTED. Contains " + sensor.CalibrationGas.Code );

            return gasEndPoint;

        } // end-foreach 2

		// If this is a sensor that uses O2 for its calibration gas, and no cylinder has been found 
		// yet, then attempt to find a cylinder that offers Fresh Air.  We don't try to find a Zero 
		// Air cylinder because one of the scans above would have already selected it if one was
		// available.  Also, O2 sensors with a cal gas concentration of 20.9 should have already
		// selected a Zero Air or Fresh Air cylinder so we don't need to check again.
		if ( sensor.CalibrationGas.Code == GasCode.O2 && sensor.CalibrationGasConcentration != 20.9 )
		{
			GasEndPoint air = GetSensorFreshAir( installedComponent, true );
			if ( air != null )
			{
				_triedGasEndPoints[air] = air;
				Cylinder cyl = air.Cylinder;
				if ( cyl.IsFreshAir )
					Log.Debug( "...SELECTED GasEndPoint.  Has FreshAir for O2." );
				else
					// We do not expect to reach this line of code, but it has been placed here to 
					// log that GetSensorFreshAir returned a cylinder.
					Log.Debug( string.Format( "...SELECTED GasEndPoint: {0}", cyl.ToString() ) );
				return air;
			}
		}

        Log.Debug( "NO APPROPRIATE CALIBRATION GAS FOUND!" );

        throw new CorrectCalibrationGasUnavailable( string.Format( "Sensor {0}, CalGas={1}({2})", 
            sensor.Uid, sensor.CalibrationGas.Code, sensor.CalibrationGasConcentration ) ); // No gas end point was found.
    }