Package tcg.scada.da

Source Code of tcg.scada.da.DataPoint

package tcg.scada.da;

import java.util.ArrayList;
import java.util.Calendar;

import org.apache.log4j.Logger;
import tcg.common.LoggerManager;

import tcg.scada.cos.CosDpQualityEnum;
import tcg.scada.cos.CosDpValueStruct;
import tcg.scada.cos.CosDpValueTypeEnum;
import tcg.scada.cos.CosDpValueUnion;

/**
* Base class for datapoint implementation.
*
* @author Yoga
*
*/
public abstract class DataPoint implements IDataPoint
{
  /**
   * Datapoint key id. Predefined based on configuration. Can be sequential
   * number.
   */
  public int keyId = 0;

  /**
   * Datapoint name.
   */
  public String name = "";

  /**
   * Source address. Only applicable for REAL datapoint with raw protocol (eq.
   * modbus). Normally in words.
   */
  protected int address = -1;

  /**
   * Source bit address. Only applicable for REAL datapoint with raw protocol
   * (eq. modbus). Used to get binary value embedded in byte/word data.
   */
  protected short bitAddress = -1;

  /**
   * Source length. Only applicable for REAL datapoint with raw protocol (eq.
   * modbus). Use to parse string value. Normally in bytes.
   */
  protected short length = 0;

  /**
   * Datapoint source data type (used for REAL datapoint)
   *
   * Note: This is the responsibility of the poller to translate from source
   * types to supported internal types
   */
  protected ESourceDataType sourceType = ESourceDataType.TYPE_INT32;

  // source value
  protected CosDpValueUnion sourceValue = new CosDpValueUnion();
  protected CosDpQualityEnum sourceQuality = CosDpQualityEnum.QualityGood;
  protected long sourceTimestamp = 0;

  // output value
  protected CosDpValueUnion outputValue = new CosDpValueUnion();
  protected CosDpQualityEnum outputQuality = CosDpQualityEnum.QualityGood;
  protected long outputTimestamp = 0;

  // various datapoint flag
  protected boolean isOverride = false;
  protected boolean isInhibit = false;
  protected boolean isAlarmInhibit = false;
  protected boolean isAlarmNotAck = false;
  protected boolean isAlarmNotNorm = false;

  // subsystem
  protected ISubsystem subsystem = null;

  // equipment
  protected IEquipment equipment = null;

  // quality datapoint
  protected IDataPoint qualityPoint = null;

  // datastore. for subscription notification and database persistence
  protected IDataStore datastore = null;

  /**
   * List of calculated points which use this datapoint as parameter
   */
  protected DataPointList calculatedPoints = new DataPointList();

  /**
   * List of meter points which use this datapoint as source
   */
  protected DataPointList meterPoints = new DataPointList();

  /**
   * List of datapoints which use this datapoint as quality point
   */
  protected DataPointList childPoints = new DataPointList();

  /**
   * Internal timestamp. This is distinct from value timestamp because it will
   * always be updated with the local current time after each operation
   * (whereas value timestamp might use the source timestamp)
   */
  protected long updateTimestamp_ = 0;

  /**
   * Launching condition for control point (temporary storage)
   */
  protected String lccExpression = "";

  /**
   * Return condition for control point (temporary storage)
   */
  protected String rccExpression = "";

  /**
   * Deadband value (+/- from last value).
   */
  protected double deadband = 0.0;

  /**
   * Expression for engineering conversion (temporary storage)
   */
  protected String ecExpression = "";

  /**
   * Expression string for calculated point (temporary storage)
   */
  protected String expression = "";

  /**
   * Evaluated flag for calculated point (temporary flag)
   */
  protected boolean hasBeenEvaluated = false;

  // logger
  protected Logger logger = LoggerManager
      .getLogger(this.getClass().getName());

  protected boolean isBatchOperation = false;

  /**
   * Default ctor
   */
  public DataPoint()
  {
    // nothing
  }

  /**
   * Preferred ctor.
   *
   * @param inDataType
   *            - the internal data type
   */
  public DataPoint(CosDpValueTypeEnum inDataType)
  {
    // initialize internal value
    _setDataType(inDataType);
  }

  /**
   * Set internal data type.
   *
   * @param inDataType
   *            - the internal data type
   */
  protected void _setDataType(CosDpValueTypeEnum inDataType)
  {
    // initialize internal value
    switch (inDataType.value())
    {
      case CosDpValueTypeEnum._TypeBoolean:
        sourceValue.boolValue(false);
        outputValue.boolValue(false);
        break;
      case CosDpValueTypeEnum._TypeNumber:
        sourceValue.longValue(0);
        outputValue.longValue(0);
        break;
      case CosDpValueTypeEnum._TypeUnsigned:
        sourceValue.unsignedValue(0);
        outputValue.unsignedValue(0);
        break;
      case CosDpValueTypeEnum._TypeDouble:
        sourceValue.dblValue(0.0);
        outputValue.dblValue(0.0);
        break;
      case CosDpValueTypeEnum._TypeString:
        sourceValue.charValue("");
        outputValue.charValue("");
        break;
    }
  }

  /**
   * Helper function to initialize the datapoint state. This will set the
   * internal states without triggering notification to datastore.
   *
   * @param inIsInhibit
   *            - last known inhibit flag
   * @param inIsOverride
   *            - last known override flag
   * @param inIsAlarmInhibit
   *            - last known alarm inhibit flag
   * @param inIsAlarmNotAck
   *            - last known alarm not-ack flag
   * @param inIsAlarmNotNorm
   *            - last known alarm not-norm flag
   */
  protected synchronized void _setInitialState(boolean inIsInhibit,
      boolean inIsOverride, boolean inIsAlarmInhibit,
      boolean inIsAlarmNotAck, boolean inIsAlarmNotNorm)
  {
    isInhibit = inIsInhibit;
    isOverride = inIsOverride;
    isAlarmInhibit = inIsAlarmInhibit;
    isAlarmNotAck = inIsAlarmNotAck;
    isAlarmNotNorm = inIsAlarmNotNorm;
  }

