Location: PHPKode > projects > Huygens Remote Manager > hrm/inc/Setting.inc
<?php
// This file is part of the Huygens Remote Manager
// Copyright and license notice: see license.txt

require_once ("Parameter.inc");
require_once ("Database.inc");
require_once ("hrm_config.inc");

//!---------------------------------------------------------
// @class    Setting
// @desc     Abstract superclass of specific setting classes
//!---------------------------------------------------------
Class Setting {
	public $parameter; // @public parameter    Array    The set of parameter
	public $message; // @public message      String   The user message for the last inconsistent set of papubliceters  
	public $owner; // @public owner        Owner    The user or owner of the setting         
	public $name; // @public name         String   The name of the setting 
	public $isDefault; // @public isDefault    Boolean  Tells whether the setting is the default setting

	//!---------------------------------------------------------
	// @function    Setting::Setting
	// @desc        Constructor. Creates an empty setting
	// @return      void
	//!---------------------------------------------------------
	function Setting() {
		$this->parameter = array ();
		$this->isDefault = False;
	}

	//!---------------------------------------------------------
	// @function    Setting::parameter
	// @desc        Answer the parameter named name
	// @param       name  String  The name of the parameter
	// @return      Parameter
	//!---------------------------------------------------------
	function parameter($name) {
		return $this->parameter[$name];
	}

	//!---------------------------------------------------------
	// @function    Setting::set
	// @desc        Set a parameter. The parameter is stored
	//              in the setting under its name.
	// @param       parameter  Parameter  The parameter to be set
	// @return      Void
	//!---------------------------------------------------------  
	function set($parameter) {
		$this->parameter[$parameter->name()] = $parameter;
	}

	// TODO refactor
	//!---------------------------------------------------------
	// @function    Setting::values
	// @desc        Answer the parameter values
	// @param       name  String  The name of the parameter
	// @return      Array
	//!---------------------------------------------------------
	function values($name) {
		$db = new DatabaseConnection();
		$parameter = $this->parameter($name);
		return $db->readPossibleValues($parameter);
	}

	// TODO refactor
	//!---------------------------------------------------------
	// @function    Setting::translatedValues
	// @desc        Answer the translated parameter values
	// @param       name  String  The name of the parameter
	// @return      Array
	//!---------------------------------------------------------
	function translation($name, $value) {
		$db = new DatabaseConnection();
		$parameter = new Parameter($name);
		$parameter->setValue($value);
		return $db->translationFor($parameter);
	}

	//!---------------------------------------------------------
	// @function    Setting::message
	// @desc        Answer the message set by the last check
	//              performed on this setting
	// @return      String
	//!---------------------------------------------------------    
	function message() {
		return $this->message;
	}

	//!---------------------------------------------------------
	// @function    Setting::checkChoiceValue
	// @desc        Check if a choice parameter has a valid value
	// @param       name  String  The name of the parameter
	// @param       label String  The name of the parameter as it is displayed on the screen
	// @return      Void
	//!---------------------------------------------------------  
	function checkChoiceValue($name, $label) {
		$parameter = $this->parameter($name);
		if (!$parameter->check()) {
			$options = $parameter->possibleValuesString();
			$this->message = "Please select the $label (" . $options . ')!';
			return False;
		}
		return True;
	}

	//!---------------------------------------------------------
	// @function    Setting::checkSampleMedium
	// @desc        Check if the sample medium is defined
	// @return      Bool
	//!---------------------------------------------------------  
	function checkSampleMedium() {
		$parameter = $this->parameter('SampleMedium');
		$value = $parameter->value( );
		if ( empty( $value ) == true ) {
			$this->message = "Please choose one of the preset sample media or specify a refractive index yourself!";
			return False;
		}
		return True;
	}

	//!---------------------------------------------------------
	// @function    Setting::checkNumericalValue
	// @desc        Check if a numerical parameter has a valid value
	// @param       name  String  The name of the parameter
	// @param       label String  The name of the parameter as it is displayed on the screen
	// @return      Void
	//!---------------------------------------------------------  
	function checkNumericalValue($name, $label) {
		$parameter = $this->parameter($name);
		$min = $parameter->min();
		$max = $parameter->max();
		$notice = '';
		if ($parameter->checkMin() && $parameter->checkMax()) {
			$notice = "The value must be between $min and $max.";
		} else {
			if ($parameter->checkMin()) {
				$notice = "The value must be bigger than $min.";
			}
			if ($parameter->checkMax()) {
				$notice = "The value must be smaller than $max.";
			}
		}
		if (!$parameter->check()) {
			$this->message = "Please enter a valid $label! $notice";
			return False;
		}
		return True;
	}

	//!---------------------------------------------------------
	// @function    Setting::checkNumericalValues
	// @desc        Check if each of the numerical values (one 
	//              for each channel) is valid.
	// @param       name             String  The name of the parameter
	// @param       label            String  The name of the parameter as it is displayed on the screen
	// @param       numberOfChannels Integer The actual number of channels
	// @return      Boolean
	//!---------------------------------------------------------  
	function checkNumericalValues($name, $label, $numberOfChannels) {
		$parameter = $this->parameter($name);
		$values = $parameter->internalValue();
		if ($name == "BackgroundOffsetPercent" && ($values[0] == "auto" || $values[0] == "object"))
			return True;
		// TODO: check if this should be the normal behavior
		if ($numberOfChannels < 2) {
			$result = $this->checkNumericalValue($name, $label);
			return $result;
		}
		$result = True;
		$theLabel = $label;
		for ($i = 0; $i < $numberOfChannels; $i++) {
			$ok = $parameter->checkValue($values[$i]);
			if (!$ok) {
				$theLabel = $label . " for channel $i";
				$result = $result && $this->checkNumericalValue($name, $theLabel);
				break;
			}
		}
		return $result;
	}

	//!---------------------------------------------------------
	// @function    Setting::parameterNames()
	// @desc        Answer the names of all parameters
	// @return      Array
	//!---------------------------------------------------------    
	function parameterNames() {
		$names = array ();
		foreach ($this->parameter as $parameter) {
			$names[] = $parameter->name();
		}
		return $names;
	}

	//!---------------------------------------------------------
	// @function    Setting::rangeParameter()
	// @desc        Answer all range parameter (parameter for 
	//              which between 2 and 4 values can be entered)
	// @return      Array
	//!---------------------------------------------------------    
	function rangeParameter() {
		$result = array ();
		foreach ($this->parameter as $parameter) {
			if ($parameter->isRangeParameter()) {
				$result[] = $parameter;
			}
		}
		return $result;
	}

	//!---------------------------------------------------------
	// @function    Setting::owner
	// @desc        Answer the owner of the setting
	// @return      Owner
	//!---------------------------------------------------------
	function owner() {
		return $this->owner;
	}

	//!---------------------------------------------------------
	// @function    Setting::setOwner
	// @desc        Set the owner of the setting
	// @param       owner    Owner    set the owner of the setting
	// @return      void
	//!---------------------------------------------------------
	function setOwner($owner) {
		$this->owner = $owner;
	}

	//!---------------------------------------------------------
	// @function    Setting::name
	// @desc        Answer the name of the setting
	// @return      string
	//!---------------------------------------------------------
	function name() {
		return $this->name;
	}

	//!---------------------------------------------------------
	// @function    Setting::setName
	// @desc        Set the name of the setting
	// @param       name    String    set the name of the setting
	// @return      void
	//!---------------------------------------------------------
	function setName($name) {
		$this->name = $name;
	}

	//!---------------------------------------------------------
	// @function    Setting::isDefault
	// @desc        Answer whether the setting is the user's 
	//              default setting
	// @return      boolean
	//!---------------------------------------------------------
	function isDefault() {
		return $this->isDefault;
	}

	//!---------------------------------------------------------
	// @function    Setting::beDefault
	// @desc        Make the setting the user's default setting
	// @return      void
	//!---------------------------------------------------------
	function beDefault() {
		$this->isDefault = True;
	}

	//!---------------------------------------------------------
	// @function    Setting::resetDefault
	// @desc        The setting won't be the default setting 
	//              anymore
	// @return      void
	//!---------------------------------------------------------
	function resetDefault() {
		$this->isDefault = False;
	}

	//!---------------------------------------------------------
	// @function    Setting::copyParamterFrom
	// @desc        Copy the parameter values from setting to
	//              the receiver.
	// @param       setting  Setting  The setting from which the
	//                                values are copied to the 
	//                                receiver
	// @return      void
	//!---------------------------------------------------------
	function copyParameterFrom($setting) {
		foreach ($setting->parameterNames() as $name) {
			$parameter = $this->parameter[$name];
			$otherParameter = $setting->parameter($name);
			$newValue = $otherParameter->internalValue();
			$parameter->setValue($newValue);
			$this->parameter[$name] = $parameter;
		}
	}

	//!---------------------------------------------------------
	// @function    Setting::load
	// @desc        Load the parameter values for this setting
	//              from the database and answer a modified 
	//              version of the receiver.
	// @return      bool
	//!---------------------------------------------------------  
	function load() {
		$db = new DatabaseConnection();
		$result = $db->loadParameterSettings($this);
		if (!$result) {
			$this->message = "load setting - database access failed!";
		}
		return $result;
	}

	//!---------------------------------------------------------
	// @function    Setting::save
	// @desc        Save the parameter setting with the parameter
	//              values under its name in the database.
	// @return      bool
	//!---------------------------------------------------------    
	function save() {
		$db = new DatabaseConnection();
		$result = $db->saveParameterSettings($this);
		if (!$result) {
			$this->message = "save setting - database access failed!";
		}
		return $result;
	}

	//!---------------------------------------------------------
	// @function    Setting::display
	// @desc        Display the setting as a text containing
	//              the parameters and their values.
	// @return      Void
	//!---------------------------------------------------------      
	function display() {
		print $this->displayString();
	}

	//!---------------------------------------------------------
	// @function    Setting::displayString
	// @desc        Answer the display string of the setting.
	//              It contains the names and values of the 
	//              settings parameters.
	// @return      Void
	//!---------------------------------------------------------        
	function displayString() {
		$result = '';
		
		// These parameters are important to properly display all the others
		$numberOfChannels = $this->parameter( "NumberOfChannels" )->value( );
		$PSF = $this->parameter( "PointSpreadFunction" )->value( );
		$performAberrationCorrection = $this->parameter( "PerformAberrationCorrection" )->value( );
		$aberrationCorrectionMode = $this->parameter( "AberrationCorrectionMode" )->value( );
		$advancedCorrectionOptions = $this->parameter( "AdvancedCorrectionOptions" )->value( );
		
		// The relevant parameters for theoretical vs. measured PSF are
		// displayed, making sure that the number of entries (e.g. for the
		// wavelengths) reflect the user-defined number of channels
		foreach ($this->parameter as $parameter) {
			if ($this->isFixedGeometryFormat() && $parameter->name() == 'ImageGeometry')
				continue;
			if (!$this->isMultiPointOrSinglePointConfocal() && $parameter->name() == 'PinholeSize')
				continue;
			if (!$this->isMultiChannel() && $parameter->name() == 'NumberOfChannels')
				continue;
			if (!$this->isThreeDimensional() && $parameter->name() == 'ZStepSize')
				continue;
			if ($parameter->name() == 'IsMultiChannel' || $parameter->name() == 'HasAdaptedValues' || $parameter->name() == 'PSF')
				continue;
			if ( ( $parameter->name() == 'ExcitationWavelength' || $parameter->name() == 'EmissionWavelength' ) && $PSF == 'measured' )
				continue;
			if ($parameter->name() == 'SampleMedium' && $PSF == 'measured' )
				continue;		
			if ($parameter->name() == 'CMount' ) // This is obsolete
				continue;		
			if ($parameter->name() == 'TubeFactor' ) // This is obsolete
				continue;		
			if ($parameter->name() == 'CCDCaptorSizeX' && $PSF == 'measured' )
				continue;		
			if ($parameter->name() == 'CoverslipRelativePosition' && $PSF == 'measured' )
				continue;
			if ($parameter->name() == 'CoverslipRelativePosition' && $performAberrationCorrection == 0 )
				continue;
			if ($parameter->name() == 'AberrationCorrectionMode' && $performAberrationCorrection == 0 )
				continue;
			if ($parameter->name() == 'AdvancedCorrectionOptions' && !( $performAberrationCorrection == 1 && $aberrationCorrectionMode == 'advanced' ) )
				continue;
			if ($parameter->name() == 'PSFGenerationDepth' && !( $performAberrationCorrection == 1 && $aberrationCorrectionMode == 'advanced' && $advancedCorrectionOptions == 'user' ) )
				continue;
            $result = $result . $parameter->displayString( $numberOfChannels );
		}
		return $result;
	}
}

