/*
 * SmartHome server: Plug-in tcpserver
 *
 * 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 shtcpserver.cpp
 * @brief Allows other applications to interact with the system via TCP/IP connection
 * @author Daniel Pisi
 */

#include "shtcpserver.h"

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

/**
 * \brief Initialization of the plug-in, creating a TCP/IP listener
 * \param param Defines the host, port and details of communication protocol
 * \return true if the plug-in has been initialized successfully
 */
bool ShTcpServer::init(QString param)
{
    setIdApi(param.toUpper().contains("FORMAT=ID"));

    mClientConnection = NULL;
    mTcpServer = new QTcpServer(this);

    qDebug("Starting TCP server");
    if (!mTcpServer->listen(QHostAddress::LocalHost, 12345))
    {
        qCritical(tr("Unable to start the TCP server: %1.").arg(mTcpServer->errorString()).toLatin1());
        return false;
    }

    connect(mTcpServer, SIGNAL(newConnection()), this, SLOT(newClientConnected()));
    return true;
}
// -----------------------------------------------------------------------------

/**
 * \brief Relays the message to the TCP/IP socket
 * \param message Shared pointer to the message
 */
void ShTcpServer::processMessage(ShMessagePtr message)
{
    if (mClientConnection != NULL)
    {
        mClientConnection->write(
                QString("%1;%2;%3\n").arg(message->signal(),
                                          message->msgTypeStr(),
                                          message->value().toString()).toUtf8());
    }
}
// -----------------------------------------------------------------------------

/**
 * \brief Parses and dispatches a command received through TCP/IP connection
 * \param cmd Received command
 */
void ShTcpServer::processPacket(const QString &cmd)
{
    // pin;command;parameter
    QRegExp rx("([a-zA-Z0-9_-]*);([a-zA-Z0-9_-]*);(.*)");

    qDebug(QString("processCommand(%1)").arg(cmd).toLatin1());

    if (rx.exactMatch(cmd))
    {
        ShMessagePtr message = ShMessagePtr(new ShMessage);
        message->setMsgType(rx.cap(2));
        message->setSignal(rx.cap(1));
        message->setValue(rx.cap(3));
        message->setRequireAck(true);
        dispatchMessage(message);
    }
}
// -----------------------------------------------------------------------------

/**
 * \brief Slot accepting new client connection
 */
void ShTcpServer::newClientConnected()
{
    mClientConnection = mTcpServer->nextPendingConnection();

    connect(mClientConnection, SIGNAL(readyRead()), this, SLOT(dataAvailable()));

    qDebug("New TCP connection initialized");
}
// -----------------------------------------------------------------------------

/**
 * \brief Slot reading incoming data
 */
void ShTcpServer::dataAvailable()
{
    qint64 n;

    if (mClientConnection)
    {
        while ((n = mClientConnection->readLine(mBuffer+mBufLen, sizeof(mBuffer)-mBufLen)) > 0)
        {
            mBufLen += n;
            if (mBuffer[mBufLen-1] == '\n')
            {
                mBuffer[mBufLen-1] = 0;
                processPacket(mBuffer);
                mBufLen = 0;
            }
        }
        if (n < 0)
        {
            qCritical((tr("Unable to read TCP socket: %1.").arg(mClientConnection->errorString())).toLatin1());
            mClientConnection->disconnectFromHost();
            mBufLen = 0;
        }
    }
}
// -----------------------------------------------------------------------------

Q_EXPORT_PLUGIN2(tcpserver, ShTcpServer);