  /**
   * Set the initial value of this datapoint. This will set the source and
   * output value without triggering notification to datastore.
   *
   * <p>
   * No deadband check nor engineering conversion is performed. It is just a
   * simple set value.
   * </p>
   *
   * <p>
   * <b>No value translation is performed.</b> If the caller has no idea of
   * the internal data type, then it should probably not use this function at
   * all!
   * </p>
   *
   * @param inSourceValue
   *            - initial source value
   * @param inOutputValue
   *            - initial output value
   */
  protected synchronized void _setInitialValue(CosDpValueUnion inSourceValue,
      CosDpValueUnion inOutputValue)
  {
    // validation: InSourceValue
    // none. if it is null, just do not set it

    // validation: inOuputValue
    // none. if it is null, just do not set it

    // copy source value
    if (inSourceValue != null
        && inSourceValue.discriminator() == sourceValue.discriminator())
    {
      copy(sourceValue, inSourceValue);
    }

    // copy output value
    if (inOutputValue != null
        && inOutputValue.discriminator() == outputValue.discriminator())
    {
      copy(outputValue, inOutputValue);
    }
  }

  /**
   * Get the current source value in string format. Can be used for database
   * persistence.
   *
   * @return current source value in string.
   */
  protected String _getStringifiedSourceValue()
  {
    return convCosDpValueUnion2String(sourceValue);
  }

  /**
   * Get the current output value in string format. Can be used for database
   * persistence.
   *
   * @return current output value in string.
   */
  protected String _getStringifiedValue()
  {
    return convCosDpValueUnion2String(outputValue);
  }

  /**
   * <p>
   * Synchronize between the source value/source timestamp and output
   * value/output timestamp. The output quality is also recalculated.
   * </p>
   *
   * @return +1 if output value/output timestamp/output quality is updated, 0
   *         if none is updated because it is already the expected value, -1
   *         if the operation fails.
   */
  protected synchronized int _synchronize()
  {
    if (isInhibit || isOverride)
    {
      return -1;
    }

    int status1 = 0, status2 = 0, status3 = 0;

    // try to copy over the value
    status1 = copy(outputValue, sourceValue);

    // try to copy over the quality
    CosDpQualityEnum newQuality = calculate_quality();
    if (outputQuality != newQuality)
    {
      outputQuality = newQuality;
      status2 = +1;
    }

    // ALTERNATIVE IMPLEMENTATION. DO NOT DELETE!!!
    // // only update timestamp and quality if the value/quality has
    // changed.
    // // NOTE: This is a design decision to protect against cases where
    // // timestamp always change even though the value never changed.
    // (Ideally,
    // // timestamp is only updated when the value has changed)
    // if (status1 > 0 || status2 > 0)
    // {
    // outputTimestamp = sourceTimestamp;
    // // update the timestamp
    // updateTimestamp_ = Calendar.getInstance().getTimeInMillis();
    // return +1;
    // }

    // update output value timestamp
    if (outputTimestamp != sourceTimestamp)
    {
      outputTimestamp = sourceTimestamp;
      status3 = +1;
    }

    // update the timestamp
    int retval = 0;
    if (status1 > 0 || status2 > 0 || status3 > 0)
    {
      retval = +1;
      // update the timestamp
      updateTimestamp_ = Calendar.getInstance().getTimeInMillis();
      // TODO: notify datastore
    }

    return retval;
  }

  @Override
  public CosDpValueTypeEnum getInternalDataType()
  {
    return outputValue.discriminator();
  }

  @Override
  public int getKeyId()
  {
    return keyId;
  }

  @Override
  public String getName()
  {
    return name;
  }

  @Override
  public int getAddress()
  {
    return address;
  }

  @Override
  public short getBitAddress()
  {
    return bitAddress;
  }

  @Override
  public short getLength()
  {
    return length;
  }

  @Override
  public ESourceDataType getSourceType()
  {
    return sourceType;
  }

  @Override
  public ISubsystem getSubsystem()
  {
    return subsystem;
  }

  @Override
  public CosDpQualityEnum getQuality()
  {
    return outputQuality;
  }

  @Override
  public CosDpQualityEnum getSourceQuality()
  {
    return sourceQuality;
  }

  @Override
  public long getSourceTimestamp()
  {
    return sourceTimestamp;
  }

  @Override
  public CosDpValueUnion getSourceValue()
  {
    return sourceValue;
  }

  @Override
  public long getTimestamp()
  {
    return outputTimestamp;
  }

  @Override
  public CosDpValueUnion getValue()
  {
    return outputValue;
  }

  @Override
  public long getUpdateTimestamp()
  {
    return updateTimestamp_;
  }

  @Override
  public synchronized void setDataStore(IDataStore inDataStore)
  {
    // validation: inDataStore
    if (inDataStore == null)
    {
      return;
    }

    datastore = inDataStore;
  }

  @Override
  public synchronized void setEquipment(IEquipment inEquipment)
  {
    // validation: inEquipment
    if (inEquipment == null)
    {
      return;
    }

    // copy locally and add to the equipment's list of children
    equipment = inEquipment;
    equipment.addDataPoint(this);
  }

  @Override
  public synchronized boolean setQualityPoint(IDataPoint inQualityPoint)
  {
    // validation
    if (inQualityPoint == null)
    {
      return false;
    }

    // make sure the datapoint is boolean type
    if (inQualityPoint.getInternalDataType() != CosDpValueTypeEnum.TypeBoolean)
    {
      return false;
    }

    // copy locally and to the point's child
    qualityPoint = inQualityPoint;
    qualityPoint.addChildPoint(this);

    return true;
  }

  @Override
  public synchronized void setSubsystem(ISubsystem inSubsystem)
  {
    // validation: inSubsystem
    if (inSubsystem == null)
    {
      return;
    }

    // copy locally and add to subsystem's list of managed datapoints
    subsystem = inSubsystem;
    subsystem.addDataPoint(this);
  }