//!---------------------------------------------------------
// @class    ParameterSetting
// @desc     A parameter setting is a complete set of 
//           microscope, image and capture parameters.
//!---------------------------------------------------------
Class ParameterSetting extends Setting {
	//!---------------------------------------------------------
	// @function    ParameterSetting::ParameterSetting
	// @desc        Constructor. Creates a new ParameterSetting
	// @return      void
	//!---------------------------------------------------------
	function ParameterSetting() {
		$this->Setting();
		// manage parameter adaption
		// manage measured PSF
		// support for Nipkow spinning disk
		$parameterClasses = array (
			'HasAdaptedValues',
			'IsMultiChannel',
			'ImageFileFormat',
			'NumberOfChannels',
			'ImageGeometry',
			'MicroscopeType',
			'NumericalAperture',
			'ObjectiveMagnification',
			'ObjectiveType',
			'SampleMedium',
			'Binning',
			'ExcitationWavelength',
			'EmissionWavelength',
			'CMount',
			'TubeFactor',
			'CCDCaptorSizeX',
			'ZStepSize',
			'TimeInterval',
			'PinholeSize',
			'PinholeSpacing',
			'PointSpreadFunction',
			'PSF',
			'CoverslipRelativePosition',
			'AberrationCorrectionNecessary',
			'PerformAberrationCorrection',
			'AberrationCorrectionMode',
			'AdvancedCorrectionOptions',
			'PSFGenerationDepth'
		);
		$db = new DatabaseConnection();
		foreach ($parameterClasses as $class) {
			$param = new $class;
			$name = $param->name();
			$param->setupAllowedValues($db);
			$this->parameter[$name] = $param;
		}
	}

	//!---------------------------------------------------------
	// @function    ParameterSetting::getAberractionCorrectionParameters()
	// @desc        Returns the parameters needed for the aberration correction.
	// @return      Array
	//!---------------------------------------------------------    
	function getAberractionCorrectionParameters() {
		$parameters = array(
			'AberrationCorrectionNecessary' => $this->parameter('AberrationCorrectionNecessary')->value(),
			'PerformAberrationCorrection' => $this->parameter('PerformAberrationCorrection')->value(),
			'CoverslipRelativePosition' => $this->parameter('CoverslipRelativePosition')->value(),
			'AberrationCorrectionMode' => $this->parameter('AberrationCorrectionMode')->value(),
			'AdvancedCorrectionOptions'=>$this->parameter('AdvancedCorrectionOptions')->value(),
			'PSFGenerationDepth'=> $this->parameter('PSFGenerationDepth')->value() );
		return $parameters;
	}
	
	//!---------------------------------------------------------
	// @function    ParameterSetting::imageParameterNames()
	// @desc        Answer the names of parameters concerning the image.
	// @return      Array
	//!---------------------------------------------------------    
	function imageParameterNames() {
		$names = array ();
		foreach ($this->parameter as $parameter) {
			if ($parameter->isForImage()) {
				$names[] = $parameter->name();
			}
		}
		return $names;
	}

	//!---------------------------------------------------------
	// @function    ParameterSetting::microscopeParameterNames()
	// @desc        Answer the names of parameters concerning the microscope
	// @return      Array
	//!---------------------------------------------------------    
	function microscopeParameterNames() {
		$names = array ();
		foreach ($this->parameter as $parameter) {
			if ($parameter->isForMicroscope()) {
				$names[] = $parameter->name();
			}
		}
		return $names;
	}
	//!---------------------------------------------------------
	// @function    ParameterSetting::capturingParameterNames()
	// @desc        Answer the names of parameters concerning the captor
	// @return      Array
	//!---------------------------------------------------------    
	function capturingParameterNames() {
		$names = array ();
		foreach ($this->parameter as $parameter) {
			if ($parameter->isForCapture()) {
				$names[] = $parameter->name();
			}
		}
		return $names;
	}
	//!---------------------------------------------------------
	// @function    ParameterSetting::checkImageParameter()
	// @desc        Check the image parameter. Answer true if they
	//              are valid. Answer false and set the message
	//              otherwise.
	// @return      Boolean
	//!---------------------------------------------------------    
	function checkImageParameter() {
		$result = True;
		$this->message = '';
		if ($this->isMultiChannel()) {
			$result = $this->checkMultiChannelImageParameter();
		} else {
			$result = $this->checkSingleChannelImageParameter();
		}
		return $result;
	}
	//!---------------------------------------------------------
	// @function    ParameterSetting::checkMicroscopeParameter()
	// @desc        Check the microscope parameter. Answer true if they
	//              are valid. Answer false and set the message
	//              otherwise.
	// @return      Boolean
	//!---------------------------------------------------------    
	function checkMicroscopeParameter() {
		$this->message = '';
		if (!$this->checkChoiceValue('MicroscopeType', 'microscope type')) {
			return False;
		}
		if (!$this->checkNumericalAperture()) {
			return False;
		}
		if (!$this->checkWavelength('Excitation')) {
			return False;
		}
		if (!$this->checkWavelength('Emission')) {
			return False;
		}
		if (!$this->checkChoiceValue('ObjectiveType', 'objective type')) {
			return False;
		}
		if (!$this->checkSampleMedium()) {
			return False;
		}		//if (!$this->checkNumericalValue('CMount', 'cmount')) {
		//	return False;
		//}
		//if (!$this->checkNumericalValue('TubeFactor', 'tube factor')) {
		//	return False;
		//}
		return True;
	}
	//!---------------------------------------------------------
	// @function    ParameterSetting::checkCapturingParameter()
	// @desc        Check the capturing  parameter. Answer true if they
	//              are valid. Answer false and set the message
	//              otherwise.
	// @return      Boolean
	//!---------------------------------------------------------    
	function checkCapturingParameter() {
		$this->message = '';

		$text = $this->captorSizeText();
		if (!$this->checkNumericalValue('CCDCaptorSizeX', $text)) {
			return False;
		}
		if ($this->isThreeDimensional()) {
			if (!$this->checkNumericalValue('ZStepSize', 'size of the z-step')) {
				return False;
			}
		}
		if ($this->isTimeSeries()) {
			if (!$this->checkNumericalValue('TimeInterval', 'time interval')) {
				return False;
			}
		}
		if ($this->isMultiPointOrSinglePointConfocal()) {
			// Check pinhole radius for every channel
			if (!$this->checkPinholeSize()) {
				return False;
			}
		}
		// Support for Nipkow spinning disk
		if ($this->isNipkowDisk()) {
			if (!$this->checkPinholeSpacing()) {
				return False;
			}
		}
		// Check Nyquist rate only if parameters are not already adapted
		if (!$this->hasAdaptedParameters() && !$this->checkNyquistRate()) {
			return False;
		}
		return True;
	}

	//!---------------------------------------------------------
	// @function    ParameterSetting::checkCalculateParameter()
	// @desc        Check the parameters needed the compute the pixel size
	//		from the microscope and camera parameters. Answer true
	//              if they are valid. Answer false and set the message
	//              otherwise.
	// @return      Boolean
	//!---------------------------------------------------------    
	function checkCalculateParameter() {
		$this->message = '';
		if (!$this->checkNumericalValue('CCDCaptorSizeX', 'CCD element size')) {
			$this->message = "Please enter a valid CCD element size!";
			return False;
		}
		if (!$this->checkNumericalValue('CMount', 'cmount')) {
			return False;
		}
		if (!$this->checkNumericalValue('TubeFactor', 'tube factor')) {
			return False;
		}
		return True;
	}

	// manage parameter adaption
	function hasAdaptedParameters() {
		$parameter = $this->parameter('HasAdaptedValues');
		if ($parameter->value() == "True")
			return True;
		else
			return False;
	}

	// manage parameter adaption
	function setAdaptedParameters($value) {
		$parameter = $this->parameter('HasAdaptedValues');
		if ($value)
			$parameter->setValue("True");
		else
			$parameter->setValue("False");
		$this->parameter['HasAdaptedValues'] = $parameter;
	}

	//!---------------------------------------------------------
	// @function    ParameterSetting::checkPointSpreadFunction()
	// @desc        Answer true if a PSF file is selected for every
	//              channel. Answer false and set the message
	//              otherwise.
	// @return      Boolean
	//!---------------------------------------------------------    
	function checkPointSpreadFunction() {
		$this->message = '';
		$parameter = $this->parameter('PSF');
		$value = $parameter->value();
		for ($i = 0; $i < $this->numberOfChannels(); $i++) {
			if ($value[$i] == NULL) {
				$this->message = "Please select a PSF file for channel $i!";
				return False;
			}
		}
		return True;
	}

	// Support for Nipkow spinning disk
	//!---------------------------------------------------------
	// @function    ParameterSetting::checkPinholeSpacing
	// @desc        TODO
	// @return      Boolean
	//!---------------------------------------------------------
	function checkPinholeSpacing() {
		$result = True;
		$parameter = $this->parameter('PinholeSpacing');
		$pinholeSpacingInputString = $parameter->value();
		if (!is_numeric($pinholeSpacingInputString)) {
			$this->message = "The pinhole spacing must be a number!";
			if (strstr($pinholeSpacingInputString, ',')) {
				$this->message = $this->message . " Please use a point (.) instead of a comma (,)!";
			}
			$result = False;
		}
		return $result;
	}

	//!---------------------------------------------------------
	// @function    ParameterSetting::checkPinholeSize
	// @desc        TODO
	// @return      Boolean
	//!---------------------------------------------------------    
	function checkPinholeSize() {
		$parameter = $this->parameter('PinholeSize');
		for ($i = 0; $i < $this->numberOfChannels(); $i++) {
			if (!$parameter->checkValue($parameter->value[$i])) {
				$this->message = "Please enter a valid pinhole size for channel $i!";
				return False;
			}
		}
		return True;
	}

	//!---------------------------------------------------------
	// @function    ParameterSetting::checkNumericalAperture
	// @desc        The numerical aperture must not be bigger 
	//              than the lens refractive index or the medium
	//              refractive index. It must not be smaller than
	//              0.2
	// @return      Boolean
	//!---------------------------------------------------------    
	function checkNumericalAperture() {
		$result = True;
		
		$parameter = $this->parameter('NumericalAperture');
		$numericalApertureInputString = $parameter->value();
		$numericalAperture = (float) $parameter->value();
		
		$parameter = $this->parameter('ObjectiveType');
		$lensRefractiveIndex = (float) $parameter->translatedValue();
		
		if ($numericalAperture > $lensRefractiveIndex) {
			$this->message = "The numerical aperture cannot be larger than the lens refractive index which is $lensRefractiveIndex for the selected objective type. Please lower the numerical aperture!";
			$result = False;
		}
		// The following check (numericalAperture>mediumRefractiveIndex) was
		// removed in HuygensPro, and we therefore de-activate it in the HRM
		// as well
		//$parameter = $this->parameter('SampleMedium');
		//$mediumRefractiveIndex = (float) $parameter->translatedValue();
		//if ($numericalAperture > $mediumRefractiveIndex) {
		//	$this->message = "The numerical aperture cannot be larger than the medium refractive index which is $mediumRefractiveIndex for the selected medium. Please lower the numerical aperture!";
		//	$result = False;
		//}
		if ($numericalAperture < 0.1) {
			$this->message = "The numerical aperture must not be smaller than 0.1!";
			$result = False;
		}
		if (!is_numeric($numericalApertureInputString)) {
			$this->message = "The numerical aperture must be a number!";
			if (strstr($numericalApertureInputString, ',')) {
				$this->message = $this->message . " Please use a point (.) instead of a comma (,)!";
			}
			$result = False;
		}
		return $result;
	}

	// TODO refactor
	//!---------------------------------------------------------
	// @function    ParameterSetting::adaptedLateralSampleSize
	// @desc        Test if the sampling size lies around the ideal
	//              sampling size according to the nyquist criterium.
	//              If this is not the case adapt the sample size 
	//              to the ideal value according to the nyquist
	//              criterium.
	// @param       size  float  The sample size entered by the user
	// @return      float
	//!---------------------------------------------------------    
	function adaptedLateralSampleSize() {
		$result = False;
		// Use the most restrictive wavelength to compute the adaption
		$parameter = $this->parameter('EmissionWavelength');
		if ($this->isTwoPhoton() || $this->isMultiPointOrSinglePointConfocal()) {
			$parameter = $this->parameter('ExcitationWavelength');
		}
		$value = $parameter->value();
		$mostRestrictiveWavelengthChannel = 0;
		$mostRestrictiveWavelength = $value[0];
		for ($i = 1; $i < $this->numberOfChannels(); $i++) {
			if ($value[$i] < $mostRestrictiveWavelength) {
				$mostRestrictiveWavelengthChannel = $i;
				$mostRestrictiveWavelength = $value[$i];
			}
		}
		// Check for undersampling and oversampling using the Nyquist criterium
		$parameter = $this->parameter('CCDCaptorSizeX');
		$deltaX = (float) $parameter->value();
		$parameter = $this->parameter('NumericalAperture');
		$na = (float) $parameter->value();
		$lambda = $mostRestrictiveWavelength;
		$idealDeltaX = $lambda / (4 * $na);
		if ($this->isMultiPointOrSinglePointConfocal())
			$idealDeltaX = $idealDeltaX / 2;
		if ((0.5 * $idealDeltaX <= $deltaX) && ($deltaX <= 1.2 * $idealDeltaX)) {
			$result = $deltaX;
		} else {
			$result = $idealDeltaX;
		}
		return $result;
	}

	// TODO refactor
	//!---------------------------------------------------------
	// @function    ParameterSetting::adaptedLateralSampleSize
	// @desc        Test if the sampling size lies around the ideal
	//              sampling size according to the nyquist criterium.
	//              If this is not the case adapt the sample size 
	//              to the ideal value according to the nyquist
	//              criterium.
	// @param       size  float  The sample size entered by the user
	// @return      float
	//!---------------------------------------------------------    
	function adaptedLateralSampleSizeFor($size) {
		$result = False;
		// Check for undersampling and oversampling using the Nyquist criterium
		$deltaX = $size;
		$parameter = $this->parameter('NumericalAperture');
		$na = (float) $parameter->value();
		$parameter = $this->parameter('ExcitationWavelength');
		$value = $parameter->value();
		$lambda = $value[0];
		$idealDeltaX = $lambda / (4 * $na);
		$idealDeltaX = $idealDeltaX / 2;
		if ((0.5 * $idealDeltaX <= $deltaX) && ($deltaX <= 1.2 * $idealDeltaX)) {
			$result = $deltaX;
		} else {
			$result = $idealDeltaX;
		}
		return $result;
	}

	/* TODO refactor
	//!---------------------------------------------------------
	// @function    ParameterSetting::adaptedLateralSampleSizeFor
	// @desc        Test if the sampling size lies around the ideal
	//              sampling size according to the nyquist criterium.
	//              If this is not the case adapt the sample size 
	//              to the ideal value according to the nyquist
	//              criterium.
	// @param       channel  int  The number of the channel (1-4)
	// @return      float
	//!---------------------------------------------------------   
	function adaptedLateralSampleSizeFor($channel) {
	    $result = False;
	    // Check for undersampling and oversampling using the Nyquist criterium
	    $parameter = $this->parameter('CCDCaptorSizeX');    
	    $deltaX = (float)$parameter->value();
	    $parameter = $this->parameter('NumericalAperture');    
	    $na = (float)$parameter->value();
	    $parameter = $this->parameter('ExcitationWavelength');
	    $value = $parameter->value();
	    $lambda = $value[$channel];
	    $idealDeltaX = $lambda / (4 * $na); 	
	    $idealDeltaX = $idealDeltaX / 2;
	    if ((0.5 * $idealDeltaX <= $deltaX) && ($deltaX <= 1.2 * $idealDeltaX)) {
	        $result = $deltaX;
	    } else {
	        $result = $idealDeltaX;
	    } 
	    return $result; 
	}*/

	/* TODO refactor
	//!---------------------------------------------------------
	// @function    ParameterSetting::adaptedNumericalAperture
	// @desc        Test if the sampling size lies around the ideal
	//              sampling size according to the nyquist criterium.
	//              If this is not the case lower the numerical 
	//              aperture until the condition is met. Answer the
	//              adapted numerical aperture if one was found. Uses
	//              the most restrictive wavelength.
	//              Otherwise answer Null.
	// @return      Boolean
	//!---------------------------------------------------------    
	function adaptedNumericalAperture() {
	    $result = Null;
	    // use most restrictive wavelength
	    $parameter = $this->parameter('EmissionWavelength');
	    if ($this->isTwoPhoton()) {
	        $parameter = $this->parameter('ExcitationWavelength');
	    } 
	    $value = $parameter->value();
	    $mostRestrictiveWavelengthChannel = 0;
	    $mostRestrictiveWavelength = $value[0];
	    for ($i=1; $i< $this->numberOfChannels(); $i++) {
	        if ($value[$i] < $mostRestrictiveWavelength) {
	            $mostRestrictiveWavelengthChannel = $i;
	            $mostRestrictiveWavelength = $value[$i];
	        }
	    }
	    $parameter = $this->parameter('CCDCaptorSizeX');    
	    $deltaX = (float)$parameter->value();
	    $parameter = $this->parameter('NumericalAperture');    
	    $na = (float)$parameter->value();
	    $lambda = $mostRestrictiveWavelength;
	    for ($adapted_na = $na; $adapted_na >= 0.2; $adapted_na = $adapted_na - 0.0025) {
	        $idealDeltaX = $lambda / (4 * $adapted_na);
	        if ((0.5 * $idealDeltaX <= $deltaX) && ($deltaX <= 1.2 * $idealDeltaX)) {
	            $result = $adapted_na;
	            break;
	        } 
	    }
	    return $result;     
	}
	
	//!---------------------------------------------------------
	// @function    ParameterSetting::adaptedNumericalApertureFor
	// @desc        Test if the sampling size lies around the ideal
	//              sampling size according to the nyquist criterium.
	//              If this is not the case lower the numerical 
	//              aperture until the condition is met. Answer the
	//              adapted numerical aperture if one was found. 
	//              Otherwise answer Null.
	// @param       channel  int  The number of the channel (1-4)
	// @return      Boolean
	//!---------------------------------------------------------    
	function adaptedNumericalApertureFor($channel) {
	    $result = Null;
	    $parameter = $this->parameter('CCDCaptorSizeX');    
	    $deltaX = (float)$parameter->value();
	    $parameter = $this->parameter('NumericalAperture');    
	    $na = (float)$parameter->value();
	    $parameter = $this->parameter('EmissionWavelength');
	    if ($this->isTwoPhoton()) { 
	        $parameter = $this->parameter('ExcitationWavelength');
	    } 
	    $value = $parameter->value();
	    $lambda = $value[$channel];
	    for ($adapted_na = $na; $adapted_na >= 0.2; $adapted_na = $adapted_na - 0.0025) {
	        $idealDeltaX = $lambda / (4 * $adapted_na);
	        if ((0.5 * $idealDeltaX <= $deltaX) && ($deltaX <= 1.2 * $idealDeltaX)) {
	            $result = $adapted_na;
	            break;
	        } 
	    }
	    return $result;     
	}*/

        //!---------------------------------------------------------
        // @function    ParameterSetting::calculateNyquistRate
        // @desc        Ask hucore for the ideal (Nyquist) sampling rate
        //              for the current conditions. 
        // @return      An array with the XY and Z ideal sampling.
        //!---------------------------------------------------------    
        function calculateNyquistRate() {
            // Use the most restrictive wavelength to compute the adaption
            $parameter = $this->parameter('EmissionWavelength');
            if ( $this->isTwoPhoton()
                || $this->isMultiPointOrSinglePointConfocal()) {
                $parameter = $this->parameter('ExcitationWavelength');
            }
            $value = $parameter->value();
            $mostRestrictiveChannel = 0;
            $mostRestrictiveWavelength = $value[0];
            for ($i = 1; $i < $this->numberOfChannels(); $i++) {
                if ($value[$i] < $mostRestrictiveWavelength) {
                    $mostRestrictiveChannel = $i;
                    $mostRestrictiveWavelength = $value[$i];
                }
            }
            $parameter = $this->parameter('EmissionWavelength');
            $value = $parameter->value();
            $em = $value[$mostRestrictiveChannel];
            $parameter = $this->parameter('ExcitationWavelength');
            $value = $parameter->value();
            $ex = $value[$mostRestrictiveChannel];

            $parameter = $this->parameter('NumericalAperture');
            $na = (float) $parameter->value();

            $parameter = $this->parameter('MicroscopeType');
            $micr = $parameter->translatedValue();

            $parameter = $this->parameter('ObjectiveType');
            $ril = $parameter->translatedValue();

            if ($this->isTwoPhoton()) {
                $pcnt = 2;
            } else {
                $pcnt = 1;
            }
            // Only micr, na, em, ex and pcnt are necessary to calculate it.

            $opt = "-micr $micr -na $na -em $em -ex $ex -pcnt $pcnt -ril $ril";
            $ideal = askHuCore ("calculateNyquistRate", $opt);
            // print_r($ideal);
            return array( $ideal['xy'], $ideal['z'] );
        }

	// sample size adaption for all microscopes
	// TODO don't answer false if data is over sampled
	// TODO refactor
	//!---------------------------------------------------------
	// @function    ParameterSetting::isNyquistRateOK
	// @desc        TODO
	// @return      Boolean
	//!---------------------------------------------------------    
	function isNyquistRateOK() {
		$result = True;
		$adaption = False;
		// Use the most restrictive wavelength to compute the adaption
		$parameter = $this->parameter('EmissionWavelength');
		if ($this->isTwoPhoton() || $this->isMultiPointOrSinglePointConfocal()) {
			$parameter = $this->parameter('ExcitationWavelength');
		}
		$value = $parameter->value();
		$mostRestrictiveWavelengthChannel = 0;
		$mostRestrictiveWavelength = $value[0];
		for ($i = 1; $i < $this->numberOfChannels(); $i++) {
			if ($value[$i] < $mostRestrictiveWavelength) {
				$mostRestrictiveWavelengthChannel = $i;
				$mostRestrictiveWavelength = $value[$i];
			}
		}
		// Check if data is under sampled and if parameter values can be adapted
		// In the case of confocal microscopes, the sample size is adapted

		// 1) check if undersampled or oversampled
		// sample size
		$parameter = $this->parameter('CCDCaptorSizeX');
		$deltaX = (float) $parameter->value();
		// ideal sample size
		$lambda = $mostRestrictiveWavelength;
		$parameter = $this->parameter('NumericalAperture');
		$na = (float) $parameter->value();
		$idealDeltaX = $lambda / (4 * $na);
		if ($this->isMultiPointOrSinglePointConfocal())
			$idealDeltaX /= 2;
		// sampling factor
		$factor = $idealDeltaX / $deltaX;

		// if 3-D, check if sample size in z direction also has to be adapted
		if ($this->isThreeDimensional()) {
			$parameter = $this->parameter('ZStepSize');
			$sampleSizeZ = (float) $parameter->value();
			$idealSampleSizeZ = $this->idealSampleSizeZ(); // EDIT
			$z_factor = $idealSampleSizeZ / $sampleSizeZ;
		}

		// 2) if undersampled, compute adapted sample size, warn and ask for confirmation
		if ($factor < 1 || !((0.5 * $idealSampleSizeZ <= $sampleSizeZ) && ($sampleSizeZ <= 1.2 * $idealSampleSizeZ))) { // EDIT
			// TODO refactor here
			$this->message = "<p>WARNING: sample size will be adapted to ideal</p>\n";
			$this->message = $this->message . "<p>Sampling rate w.r.t. Nyquist criterion:<br />";
			$this->message = $this->message . "X-dir: " . number_format(round($idealDeltaX / $deltaX, 2), 2, ',', '') . "<br />Y-dir: " . number_format(round($idealDeltaX / $deltaX, 2), 2, ',', '');
			if ($this->isThreeDimensional()) {
				$param = $this->parameter('ZStepSize');
				$size = (float) $param->value();
				$this->message = $this->message . "<br />Z-dir: " . number_format(round($idealSampleSizeZ / $sampleSizeZ, 2), 2, ',', ''); // EDIT
			}
			$this->message = $this->message . "<br />(values > 1 represent supersampling)</p>\n";
			$this->message = $this->message . "<p>Sampling precisely according to the Nyquist criterion would involve sampling distances (nm):<br />";
			$this->message = $this->message . "X-dir: " . floor($idealDeltaX) . "<br />Y-dir: " . floor($idealDeltaX);
			if ($this->isThreeDimensional()) {
				$this->message = $this->message . "<br />Z-dir: " . floor($idealSampleSizeZ) . "<br />"; // EDIT
			}
			$this->message = $this->message . "</p>\n<p>If you still want to use these parameter settings, press the OK button again.</p>\n";
			$this->setAdaptedParameters(True);
			$result = False;
		}

		// 3) else if oversampled by factor > 1.5, warn and ask for confirmation
		else if ($factor >= 1.5 || $z_factor > 1.5) {
			$this->message = "";
			if ($factor >= 1.5) {
				$this->message .= "The image is oversampled by a factor of " . number_format(round($factor, 2), 2, ',', '') . " in lateral direction";
			}
			if ($z_factor > 1.5) {
				$this->message .= "\nThe image is oversampled by a factor of " . number_format(round($z_factor, 2), 2, ',', '') . " in axial direction";
			}
			$this->message .= "\nIf you still want to use these parameter settings, press the OK button again.\n";
			$result = False;
		}

		// 4) else accept happily
		else {
			$result = True;
		}
		//}
		return $result;
	}

	//!---------------------------------------------------------
	// @function    ParameterSetting::checkNyquistRate
	// @desc        For widefield microscope check the nyquist
	//              rate. Adapt the numerical aperture for each
	//              channel if necessary. Answer true if under
	//              sampling and over sampling are limited to
	//              a reasonable amount.
	// @return      Boolean
	//!---------------------------------------------------------    
	function checkNyquistRate() {
		// Check Nyquist Rate for every microscope
		//return $this->isNyquistRateOK();
		return True;
	}

	//!---------------------------------------------------------
	// @function    ParameterSetting::checkWavelength()
	// @desc        Check the emission or excitation wavelengths.
	//              This case is treated seperately because there
	//              is one wavelength value per channel.
	// @param       name  String  Emission or Excitation
	// @return      Boolean
	//!---------------------------------------------------------    
	function checkWavelength($name) {
		$parameterName = $name . 'Wavelength';
		$label = strtolower($name);
		$parameter = $this->parameter($parameterName);
		for ($i = 0; $i < $this->numberOfChannels(); $i++) {
			if (!$parameter->checkValue($parameter->value[$i])) {
				$this->message = "Please enter a valid $label wavelength for channel $i!";
				return False;
			}
		}
		return True;
	}
	//!---------------------------------------------------------
	// @function    ParameterSetting::checkSingleChannelImageParameter()
	// @desc        Check the parameter if single channel had been
	//              chosen.
	// @return      Boolean
	//!---------------------------------------------------------    
	function checkSingleChannelImageParameter() {

		// Modification by Aaron Ponti, 2005/12/13

		return True;

		// End of modification by Aaron Ponti, 2005/12/13

		$result = True;
		$parameter = $this->parameter('ImageFileFormat');
		$fileFormat = $parameter->value();
		if ((!in_array($fileFormat, $this->singleChannelFileFormats()))) {
			$this->message = "Please select a single channel file format (" . implode(", ", $this->singleChannelFileFormats()) . ")!";
			return False;
		}
		if ($fileFormat != 'tiff-single') {
			$result = $this->checkGeometry('single');
		}
		return $result;
	}
	//!---------------------------------------------------------
	// @function    ParameterSetting::checkMultiChannelImageParameter()
	// @desc        Check the parameter if multichannel had been
	//              chosen.
	// @return      Boolean
	//!---------------------------------------------------------    
	function checkMultiChannelImageParameter() {
		$result = True;
		$parameter = $this->parameter('ImageFileFormat');
		$fileFormat = $parameter->value();
		if ((!in_array($fileFormat, $this->multiChannelFileFormats()))) {
			$this->message = "Please select a multichannel file format (" . implode(", ", $this->multiChannelFileFormats()) . ")!";
			return False;
		}
		if (!in_array($fileFormat, $this->fixedGeometryFileFormats())) {
			$result = $this->checkGeometry('multi');
		}
		if (in_array($fileFormat, $this->variableChannelFileFormats())) {
			$result = $this->checkNumberOfChannels() && $result;
		}
		return $result;
	}
	//!---------------------------------------------------------
	// @function    ParameterSetting::checkGeometry
	// @desc        Check the image geometry parameter (two or
	//              three dimensional, time series or single image).
	// @param       prefix  String  single or multi (for single 
	//              channel or multi channel geometries.
	// @return      Boolean
	//!---------------------------------------------------------    
	function checkGeometry($prefix) {
		$result = True;
		$parameter = $this->parameter('ImageGeometry');
		$geometry = $parameter->internalValue();
		if ($geometry == '') {
			$geometry = '_';
		}
		$parts = explode('_', $geometry);
		$geometry = $parts[1];
		$prefix_ok = True;
		if ($prefix != $parts[0]) {
			$prefix_ok = False;
		}
		if (!$parameter->check() || !$prefix_ok) {
			$this->message = "Please select the image kind (" . implode(", ", $parameter->possibleValues()) . ")!";
			return False;
		}
		return $result;
	}
	//!---------------------------------------------------------
	// @function    ParameterSetting::checkNumberOfChannels()
	// @desc        Check the number of channels. Must be between 
	//              1 to 5.
	// @return      Boolean
	//!---------------------------------------------------------    
	function checkNumberOfChannels() {
		$result = True;
		$parameter = $this->parameter('NumberOfChannels');
		$numberOfChannels = (int) $parameter->value();
		if ($numberOfChannels < 1 || $numberOfChannels > 5 ) {
			$result = False;
			$this->message = "Please select the number of channels (1-5)!";
		}
		return $result;
	}

	function threeDimensionalGeometries() {
		static $threeDimensionalGeometries;
		if ($threeDimensionalGeometries == NULL) {
			$db = new DatabaseConnection();
			$threeDimensionalGeometries = $db->geometriesWith(True, NULL);
		}
		return $threeDimensionalGeometries;
	}

	function timeSeriesGeometries() {
		static $timeSeriesGeometries;
		if ($timeSeriesGeometries == NULL) {
			$db = new DatabaseConnection();
			$timeSeriesGeometries = $db->geometriesWith(NULL, True);
		}
		return $timeSeriesGeometries;
	}

	//!---------------------------------------------------------
	// @function    ParameterSetting::fixedGeometryFileFormats
	// @desc        Answer an array of file formats that have a
	//              fixed geometry (2d images).
	// @return      array
	//!---------------------------------------------------------    
	function fixedGeometryFileFormats() {
		static $fixedGeometryFileFormats;
		if ($fixedGeometryFileFormats == NULL) {
			$db = new DatabaseConnection();
			$fixedGeometryFileFormats = $db->fileFormatsWith(NULL, NULL, True);
		}
		return $fixedGeometryFileFormats;
	}

	function isFixedGeometryFormat() {
		$param = $this->parameter('ImageFileFormat');
		$result = in_array($param->value(), $this->fixedGeometryFileFormats());
		return $result;
	}

	//!---------------------------------------------------------
	// @function    ParameterSetting::singleChannelFileFormats
	// @desc        Answer an array of file formats that support
	//              single channel images.
	// @return      array
	//!---------------------------------------------------------    
	function singleChannelFileFormats() {
		static $singleChannelFileFormats;
		if ($singleChannelFileFormats == NULL) {
			$db = new DatabaseConnection();
			$singleChannelFileFormats = $db->fileFormatsWith(True, NULL, NULL);
		}
		return $singleChannelFileFormats;
	}

	//!---------------------------------------------------------
	// @function    ParameterSetting::multiChannelFileFormats
	// @desc        Answer an array of file formats that support
	//              multi channel images.
	// @return      array
	//!---------------------------------------------------------    
	function multiChannelFileFormats() {
		static $multiChannelFileFormats;
		if ($multiChannelFileFormats == NULL) {
			$db = new DatabaseConnection();
			$multiChannelFileFormats = $db->fileFormatsWith(False, NULL, NULL);
		}
		return $multiChannelFileFormats;
	}

	//!---------------------------------------------------------
	// @function    ParameterSetting::variableChannelFileFormats
	// @desc        Answer an array of file formats that support
	//              a variable number of channels in one file
	// @return      array
	//!---------------------------------------------------------    
	function variableChannelFileFormats() {
		static $variableChannelFileFormats;
		if ($variableChannelFileFormats == NULL) {
			$db = new DatabaseConnection();
			$variableChannelFileFormats = $db->fileFormatsWith(NULL, True, NULL);
		}
		return $variableChannelFileFormats;
	}

	//!---------------------------------------------------------
	// @function    ParameterSetting::isMultiChannel
	// @desc        Answer true if the setting is for a multi
	//              channel image.
	// @return      boolean
	//!---------------------------------------------------------    
	function isMultiChannel() {
		$parameter = $this->parameter('NumberOfChannels');
		$num_channels = (int) $parameter->value();
		if ($num_channels > 1) {
			$result = True;
		} else {
			$result = False;
		}
		return $result;
	}

	function isVariableChannelFormat() {
		$result = False;
		$parameter = $this->parameter('ImageFileFormat');
		if (in_array($parameter->value(), $this->variableChannelFileFormats())) {
			$result = True;
		}
		return $result;
	}

	function isTif() {
		$result = False;
		$parameter = $this->parameter('ImageFileFormat');
		if (strstr($parameter->value(), 'tif'))
			$result = True;
		return $result;
	}

	//!---------------------------------------------------------
	// @function    ParameterSetting::numberOfChannels
	// @desc        Answer the number of channels of the setting.
	// @return      Integer
	//!---------------------------------------------------------    
	function numberOfChannels() {
		$result = 3;
		if (!$this->isMultiChannel()) {
			return 1;
		}
		if ($this->isVariableChannelFormat()) {
			$parameter = $this->parameter('NumberOfChannels');
			return (int) $parameter->value();
		}
		return $result;
	}

	// Support for Nipkow spinning disk
	//!---------------------------------------------------------
	// @function    ParameterSetting::isNipkowDisk
	// @desc        Answer true if the setting is for a Nipkow
	//              spinning disk microscope.
	// @return      bool
	//!---------------------------------------------------------    
	function isNipkowDisk() {
		return $this->isMultiPointConfocal();
	}

	//!---------------------------------------------------------
	// @function    ParameterSetting::isTwoPhoton
	// @desc        Answer true if the setting is for a two
	//              photon microscope.
	// @return      bool
	//!---------------------------------------------------------    
	function isTwoPhoton() {
		$parameter = $this->parameter('MicroscopeType');
		$value = $parameter->value();
		return ($value == 'two photon');
	}

	//!---------------------------------------------------------
	// @function    ParameterSetting::isSinglePointConfocal
	// @desc        Answer true if the setting is for a single
	//              point confocal microscope.
	// @return      bool
	//!---------------------------------------------------------      
	function isSinglePointConfocal() {
		$parameter = $this->parameter('MicroscopeType');
		$value = $parameter->value();
		return ($value == 'single point confocal');
	}

	//!---------------------------------------------------------
	// @function    ParameterSetting::isMultiPointConfocal
	// @desc        Answer true if the setting is for a multi
	//              point confocal microscope.
	// @return      bool
	//!---------------------------------------------------------      
	function isMultiPointConfocal() {
		$parameter = $this->parameter('MicroscopeType');
		$value = $parameter->value();
		return ($value == 'multipoint confocal (spinning disk)');
	}

	//!---------------------------------------------------------
	// @function    ParameterSetting::isWidefield
	// @desc        Answer true if the setting is for a widefield
	//              microscope.
	// @return      bool
	//!---------------------------------------------------------      
	function isWidefield() {
		$parameter = $this->parameter('MicroscopeType');
		$value = $parameter->value();
		return ($value == 'widefield');
	}

	//!---------------------------------------------------------
	// @function    ParameterSetting::isWidefieldOrMultiPoint
	// @desc        Answer true if the setting is for a widefield
	//              or multi point confocal microscope.
	// @return      bool
	//!---------------------------------------------------------    
	function isWidefieldOrMultiPoint() {
		return ($this->isWidefield() || $this->isMultiPointConfocal());
	}

	//!---------------------------------------------------------
	// @function    ParameterSetting::isTwoPhotonOrSinglePoint
	// @desc        Answer true if the setting is for a two photon
	//              or single point confocal microscope.
	// @return      bool
	//!---------------------------------------------------------      
	function isTwoPhotonOrSinglePoint() {
		return ($this->isSinglePointConfocal() || $this->isTwoPhoton());
	}

	//!---------------------------------------------------------
	// @function    ParameterSetting::isMultiPointOrSinglePointConfocal
	// @desc        Answer true if the setting is for a single
	//              point or multi point confocal microscope.
	// @return      bool
	//!---------------------------------------------------------      
	function isMultiPointOrSinglePointConfocal() {
		return ($this->isSinglePointConfocal() || $this->isMultiPointConfocal());
	}

	//!---------------------------------------------------------
	// @function    ParameterSetting::isThreeDimensional
	// @desc        Answer true if the setting is for a three
	//              dimensional image geometry.
	// @return      bool
	//!---------------------------------------------------------      
	function isThreeDimensional() {
		$parameter = $this->parameter('ImageGeometry');
		$value = $parameter->value();
		$format = $this->parameter('ImageFileFormat');
		$formatValue = $format->value();
		return (in_array($value, $this->threeDimensionalGeometries()) && !in_array($formatValue, $this->fixedGeometryFileFormats()));
	}

	//!---------------------------------------------------------
	// @function    ParameterSetting::isTimeSeries
	// @desc        Answer true if the setting is for a time
	//              series of images.
	// @return      bool
	//!---------------------------------------------------------      
	function isTimeSeries() {
		if ($this->isFixedGeometryFormat())
			return False;
		$parameter = $this->parameter('ImageGeometry');
		$value = $parameter->value();
		return (in_array($value, $this->timeSeriesGeometries()));
	}

	// pixel size = lateral sample size (nm)
	// TODO rename CCDCaptorSizeX to SampleSizeX
	//!---------------------------------------------------------
	// @function    ParameterSetting::pixelSize
	// @desc        Answer the lateral sample size in nanometer
	// @return      number
	//!---------------------------------------------------------        
	function pixelSize() {
		$param = $this->parameter('CCDCaptorSizeX');
		$size = (float) $param->value();
		//return $this->sampleSize($size);
		return $size;
	}

	// TODO refactor
	//!---------------------------------------------------------
	// @function    ParameterSetting::sampleSizeX
	// @desc        Answer the lateral sample size in micron
	// @return      number
	//!---------------------------------------------------------        
	function sampleSizeX() {
		$size = $this->pixelSize();
		//return $this->sampleSize($size) / 1000;
		return $size / 1000;
	}

	//!---------------------------------------------------------
	// @function    ParameterSetting::sampleSizeY
	// @desc        Answer the lateral sample size in micron
	// @return      number
	//!---------------------------------------------------------        
	function sampleSizeY() {
		return $this->sampleSizeX();
	}

	//!---------------------------------------------------------
	// @function    ParameterSetting::sampleSizeZ
	// @desc        Answer the sample size in z direction in micron
	// @return      number
	//!---------------------------------------------------------        
	function sampleSizeZ() {
		$param = $this->parameter('ZStepSize');
		$size = (float) $param->value();
		//if ($this->hasAdaptedParameters()) $size = $size * $this->sampleSizeAdaptionFactor();
		return $size / 1000;
	}

	//!---------------------------------------------------------
	// @function    ParameterSetting::sampleSizeT
	// @desc        Answer the time between to images of the 
	//              time series in seconds. 
	// @return      number
	//!---------------------------------------------------------        
	function sampleSizeT() {
		$param = $this->parameter('TimeInterval');
		$size = (float) $param->value();
		return $size / 1;
	}

	// sample size adaption for all microscopes
	//!---------------------------------------------------------
	// @function    ParameterSetting::sampleSize
	// @desc        Answer the lateral sample size in nanometer.
	//              For confocal microscopes the sample size
	//              may be adapted to fit the nyquist criterium.
	// @param       size  float  The ccd captor or sampling size
	//              in nanometer. This Bloquer les numéros 0900?is the value the user 
	//              entered. 
	// @return      number
	//!---------------------------------------------------------          

    // WARNING: the sampling sizes is a property of the image, not something
    // taht can be adapted after the acquisition!!! It makes no sense to adapt
    // the samplign to the Nyquist rate. What must be done is to ACQUIRE the
    // image with the Nyquist rate, but never describe it with fake parameters!
	function sampleSize($size) {
		$result = $size;
		//if ($this->isMultiPointOrSinglePointConfocal()) {
		// Adapt sample size if necessary according to the nyquist criterium
		//    $result = $this->sampleSizeForConfocal($size);
		//}
		// if ($this->hasAdaptedParameters() && 1 == 0 )
		//	$result = $this->adaptedLateralSampleSizeFor($size);
		return $result;
	}

	// sample size adaption for all micrsocopes
	function sampleSizeAdaptionFactor() {
		$result = 1; // for widefield and two photon since NA is adapted and sample size is not changed
		/*if ($this->isMultiPointOrSinglePointConfocal()) {
		    $size = $this->pixelSize();
		    $result = $this->sampleSize($size) / $size;
		}*/
		return $result;
	}

	/* TODO refactor
	//!---------------------------------------------------------
	// @function    ParameterSetting::sampleSizeForCCDCaptorElementSize
	// @desc        Compute and answer the sample size (pixel size) 
	//              from the single ccd captor size and the microscope 
	//              parameters
	// @param       size  float  The ccd captor size in nanometer. 
	//              This is the value the user entered. 
	// @return      number
	//!---------------------------------------------------------
	function sampleSizeForCCDCaptorElementSize($size) {
	    $param = $this->parameter('Binning');
	    $binning = (float)$param->value();
	    $param = $this->parameter('ObjectiveMagnification');
	    $magnification = (float)$param->value();
	    $param = $this->parameter('CMount');
	    $cmount = (float)$param->value();
	    $param = $this->parameter('TubeFactor');
	    $tube = (float)$param->value();
	    $result = ($size * $binning) / ($magnification * $cmount * $tube);
	    return $result;
	}*/

	/* TODO refactor
	//!---------------------------------------------------------
	// @function    ParameterSetting::sampleSizeForConfocal
	// @desc        If necessary adapt the sample size to fit
	//              the nyquist criterium.
	// @param       size  float  The pixel size the user entered. 
	// @return      number
	//!---------------------------------------------------------
	function sampleSizeForConfocal($size) {
	    $result = $this->adaptedLateralSampleSize(1);
	    return $result;
	}*/

	//!---------------------------------------------------------
	// @function    ParameterSetting::table()
	// @desc        Answer the name of the database table in 
	//              which the parameter settings are stored. The 
	//              table contains the setting's name the owner 
	//              and the standard (default) flag.
	// @return      String
	//!---------------------------------------------------------    
	function table() {
		return "parameter_setting";
	}

	//!---------------------------------------------------------
	// @function    ParameterSetting::parameterTable()
	// @desc        Answer the name of the database table in
	//              which the parameters for settings of the 
	//              receiver's kind are stored. 
	// @return      String
	//!---------------------------------------------------------    
	function parameterTable() {
		return "parameter";
	}

	// TODO refactor and remove if not needed
	function usesPhotomultiplier() {
		if ($this->isSinglePointConfocal() || $this->isTwoPhoton()) {
			$result = True;
		} else {
			$result = False;
		}
		return $result;
	}

	// TODO refactor and remove if not needed
	function usesCCDCamera() {
		if ($this->isMultiPointConfocal() || $this->isWidefield()) {
			$result = True;
		} else {
			$result = False;
		}
		return $result;
	}

	// TODO refactor and remove if not needed
	function captorSizeText() {
		$result = 'x size of the ccd captor';
		if ($this->usesPhotomultiplier()) {
			$result = 'pixel size';
		}
		return $result;
	}

	// TODO refactor if needed
	function idealSampleSizeZ() {
		// use most restrictive wavelength
		if ($this->isWidefield()) {
			$parameter = $this->parameter('EmissionWavelength');
		} else {
			$parameter = $this->parameter('ExcitationWavelength');
		}
		$value = $parameter->value();
		$mostRestrictiveWavelengthChannel = 0;
		$mostRestrictiveWavelength = $value[0];
		for ($i = 1; $i < $this->numberOfChannels(); $i++) {
			if ($value[$i] < $mostRestrictiveWavelength) {
				$mostRestrictiveWavelengthChannel = $i;
				$mostRestrictiveWavelength = $value[$i];
			}
		}
		$lambda = $mostRestrictiveWavelength;
		if ($this->isWidefield()) {
			$factor = 2;
		} else {
			$factor = 4;
		}
		$parameter = $this->parameter('ObjectiveType');
		$rim = (float) $parameter->translatedValue();
		// TODO check if NA should be adapted in case of widefield and two-photon
		$parameter = $this->parameter('NumericalAperture');
		$na = (float) $parameter->value();
		$deltaZ = $lambda / ($factor * $rim * (1 - cos(asin($na / $rim))));
		return $deltaZ;
	}

	function idealSampleSizeZFor($channel) {
		if ($this->isWidefield()) {
			$parameter = $this->parameter('EmissionWavelength');
			$value = $parameter->value();
			$lambda = $value[$channel];
			$factor = 2;
		} else {
			$parameter = $this->parameter('ExcitationWavelength');
			$value = $parameter->value();
			$lambda = $value[$channel];
			$factor = 4;
		}
		$parameter = $this->parameter('ObjectiveType');
		$rim = (float) $parameter->translatedValue();
		// TODO check if NA should be adapted in case of widefield and two-photon
		$parameter = $this->parameter('NumericalAperture');
		$na = (float) $parameter->value();
		$deltaZ = $lambda / ($factor * $rim * (1 - cos(asin($na / $rim))));
		return $deltaZ;
	}
}

