#include "XDebugCommThread.h"
#include "XDebugManager.h"
#include <wx/buffer.h>
#include <file_logger.h>
#include <string>
#include <wx/log.h>
void XDebugComThread::SendMsg(const wxString& msg)
{
    m_queue.Post( msg );
}

XDebugComThread::~XDebugComThread()
{
    Stop();
}

void XDebugComThread::Stop()
{
    if ( IsAlive() ) {
        Delete(NULL, wxTHREAD_WAIT_BLOCK);

    } else {
        Wait(wxTHREAD_WAIT_BLOCK);

    }
}

void* XDebugComThread::Entry()
{
    wxLog::EnableLogging(false);
    
    CL_DEBUG("CodeLite >>> XDebugComThread started");
    //----------------------------------------------------------------
    // Start the debugger server and wait for XDebug to connect to us
    //----------------------------------------------------------------
    clSocketBase::Ptr_t client;
    int retry(0);
    try {
        CL_DEBUG("CodeLite >>> Creating server on %s:%d", m_host, m_port);
        
        wxCharBuffer cb = m_host.mb_str(wxConvUTF8);
        m_server.CreateServer(cb.data(), m_port);
        
        CL_DEBUG("CodeLite >>> Listening on %s:%d", m_host, m_port);
        
        // Wait for new connection (up to 5 seconds )
        do {
            if ( retry > 5 ) {
                // Don't wait any longer for XDebug
                m_xdebugMgr->CallAfter( &XDebugManager::XDebugNotConnecting );
                return NULL;
            }
            client = m_server.WaitForNewConnection(1);
            ++retry;
            CL_DEBUG("CodeLite >>> waiting for connection..");
        } while( !TestDestroy() && !client );
        
        CL_DEBUG("CodeLite >>> Successfully accepted connection from XDebug!");
        m_xdebugMgr->CallAfter( &XDebugManager::SetConnected, true );

        //----------------------------------------------------------------
        // Protocol:
        // First we read the init XML
        //----------------------------------------------------------------

        std::string initXML;
        if ( DoReadReply( initXML, client ) ) {
            m_xdebugMgr->CallAfter( &XDebugManager::OnSocketInput, initXML );

        } else {
            // Something bad happened
            m_xdebugMgr->CallAfter( &XDebugManager::OnCommThreadTerminated );
            return NULL;
        }

        // The main loop: request-reply mode
        while ( !TestDestroy() ) {
            wxString command;
            if ( m_queue.ReceiveTimeout(20, command) == wxMSGQUEUE_NO_ERROR ) {
                DoSendCommand( command, client );

                // Wait for the reply
                std::string reply;
                if ( !DoReadReply( reply, client ) ) {
                    // AN error occured - close session
                    break;
                }

                // Notify XDebugManager
                m_xdebugMgr->CallAfter( &XDebugManager::OnSocketInput, reply );
            }
        }
    } catch (clSocketException &e) {
        CL_DEBUG("XDebugComThread caught an exception: %s", e.what());
        m_xdebugMgr->CallAfter( &XDebugManager::OnCommThreadTerminated );
        return NULL;
    }

    m_xdebugMgr->CallAfter( &XDebugManager::OnCommThreadTerminated );
    return NULL;
}

bool XDebugComThread::DoReadReply(std::string& reply, clSocketBase::Ptr_t client)
{
    if ( !client ) {
        return false;
    }

    try {
        // Read the data length
        wxString length;
        while ( true ) {
            char c = 0;
            size_t count = 0;
            client->Read( &c, 1, count);
            if ( c == 0 ) {
                break;
            }
            length << c;
        }

        long dataLengh (0);
        if ( !length.ToCLong(&dataLengh) ) {
            // session terminated!
            return false;
        }

        // Read the actual buffer
        ++dataLengh; // +1 for NULL
        char *buffer = new char[dataLengh];
        memset(buffer, 0, dataLengh);
        size_t actualSize(0);
        client->Read(buffer, dataLengh, actualSize);
        std::string content(buffer, dataLengh);
        reply.swap( content );
        wxDELETEA( buffer );

    } catch (clSocketException& e) {
        wxUnusedVar(e);
        return false;
    }
    return true;
}

void XDebugComThread::DoSendCommand(const wxString& command, clSocketBase::Ptr_t client)
{
    // got message, process it
    if ( !client ) {
        return;
    }
    CL_DEBUGS(wxString() << "CodeLite >>> " << command );

    wxMemoryBuffer buff;
    buff.AppendData(command.mb_str(wxConvISO8859_1), command.length());
    buff.AppendByte(0);
    std::string cmd((const char*)buff.GetData(), buff.GetDataLen());
    client->Send(cmd);
}