  /**
   * <p>
   * Set a value with another. Do a value translation if necessary.
   * </p>
   *
   * @param ioValue
   *            - the data point to set the value
   * @param inNewValue
   *            - the source data point
   * @return +1 if successful, 0 if the value is already the target value, -1
   *         if the source value is invalid
   */
  protected static int copy(CosDpValueUnion ioValue,
      final CosDpValueUnion inNewValue)
  {
    // validation: ioValue
    if (ioValue == null)
    {
      return -1;
    }

    // validation: inNewValue
    if (inNewValue == null)
    {
      return -1;
    }

    // copy the value
    switch (ioValue.discriminator().value())
    {
      case CosDpValueTypeEnum._TypeBoolean:
      {
        boolean boolVal = false;
        switch (inNewValue.discriminator().value())
        {
          case CosDpValueTypeEnum._TypeBoolean:
            boolVal = inNewValue.boolValue();
            break;
          case CosDpValueTypeEnum._TypeNumber:
            boolVal = (inNewValue.longValue() != 0);
            break;
          case CosDpValueTypeEnum._TypeUnsigned:
            boolVal = (inNewValue.unsignedValue() != 0);
            break;
          case CosDpValueTypeEnum._TypeDouble:
            boolVal = (inNewValue.dblValue() != 0);
            break;
          case CosDpValueTypeEnum._TypeString:
            boolVal = (inNewValue.charValue() != null && inNewValue
                .charValue().length() > 0);
            break;
          default:
            return -1;
        }
        // ONLY copy if the new value is really different with the
        // current
        // value
        if (boolVal != ioValue.boolValue())
        {
          ioValue.boolValue(boolVal);
        }
        else
        {
          return 0;
        }
      }
        break;
      case CosDpValueTypeEnum._TypeNumber:
      {
        int longVal = 0;
        switch (inNewValue.discriminator().value())
        {
          case CosDpValueTypeEnum._TypeBoolean:
            longVal = (inNewValue.boolValue() ? 1 : 0);
            break;
          case CosDpValueTypeEnum._TypeNumber:
            longVal = inNewValue.longValue();
            break;
          case CosDpValueTypeEnum._TypeUnsigned:
            longVal = inNewValue.unsignedValue();
            break;
          case CosDpValueTypeEnum._TypeDouble:
            longVal = (int) inNewValue.dblValue();
            break;
          case CosDpValueTypeEnum._TypeString:
            longVal = parseInt(inNewValue.charValue());
            break;
          default:
            return -1;
        }
        // ONLY copy if the new value is really different with the
        // current
        // value
        if (longVal != ioValue.longValue())
        {
          ioValue.longValue(longVal);
        }
        else
        {
          return 0;
        }
      }
        break;
      case CosDpValueTypeEnum._TypeUnsigned:
      {
        int unsignedVal = 0;
        switch (inNewValue.discriminator().value())
        {
          case CosDpValueTypeEnum._TypeBoolean:
            unsignedVal = (inNewValue.boolValue() ? 1 : 0);
            break;
          case CosDpValueTypeEnum._TypeNumber:
            unsignedVal = inNewValue.longValue();
            if (unsignedVal < 0)
            {
              unsignedVal *= -1;
            }
            break;
          case CosDpValueTypeEnum._TypeUnsigned:
            unsignedVal = inNewValue.unsignedValue();
            break;
          case CosDpValueTypeEnum._TypeDouble:
            unsignedVal = (int) inNewValue.dblValue();
            if (unsignedVal < 0)
            {
              unsignedVal *= -1;
            }
            break;
          case CosDpValueTypeEnum._TypeString:
            unsignedVal = parseInt(inNewValue.charValue());
            if (unsignedVal < 0)
            {
              unsignedVal *= -1;
            }
            break;
          default:
            return -1;
        }
        // ONLY copy if the new value is really different with the
        // current
        // value
        if (unsignedVal != ioValue.unsignedValue())
        {
          ioValue.unsignedValue(unsignedVal);
        }
        else
        {
          return 0;
        }
      }
        break;
      case CosDpValueTypeEnum._TypeDouble:
      {
        double dblVal = 0.0;
        switch (inNewValue.discriminator().value())
        {
          case CosDpValueTypeEnum._TypeBoolean:
            dblVal = (inNewValue.boolValue() ? 1.0 : 0.0);
            break;
          case CosDpValueTypeEnum._TypeNumber:
            dblVal = (double) inNewValue.longValue();
            break;
          case CosDpValueTypeEnum._TypeUnsigned:
            dblVal = (double) inNewValue.unsignedValue();
            break;
          case CosDpValueTypeEnum._TypeDouble:
            dblVal = inNewValue.dblValue();
            break;
          case CosDpValueTypeEnum._TypeString:
            dblVal = parseDbl(inNewValue.charValue());
            break;
          default:
            return -1;
        }
        // ONLY copy if the new value is really different with the
        // current
        // value
        if (dblVal != ioValue.dblValue())
        {
          ioValue.dblValue(dblVal);
        }
        else
        {
          return 0;
        }
      }
        break;
      case CosDpValueTypeEnum._TypeString:
      {
        String strValue;
        switch (inNewValue.discriminator().value())
        {
          case CosDpValueTypeEnum._TypeBoolean:
            strValue = Boolean.toString(inNewValue.boolValue());
            break;
          case CosDpValueTypeEnum._TypeNumber:
            strValue = Integer.toString(inNewValue.longValue());
            break;
          case CosDpValueTypeEnum._TypeUnsigned:
            strValue = Integer.toString(inNewValue.unsignedValue());
            break;
          case CosDpValueTypeEnum._TypeDouble:
            strValue = Double.toString(inNewValue.dblValue());
            break;
          case CosDpValueTypeEnum._TypeString:
            strValue = inNewValue.charValue();
            if (strValue == null)
            {
              strValue = "";
            }
            break;
          default:
            return -1;
        } // end of switch (srcDpValue._d())
        // ONLY copy if the new value is really different with the
        // current
        // value
        // must take care truncation!!
        if (strValue.length() != ioValue.charValue().length())
        {
          // (in which case strncmp will give 0 eventhough the string
          // is
          // not actually
          // the same!)
          ioValue.charValue(strValue);
        }
        else if (ioValue.charValue().compareTo(strValue) != 0)
        {
          ioValue.charValue(strValue);
        }
        else
        {
          return 0;
        }
      }
        break;
      default:
        // unknown datatype
        return -1;
    } // end of switch (dpValue._d())

    return 1;
  }

  /**
   * <p>
   * Compare two values
   * </p>
   *
   * @param inValue1
   *            - the first data point
   * @param inValue2
   *            - the second data point
   * @return +1 if first < second or if different boolean value, 0 if first =
   *         second, -1 if first > second or different data type
   */
  protected static int compare(final CosDpValueUnion inValue1,
      final CosDpValueUnion inValue2)
  {
    // validation: inValue1
    if (inValue1 == null)
    {
      return -1;
    }

    // validation: inValue2
    if (inValue2 == null)
    {
      return -1;
    }

    // don't bother to compare 2 different type
    if (inValue1.discriminator() != inValue2.discriminator())
    {
      return -1;
    }

    // compare
    switch (inValue1.discriminator().value())
    {
      case CosDpValueTypeEnum._TypeBoolean:
        // return 1 if not the same
        if (inValue1.boolValue() != inValue2.boolValue())
        {
          return +1;
        }
        else
        {
          return 0;
        }
      case CosDpValueTypeEnum._TypeNumber:
        if (inValue1.longValue() < inValue2.longValue())
        {
          return -1;
        }
        else if (inValue1.longValue() > inValue2.longValue())
        {
          return +1;
        }
        else
        {
          return 0;
        }
      case CosDpValueTypeEnum._TypeUnsigned:
        if (inValue1.unsignedValue() < inValue2.unsignedValue())
        {
          return -1;
        }
        else if (inValue1.unsignedValue() > inValue2.unsignedValue())
        {
          return +1;
        }
        else
        {
          return 0;
        }
      case CosDpValueTypeEnum._TypeDouble:
        if (inValue1.dblValue() < inValue2.dblValue())
        {
          return -1;
        }
        else if (inValue1.dblValue() > inValue2.dblValue())
        {
          return +1;
        }
        else
        {
          return 0;
        }
      case CosDpValueTypeEnum._TypeString:
      {
        int status = inValue1.charValue().compareTo(
            inValue2.charValue());
        if (status < 0)
        {
          return -1;
        }
        else if (status > 0)
        {
          return +1;
        }
        else
        {
          return 0;
        }
      }
    } // end of switch (dpValue._d())

    // if we get here, it is unknown datatype
    return -1;
  }