//!---------------------------------------------------------
// @class    TaskSetting
// @desc     A task setting is a complete set of 
//           image processing parameters.
//!---------------------------------------------------------
Class TaskSetting extends Setting {
	public $numberOfChannels;
	//!---------------------------------------------------------
	// @function    TaskSetting::TaskSetting
	// @desc        Konstruktor. Creates a new TaskSetting
	// @return      void
	//!---------------------------------------------------------
	function TaskSetting() {
		$this->Setting();
		$parameterClasses = array (
			'StyleOfProcessing',	// step processing or not
			'RemoveNoise',
			'RemoveNoiseEffectiveness',
			'RemoveBackground',
			'RemoveBackgroundPercent',
			'FullRestoration',
			'SignalNoiseRatio',
			'SignalNoiseRatioUseRange',
			'SignalNoiseRatioRange',
			'BackgroundOffsetPercent',	// intensity value(s) to be remove from each channel (background mode: remove constant value) 
			'BackgroundOffsetUseRange',
			'BackgroundOffsetRange',
			'NumberOfIterations',
			'NumberOfIterationsUseRange',
			'NumberOfIterationsRange',
			'OutputFileFormat',
			'MultiChannelOutput',
			'QualityChangeStoppingCriterion',
			'DeconvolutionAlgorithm'
		);
		$db = new DatabaseConnection();
		foreach ($parameterClasses as $class) {
			$param = new $class;
			$name = $param->name();
			$param->setupAllowedValues($db);
			// definition of the associative array that contains all the pairs task parametr name / task parameter value
			$this->parameter[$name] = $param;	// parameter is a member of the class 'Setting'
			$this->numberOfChannels = NULL;
		}
	}

	//!---------------------------------------------------------
	// @function    TaskSetting::isOutputIms
	// @desc        Answer true if the output file format ims
	//              (imaris) has been choosen
	// @return      Boolean
	//!---------------------------------------------------------    
	function isOutputIms() {
		$result = False;
		$parameter = $this->parameter('OutputFileFormat');
		if (strstr($parameter->value(), 'ims'))
			$result = True;
		return $result;
	}

	//!---------------------------------------------------------
	// @function    TaskSetting::isStepProcessing
	// @desc        Answer true if step processing will be performed
	//              because either step processing or step combined
	//              processing had been choosen as style of processingy
	// @return      Boolean
	//!---------------------------------------------------------
	function isStepProcessing() {
		$parameter = $this->parameter('StyleOfProcessing');
		return ($parameter->value() == 'step' || $parameter->value() == 'step combined');
	}

	//!---------------------------------------------------------
	// @function    TaskSetting::isStepCombinedProcessing
	// @desc        Answer true if step combined processing has
	//              been choosen. The images will first be processed
	//              using step processing. Afterwards a standard
	//              full restoration with the same psf and fixed
	//              parameters is applied to the results.
	// @return      Boolean
	//!---------------------------------------------------------
	function isStepCombinedProcessing() {
		return false;
		// TODO This is obsolete code that should be removed!!
		
		//$parameter = $this->parameter('StyleOfProcessing');
		//return $parameter->value() == 'step combined';
	}

	//!---------------------------------------------------------
	// @function    TaskSetting::setNumberOfChannels
	// @desc        Set the number of channels. The number has to be
	//              known for the parameters that have to be 
	//              supplied per channel like background offset
	//              and remove background.
	// @param       channels  int  The number of channels
	// @return      Void
	//!---------------------------------------------------------    
	function setNumberOfChannels($channels) {
		$this->numberOfChannels = $channels;
		foreach ($this->parameter as $parameter) {
			if ($parameter->isVariableChannel()) {
				$parameter->setNumberOfChannels($this->numberOfChannels);
				$this->set($parameter);
			}
		}
	}

	//!---------------------------------------------------------
	// @function    TaskSetting::numberOfChannels
	// @desc        Answer the number of channels. The number has to be
	//              known for the parameters that have to be 
	//              supplied per channel like background offset
	//              and remove background.
	// @return      int
	//!---------------------------------------------------------    
	function numberOfChannels() {
		return $this->numberOfChannels;
	}

	//!---------------------------------------------------------
	// @function    TaskSetting::checkSignalNoiseRatio
	// @desc        TODO
	// @return      Boolean
	//!---------------------------------------------------------    
	function checkSignalNoiseRatio() {
		$parameter = $this->parameter('SignalNoiseRatioUseRange');
		if ($parameter->value() == 'True') {
			$parameter = $this->parameter('SignalNoiseRatioRange');
            $range = count(array_filter($parameter->value[0]));
			for ($i = 0; $i < $this->numberOfChannels(); $i++) {
				$val = $parameter->value[$i];
                if ($range != count(array_filter($val))) {
                    $this->message = "Please enter the same number of values for all channels!";
                    return False;
                }

				if ($val[0] == NULL) {
					$this->message = "Please enter a valid signal/noise ratio for channel " . $i . "! The value must be larger than 0.";
					return False;
				}
				
				/*for ($j = 0; $j < count($val); $j++) {
					if (!$parameter->checkValue($val[$j])) {
						$this->message = "Please enter a valid signal/noise ratio for channel " . $i . "! The value must be larger than 0.";
						return False;
					}
					else {
						$this->message .= " channel " . $i . " value " . $j . " OK";
					}
				}*/
				
			}
			
		}
		else {
			$parameter = $this->parameter('SignalNoiseRatio');
			for ($i = 0; $i < $this->numberOfChannels(); $i++) {
				if (!$parameter->checkValue($parameter->value[$i])) {
					$this->message = "Please enter a valid signal/noise ratio for channel " . $i . "! The value must be larger than 0.";
					return False;
				}
			}
		}
		
		return True;
	}

	//!---------------------------------------------------------
	// @function    TaskSetting::checkParameter
	// @desc        Check the entered parameter. Answer true if
	//              they are ok and false if some illegal values
	//              have been supplied.
	// @return      Boolean
	//!---------------------------------------------------------    
	function checkParameter() {
		$result = True;
		$numberOfOperations = 0;
		$this->message = '';
		$parameter = $this->parameter('RemoveNoise');
		if ($parameter->value() == 'True') {
			$numberOfOperations++;
			if (!$this->checkChoiceValue('RemoveNoiseEffectiveness', 'effectiveness of the remove noise task')) {
				return False;
			}
		}
		$parameter = $this->parameter('RemoveBackground');
		if ($parameter->value() == 'True') {
			$numberOfOperations++;
			if (!$this->checkNumericalValues('RemoveBackgroundPercent', 'value for the remove background task', $this->numberOfChannels())) {
				return False;
			}
		}
		$parameter = $this->parameter('FullRestoration');
		if ($parameter->value() == 'True') {
			$numberOfOperations++;
			/*$parameter = $this->parameter('SignalNoiseRatioUseRange');
			if ($parameter->value() == 'True') {
				if (!$this->checkRange('SignalNoiseRatioRange', 'signal/noise ratio range')) {
					return False;
				}
			} else {*/
				if (!$this->checkSignalNoiseRatio() /*!$this->checkNumericalValue('SignalNoiseRatio', 'signal/noise ratio')*/
					) {
					return False;
				}
			//}
			$parameter = $this->parameter('BackgroundOffsetUseRange');
			if ($parameter->value() == 'True') {
				if (!$this->checkRange('BackgroundOffsetRange', 'background offset range')) {
					return False;
				}
			} else {
				if (!$this->checkNumericalValues('BackgroundOffsetPercent', 'background offset', $this->numberOfChannels())) {
					return False;
				}
			}
			$parameter = $this->parameter('NumberOfIterationsUseRange');
			if ($parameter->value() == 'True') {
				if (!$this->checkRange('NumberOfIterationsRange', 'number of iterations range')) {
					return False;
				}
			} else {
				if (!$this->checkNumericalValue('NumberOfIterations', 'number of iterations')) {
					return False;
				}
			}
			if (!$this->checkNumericalValue('QualityChangeStoppingCriterion', 'quality change stopping criterion')) {
				return False;
			}
		}
		$parameter = $this->parameter('MultiChannelOutput');
		if ($parameter->value() == 'True') {
			$numberOfOperations++;
		}
		if ($numberOfOperations < 1) {
			$this->message = "Please choose at least one operation!";
			return False;
		}
		return $result;
	}

	//!---------------------------------------------------------
	// @function    TaskSetting::checkRange
	// @desc        Check the entered values for the range parameter. 
	//              For a range parameter at least two values must
	//              be entered. Each value must be a valid value
	//              for the parameter.
	// @return      Boolean
	//!---------------------------------------------------------    
	function checkRange($parameterName, $originalLabel) {
		$param = $this->parameter($parameterName);
		$originalValues = $param->value();
		$values = $param->value();
		$result = True;
		/* normally useless
		if ($values[0] == NULL || $values[1] == NULL || $values[0] == '' || $values[1] = '') {
			$this->message = "Please enter at least two values for the $originalLabel, or don't use range.";
			return False;
		}*/
		$index = 0;
		foreach ($originalValues as $value) {
			$label = $originalLabel . " value $index";
			if ($value != NULL && $value != '') {
				$param->setValue($value);
				$this->set($param);
				if (!$this->checkNumericalValue("$parameterName", $label)) {
					$param->setValue($originalValues);
					$this->set($param);
					return False;
				}
			}
			$index++;
		}
		$param->setValue($originalValues);
		$this->set($param);

		return $result;
	}

	//!---------------------------------------------------------
	// @function    TaskSetting::table()
	// @desc        Answer the name of the database table in 
	//              which the task settings are stored. The 
	//              table contains the setting's name the owner 
	//              and the standard (default) flag.
	// @return      String
	//!---------------------------------------------------------    
	function table() {
		return "task_setting";
	}

	//!---------------------------------------------------------
	// @function    TaskSetting::parameterTable()
	// @desc        Answer the name of the database table in
	//              which the parameters for settings of the 
	//              receiver's kind are stored. 
	// @return      String
	//!---------------------------------------------------------    
	function parameterTable() {
		return "task_parameter";
	}

	//!---------------------------------------------------------
	// @function    TaskSetting::display
	// @desc        Display the setting as a text containing
	//              the parameters and their values.
	// @return      Void
	//!---------------------------------------------------------      
	function display() {
		print $this->displayString();
	}

	// TODO refactor!
	//!---------------------------------------------------------
	// @function    TaskSetting::displayString
	// @desc        Answer the display string of the setting.
	//              It contains the names and values of the 
	//              task settings parameters.
	// @return      Void
	//!---------------------------------------------------------        
	function displayString( $numberOfChannels = 0 ) {	// return the string that will be attach to the success notification message 
		$result = '';
        $algorithm = $this->parameter('DeconvolutionAlgorithm')->value();
		$parameter = $this->parameter('SignalNoiseRatioUseRange');
		$rangeUsedForSignalNoiseRatio = ($parameter->value() == 'True');
		$parameter = $this->parameter('BackgroundOffsetUseRange');
		$rangeUsedForBackgroundOffset = ($parameter->value() == 'True');
		$parameter = $this->parameter('NumberOfIterationsUseRange');
		$rangeUsedForNumberOfIterations = ($parameter->value() == 'True');
		$parameter = $this->parameter('RemoveNoise');
		$removeNoise = ($parameter->value() == 'True');
		$parameter = $this->parameter('RemoveBackground');
		$removeBackground = ($parameter->value() == 'True');
		$parameter = $this->parameter('FullRestoration');
		$fullRestoration = ($parameter->value() == 'True');
		foreach ($this->parameter as $parameter) {
			if ($parameter->name() == 'StyleOfProcessing' ) {
				// There is only one style of processing
				continue;
			}
			if ($parameter->name() == 'SignalNoiseRatio' && $rangeUsedForSignalNoiseRatio) {	
				continue;
			}
			if ($parameter->name() == 'SignalNoiseRatioRange' && !$rangeUsedForSignalNoiseRatio) {
				continue;
			}
			if ($parameter->name() == 'SignalNoiseRatioUseRange' ) {
				continue;
			}
			if ($parameter->name() == 'NumberOfIterationsUseRange' ) {
				continue;
			}
			if ($parameter->name() == 'BackgroundOffsetPercent' && $rangeUsedForBackgroundOffset) {
				continue;
			}
			if ($parameter->name() == 'BackgroundOffsetRange' && !$rangeUsedForBackgroundOffset) {
				continue;
			}
			if ($parameter->name() == 'NumberOfIterations' && $rangeUsedForNumberOfIterations) {
				continue;
			}
			if ($parameter->name() == 'NumberOfIterationsRange' && !$rangeUsedForNumberOfIterations) {
				continue;
			}
			if ($parameter->name() == 'RemoveNoiseEffectiveness' && !$removeNoise) {
				continue;
			}
			if ($parameter->name() == 'RemoveBackgroundPercent' && !$removeBackground) {
				continue;
			}
			if (in_array($parameter->name(), array (
					'BackgroundOffsetPercent',
					'NumberOfIterations'
				)) && !$fullRestoration) {
				continue;
			}
			if ($parameter->name() == 'FullRestoration' || $parameter->name() == 'RemoveNoise' || $parameter->name() == 'RemoveBackground')
				continue;
            if ($parameter->name() == 'SignalNoiseRatio') {
                $snr = $parameter->value();
				$parameter->setValue(array_slice($snr, 0, $this->numberOfChannels() ));
                if ($algorithm == 'cmle')
                    $result = $result . $parameter->displayCMLEString($this->numberOfChannels());
                else if ($algorithm == 'qmle')
                    $result = $result . $parameter->displayQMLEString($this->numberOfChannels());
            }
            else {
                $result = $result . $parameter->displayString($this->numberOfChannels());
            }
		}
		return $result;
	}

	//!---------------------------------------------------------
	// @function    TaskSetting::displayWithoutOutputFileFormat
	// @desc        Display the setting as a text containing
	//              the parameters and their values. Only
	//              the parameter OutputFileFormat is left out.
	//              This is used for the web display where the
	//              output file format has not been choosen yet.
	// @return      Void
	//!---------------------------------------------------------        
	function displayWithoutOutputFileFormat( $numberOfChannels = 0 ) {
		print $this->displayStringWithoutOutputFileFormat( $numberOfChannels );
	}

	//!---------------------------------------------------------
	// @function    TaskSetting::displayStringWithoutOutputFileFormat
	// @desc        Answer the display string of the setting.
	//              It contains the names and values of the 
	//              task settings parameters. Only
	//              the parameter OutputFileFormat is left out.
	//              This is used for the web display where the
	//              output file format has not been choosen yet.
	// @return      Void
	//!---------------------------------------------------------
	function displayStringWithoutOutputFileFormat( $numberOfChannels = 0 ) {
		$parameter = $this->parameter('OutputFileFormat');
		$parameterList = $this->parameter;
		unset ($parameterList['OutputFileFormat']);
		$this->parameter = $parameterList;
		$result = $this->displayString( $numberOfChannels );
		$parameterList['OutputFileFormat'] = $parameter;
		$this->parameter = $parameterList;
		return $result;
	}
}

