void CLSSIS3820ScalerDarkCurrentMeasurementAction::onFailed(QObject *action)
{
	// Cleanup after the measurement action and restore pre-measurement settings.

	onMeasurementFinished(action);

	// Notify each detector that the dark current measurement failed.

	CLSSIS3820Scaler *scaler = CLSBeamline::clsBeamline()->scaler();

	if (scaler && scaler->isConnected()) {

		for (int i = 0; i < scaler->channels().count(); i++) {
			CLSSIS3820ScalerChannel *channel = scaler->channelAt(i);

			if (channel && channel->isEnabled() && channel->detector() && channel->detector()->canDoDarkCurrentCorrection()) {
				channel->detector()->setDarkCurrentValue(0);
				channel->detector()->setDarkCurrentValidState(false);
			}
		}
	}

	// Issue error.

	QString message = "Failed to complete scaler dark current measurement.";
	AMErrorMon::alert(this, CLSSIS3820SCALERDARKCURRENTMEASUREMENTACTION_ACTION_FAILED, message);
	setFailed(message);
}
void CLSSIS3820ScalerDarkCurrentMeasurementAction::measurementInitialization()
{
	CLSSIS3820Scaler *scaler = CLSBeamline::clsBeamline()->scaler();

	if (scaler)
		oldTime_ = scaler->dwellTime();
}
AMAction3* CLSSIS3820ScalerDarkCurrentMeasurementAction::createMeasurementAction(double secondsDwell)
{
	AMAction3 *result = 0;

	CLSSIS3820Scaler *scaler = CLSBeamline::clsBeamline()->scaler();

	if (scaler) {
		AMListAction3 *measurementAction = new AMListAction3(new AMListActionInfo3("Taking dark current measurement.", "Taking dark current measurement."), AMListAction3::Sequential);

		measurementAction->addSubAction(scaler->createDwellTimeAction3(secondsDwell));
		measurementAction->addSubAction(scaler->createTriggerAction(AMDetectorDefinitions::SingleRead));

		AMListAction3 *notifyChannelDetectors = new AMListAction3(new AMListActionInfo3("Set last measurement as dark current measurement", "Set last measurement as dark current measurement"));

		for (int i = 0; i < scaler->channels().count(); i++) {
			CLSSIS3820ScalerChannel *channel = scaler->channelAt(i);

			if (channel && channel->isEnabled() && channel->detector() && channel->detector()->canDoDarkCurrentCorrection()) {
				notifyChannelDetectors->addSubAction(channel->detector()->createSetLastMeasurementAsDarkCurrentAction());
			}
		}

		measurementAction->addSubAction(notifyChannelDetectors);

		result = measurementAction;
	}

	return result;
}
void CLSSIS3820ScalerDarkCurrentMeasurementAction::measurementCleanup()
{
	CLSSIS3820Scaler *scaler = CLSBeamline::clsBeamline()->scaler();

	if (scaler)
		scaler->setDwellTime(oldTime_);
}
void CLSSIS3820ScalerDarkCurrentMeasurementAction::startImplementation()
{
	// Must have a valid, connected scaler.

	CLSSIS3820Scaler *scaler = CLSBeamline::clsBeamline()->scaler();

	if (! (scaler && scaler->isConnected()) ) {
		QString message = QString("There was an error measuring scaler dark current. The scaler is invalid or not connected.");
		AMErrorMon::alert(this, CLSSIS3820SCALERDARKCURRENTMEASUREMENTACTION_INVALID_SCALER, message);
		setFailed(message);
	}

	// Must have a valid dwell time.

	double secondsDwell = scalerDarkCurrentMeasurementActionInfo()->dwellTime();

	if (!validDwellTime(secondsDwell)) {
		QString message = QString("There was an error measuring scaler dark current. The dwell time provided (%1 s) is invalid.").arg(secondsDwell);
		AMErrorMon::alert(this, CLSSIS3820SCALERDARKCURRENTMEASUREMENTACTION_INVALID_DWELL_TIME, message);
		setFailed(message);
	}

	// Update pre-measurement settings, to be restored once measurement is complete.

	measurementInitialization();

	// Create measurement action.

	AMAction3 *measurementAction = createMeasurementAction(secondsDwell);

	// Make connections and start action.

	if (measurementAction) {

		startedMapper_->setMapping(measurementAction, measurementAction);
		failedMapper_->setMapping(measurementAction, measurementAction);
		succeededMapper_->setMapping(measurementAction, measurementAction);

		connect( measurementAction, SIGNAL(started()), startedMapper_, SLOT(map()) );
		connect( measurementAction, SIGNAL(failed()), failedMapper_, SLOT(map()) );
		connect( measurementAction, SIGNAL(succeeded()), succeededMapper_, SLOT(map()) );

		measurementAction->start();

	} else {

		QString message = QString("There was an error measuring scaler dark current. An invalid measurement action was generated.");
		AMErrorMon::alert(this, CLSSIS3820SCALERDARKCURRENTMEASUREMENTACTION_INVALID_ACTION, message);
		setFailed(message);
	}
}
void BioXASSIS3820ScalerDarkCurrentMeasurementAction::measurementCleanup()
{
	// General cleanup.

	CLSSIS3820ScalerDarkCurrentMeasurementAction::measurementCleanup();

	// BioXAS-specific cleanup.

	CLSSIS3820Scaler *scaler = CLSBeamline::clsBeamline()->scaler();

	if (scaler) {
		AMZebraDetectorTriggerSource *triggerSource = qobject_cast<AMZebraDetectorTriggerSource*>(scaler->triggerSource());

		if (triggerSource) {

			// Update the detectors and managers.

			triggerSource->removeAllDetectors();
			triggerSource->removeAllDetectorManagers();

			foreach (AMDetector* detector, originalDetectors_)
				triggerSource->addDetector(detector);

			foreach (QObject* manager, originalDetectorManagers_)
				triggerSource->addDetectorManager(manager);
		}
	}
}
void CLSSIS3820ScalerDarkCurrentMeasurementAction::onActionFailed()
{
	AMErrorMon::alert(this, CLSSIS3820SCALERDARKCURRENTMEASUREMENTACTION_ACTION_FAILED, "Failed to complete dark current measurement.");

	CLSSIS3820Scaler *scaler = CLSBeamline::clsBeamline()->scaler();

	if (scaler && scaler->isConnected()) {

		// Notify each able channel detector that the dark current measurement has failed.

		for (int i = 0; i < scaler->channels().count(); i++) {
			CLSSIS3820ScalerChannel *channel = scaler->channelAt(i);

			if (channel && channel->isEnabled() && channel->detector() && channel->detector()->canDoDarkCurrentCorrection()) {
				channel->detector()->setDarkCurrentValue(0);
				channel->detector()->setDarkCurrentValidState(false);
			}
		}
	}
}
CLSSIS3820ScalerDarkCurrentMeasurementAction::CLSSIS3820ScalerDarkCurrentMeasurementAction(CLSSIS3820ScalerDarkCurrentMeasurementActionInfo *info, QObject *parent) :
    AMListAction3(info, AMListAction3::Sequential, parent)
{
	CLSSIS3820Scaler *scaler = CLSBeamline::clsBeamline()->scaler();
	double secondsDwell = scalerDarkCurrentMeasurementActionInfo()->dwellTime();

	connect( this, SIGNAL(failed()), this, SLOT(onActionFailed()) );

	if (scaler && scaler->isConnected() && secondsDwell > 0) {

		// pre-measurement settings.
		double oldDwell = scaler->dwellTime();

		// first turn off beam.
//		addSubAction(AMBeamline::bl()->createTurnOffBeamActions());

		// set the scaler's dwell time to new time.
		addSubAction(scaler->createDwellTimeAction3(secondsDwell));

		// initiate a scaler measurement and wait until it is complete.
		addSubAction(scaler->createStartAction3(true));
		addSubAction(scaler->createWaitForDwellFinishedAction(secondsDwell + 5.0));

		// notify attached and able scaler channel detectors that the latest measurement was a dark current measurement.
		AMListAction3 *notifyChannelDetectors = new AMListAction3(new AMListActionInfo3("Set last measurement as dark current measurement", "Set last measurement as dark current measurement"));

		for (int i = 0; i < scaler->channels().count(); i++) {
			CLSSIS3820ScalerChannel *channel = scaler->channelAt(i);

			if (channel && channel->isEnabled() && channel->detector() && channel->detector()->canDoDarkCurrentCorrection()) {
				notifyChannelDetectors->addSubAction(channel->detector()->createSetLastMeasurementAsDarkCurrentAction());
			}
		}

		addSubAction(notifyChannelDetectors);

		// reset settings to pre-measurement conditions.
		addSubAction(scaler->createDwellTimeAction3(oldDwell));

	} else {
		AMErrorMon::alert(this, CLSSIS3820SCALERDARKCURRENTMEASUREMENTACTION_SCALER_NOT_VALID, "Failed to complete dark current measurement--scaler not valid.");
		setFailed();
	}

}
void BioXASSIS3820ScalerDarkCurrentMeasurementAction::measurementInitialization()
{
	// General initialization.

	CLSSIS3820ScalerDarkCurrentMeasurementAction::measurementInitialization();

	// BioXAS-specific initialization.

	CLSSIS3820Scaler *scaler = CLSBeamline::clsBeamline()->scaler();

	if (scaler) {
		AMZebraDetectorTriggerSource *triggerSource = qobject_cast<AMZebraDetectorTriggerSource*>(scaler->triggerSource());

		if (triggerSource) {
			originalDetectors_ = triggerSource->detectors();
			originalDetectorManagers_ = triggerSource->detectorManagers();

			// Update the detectors and managers.

			triggerSource->removeAllDetectors();
			triggerSource->removeAllDetectorManagers();

			AMDetector *i0Detector = BioXASBeamline::bioXAS()->i0Detector();
			if (i0Detector)
				triggerSource->addDetector(i0Detector);

			AMDetector *i1Detector = BioXASBeamline::bioXAS()->i1Detector();
			if (i1Detector)
				triggerSource->addDetector(i1Detector);

			AMDetector *i2Detector = BioXASBeamline::bioXAS()->i2Detector();
			if (i2Detector)
				triggerSource->addDetector(i2Detector);

			triggerSource->addDetectorManager(scaler);
		}
	}
}