  /**
   * Set a value using the native type of the value.
   *
   * @param outValue
   *            - the datapoint value
   * @param inBoolValue
   *            - the new boolean value
   * @return +1 if successful, 0 if the value is already the target value, -1
   *         if the new value is invalid
   */
  protected static int setBooleanValue(CosDpValueUnion outValue,
      boolean inBoolValue)
  {
    // validation: outValue
    if (outValue == null)
    {
      return -1;
    }

    // validation: inBoolValue
    // none

    // we can do a value translation here. but I think it is not worth the
    // effort.
    // instead, just return with error with the value type is not boolean
    if (outValue.discriminator() != CosDpValueTypeEnum.TypeBoolean)
    {
      return -1;
    }

    // set the value if and only if the new value is different
    if (outValue.boolValue() == inBoolValue)
    {
      return 0;
    }

    // set the value
    outValue.boolValue(inBoolValue);

    return +1;
  }

  /**
   * Set a value using the native type of the value.
   *
   * @param outValue
   *            - the datapoint value
   * @param inLngValue
   *            - the new corba::long value
   * @return +1 if successful, 0 if the value is already the target value, -1
   *         if the new value is invalid
   */
  protected static int setNumberValue(CosDpValueUnion outValue, int inLngValue)
  {
    // validation: outValue
    if (outValue == null)
    {
      return -1;
    }

    // validation: inNumberValue
    // none

    // we can do a value translation here. but I think it is not worth the
    // effort.
    // instead, just return with error with the value type is not number
    if (outValue.discriminator() != CosDpValueTypeEnum.TypeNumber)
    {
      return -1;
    }

    // set the value if and only if the new value is different
    if (outValue.longValue() == inLngValue)
    {
      return 0;
    }

    // set the value
    outValue.longValue(inLngValue);

    return +1;
  }

  /**
   * Set a value using the native type of the value.
   *
   * @param outValue
   *            - the datapoint value
   * @param inUnsignedValue
   *            - the new corba::unsigned value
   * @return +1 if successful, 0 if the value is already the target value, -1
   *         if the new value is invalid
   */
  protected static int setUnsignedValue(CosDpValueUnion outValue,
      int inUnsignedValue)
  {
    // validation: outValue
    if (outValue == null)
    {
      return -1;
    }

    // validation: inUnsignedValue
    // none

    // we can do a value translation here. but I think it is not worth the
    // effort.
    // instead, just return with error with the value type is not unsigned
    if (outValue.discriminator() != CosDpValueTypeEnum.TypeUnsigned)
    {
      return -1;
    }

    // set the value if and only if the new value is different
    if (outValue.unsignedValue() == inUnsignedValue)
    {
      return 0;
    }

    // set the value
    outValue.unsignedValue(inUnsignedValue);

    return +1;
  }

  /**
   * Set a value using the native type of the value.
   *
   * @param outValue
   *            - the datapoint value
   * @param inDblValue
   *            - the new double value
   * @return +1 if successful, 0 if the value is already the target value, -1
   *         if the new value is invalid
   */
  protected static int setDoubleValue(CosDpValueUnion outValue,
      double inDblValue)
  {
    // validation: outValue
    if (outValue == null)
    {
      return -1;
    }

    // validation: inDblValue
    // none

    // we can do a value translation here. but I think it is not worth the
    // effort.
    // instead, just return with error with the value type is not double
    if (outValue.discriminator() != CosDpValueTypeEnum.TypeDouble)
    {
      return -1;
    }

    // set the value if and only if the new value is different
    if (outValue.dblValue() == inDblValue)
    {
      return 0;
    }

    // set the value
    outValue.dblValue(inDblValue);

    return +1;
  }

  /**
   * Set a value using the native type of the value.
   *
   * @param outValue
   *            - the datapoint value
   * @param inStrValue
   *            - the new string value
   * @return +1 if successful, 0 if the value is already the target value, -1
   *         if the new value is invalid
   */
  protected static int setStringValue(CosDpValueUnion outValue,
      String inStrValue)
  {
    // validation: outValue
    if (outValue == null)
    {
      return -1;
    }

    // validation: inStrValue
    if (inStrValue == null)
    {
      return -1;
    }

    // we can do a value translation here. but I think it is not worth the
    // effort.
    // instead, just return with error with the value type is not double
    if (outValue.discriminator() != CosDpValueTypeEnum.TypeString)
    {
      return -1;
    }

    // set the value if and only if the new value is different
    if (outValue.charValue().length() == inStrValue.length()
        && 0 == outValue.charValue().compareTo(inStrValue))
    {
      return 0;
    }

    // set the value
    outValue.charValue(inStrValue);

    return +1;
  }

