/**
 * @file JAMessageGAM.h
 * @brief Header file for class JAMessageGAM
 * @date Jan, 2019
 * @author rhari
 *
 * @copyright Copyright 2015 F4E | European Joint Undertaking for ITER and
 * the Development of Fusion Energy ('Fusion for Energy').
 * Licensed under the EUPL, Version 1.1 or - as soon they will be approved
 * by the European Commission - subsequent versions of the EUPL (the "Licence")
 * You may not use this work except in compliance with the Licence.
 * You may obtain a copy of the Licence at: http://ec.europa.eu/idabc/eupl
 *
 * @warning Unless required by applicable law or agreed to in writing,
 * software distributed under the Licence is distributed on an "AS IS"
 * basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
 * or implied. See the Licence permissions and limitations under the Licence.

 * @details This header file contains the declaration of the class JAMessageGAM
 * with all of its public, protected and private members. It may also include
 * definitions for inline methods which need to be visible to the compiler.
 */

#ifndef GAMS_JAMESSAGEGAM_H_
#define GAMS_JAMESSAGEGAM_H_

/*---------------------------------------------------------------------------*/
/*                        Standard header includes                           */
/*---------------------------------------------------------------------------*/

/*---------------------------------------------------------------------------*/
/*                        Project header includes                            */
/*---------------------------------------------------------------------------*/

#include "GAM.h"
#include "Message.h"

/*---------------------------------------------------------------------------*/
/*                           Class declaration                               */
/*---------------------------------------------------------------------------*/

/**
 * @brief GAM that sends a message when input signals have expected values. Message will not be sent multiple
 * times without first changing the application state.
 *
 * The configuration syntax is (names and signal quantity are only given as an example):
 * <pre>
 * +MessageGAM = {
 *      Class = JAMessageGAM
 *      Operation = AND // Accepted values are: AND, OR, XOR, NOR. Default value is AND.
 *      ExpectedIntValues = {1 10} // Expected values for input signals of integral type.
 *      ExpectedFloatValues = {3.5} // Expected values for float signals of floting point type.
 *      Comparators = {EQUALS GREATER NOT} // Accepted values are: EQUALS, NOT, GREATER, EQUALS_OR_GREATER, LESS, EQUALS_OR_LESS
 *                                         // Comparators element is optional. Default comparator is EQUALS.
 *      InputSignals = {
 *          Sig1 = {
 *              DataSource = EPICSCAInput
 *              Type = uint32
 *          }
 *          Sig2 = {
 *              DataSource = EPICSCAInput
 *              Type = float32
 *          }
 *          Sig3 = {
 *              DataSource = EPICSCAInput
 *              Type = uint32
 *          }
 *      }
 *      +Event = { // Message to be sent when condition is true.
 *          Class = Message
 *          Destination = StateMachine
 *          Function = GoDisabled
 *      }
 *  }
 * </pre>
 * This example will send Event message when Sig1 == 1 && Sig2 > 3.5 && Sig3 != 10
 */
class JAMessageGAM : public MARTe::GAM, public MARTe::StatefulI  {
public:
    CLASS_REGISTER_DECLARATION()

    JAMessageGAM();

    virtual ~JAMessageGAM();

    virtual bool Initialise(MARTe::StructuredDataI & data);

    virtual bool Setup();

    virtual bool Execute();

    virtual bool PrepareNextState(const MARTe::char8 * const currentStateName,
                                  const MARTe::char8 * const nextStateName);

    enum ComparisonMode {
        Equals, Not, Greater, EqualsOrGreater, Less, EqualsOrLess
    };

private:
    /**
     * @brief Does the input signal at provided index have the expected value.
     * @param[in] index of the signal.
     * @param[out] floatValueIndex lookup index for expected float values array.
     * @param[out] intValueIndex lookup index for expected integer values array.
     * @return true if the signal has expected value.
     */
    bool Compare(MARTe::uint32 index, MARTe::uint32 &floatValueIndex, MARTe::uint32 &intValueIndex);

    enum OperationMode {
        And, Or, Xor, Nor
    };

    // Input signals
    void **inputSignals;

    MARTe::TypeDescriptor *inputSignalTypes;

    // Condition operation.
    OperationMode operation;

    // Message to be sent when conditions are met.
    MARTe::ReferenceT<MARTe::Message> eventMsg;

    // Was the message already sent and we are waiting for a state change before next message can be sent.
    bool needsReset;

    // Array of expected integer values of input signals.
    MARTe::uint64* expectedValuesInt;

    // Array of expected float values for input signals.
    MARTe::float64* expectedValuesFloat;

    // Expected integer values count (must be equal to numberOfInputSignals - floatValuesCount)
    MARTe::uint32 intValuesCount;

    // Expected integer values count (must be equal to numberOfInputSignals - floatValuesCount)
    MARTe::uint32 floatValuesCount;

    // Array of comparators
    ComparisonMode* comparators;
};



/*---------------------------------------------------------------------------*/
/*                        Inline method definitions                          */
/*---------------------------------------------------------------------------*/

#endif /* GAMS_JAMESSAGEGAM_H_ */