//!---------------------------------------------------------
// @class    JobParameterSetting
// @desc     A parameter setting is a complete set of 
//           microscope, image and capture parameters. A job
//           parameter setting is a parameter setting that 
//           is used when a job is executed by the queue
//           manager. It uses different database tables and
//           knows how to put its parameter settings onto a 
//           script.
//!---------------------------------------------------------
Class JobParameterSetting extends ParameterSetting {
	//!---------------------------------------------------------
	// @function    JobParameterSetting::table()
	// @desc        Answer the name of the database table in 
	//              which the job parameter settings are stored. The 
	//              table contains the setting's name the owner 
	//              and the standard (default) flag.
	// @return      String
	//!---------------------------------------------------------    
	function table() {
		return "job_parameter_setting";
	}
	//!---------------------------------------------------------
	// @function    JobParameterSetting::parameterTable()
	// @desc        Answer the name of the database table in
	//              which the parameters for settings of the 
	//              receiver's kind are stored. 
	// @return      String
	//!---------------------------------------------------------    
	function parameterTable() {
		return "job_parameter";
	}

	function putScriptOn($script) { 
		$newScript = $script;
		$newScript = $newScript . '$imageName setp ';
		$newScript = $newScript . $this->microscopeParameterString();
		$newScript = $newScript . $this->microscopeTypeString();
		$newScript = $newScript . $this->numericalApertureString();
		$newScript = $newScript . $this->lensRefractiveIndexString();
		$newScript = $newScript . $this->mediumRefractiveIndexString();
		// Support for Nipkow spinning disk
		if ($this->isNipkowDisk()) {
			$newScript = $newScript . $this->pinholeSpacingString();
		}
		$newScript = $newScript . $this->photonCountString();
		$newScript = $newScript . "\n";
		$newScript = $newScript . $this->excitationWavelengthsString();
		$newScript = $newScript . $this->emissionWavelengthsString();
		if ($this->isMultiPointOrSinglePointConfocal()) {
			$newScript = $newScript . $this->pinholeRadiusString();
		}
		return $newScript;
	}

	function excitationWavelengthsString() {
		$result = $this->multiChannelParameterString('ExcitationWavelength', 'ex');
		return $result;
	}

	function emissionWavelengthsString() {
		$result = $this->multiChannelParameterString('EmissionWavelength', 'em');
		return $result;
	}

	function multiChannelParameterString($name, $command) {
		$parameter = $this->parameter($name);
		$values = $parameter->value();
		$result = "";
		$currentChannel = 0;
			for ($i = 0; $i < 1 /*$this->numberOfChannels()*/; $i++) {
			//error_log("GENERATING SCRIPT (Setting): ".$name." -> ".$values[$i]);
			if (!empty ($values[$i])) {
				$result = $result . '$imageName setp -chan ';
				$chan = (int) $currentChannel;
				$result = $result . $chan;
				$result = $result . ' -' . "$command ";
				$result = $result . $values[$i];
				$result = $result . "\n";
				// Update $currentChannel
				$currentChannel++;
			}
		}
		return $result;
	}

	function microscopeParameterString() {
		$sampleSizesString = $this->sampleSizesString();
		$string = '-s {' . $sampleSizesString . '} ';
		return $string;
	}

	function microscopeTypeString() {
		$param = $this->parameter('MicroscopeType');
		$value = $param->translatedValue();
		$result = "-micr $value ";
		return $result;
	}

	// sample size adaption for all microscopes
	function numericalApertureString() {
		//if ($this->isMultiPointOrSinglePointConfocal()) {
		$param = $this->parameter('NumericalAperture');
		$value = $param->translatedValue();
		//} else {
		//    $value = $this->adaptedNumericalApertureFor(1);
		//} 
		$result = "-na $value ";
		return $result;
	}

	function pinholeRadiusString() {
		$result = $this->multiChannelParameterString('PinholeSize', 'pr');
		return $result;
	}

	// Support for Nipkow spinning disk
	function pinholeSpacingString() {
		$param = $this->parameter('PinholeSpacing');
		$value = $param->translatedValue();
		$result = "-ps $value ";
		return $result;
	}

	function sampleSizesString() {
		$result = '';
		$result = $result . (string) $this->sampleSizeX() . ' ';
		$result = $result . (string) $this->sampleSizeY();
		if ($this->isThreeDimensional()) {
			$result = $result . ' ' . (string) $this->sampleSizeZ();
		} else {
			// Use current channel
			//$result = $result . ' ' . (string) ($this->idealSampleSizeZFor(1));
		}
		if ($this->isTimeSeries()) {
			$result = $result . ' ' . (string) $this->sampleSizeT();
		}
		return $result;
	}

	function originalSampleSizesString() {
		$result = '';
		$result = $result . (string) ($this->sampleSizeX() / $this->sampleSizeAdaptionFactor()) . ' ';
		$result = $result . (string) ($this->sampleSizeY() / $this->sampleSizeAdaptionFactor());
		if ($this->isThreeDimensional()) {
			$result = $result . ' ' . (string) ($this->sampleSizeZ() / $this->sampleSizeAdaptionFactor());
		} else {
			// Use current channel
			$result = $result . ' ' . (string) ($this->idealSampleSizeZFor(1));
		}
		if ($this->isTimeSeries()) {
			$result = $result . ' ' . (string) $this->sampleSizeT();
		}
		return $result;
	}

	function lensRefractiveIndexString() {
		$param = $this->parameter('ObjectiveType');
		$value = $param->translatedValue();
		$result = "-ril $value ";
		return $result;
	}

	function mediumRefractiveIndexString() {
		$param = $this->parameter('SampleMedium');
		$value = $param->translatedValue();
		$result = "-ri $value ";
		return $result;
	}

	function photonCountString() {
		$result = "-pcnt ";
		if ($this->isTwoPhoton()) {
			$result = $result . "2";
		} else {
			$result = $result . "1";
		}
		return $result;
	}
}