  /**
   * <p>
   * Recalculate the output quality.
   * </p>
   *
   * <p>
   * Note: The output quality is determined by the following components:
   * <ul>
   * <li>source quality</li>
   * <li>subsystem quality</li>
   * <li>quality datapoint's value/quality</li>
   * </ul>
   * </p>
   *
   * <p>
   * Note: The following rule applies:
   * <ul>
   * <li>If source quality is <i>BadQuality</i>, set output quality to
   * <i>BadQuality</i>.</li>
   * <li>If subsystem quality is <i>BadQuality</i>, set output quality to
   * <i>BadQuality</i>.</li>
   * <li>If quality datapoint's quality is <i>BadQuality</i>, set output
   * quality to <i>BadQuality</i>.</li>
   * <li>If quality datapoint's value is false (or equivalent), set output
   * quality to <i>BadQuality</i>.</li>
   * <li>If, and only if, all quality components are <i>GoodQuality</i> and
   * quality datapoint's value is true (or equivalent), set output quality to
   * <i>GoodQuality</i>.</li>
   * </ul>
   * </p>
   *
   * <p>
   * Note: Expression quality for calculated point is represented as source
   * quality. (The source value is the expression result)
   * </p>
   */
  private CosDpQualityEnum calculate_quality()
  {
    // source quality (used as expression quality in calculated point)
    if (sourceQuality == CosDpQualityEnum.QualityBad)
    {
      return CosDpQualityEnum.QualityBad;
    }

    // subsystem quality
    if (subsystem != null
        && subsystem.getQuality() == CosDpQualityEnum.QualityBad)
    {
      return CosDpQualityEnum.QualityBad;
    }

    // quality datapoint
    if (qualityPoint != null)
    {
      // quality point's quality
      if (qualityPoint.getQuality() == CosDpQualityEnum.QualityBad)
      {
        return CosDpQualityEnum.QualityBad;
      }
      // quality point's value
      switch (qualityPoint.getInternalDataType().value())
      {
        case CosDpValueTypeEnum._TypeBoolean:
          if (qualityPoint.getValue().boolValue() == false)
          {
            return CosDpQualityEnum.QualityBad;
          }
          break;
        case CosDpValueTypeEnum._TypeNumber:
          if (qualityPoint.getValue().longValue() == 0)
          {
            return CosDpQualityEnum.QualityBad;
          }
          break;
        case CosDpValueTypeEnum._TypeUnsigned:
          if (qualityPoint.getValue().unsignedValue() == 0)
          {
            return CosDpQualityEnum.QualityBad;
          }
          break;
        case CosDpValueTypeEnum._TypeDouble:
          if (qualityPoint.getValue().dblValue() == 0)
          {
            return CosDpQualityEnum.QualityBad;
          }
          break;
        case CosDpValueTypeEnum._TypeString:
          String tmpString = qualityPoint.getValue().charValue();
          if (tmpString == null || tmpString.isEmpty())
          {
            return CosDpQualityEnum.QualityBad;
          }
          break;
      }
    }

    // everything is good
    return CosDpQualityEnum.QualityGood;
  }

  protected static String convCosDpValueUnion2String(CosDpValueUnion inValue)
  {
    // validation: value
    if (inValue == null)
    {
      return "";
    }

    switch (inValue.discriminator().value())
    {
      case CosDpValueTypeEnum._TypeBoolean:
        if (inValue.boolValue())
        {
          return "1";
        }
        else
        {
          return "0";
        }
      case CosDpValueTypeEnum._TypeNumber:
        return Integer.toString(inValue.longValue());
      case CosDpValueTypeEnum._TypeUnsigned:
        return Integer.toString(inValue.unsignedValue());
      case CosDpValueTypeEnum._TypeDouble:
        return Double.toString(inValue.dblValue());
      case CosDpValueTypeEnum._TypeString:
        return inValue.charValue();
      default:
        return "";
    }
  }

  protected static CosDpValueUnion convString2CosDpValueUnion(
      CosDpValueTypeEnum inType, String inStr)
  {
    // validation: inType
    if (inType == null)
    {
      return null;
    }

    // validation: inStr
    // none. validation is performed as part of the conversion

    CosDpValueUnion value = new CosDpValueUnion();

    switch (inType.value())
    {
      case CosDpValueTypeEnum._TypeBoolean:
        if (inStr != null && inStr.compareToIgnoreCase("1") == 0)
        {
          value.boolValue(true);
        }
        else
        {
          value.boolValue(false);
        }
        break;
      case CosDpValueTypeEnum._TypeNumber:
        value.longValue(parseInt(inStr));
        break;
      case CosDpValueTypeEnum._TypeUnsigned:
        value.unsignedValue(parseInt(inStr));
        break;
      case CosDpValueTypeEnum._TypeDouble:
        value.dblValue(parseDbl(inStr));
        break;
      case CosDpValueTypeEnum._TypeString:
        value.charValue(inStr);
        break;
      default:
        value.longValue(0);
    }

    return value;
  }

  protected static Object convCosDpValueUnion2Object(CosDpValueUnion inValue)
  {
    // validation: value
    if (inValue == null)
    {
      return null;
    }

    switch (inValue.discriminator().value())
    {
      case CosDpValueTypeEnum._TypeBoolean:
        return Boolean.valueOf(inValue.boolValue());
      case CosDpValueTypeEnum._TypeNumber:
        return Integer.valueOf(inValue.longValue());
      case CosDpValueTypeEnum._TypeUnsigned:
        return Integer.valueOf(inValue.unsignedValue());
      case CosDpValueTypeEnum._TypeDouble:
        return new Double(inValue.dblValue());
      case CosDpValueTypeEnum._TypeString:
        return inValue.charValue();
    }

    return null;
  }

  protected static CosDpValueUnion convObject2CosDpValueUnion(
      CosDpValueTypeEnum inType, Object inObj)
  {
    // validation: type
    if (inType == null)
    {
      return null;
    }

    // validation: obj
    // none. validation is performed as part of the conversion

    CosDpValueUnion value = new CosDpValueUnion();

    Boolean boolObj = null;
    Integer intObj = null;
    Double dblObj = null;
    String strObj = null;

    switch (inType.value())
    {
      case CosDpValueTypeEnum._TypeBoolean:
        // cast it
        boolObj = null;
        try
        {
          boolObj = (Boolean) inObj;
        }
        catch (Exception ex)
        {
          // ignore
        }
        // set the value
        if (boolObj == null)
        {
          value.boolValue(false); // default value
        }
        else
        {
          value.boolValue(boolObj.booleanValue());
        }
        break;
      case CosDpValueTypeEnum._TypeNumber:
        // cast it
        intObj = null;
        try
        {
          intObj = (Integer) inObj;
        }
        catch (Exception ex)
        {
          // ignore
        }
        // set the value
        if (intObj == null)
        {
          value.longValue(0); // default value
        }
        else
        {
          value.longValue(intObj.intValue());
        }
        break;
      case CosDpValueTypeEnum._TypeUnsigned:
        // cast it
        intObj = null;
        try
        {
          intObj = (Integer) inObj;
        }
        catch (Exception ex)
        {
          // ignore
        }
        // set the value
        if (intObj == null)
        {
          value.unsignedValue(0); // default value
        }
        else
        {
          value.unsignedValue(intObj.intValue());
        }
        break;
      case CosDpValueTypeEnum._TypeDouble:
        // cast it
        dblObj = null;
        try
        {
          dblObj = (Double) inObj;
        }
        catch (Exception ex)
        {
          // ignore
        }
        // set the value
        if (dblObj == null)
        {
          value.dblValue(0); // default value
        }
        else
        {
          value.dblValue(dblObj.doubleValue());
        }
        break;
      case CosDpValueTypeEnum._TypeString:
        // cast it
        strObj = null;
        try
        {
          strObj = (String) inObj;
        }
        catch (Exception ex)
        {
          // ignore
        }
        // set the value
        if (strObj == null)
        {
          value.charValue(""); // default value
        }
        else
        {
          value.charValue(strObj);
        }
        break;
    }

    return value;
  }

