/*
 * SmartHome server: Plug-in x10
 *
 * 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 shx10.cpp
 * @brief Interfaces the X10 network using a CM12U controller
 * @author Daniel Pisi
 */

#include "shx10.h"
#include <QStringList>

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

/**
 * \brief Constructor of ShX10
 * \param parent Pointer to the parent object
 */
ShX10::ShX10(QObject *parent) : ShObjectHelper(parent)
{
}
// -----------------------------------------------------------------------------

/**
 * \brief Initialization of the plug-in
 * \param param Defines a port that is the X10 controller connected to
 * \return true if the plug-in has been initialized successfully
 */
bool ShX10::init(QString param)
{
    mInterface = new X10Interface(param);

    connect(mInterface, SIGNAL(transmissionDone()),
            this, SLOT(emitAck()));

    connect(mInterface, SIGNAL(transmissionFailed(QString)),
            this, SLOT(emitErr(QString)));

    mInterface->sendTime();

    qDebug("X10 initialized");
    return true;
}
// -----------------------------------------------------------------------------

/**
 * \brief Enqueue the incomming messages
 * \param message Shared pointer to the message
 */
void ShX10::processMessage(ShMessagePtr message)
{
    qDebug("X10: Processing message from object %d, signal = %s, value = %s",
           message->senderId(), qPrintable(message->signal()), qPrintable(message->value().toString()));

    if (message->msgType() == ShMessage::mtValue)
    {
        mMessageQueue.enqueue(message);
        processNextMessage();
    }
}
// -----------------------------------------------------------------------------

/**
 * \brief Hands over the next message to the x10interface object
 */
void ShX10::processNextMessage()
{
    if ((mMessageQueue.isEmpty()) ||
        (mInterface->state() != X10Interface::stReady))
        return;

    QRegExp rxn("([A-P])(1[0-5]|[0-9])((?:\\s*,\\s*)(1[0-5]|[0-9]))*");
    QRegExp rxa("([A-P])\\*");

    QString  devices = mMessageQueue.head()->signal().toUpper();
    QVariant value   = mMessageQueue.head()->value();
    QString  valStr  = value.toString().toUpper();

    if (rxn.exactMatch(devices))
    {
        if ( (valStr == "ON") ||
            ((valStr == "1") && (mMessageQueue.head()->pin().type() == ShPin::ptBool)) )
        {
            mInterface->onOffDevices(devices, true);
        }
        else if ((valStr == "OFF") || (valStr == "0"))
        {
            mInterface->onOffDevices(devices, false);
        }
        else if (value.canConvert<int>())
        {
            mInterface->dimLights(devices, value.toInt());
        }
        else
            emitErr("unsupported value");
    }
    else if (rxa.exactMatch(devices))
    {
        mInterface->onOffAllLights(devices[0].toAscii(), value.toBool() || valStr == "ON");
    }
}
// -----------------------------------------------------------------------------

/**
 * \brief Slot invoked after successful X-10 transmission
 */
void ShX10::emitAck()
{
    ShMessagePtr message = mMessageQueue.dequeue();

    if (message->requireAck())
        ackMessage(message);

    processNextMessage();
}
// -----------------------------------------------------------------------------

/**
 * \brief Slot invoked after X-10 transmission failed
 */
void ShX10::emitErr(QString reason)
{
    ShMessagePtr message = mMessageQueue.dequeue();

    errorMessage(message, reason);
    processNextMessage();
}
// -----------------------------------------------------------------------------

Q_EXPORT_PLUGIN2(x10, ShX10);
