/*
 * SmartHome server: Plug-in logic
 *
 * Copyright (C) 2010 Daniel Pisi <dan.pisi@gmail.com>
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of version 2 of the GNU General Public License
 * as published by the Free Software Foundation.
 *
 */

/**
 * @file shlogic.cpp
 * @brief Implements a simple logic gate
 * @author Daniel Pisi
 */

#include "shlogic.h"

// -----------------------------------------------------------------------------

/**
 * \brief Constructor of ShLogic
 */
ShLogic::ShLogic()
{
    mGateType = gtAnd;
    mOutput = false;
}
// -----------------------------------------------------------------------------

/**
 * \brief Initialization of the plug-in
 * \param param Defines a desired logic function
 * \return true if the plug-in has been initialized successfully
 */
bool ShLogic::init(QString param)
{
    param = param.toUpper();

         if (param == "AND")  mGateType = gtAnd;
    else if (param == "NAND") mGateType = gtNand;
    else if (param == "OR")   mGateType = gtOr;
    else if (param == "NOR")  mGateType = gtNor;
    else if (param == "XOR")  mGateType = gtXor;

    qDebug("Logic gate initialized");
    return true;
}
// -----------------------------------------------------------------------------

/**
 * \brief Updates a list of gate inputs
 * \param pins List of pins belonging to plug-in
 */
void ShLogic::updatePins(const QList<ShPin> &pins)
{
    mInputs.clear();

    foreach (ShPin pin, pins)
    {
        if (pin.isInput())
            mInputs.insert(pin.signal(), false);
    }
}
// -----------------------------------------------------------------------------

/**
 * \brief Updates the output of the logic gate
 */
void ShLogic::updateOutput()
{
    bool output = ((mGateType == gtAnd) || (mGateType == gtNand));

    foreach (bool input, mInputs)
    {
        switch (mGateType)
        {
        case gtAnd:
        case gtNand:
            output &= input;
            break;

        case gtOr:
        case gtNor:
            output |= input;
            break;

        case gtXor:
            output ^= input;
            break;
        }
    }

    if ((mGateType == gtNand) || (mGateType == gtNor))
        output = !output;

    if (output != mOutput)
    {
        mOutput = output;
        outputUpdated("Y", mOutput);
    }
}
// -----------------------------------------------------------------------------

/**
 * \brief Processes incoming messages (input changes)
 * \param message Shared pointer to the message
 */
void ShLogic::processMessage(ShMessagePtr message)
{
    qDebug("Logic gate: Processing message from object %d, signal = %s, value = %s",
           message->senderId(), qPrintable(message->signal()), qPrintable(message->value().toString()));

    if (message->msgType() == ShMessage::mtValue)
    {
        if (mInputs.contains(message->signal()))
        {
            mInputs[message->signal()] = message->value().toBool();
            updateOutput();

            if (message->requireAck())
                ackMessage(message);
        }
        else
            errorMessage(message, "Invalid signal");
    }
    else if ((message->msgType() == ShMessage::mtGet) &&
            (message->signal() == "Y"))
    {
        outputUpdated("Y", mOutput);
    }
}
// -----------------------------------------------------------------------------

Q_EXPORT_PLUGIN2(logic, ShLogic);