  protected static CosDpValueUnion createCosDpValueUnion(
      CosDpValueTypeEnum inType)
  {
    // validation: inType
    if (inType == null)
    {
      return null;
    }

    CosDpValueUnion value = new CosDpValueUnion();

    // initialize internal value
    switch (inType.value())
    {
      case CosDpValueTypeEnum._TypeBoolean:
        value.boolValue(false);
        break;
      case CosDpValueTypeEnum._TypeNumber:
        value.longValue(0);
        break;
      case CosDpValueTypeEnum._TypeUnsigned:
        value.unsignedValue(0);
        break;
      case CosDpValueTypeEnum._TypeDouble:
        value.dblValue(0.0);
        break;
      case CosDpValueTypeEnum._TypeString:
        value.charValue("");
        break;
    }

    return value;
  }

  protected static int parseInt(String inStr)
  {
    int value = 0;
    try
    {
      value = Integer.parseInt(inStr);
    }
    catch (NumberFormatException nfe)
    {
      // ignore
    }
    catch (NullPointerException npe)
    {
      // ignore
    }
    return value;
  }

  protected static double parseDbl(String inStr)
  {
    double value = 0;
    try
    {
      value = Double.parseDouble(inStr);
    }
    catch (NumberFormatException nfe)
    {
      // ignore
    }
    catch (NullPointerException npe)
    {
      // ignore
    }
    return value;
  }

  protected static CosDpValueTypeEnum convString2CosDpValueTypeEnum(
      String inStr)
  {
    // validation: inStr
    if (inStr == null || inStr.length() == 0)
    {
      return CosDpValueTypeEnum.TypeNumber;
    }

    // parse the string
    if (inStr.compareToIgnoreCase("BOOL") == 0)
    {
      return CosDpValueTypeEnum.TypeBoolean;
    }
    else if (inStr.compareToIgnoreCase("NUMBER") == 0)
    {
      return CosDpValueTypeEnum.TypeNumber;
    }
    else if (inStr.compareToIgnoreCase("UNSIGNED") == 0)
    {
      return CosDpValueTypeEnum.TypeUnsigned;
    }
    else if (inStr.compareToIgnoreCase("DOUBLE") == 0)
    {
      return CosDpValueTypeEnum.TypeDouble;
    }
    else if (inStr.compareToIgnoreCase("STRING") == 0)
    {
      return CosDpValueTypeEnum.TypeString;
    }

    // default
    return CosDpValueTypeEnum.TypeNumber;
  }

  /**
   * Parse an expression. Look for reference to other datapoint.
   *
   * <p>
   * Note: The resulting parsed expression will have all datapoint references
   * replaced with internal variable name, or replace to 0 if the reference
   * datapoint is not found in the given datapoint list.
   * </p>
   *
   * @param inDpList
   *            - list of datapoints to resolve datapoint reference
   * @param inExpression
   *            - the expression to parse
   * @param outParams
   *            - output list to hold list of datapoint reference
   * @param outVarNames
   *            - output list to hold list of variable name for each datapoint
   *            reference
   * @param outVarTypes
   *            - output list to hold list of variable type for each datapoint
   *            reference
   * @param outVarValues
   *            - output list to hold list of initial value for each datapoint
   *            reference
   * @return the parsed expression
   */
  protected String _parseExpression(DataPointList inDpList,
      String inExpression, ArrayList<IDataPoint> outParams,
      ArrayList<String> outVarNames, ArrayList<Class<?>> outVarTypes,
      ArrayList<Object> outVarValues)
  {
    StringBuffer strExpr = new StringBuffer(inExpression);
    String dpname = "";
    String varname = "";
    Class<?> vartype = int.class;
    Object varvalue = null;
    IDataPoint datapoint = null;

    // prepare list of variables
    outParams.clear();
    outVarNames.clear();
    outVarTypes.clear();
    outVarValues.clear();

    // replace all datapoint name with equivalent variable name
    // datapoint name is in the format '{{data_point_name}}'
    int loc1 = strExpr.indexOf(KEYWORD_START, 0);
    int loc2 = 0;
    while (loc1 >= 0)
    {
      // reset just in case
      varname = "";
      // get the end of the datapoint name
      loc2 = strExpr.indexOf(KEYWORD_END, loc1);
      // if it is unterminated name
      if (loc2 < 1)
      {
        // delete the unterminated name
        strExpr.replace(loc1, strExpr.length(), "0");
      }
      else
      {
        // find a data point name
        dpname = strExpr.substring(loc1 + KEYWORD_END.length(), loc2)
            .trim();
        // parse the datapoint keyword
        if (inDpList == null)
        {
          // delete the datapoint keyword.
          strExpr.replace(loc1, loc2 + KEYWORD_END.length(), "0");
        }
        else
        {
          // get the datapoint reference from datapoint list
          datapoint = inDpList.getByName(dpname);
          if (datapoint == null)
          {
            // can not find the handle for the name. invalid
            // datapoint
            logger
                .warn("Can not get datapoint component of the expression: "
                    + dpname);
            // delete the invalid datapoint
            strExpr.replace(loc1, loc2 + KEYWORD_END.length(), "0");
          }
          else
          {
            // can find the handle. replace the keyword with a var
            // name
            varname = "var" + outParams.size();
            strExpr.replace(loc1, loc2 + KEYWORD_END.length(),
                varname);
            // add the handle into the list of handle for this data
            // point
            outParams.add(datapoint);
            // store the var name
            outVarNames.add(varname);
            // determine the var type and initial value
            vartype = int.class;
            varvalue = null;
            switch (datapoint.getValue().discriminator().value())
            {
              case CosDpValueTypeEnum._TypeBoolean:
                vartype = boolean.class;
                varvalue = Boolean.valueOf(datapoint.getValue()
                    .boolValue());
                break;
              case CosDpValueTypeEnum._TypeDouble:
                vartype = double.class;
                varvalue = new Double(datapoint.getValue()
                    .dblValue());
                break;
              case CosDpValueTypeEnum._TypeNumber:
                vartype = int.class;
                varvalue = Integer.valueOf(datapoint.getValue()
                    .longValue());
                break;
              case CosDpValueTypeEnum._TypeUnsigned:
                vartype = int.class;
                varvalue = Integer.valueOf(datapoint.getValue()
                    .unsignedValue());
                break;
              case CosDpValueTypeEnum._TypeString:
                vartype = String.class;
                varvalue = datapoint.getValue()
                    .charValue();
                break;
            }
            // store the var type and initial value
            outVarTypes.add(vartype);
            outVarValues.add(varvalue);
          }
        } // if (dpServer != null)
      } // if find KEYWORD_START

      // try to find next datapoint name
      loc1 = strExpr.indexOf(KEYWORD_END, loc1 + varname.length());
    } // while (loc1 >= 0)

    // store the expression
    return strExpr.toString();
  }