//!---------------------------------------------------------
// @class    JobTaskSetting
// @desc     A job task setting is a complete set of 
//           image processing parameters that is used when
//           a job is processed by the queue manager.
//!---------------------------------------------------------
Class JobTaskSetting extends TaskSetting {
	//!---------------------------------------------------------
	// @function    JobTaskSetting::table()
	// @desc        Answer the name of the database table in 
	//              which the job task settings are stored. The 
	//              table contains the setting's name the owner 
	//              and the standard (default) flag.
	// @return      String
	//!---------------------------------------------------------    
	function table() {
		return "job_task_setting";
	}

	//!---------------------------------------------------------
	// @function    JobTaskParameterSetting::parameterTable()
	// @desc        Answer the name of the database table in
	//              which the parameters for settings of the 
	//              receiver's kind are stored. 
	// @return      String
	//!---------------------------------------------------------    
	function parameterTable() {
		return "job_task_parameter";
	}

  	function putScriptOn($script, $corrParams) {
		$step = 1;
		$newScript = $script;
		
		// Obsolete
		/*
		 $parameter = $this->parameter('RemoveNoise');
		if ($parameter->isTrue()) {
			$source = $this->sourceForStep($step);
			$dest = $this->destinationForStep($step);
			$newScript = $newScript . $this->removeNoiseString($source, $dest);
			$newScript = $newScript . $this->destroyImageString($source);
			$step++;

		$parameter = $this->parameter('RemoveBackground');
		if ($parameter->isTrue()) {
			$source = $this->sourceForStep($step);
			$dest = $this->destinationForStep($step);
			$newScript = $newScript . $this->psfComputationString($source, $constant, $depth);
			$newScript = $newScript . $this->removeBackgroundString($source, $dest);
			$newScript = $newScript . $this->destroyImageString($source);
			$step++;
		}
		}
		*/
		
		// Depending on the PSF selection and the settings for the spherical
		// aberration corrections, we have to call the psfComputationString( )
		// function below specifying either a constant or an adaptive PSF.
		// A constant PSF is used when there is a need for correction (i.e.
		// the PSF is theoretical with refractive index mismatch) but (i) the 
		// user chose not to let Huygens correct for aberrations; or (ii) when
		// the user performs an advanced correction with static FSF generated
		// at a given depth (this is combined with next check).
		$constant = 0;
		if ( ( $corrParams[ 'AberrationCorrectionNecessary' ] == 1 ) &&
			( $corrParams[ 'PerformAberrationCorrection' ] == 0 ) ) {
			$constant = 1;
		}

		// If the user chose the advanced correction mode 'partial correction
		// at user defined PSF depth', we also need to pass the depth to the
		// psfComputationString( ) function.
		$depth = 0;
		if ( ( $corrParams[ 'AberrationCorrectionNecessary' ] == 1 ) &&
			( $corrParams[ 'PerformAberrationCorrection' ] == 1 ) &&
			( $corrParams[ 'AberrationCorrectionMode' ] == 'advanced' ) &&
			( $corrParams[ 'AdvancedCorrectionOptions' ] == 'user' ) ) {
			$depth = $corrParams[ 'PSFGenerationDepth' ];
			$constant = 1; // See comment above
		}

		// The various options result in a different value for the -brMode
		// deconvolution flag. This value is to be passed to the
		// fullRestorationString( ) function below.
		if ( $corrParams[ 'AberrationCorrectionNecessary' ] == 0 ) {
			$brMode = 'auto';
		} else {
			if ( $corrParams[ 'PerformAberrationCorrection' ] == 0 ) {
				$brMode = 'one';
			} else {
				if ( $corrParams[ 'AberrationCorrectionMode' ] == 'automatic' ) {
					$brMode = 'auto';
				} else {
					if ( $corrParams[ 'AdvancedCorrectionOptions' ] == 'user' ) {
						$brMode = 'one';
					}
					if ( $corrParams[ 'AdvancedCorrectionOptions' ] == 'slice' ) {
						$brMode = 'sliceBySlice';
					}
					if ( $corrParams[ 'AdvancedCorrectionOptions' ] == 'few' ) {
						$brMode = 'few';
					}
				}
			}
		}
		
		// effective deconvolution script; step = 3 -> $source = b; $dest = c;
		$parameter = $this->parameter('FullRestoration');
		if ($parameter->isTrue()) {
			$source = $this->sourceForStep($step);
			$dest = $this->destinationForStep($step);
			$newScript = $newScript . $this->psfComputationString($source, $constant, $depth);
			$newScript = $newScript . $this->fullRestorationString($source, $dest, $brMode);
			$newScript = $newScript . $this->destroyImageString($source);
			$step++;
		}
		return $newScript;
	}

	// manage measured PSF
	function putScriptForMeasuredPointSpreadFunctionOn($script) {
		$step = 1;
		$newScript = $script;
		// Obsolete
		/*
		 $parameter = $this->parameter('RemoveNoise');
		if ($parameter->isTrue()) {
			$source = $this->sourceForStep($step);
			$dest = $this->destinationForStep($step);
			$newScript = $newScript . $this->removeNoiseString($source, $dest);
			$newScript = $newScript . $this->destroyImageString($source);
			$step++;
		}
		$parameter = $this->parameter('RemoveBackground');
		if ($parameter->isTrue()) {
			$source = $this->sourceForStep($step);
			$dest = $this->destinationForStep($step);
			$newScript = $newScript . $this->removeBackgroundForMeasuredPointSpreadFunctionString($source, $dest);
			$newScript = $newScript . $this->destroyImageString($source);
			$step++;
		}
		*/
		$parameter = $this->parameter('FullRestoration');
		if ($parameter->isTrue()) {
			$source = $this->sourceForStep($step);
			$dest = $this->destinationForStep($step);
			$newScript = $newScript . $this->fullRestorationForMeasuredPointSpreadFunctionString($source, $dest);
			$newScript = $newScript . $this->destroyImageString($source);
			$step++;
		}
		return $newScript;
	}

	function destroyImageString($imageName) {
		$result = '';
		$result = $result . $imageName . ' del';
		$result = $result . "\n";
		return $result;
	}

	function getNumberOfOperations() {
		$result = 0;
		$parameter = $this->parameter('RemoveNoise');
		if ($parameter->isTrue()) {
			$result++;
		}
		$parameter = $this->parameter('RemoveBackground');
		if ($parameter->isTrue()) {
			$result++;
		}
		$parameter = $this->parameter('FullRestoration');
		if ($parameter->isTrue()) {
			$result++;
		}
		return $result;
	}

	function sourceForStep($stepNumber) {
		$stepSources = array (
			'$imageName',
			'a',
			'b'
		);
		$index = $stepNumber -1;
		return $stepSources[$index];
	}

	function destinationForStep($stepNumber) {
		$maxSteps = $this->getNumberOfOperations();
		$stepDestinations = array (
			array (
				'c',
				'a',
				'a'
			),
			array (
				'x',
				'c',
				'b'
			),
			array (
				'x',
				'x',
				'c'
			)
		);
		$index = $stepNumber -1;
		$row = $stepDestinations[$index];
		$index = $maxSteps -1;
		return $row[$index];
	}

	function psfComputationString($source, $constant = 0, $position = 0) {
		// To calculate a theoretical PSF, the best thing is to provide an empty
        // one. Huygens will take the necessary decisions, see
        // http://support.svi.nl/wiki/TheoreticalPsf
        if (!$constant ) {
            return "catch { psf clear }\n";
        }
        // Alternatively, this calculates a constant PSF for the provided
        // parameters, and will be adapted to the sample depth if spherical
        // aberration is present.
		return 'catch { ' . $source . ' genpsf -> psf -dims auto -zPos '.
			$position .' }' . "\n";
	}

	/* TODO This is obsolete code and should be removed!
	function removeNoiseString($source, $dest) {
		$result = '';
		$result = $result . $source . ' gauss -> ' . $dest . ' -sigma ';
		$result = $result . $this->noiseLevelString();
		$result = $result . ' -units s';
		$result = $result . "\n";
		return $result;
	}

	// never called: to remove
	function removeBackgroundString($source, $dest) {
		$result = '';
		$result = $result . $source . ' cmle psf -> ' . $dest . ' ';
		$result = $result . "-it 3 ";
		$result = $result . '-bgMode object ';
		$result = $result . '-blMode auto ';
		$result = $result . '-q 0 ';
		$result = $result . '-mode fast ';
		$result = $result . '-pad auto';
		$result = $result . "\n";
		return $result;
	}

	// manage measured PSF
	// never called: to remove
	function removeBackgroundForMeasuredPointSpreadFunctionString($source, $dest) {
		$result = '';
		$result = $result . $source . ' cmle $psf -> ' . $dest . ' ';
		$result = $result . "-it 3 ";		// !!
		$result = $result . '-bgMode object ';
		$result = $result . $this->removeBackgroundPercentString();
		$result = $result . '-blMode auto ';
		$result = $result . '-q 0 ';
		//$result = $result . '-mode fast ';
		$result = $result . '-pad auto';
		$result = $result . "\n";
		return $result;
	}
	*/
	
	function fullRestorationString($source, $dest, $brMode) {
		$result = '';

		$parameter = $this->parameter('DeconvolutionAlgorithm');
		$string = $parameter->name();
		$value = $parameter->value();

		// (Obsolete) This restores the default behavior in case the entry "DeconvolutionAlgorithm"
		// is not in the database
		if ( empty( $value ) == true )
		  $value = "cmle";

		$result = $result . $source . ' ' . $value . ' psf -> ' . $dest . ' ';	
		//$result = $result . $source . ' cmle psf -> ' . $dest . ' ';
		$result = $result . $this->signalNoiseRatioString();
		$result = $result . $this->maxIterationsString();
		// background estimation manual/auto
		$parameter = $this->parameter("BackgroundOffsetPercent");
        #printDebug("fullRestorationString", $parameter);
        #printDebug(debug_backtrace()); exit;
		$value = $parameter->value();
		$internalValue = $parameter->internalValue();
		//$result = $result . '-bgMode object ';
		//error_log("GENERATING SCRIPT (Setting): background offset percent -> ".$value[0].", ".$value[1]." | ".$internalValue[0].", ".$internalValue[1]." |");
		if ($value[0] == "auto" || $internalValue[0] == "auto") {
			$result = $result . '-bgMode auto ';
		} else if ($value[0] == "object" || $internalValue[0] == "object") {
			$result = $result . '-bgMode object ';
		} else {
			$result = $result . '-bgMode manual ';
			$result = $result . $this->backgroundPerChannelString();
		}
		$result = $result . '-blMode auto ';
		$result = $result . '-q ';
		$parameter = $this->parameter("QualityChangeStoppingCriterion");
		$result = $result . $parameter->value() . " ";
		$result = $result . '-brMode ' . $brMode . " ";
		$result = $result . '-pad auto';
		$result = $result . "\n";
		return $result;
	}

	// manage measured PSF
	function fullRestorationForMeasuredPointSpreadFunctionString($source, $dest) {
		$result = '';
		
		// (Obsolete) This restores the default behavior in case the entry "DeconvolutionAlgorithm"
		// is not in the database
		$value = $this->decAlgorithmString();
		if ( empty( $value ) == true )
			$value = "cmle";
		$result = $result . $source . ' ' .$value . ' psf -> ' . $dest . ' ';

		//$result = $result . $source . $this->decAlgorithmString() . ' psf -> ' . $dest . ' ';
		//$result = $result . $source . ' cmle $psf -> ' . $dest . ' ';
		$result = $result . $this->signalNoiseRatioString();
		$result = $result . $this->maxIterationsString();
		// background estimation manual/auto
		$parameter = $this->parameter("BackgroundOffsetPercent");
		$value = $parameter->value();
		$internalValue = $parameter->internalValue();
		//$result = $result . '-bgMode object ';
		if ($value[0] == "auto" || $internalValue[0] == "auto") {
			$result = $result . '-bgMode auto ';
		} else if ($value[0] == "object" || $internalValue[0] == "object") {
			$result = $result . '-bgMode object ';
		} else {
			$result = $result . '-bgMode manual ';
			$result = $result . $this->backgroundPerChannelString();
		}
		$result = $result . '-blMode auto ';
		$result = $result . '-q ';
		$parameter = $this->parameter("QualityChangeStoppingCriterion");
		$result = $result . $parameter->value() . " ";
		$result = $result . '-brMode auto ';
		$result = $result . '-pad auto';
		$result = $result . "\n";
		return $result;
	}

	function noiseLevelString() {
		$parameter = $this->parameter('RemoveNoiseEffectiveness');
		$value = $parameter->value();
		$result = '{';
		$result = $result . "$value $value 0 0 }";
		return $result;
	}

	function backgroundPerChannelString() {
		$parameter = $this->parameter('BackgroundOffsetPercent');
		$values = $parameter->value();
		/*if (!is_array($values)) {
			$channels = $this->numberOfChannels();
			$values = array_fill(1, $channels, $values);
		}
		$result = '-bg {';
		for ($i = 0; $i < $this->numberOfChannels(); $i++) {
			$newValue = -1 * (100 - $values[$i]);
			$result = $result . $newValue;
			if ($i < $this->numberOfChannels()) {
				$result = $result . " ";
			}
		}
		$result = $result . '} ';*/

        /* TODO: why does this return channel zero's? */
		$result = '-bg ' . $values[0] . " ";
		return $result;
	}

	function removeBackgroundPercentString() {
		$parameter = $this->parameter('RemoveBackgroundPercent');
		$values = $parameter->value();
		if (!is_array($values)) {
			$channels = $this->numberOfChannels();
			$values = array_fill(1, $channels, $values);
		}
		$result = '-bg {';
		for ($i = 0; $i < $this->numberOfChannels(); $i++) {
			$newValue = -1 * (100 - $values[$i]);
			$result = $result . $newValue;
			if ($i < $this->numberOfChannels()) {
				$result = $result . " ";
			}
		}
		$result = $result . '} ';
		return $result;
	}

	function signalNoiseRatioString() {
		$parameter = $this->parameter('SignalNoiseRatio');
		$values = $parameter->value();
		//if (!is_array($values)) {
		//	$values = array_fill(1, $this->numberOfChannels(), $values);
		//}
		//$result = '-sn {';
		//for ($i = 1; $i <= $this->numberOfChannels(); $i++) {
		//	$result = $result . $values[$i];
		//	if ($i < $this->numberOfChannels()) {
		//		$result = $result . " ";
		//	}
		//}
		//$result = $result . '} ';
		
		$parameter = $this->parameter('DeconvolutionAlgorithm');
		$deconvolutionAlgorithm = $parameter->value();
		
		$value = $values[0];
		if ($deconvolutionAlgorithm == "qmle") {
			if ($value == "1")	$value = "low";
			else if ($value == "2")	$value = "fair";
			else if ($value == "3")	$value = "good";
                        else if ($value == "4")	$value = "inf";
			else			$value = "fair";
		}
		
		$result = '-sn ' . $value . " ";
		return $result;
	}

	function maxIterationsString() {
		$parameter = $this->parameter('NumberOfIterations');
		$value = $parameter->value();
		$result = "-it $value ";
		return $result;
	}
	
	function decAlgorithmString() {
		$parameter = $this->parameter('DeconvolutionAlgorithm');
		$value = $parameter->value();
		$result = " $value";
		return $result;
	}
}
Return current item: Huygens Remote Manager