  @Override
  public synchronized int setValue(CosDpValueUnion inValue)
  {
    // default implementation
    return -1;
  }

  @Override
  public synchronized int setBooleanValue(boolean inValue)
  {
    // default implementation
    return -1;
  }

  @Override
  public synchronized int setNumberValue(int inValue)
  {
    // default implementation
    return -1;
  }

  @Override
  public synchronized int setUnsignedValue(int inValue)
  {
    // default implementation
    return -1;
  }

  @Override
  public synchronized int setDoubleValue(double inValue)
  {
    // default implementation
    return -1;
  }

  @Override
  public synchronized int setStringValue(String inValue)
  {
    // default implementation
    return -1;
  }

  @Override
  public synchronized int setSourceQuality(CosDpQualityEnum inQuality,
      boolean inUpdateTimestamp)
  {
    // default implementation
    return -1;
  }

  @Override
  public synchronized int setSourceTimestamp(long inTimestamp)
  {
    // default implementation
    return -1;
  }

  @Override
  public synchronized int setSourceValue(CosDpValueUnion inValue,
      boolean inUpdateTimestamp)
  {
    // default implementation
    return -1;
  }

  @Override
  public synchronized int setBooleanSourceValue(boolean inValue,
      boolean inUpdateTimestamp)
  {
    // default implementation
    return -1;
  }

  @Override
  public synchronized int setNumberSourceValue(int inValue,
      boolean inUpdateTimestamp)
  {
    // default implementation
    return -1;
  }

  @Override
  public synchronized int setUnsignedSourceValue(int inValue,
      boolean inUpdateTimestamp)
  {
    // default implementation
    return -1;
  }

  @Override
  public synchronized int setDoubleSourceValue(double inValue,
      boolean inUpdateTimestamp)
  {
    // default implementation
    return -1;
  }

  @Override
  public synchronized int setStringSourceValue(String inValue,
      boolean inUpdateTimestamp)
  {
    // default implementation
    return -1;
  }

  @Override
  public synchronized int setSourceValue(CosDpValueStruct inValue)
  {
    // default implementation
    return -1;
  }

  @Override
  public synchronized boolean setInhibit()
  {
    // validation: already inhibited?
    if (isInhibit)
    {
      return true;
    }

    // inhibit and override is mutually exclusive. this is a design
    // decision.
    if (isOverride)
    {
      return false;
    }

    // set the local flag
    isInhibit = true;
    //datapoint event
    //iPendingEvent_ |= EVT_STATE_CHANGE;

    // set the quality to QualityInhibit
    outputQuality = CosDpQualityEnum.QualityInhibit;
    //datapoint event
    //iPendingEvent_ |= EVT_OUTPUT_QUALITY_CHANGE;

    //update the output timestamp
    outputTimestamp = Calendar.getInstance().getTimeInMillis();
    //datapoint event
    //iPendingEvent_ |= EVT_OUTPUT_TIMESTAMP_CHANGE;

    // cascade it to equipment
    if (equipment != null)
    {
      equipment.onDataPointInhibitChange(this, true);
    }

    // re-evaluate all related calculated points, if any
    for (int i = 0; i < calculatedPoints.size(); i++)
    {
      calculatedPoints.get(i).evaluate();
    }
    // re-calculate all related meter points, if any
    for (int i = 0; i < meterPoints.size(); i++)
    {
      meterPoints.get(i).calculateMeterValue();
    }
    // re-evaluate all child points' quality, if any
    for (int i = 0; i < childPoints.size(); i++)
    {
      childPoints.get(i).updateQuality();
    }

    // update timestamp
    updateTimestamp_ = Calendar.getInstance().getTimeInMillis();

    // TODO: notify datastore

    return true;
  }

  @Override
  public synchronized boolean removeInhibit()
  {
    // validation: never inhibited
    if (!isInhibit)
    {
      return true;
    }

    // clear the local flag
    isInhibit = false;

    // synchronize the current value
    if (_synchronize() > 0)
    {
      // re-evaluate all related calculated points, if any
      for (int i = 0; i < calculatedPoints.size(); i++)
      {
        calculatedPoints.get(i).evaluate();
      }
      // re-calculate all related meter points, if any
      for (int i = 0; i < meterPoints.size(); i++)
      {
        meterPoints.get(i).calculateMeterValue();
      }
      // re-evaluate all child points' quality, if any
      for (int i = 0; i < childPoints.size(); i++)
      {
        childPoints.get(i).updateQuality();
      }
    }

    // cascade it to equipment
    if (equipment != null)
    {
      equipment.onDataPointInhibitChange(this, false);
    }

    // update timestamp
    updateTimestamp_ = Calendar.getInstance().getTimeInMillis();

    // TODO: notify datastore

    return true;
  }

  @Override
  public boolean isInhibit()
  {
    return isInhibit;
  }

  @Override
  public synchronized boolean setOverride(CosDpValueUnion inOverrideValue)
  {
    // validation
    if (inOverrideValue == null)
    {
      return false;
    }

    // inhibit and override is mutually exclusive. this is a design
    // decision.
    if (isInhibit)
    {
      return false;
    }

    // attempt to copy the override value to output value
    if (copy(outputValue, inOverrideValue) < 0)
    {
      // can not set, somehow
      return false;
    }
    //datapoint event
    //iPendingEvent_ |= EVT_OUTPUT_VALUE_CHANGE;

    // set the local flag
    isOverride = true;
    //datapoint event
    //iPendingEvent_ |= EVT_STATE_CHANGE;

    // set output quality to QualityOverride
    outputQuality = CosDpQualityEnum.QualityOverride;
    //datapoint event
    //iPendingEvent_ |= EVT_OUTPUT_QUALITY_CHANGE;

    // update output timestamp. this is because setOverride() will override
    // the output value
    outputTimestamp = Calendar.getInstance().getTimeInMillis();
    //datapoint event
    //iPendingEvent_ |= EVT_OUTPUT_TIMESTAMP_CHANGE;

    // cascade it to the equipment
    if (equipment != null)
    {
      equipment.onDataPointOverrideChange(this, true);
    }

    // re-evaluate all related calculated points, if any
    for (int i = 0; i < calculatedPoints.size(); i++)
    {
      calculatedPoints.get(i).evaluate();
    }
    // re-calculate all related meter points, if any
    for (int i = 0; i < meterPoints.size(); i++)
    {
      meterPoints.get(i).calculateMeterValue();
    }
    // re-evaluate all child points' quality, if any
    for (int i = 0; i < childPoints.size(); i++)
    {
      childPoints.get(i).updateQuality();
    }

    // update datapoint timestamp
    updateTimestamp_ = Calendar.getInstance().getTimeInMillis();

    // TODO: notify datastore

    return true;
  }

  @Override
  public synchronized boolean removeOverride()
  {
    // validation: never overridden
    if (!isOverride)
    {
      return true;
    }

    // clear the local flag
    isOverride = false;

    // synchronize the current value
    if (_synchronize() > 0)
    {
      // re-evaluate all related calculated points, if any
      for (int i = 0; i < calculatedPoints.size(); i++)
      {
        calculatedPoints.get(i).evaluate();
      }
      // re-calculate all related meter points, if any
      for (int i = 0; i < meterPoints.size(); i++)
      {
        meterPoints.get(i).calculateMeterValue();
      }
      // re-evaluate all child points' quality, if any
      for (int i = 0; i < childPoints.size(); i++)
      {
        childPoints.get(i).updateQuality();
      }
    }

    // cascade it to equipment
    if (equipment != null)
    {
      equipment.onDataPointOverrideChange(this, false);
    }

    // update timestamp
    updateTimestamp_ = Calendar.getInstance().getTimeInMillis();

    // TODO: notify datastore

    return true;
  }

  @Override
  public boolean isOverride()
  {
    return isOverride;
  }

  @Override
  public synchronized boolean setReturnCondition(String inExpression,
      DataPointList inDpList)
  {
    // default implementation
    return false;
  }

  @Override
  public synchronized boolean checkReturnCondition()
  {
    // default implementation
    return false;
  }

  @Override
  public synchronized boolean setLaunchCondition(String inExpression,
      DataPointList inDpList)
  {
    // default implementation
    return false;
  }

  @Override
  public synchronized boolean checkLaunchCondition()
  {
    // default implementation
    return false;
  }

  @Override
  public synchronized boolean setExpression(String inExpression,
      DataPointList inDpList)
  {
    // default implementation
    return false;
  }

  @Override
  public synchronized int evaluate()
  {
    // default implementation
    return 0;
  }

  @Override
  public synchronized boolean setAlarmInhibit()
  {
    // TODO Auto-generated method stub
    return false;
  }

  @Override
  public synchronized boolean removeAlarmInhibit()
  {
    // TODO Auto-generated method stub
    return false;
  }

  @Override
  public boolean isAlarmInhibit()
  {
    return isAlarmInhibit;
  }

  @Override
  public synchronized boolean raiseAlarm()
  {
    // TODO Auto-generated method stub
    return false;
  }

  @Override
  public synchronized boolean normalizeAlarm()
  {
    // TODO Auto-generated method stub
    return false;
  }

  @Override
  public synchronized boolean acknowledgeAlarm()
  {
    // TODO Auto-generated method stub
    return false;
  }

  @Override
  public boolean isInAlarm()
  {
    return (isAlarmNotAck | isAlarmNotNorm);
  }

  @Override
  public boolean isAlarmNormalized()
  {
    return !isAlarmNotNorm;
  }

  @Override
  public boolean isAlarmAcknowledged()
  {
    return !isAlarmNotAck;
  }

  @Override
  public int setReadingRollOver(int inRollOver)
  {
    // default implementation
    return 0;
  }

  @Override
  public int getReadingRollOver()
  {
    // default implementation
    return 0;
  }

  @Override
  public int setDataPointRollOver(int inRollOver)
  {
    // default implementation
    return 0;
  }

  @Override
  public int getDataPointRollOver()
  {
    // default implementation
    return 0;
  }

  @Override
  public synchronized int adjustMeterValue(int inAdjustment)
  {
    // default implementation
    return 0;
  }

  @Override
  public boolean setMeterSourcePoint(IDataPoint inDataPoint)
  {
    // default implementation
    return false;
  }

  @Override
  public int calculateMeterValue()
  {
    // default implementation
    return -1;
  }

  @Override
  public synchronized boolean setEngineeringConversion(String inExpression)
  {
    // default implementation
    return false;
  }

  @Override
  public synchronized double setDeadBandValue(double inDeadBand)
  {
    // default implementation
    return deadband;
  }

  @Override
  public double getDeadBandValue()
  {
    return deadband;
  }

  @Override
  public synchronized void startBatchOperation()
  {
    // just set the flag
    isBatchOperation = true;
  }

  @Override
  public synchronized void finishBatchOperation()
  {
    // just clear the flag
    isBatchOperation = false;
  }

  @Override
  public synchronized void addChildPoint(IDataPoint inDataPoint)
  {
    // validation: inDataPoint
    if (inDataPoint == null)
    {
      return;
    }

    // check for duplicate entry
    if (null != childPoints.getByKeyId(inDataPoint.getKeyId()))
    {
      return;
    }

    // add to the list
    childPoints.add(inDataPoint);
  }

  @Override
  public synchronized void addMeterPoint(IDataPoint inDataPoint)
  {
    // validation: inDataPoint
    if (inDataPoint == null)
    {
      return;
    }

    // check for duplicate entry
    if (null != meterPoints.getByKeyId(inDataPoint.getKeyId()))
    {
      return;
    }

    // add to the list
    meterPoints.add(inDataPoint);
  }

  @Override
  public synchronized void addCalculatedPoint(IDataPoint inDataPoint)
  {
    // validation: inDataPoint
    if (inDataPoint == null)
    {
      return;
    }

    // check for duplicate entry
    if (null != calculatedPoints.getByKeyId(inDataPoint.getKeyId()))
    {
      return;
    }

    // add to the lisinDataPointt
    calculatedPoints.add(inDataPoint);
  }

  @Override
  public synchronized int updateQuality()
  {
    // do not update when it is inhibit or override
    if (isInhibit || isOverride)
    {
      return -1;
    }

    // update output quality
    CosDpQualityEnum newQuality = calculate_quality();
    if (outputQuality != newQuality)
    {
      outputQuality = newQuality;
      return +1;
    }

    return 0;
  }

}
TOP

Related Classes of tcg.scada.da.DataPoint

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.