/***************************************************************************
 *   Copyright (C) 2003 by liuspider                                       *
 *   liuspider@users.sourceforge.net                                       *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 ***************************************************************************/
#define USE_SCIM_KDE_SETTINGS
#include "socketserverthread.h"

#include "skimpluginmanager.h"
#include "skimglobalactions.h"

#include "utils/scimactions.h"

#include <qstringlist.h>
#include <kapplication.h>

#define SCIM_DEFAULT_SETTINGS_GROUP "SCIM"

using namespace scim;
SocketServerThread::SocketServerThread(QObject *parent, QStringList & args)
: QObject(parent), QThread(),x11FrontEndConnectSignalEmitted(true) {
    SCIM_DEBUG_MAIN (1) << "Initialize Socket Server...\n";

    // Read configurations
    _socket_address = scim_get_default_panel_socket_address();
    _socket_timeout = scim_get_default_socket_timeout();
    _current_socket_client = -1;
    _current_client_context = 0;
    _last_socket_client = -1;
    _last_client_context = 0;
    _socket_client_count = 0;
    _should_exit = false;

    String default_config_module("socket");
    for(uint argi=0; argi<args.size(); argi++)
      if(args[argi] == "c") {
        default_config_module = String(args[argi+1].latin1());
      }

    config_module = new ConfigModule (default_config_module);
    if (config_module != NULL && config_module->valid ())
      scim_config = config_module->create_config ("scim");
    else {
        std::cerr << "Config module \"" << default_config_module << "\"cannot be loaded, using dummy Config.\n Some settings may not be able to get reloaded without restarting.";

        if (config_module) delete config_module;
        config_module = NULL;

        scim_config = new DummyConfig ();
    }
    
    
    if(args.contains("no-stay"))
      _should_resident = false;
    else
      _should_resident = true;
    config = ScimKdeSettings::self()->config();
}

bool SocketServerThread::initSocketServer() {
    if( !_socket_server.create( SocketAddress( _socket_address ) ) ) {
        std::cerr << "Cannot create SocketServer. Maybe a panel is still running...\n";
        return false;
    }

    _socket_server.set_max_clients (1024);

    _socket_server.signal_connect_accept (slot (this, &SocketServerThread::AcceptConnection));
    _socket_server.signal_connect_receive (slot (this, &SocketServerThread::ReceiveData));
    _socket_server.signal_connect_exception(slot (this, &SocketServerThread::ExceptionHandler));

    return true;
}
void SocketServerThread::run() {
    SCIM_DEBUG_MAIN(1) << " In Socket Server Thread...\n";
    _socket_server.run();
}
void SocketServerThread::AcceptConnection( SocketServer * server, const Socket & ) {
    SCIM_DEBUG_MAIN (1) << " Accept Client Connection...\n";
    if (_should_exit) {
        SCIM_DEBUG_MAIN (3) << "  Exit Socket Server Thread.\n";
        server->shutdown ();
        kapp->lock();
        emit disconnectCompleted();
        kapp->unlock();
    }
}
ClientInfo SocketServerThread::SocketGetClientInfo (const Socket &client) {
    static ClientInfo null_client = { 0, UNKNOWN_CLIENT};

    std::map<int, ClientInfo>::iterator it = _client_repository.find (client.get_id ());

    if (it != _client_repository.end ())
        return it->second;

    return null_client;
}
void SocketServerThread::SocketCloseConnection (SocketServer *server, const Socket &client) {
    SCIM_DEBUG_MAIN (1) << "  Client " << client.get_id () << " closed...\n";

    ClientInfo client_info = SocketGetClientInfo (client);

    _client_repository.erase (client.get_id ());

    server->close_connection (client);

    if (client_info.type == FRONTEND_CLIENT) {
        // The focused client is closed.
        if (_current_socket_client == client.get_id ()) {

            _current_socket_client = -1;
            _current_client_context = 0;

            _last_socket_client = -1;
            _last_client_context = 0;

            turn_off_panel();
        }
    } else if (client_info.type == GUI_CLIENT) {
        kapp->lock();    
        emit guiClientDisconnected(client.get_id ());
        kapp->unlock();
    }

    // Exit panel if there is no connected client anymore.
    if (client_info.type != UNKNOWN_CLIENT &&
            _client_repository.size () == 0 && !_should_resident) {
        kapp->lock();
        kapp->quit();
        kapp->unlock();
    }
    if (_client_repository.size () == 0) {
        kapp->lock();
        emit lastConnectionFinished();
        kapp->unlock();
    }
}

bool SocketServerThread::SocketOpenConnection (SocketServer *server, const Socket &client) {
    SCIM_DEBUG_MAIN (2) << "Open socket connection for client " << client.get_id () << "\n";

    uint32 key;
    String type;

    type = scim_socket_trans_accept_connection (key,
                        String ("Panel"),
                        String ("FrontEnd,GUI,ConnectionTester"),
                        client,
                        _socket_timeout);

    __ClientType realType = UNKNOWN_CLIENT;

    if (type == "FrontEnd") realType = FRONTEND_CLIENT;
    else if (type == "GUI") realType = GUI_CLIENT;

    if (realType != UNKNOWN_CLIENT) {
        ClientInfo info;
        info.key = key;
        info.type = realType;

        SCIM_DEBUG_MAIN (2) << "Add client to repository. Type=" << type << " key=" << key << "\n";
        _client_repository [client.get_id ()] = info;

        if(realType == FRONTEND_CLIENT)
            x11FrontEndConnectSignalEmitted = false;

        return true;
    }

    SCIM_DEBUG_MAIN (2) << "Close client connection " << client.get_id () << "\n";
    server->close_connection (client);

    return false;
}

void SocketServerThread::ReceiveData( SocketServer *server, const Socket &client ) {
    int id = client.get_id ();
    int cmd = 0;
    uint32 key = 0;
    uint32 context = 0;

    ClientInfo client_info;

    if (!check_client_connection (client)) {
        SocketCloseConnection (server, client);
        return;
    }

    client_info = SocketGetClientInfo (client);

    // If it's a new client, then request to open the connection first.
    if (client_info.type == UNKNOWN_CLIENT) {
        SocketOpenConnection (server, client);
        return;
    }

    // If can not read the transaction,
    // or the transaction is not started with SCIM_TRANS_CMD_REQUEST,
    // or the key is mismatch,
    // just return.
    if (!_receive_transaction.read_from_socket (client, _socket_timeout) ||
            !_receive_transaction.get_command (cmd) || cmd != SCIM_TRANS_CMD_REQUEST ||
            !_receive_transaction.get_data (key) || key != (uint32) client_info.key)
        return;

    _send_transaction.clear ();
    _send_transaction.put_command (SCIM_TRANS_CMD_REPLY);
    // Move the read ptr to the end.
    _send_transaction.get_command (cmd);

    //     // If the UI is not initialized, tell the client it's failed.
    //     if (!_ui_initialized) {
    //         _send_transaction.put_command (SCIM_TRANS_CMD_FAIL);
    //         _send_transaction.write_to_socket (client);
    //         return;
    //     }
    if (client_info.type == FRONTEND_CLIENT) {
        if (_receive_transaction.get_data (context)) {
            _send_transaction.put_data (context);
            _send_transaction.get_data (context);
            while (_receive_transaction.get_command (cmd)) {
                if (cmd == SCIM_TRANS_CMD_FOCUS_IN) {
                    _current_socket_client = id;
                    _current_client_context = context;
                    continue;
                }

                // If it's not focused, just continue.
                if ((_current_socket_client != id || _current_client_context != context) &&
                        (_current_socket_client >= 0  || _last_socket_client != id || _last_client_context != context))
                    continue;

                // Client must focus in before do any other things.
                if (cmd == SCIM_TRANS_CMD_PANEL_TURN_ON)
                    turn_on_panel();
                else if (cmd == SCIM_TRANS_CMD_PANEL_TURN_OFF) {
                    turn_off_panel();
                    if(!x11FrontEndConnectSignalEmitted) {
                        emit x11FrontEndConnected();
                        x11FrontEndConnectSignalEmitted = true;
                    }
                } else if (cmd == SCIM_TRANS_CMD_PANEL_UPDATE_DISPLAY)
                    update_display ();
                else if (cmd == SCIM_TRANS_CMD_PANEL_UPDATE_SCREEN)
                    update_screen ();
                else if (cmd == SCIM_TRANS_CMD_PANEL_UPDATE_SPOT_LOCATION)
                    update_spot_location ();
                else if (cmd == SCIM_TRANS_CMD_PANEL_UPDATE_FACTORY_INFO)
                    update_factory_info ();
                else if (cmd == SCIM_TRANS_CMD_SHOW_PREEDIT_STRING)
                    show_preedit_string ();
                else if (cmd == SCIM_TRANS_CMD_SHOW_AUX_STRING)
                    show_aux_string ();
                else if (cmd == SCIM_TRANS_CMD_SHOW_LOOKUP_TABLE)
                    show_lookup_table ();
                else if (cmd == SCIM_TRANS_CMD_HIDE_PREEDIT_STRING)
                    hide_preedit_string ();
                else if (cmd == SCIM_TRANS_CMD_HIDE_AUX_STRING)
                    hide_aux_string ();
                else if (cmd == SCIM_TRANS_CMD_HIDE_LOOKUP_TABLE)
                    hide_lookup_table ();
                else if (cmd == SCIM_TRANS_CMD_UPDATE_PREEDIT_STRING)
                    update_preedit_string ();
                else if (cmd == SCIM_TRANS_CMD_UPDATE_PREEDIT_CARET)
                    update_preedit_caret ();
                else if (cmd == SCIM_TRANS_CMD_UPDATE_AUX_STRING)
                    update_aux_string ();
                else if (cmd == SCIM_TRANS_CMD_UPDATE_LOOKUP_TABLE)
                    update_lookup_table ();
                else if (cmd == SCIM_TRANS_CMD_REGISTER_PROPERTIES)
                    socket_register_properties (-1);
                else if (cmd == SCIM_TRANS_CMD_UPDATE_PROPERTY)
                    socket_update_property (-1);
                else if (cmd == SCIM_TRANS_CMD_FOCUS_OUT) {
                    _last_socket_client = _current_socket_client;
                    _last_client_context = _current_client_context;
                    _current_socket_client = -1;
                    _current_client_context = 0;
                    turn_off_panel();
                    break;
                } else if (cmd == SCIM_TRANS_CMD_PANEL_SHOW_HELP)
                    show_help ();
                else if (cmd == SCIM_TRANS_CMD_PANEL_SHOW_FACTORY_MENU) {
                    show_factory_menu ();
                }
                else
                    SCIM_DEBUG_MAIN (0) << "ERROR: Unknown command: " << cmd << "\n";
            }
        } else
            SCIM_DEBUG_MAIN (0) << " Something unknow happens when processing Frontend client requests.\n";
    } else if (client_info.type == GUI_CLIENT) {
        SocketTransaction forward;
        int focused_id = -1;

        forward.put_command (SCIM_TRANS_CMD_REPLY);
        forward.get_command (cmd);

        if (_current_socket_client > 0) {
            forward.put_data (_current_client_context);
            forward.get_data (context);
            focused_id = _current_socket_client;
        } else if (_last_socket_client > 0) {
            forward.put_data (_last_client_context);
            forward.get_data (context);
            focused_id = _last_socket_client;
        }

        while (_receive_transaction.get_command (cmd)) {
            if (cmd == SCIM_TRANS_CMD_COMMIT_STRING) {
                String str;
                if (_receive_transaction.get_data (str)) {
                    forward.put_command (cmd);
                    forward.put_data (str);
                }
            } else if (cmd == SCIM_TRANS_CMD_FORWARD_KEY_EVENT ||
                       cmd == SCIM_TRANS_CMD_PROCESS_KEY_EVENT) {
                KeyEvent key;
                if (_receive_transaction.get_data (key)) {
                    forward.put_command (cmd);
                    forward.put_data (key);
                }
            } else if (cmd == SCIM_TRANS_CMD_REGISTER_PROPERTIES) {
                socket_register_properties (id);
            } else if (cmd == SCIM_TRANS_CMD_UPDATE_PROPERTY) {
                socket_update_property (id);
            } else {
                SCIM_DEBUG_MAIN (0) << " Something unknow happens while processing Socket gui client requests.\n";
            }
        }

        if (focused_id > 0 && forward.get_data_type () != SCIM_TRANS_DATA_UNKNOWN) {
            Socket focused (focused_id);
            forward.write_to_socket (focused);
        }
    }

    // Send the reply only if necessary.
    if (_send_transaction.get_data_type () != SCIM_TRANS_DATA_UNKNOWN)
        _send_transaction.write_to_socket (client);
}

void SocketServerThread::ExceptionHandler( SocketServer *server, const Socket &client ) {
    SCIM_DEBUG_MAIN (2) << "  Exception occurred on client " << client.get_id () << " ...\n";

    SocketCloseConnection(server, client);
}

void SocketServerThread::update_preedit_string() {
    SCIM_DEBUG_MAIN (1) << "  socket_update_preedit_string...\n";
    String str;
    AttributeList attrs;

    if (_receive_transaction.get_data (str) &&
            _receive_transaction.get_data (attrs)) {
        kapp->lock();
        emit( updatePreeditStringReq( QString::fromUtf8( str.c_str() ), attrs ) );
        kapp->unlock();
    }
}

void SocketServerThread::update_spot_location () {
    uint32 x, y;

    if (_receive_transaction.get_data_type () == SCIM_TRANS_DATA_UINT32 &&
            _receive_transaction.get_data (x) &&
            _receive_transaction.get_data_type () == SCIM_TRANS_DATA_UINT32 &&
            _receive_transaction.get_data (y)) {
        kapp->lock();
        emit( updateSpotLocationReq( (int)x, (int)y ) );
        kapp->unlock();
    }
}

void SocketServerThread::socket_update_property (int client) {
    
    SCIM_DEBUG_MAIN (2) << "  socket_update_property on client\n";

    Property property;

    if (_receive_transaction.get_data (property)) {
        kapp->lock();
        emit updateProperty(property, client);
        kapp->unlock();
    }
}

void SocketServerThread::socket_register_properties (int client) {
    SCIM_DEBUG_MAIN (1) << "  Register properties...\n";

    PropertyList properties;

    if (_receive_transaction.get_data (properties)) {
        kapp->lock();
        emit registerProperties(properties, client);
        kapp->unlock();
    }
}

void SocketServerThread::show_preedit_string () {
    SCIM_DEBUG_MAIN (1) << "  Show preedit string...\n";
    kapp->lock();
    emit( showPreeditStringReq() );
    kapp->unlock();
}

void SocketServerThread::show_aux_string () {
    SCIM_DEBUG_MAIN (1) << "  Show aux string...\n";
    kapp->lock();
    emit( showAuxStringReq() );
    kapp->unlock();
}

void SocketServerThread::show_lookup_table () {
    SCIM_DEBUG_MAIN (1) << "  Show lookup table...\n";
    kapp->lock();
    emit( showLookupTableReq() );
    kapp->unlock();
}

void SocketServerThread::turn_on_panel () {
    SCIM_DEBUG_MAIN (1) << "  Turn on panel...\n";
    kapp->lock();
    emit( turnOnPanelReq() );
    kapp->unlock();
}

void SocketServerThread::hide_preedit_string () {
    SCIM_DEBUG_MAIN (1) << "  Hide preedit string...\n";
    kapp->lock();
    emit( hidePreeditStringReq() );
    kapp->unlock();
}

void SocketServerThread::hide_aux_string () {
    SCIM_DEBUG_MAIN (1) << "  Hide aux string...\n";
    kapp->lock();
    emit( hideAuxStringReq() );
    kapp->unlock();
}

void SocketServerThread::hide_lookup_table () {
    SCIM_DEBUG_MAIN (1) << "  Hide lookup table...\n";
    kapp->lock();
    emit( hideLookupTableReq() );
    kapp->unlock();
}

void SocketServerThread::turn_off_panel() {
    SCIM_DEBUG_MAIN (1) << "  socket_turn_off...\n";
    kapp->lock();
    emit( turnOffPanelReq() );
    kapp->unlock();
}
void SocketServerThread::update_display () {
    SCIM_DEBUG_MAIN (1) << "  socket_update_display...\n";

    String name;

    if (_receive_transaction.get_data_type () == SCIM_TRANS_DATA_STRING &&
            _receive_transaction.get_data (name)) {
        kapp->lock();
        emit(updateDisplayReq( QString::fromLatin1( name.c_str() ) ) );
        kapp->unlock();
    }
}

void SocketServerThread::update_screen () {
    SCIM_DEBUG_MAIN (1) << "  socket_update_screen...\n";

    uint32 number;

    if (_receive_transaction.get_data_type () == SCIM_TRANS_DATA_UINT32 &&
            _receive_transaction.get_data (number)) {
        kapp->lock();
        emit( updateScreenReq( number ) );
        kapp->unlock();
    }
}
void SocketServerThread::update_factory_info () {
    SCIM_DEBUG_MAIN (1) << "  socket_update_factory_info...\n";

    String name;
    String iconfile;

    if (_receive_transaction.get_data_type () == SCIM_TRANS_DATA_STRING &&
            _receive_transaction.get_data (name) &&
            _receive_transaction.get_data_type () == SCIM_TRANS_DATA_STRING &&
            _receive_transaction.get_data (iconfile)) {
        QString qname = QString::fromUtf8( name.c_str() );
        QString icon = QString::fromUtf8( iconfile.c_str() );
        kapp->lock();
        emit( updateFactoryInfoReq( qname, icon ) );
        kapp->unlock();
    }
}

void SocketServerThread::show_help () {
    SCIM_DEBUG_MAIN (1) << "  socket_show_help...\n";

    String help;
    if (_receive_transaction.get_data_type () == SCIM_TRANS_DATA_STRING &&
            _receive_transaction.get_data (help)) {
        kapp->lock();
        emit( showHelp( QString::fromUtf8( help.c_str() ) ) );
        kapp->unlock();
    }
}

void SocketServerThread::show_factory_menu () {
    SCIM_DEBUG_MAIN (1) << "  socket_show_factory_menu...\n";

    std::vector <String> names;
    std::vector <String> uuids;
    std::vector <String> langs;
    std::vector <String> icons;

    String name;
    String uuid;
    String lang;
    String icon;

    while (_receive_transaction.get_data_type () == SCIM_TRANS_DATA_STRING &&
            _receive_transaction.get_data (uuid) &&
            _receive_transaction.get_data_type () == SCIM_TRANS_DATA_STRING &&
            _receive_transaction.get_data (name) &&
            _receive_transaction.get_data_type () == SCIM_TRANS_DATA_STRING &&
            _receive_transaction.get_data (lang) &&
            _receive_transaction.get_data_type () == SCIM_TRANS_DATA_STRING &&
            _receive_transaction.get_data (icon)) {
        uuids.push_back (uuid);
        names.push_back (name);
        langs.push_back (scim_get_normalized_language (lang));
        icons.push_back (icon);
    }

    if(uuids.size()) {
        kapp->lock();
        emit( showFactoryMenu( uuids, names, langs, icons ) );
        kapp->unlock();
    }
}

void SocketServerThread::update_preedit_caret () {
    SCIM_DEBUG_MAIN (1) << "  Update preedit caret...\n";

    uint32 caret;

    if (_receive_transaction.get_data_type () == SCIM_TRANS_DATA_UINT32 &&
            _receive_transaction.get_data (caret)) {
        kapp->lock();
        emit( updatePreeditCaretReq( (int)caret ) );
        kapp->unlock();
    }
}

void SocketServerThread::update_aux_string () {
    SCIM_DEBUG_MAIN (1) << "  Update aux string...\n";

    String str;
    AttributeList attrs;

    if (_receive_transaction.get_data (str) &&
            _receive_transaction.get_data (attrs)) {
        kapp->lock();
        emit( updateAuxStringReq( QString::fromUtf8(str.c_str()), attrs ) );
        kapp->unlock();
    }
}

void SocketServerThread::update_lookup_table () {
    SCIM_DEBUG_MAIN (1) << "  Update lookup table...\n";

    CommonLookupTable table;
    if (_receive_transaction.get_data_type () == SCIM_TRANS_DATA_LOOKUP_TABLE &&
            _receive_transaction.get_data (table)) {
        size_t i;
        size_t item_num = table.get_current_page_size ();

        String         mbs;
        WideString     wcs, label;
        AttributeList  attrs;
        QValueList<AttributeList> attrslist;
        QStringList    items, labels;
        for (i = 0; i < SCIM_LOOKUP_TABLE_MAX_PAGESIZE; ++ i) {
            if (i < item_num) {
                mbs = String ();

                wcs = table.get_candidate_in_current_page (i);

                label =  table.get_candidate_label (i);

                labels <<  QString::fromUtf8( utf8_wcstombs (label).c_str() );

                mbs = utf8_wcstombs (wcs);

                // Update attributes;
                attrs = table.get_attributes_in_current_page (i);
                attrslist.push_back(attrs);
                items << QString::fromUtf8( mbs.c_str() );
            }
        }

        kapp->lock();
        emit( updateLookupTableReq( labels, items, attrslist, 
            table.is_cursor_visible () ? table.get_cursor_pos_in_current_page () : -1,
            table.get_current_page_start (), table.number_of_candidates (), item_num ) );
        kapp->unlock();
        if ( item_num < (uint)table.get_current_page_size ()) {
            _send_transaction.put_command (SCIM_TRANS_CMD_UPDATE_LOOKUP_TABLE_PAGE_SIZE);
            _send_transaction.put_data ((uint32) item_num);
        }
    }
}
void SocketServerThread::reloadScimConfig () {
    _send_transaction.clear ();
    _send_transaction.put_command (SCIM_TRANS_CMD_REPLY);
    _send_transaction.put_command (SCIM_TRANS_CMD_RELOAD_CONFIG);

    for (ClientRepository::iterator it = _client_repository.begin ();
         it != _client_repository.end (); ++it) {
        Socket client_socket (it->first);
        _send_transaction.write_to_socket (client_socket);
    }

    scim_config->reload ();
}

bool SocketServerThread::check_client_connection (const Socket &client) {
    unsigned char buf [sizeof(uint32)];

    int nbytes = client.read_with_timeout (buf, sizeof(uint32), _socket_timeout);

    if (nbytes == sizeof (uint32))
        return true;

    if (nbytes < 0) {
        SCIM_DEBUG_MAIN (4) << "   Error occurred when reading socket (" << client.get_id ()
        << "):" << client.get_error_message () << "\n";
    } else {
        SCIM_DEBUG_MAIN (4) << "   Timeout when reading socket (" << client.get_id ()
        << ").\n";
    }

    return false;
}

SocketServerThread::~SocketServerThread () {
    scim_config.reset ();

    if (config_module) {
        SCIM_DEBUG_FRONTEND(2) << " Deleting _config_module...\n";
        delete config_module;
        config_module = 0;
    }
}

void SocketServerThread::Disconnect () {
    SCIM_DEBUG_MAIN (1) << "  Closing all client...\n";

    _send_transaction.clear ();
    _send_transaction.put_command (SCIM_TRANS_CMD_REPLY);
    _send_transaction.put_command (SCIM_TRANS_CMD_EXIT);

    for (ClientRepository::iterator it = _client_repository.begin ();
         it != _client_repository.end (); ++it) {
        Socket client_socket (it->first);
        _send_transaction.write_to_socket (client_socket);
    }
}

void SocketServerThread::shutdown () {
    _should_exit = true;

    SocketClient  client;
    SCIM_DEBUG_MAIN (1) << "shuting down...\n";

    if (client.connect (SocketAddress (_socket_address))) {
        client.close ();
    }
}

void SocketServerThread::selectLookupTableItem(int item) {
    int client;
    uint32 context;

    if (_current_socket_client >= 0) {
        client = _current_socket_client;
        context = _current_client_context;
    } else {
        client = _last_socket_client;
        context = _last_client_context;
    }

    if (client >= 0) {
        Socket client_socket (client);
        _send_transaction.clear ();
        _send_transaction.put_command (SCIM_TRANS_CMD_REPLY);
        _send_transaction.put_data ((uint32) context);
        _send_transaction.put_command (SCIM_TRANS_CMD_SELECT_CANDIDATE);
        _send_transaction.put_data ((uint32)item);
        _send_transaction.write_to_socket (client_socket);
    }
}

void SocketServerThread::lookupTablePageDown() {
    int client;
    uint32 context;

    if (_current_socket_client >= 0) {
        client = _current_socket_client;
        context = _current_client_context;
    } else {
        client = _last_socket_client;
        context = _last_client_context;
    }

    if (client >= 0) {
        Socket client_socket (client);
        _send_transaction.clear ();
        _send_transaction.put_command (SCIM_TRANS_CMD_REPLY);
        _send_transaction.put_data ((uint32) context);
        _send_transaction.put_command (SCIM_TRANS_CMD_LOOKUP_TABLE_PAGE_DOWN);
        _send_transaction.write_to_socket (client_socket);
    }
}
void SocketServerThread::lookupTablePageUp() {
    int client;
    uint32 context;

    if (_current_socket_client >= 0) {
        client = _current_socket_client;
        context = _current_client_context;
    } else {
        client = _last_socket_client;
        context = _last_client_context;
    }

    if (client >= 0) {
        Socket client_socket (client);
        _send_transaction.clear ();
        _send_transaction.put_command (SCIM_TRANS_CMD_REPLY);
        _send_transaction.put_data ((uint32) context);
        _send_transaction.put_command (SCIM_TRANS_CMD_LOOKUP_TABLE_PAGE_UP);
        _send_transaction.write_to_socket (client_socket);
    }
}
void SocketServerThread::activateProperty(int client, const scim::String & property_key)
{
    if(client < 0) {  //this is a frontend property
      uint32 context;
  
      if (_current_socket_client >= 0) {
          client = _current_socket_client;
          context = _current_client_context;
      } else {
          client = _last_socket_client;
          context = _last_client_context;
      }
  
      if (client >= 0) {
          Socket client_socket (client);
          _send_transaction.clear ();
          _send_transaction.put_command (SCIM_TRANS_CMD_REPLY);
          _send_transaction.put_data ((uint32) context);
          _send_transaction.put_command (SCIM_TRANS_CMD_TRIGGER_PROPERTY);
          _send_transaction.put_data (property_key);
          _send_transaction.write_to_socket (client_socket);
      }
    } else {
        Socket client_socket (client);
        _send_transaction.clear ();
        _send_transaction.put_command (SCIM_TRANS_CMD_REPLY);
        _send_transaction.put_command (SCIM_TRANS_CMD_TRIGGER_PROPERTY);
        _send_transaction.put_data (property_key);

//FIXME
// #if GDK_MULTIHEAD_SAFE
//         _send_transaction.put_data (String (gdk_display_get_name (_current_display)));
//         _send_transaction.put_data ((uint32) gdk_screen_get_number (_current_screen));
// #endif

        _send_transaction.write_to_socket (client_socket);
    }
}
void SocketServerThread::getFactoryList() {
    int client;
    uint32 context;

    if (_current_socket_client >= 0) {
        client = _current_socket_client;
        context = _current_client_context;
    } else {
        client = _last_socket_client;
        context = _last_client_context;
    }

    if (client >= 0) {
        Socket client_socket (client);
        _send_transaction.clear ();
        _send_transaction.put_command (SCIM_TRANS_CMD_REPLY);
        _send_transaction.put_data ((uint32) context);
        _send_transaction.put_command (SCIM_TRANS_CMD_PANEL_REQUEST_FACTORY_MENU);
        _send_transaction.write_to_socket (client_socket);
    }
}

void SocketServerThread::changeFactory(const QString &uuid) {
    int client;
    uint32 context;

    if (_current_socket_client >= 0) {
        client = _current_socket_client;
        context = _current_client_context;
    } else {
        client = _last_socket_client;
        context = _last_client_context;
    }

    if (client >= 0) {
        Socket client_socket (client);
        _send_transaction.clear ();
        _send_transaction.put_command (SCIM_TRANS_CMD_REPLY);
        _send_transaction.put_data ((uint32) context);
        _send_transaction.put_command (SCIM_TRANS_CMD_PANEL_CHANGE_FACTORY);
        _send_transaction.put_data (String(uuid.latin1()));
        _send_transaction.write_to_socket (client_socket);
    }
}

void SocketServerThread::getHelp() {
    int client;
    uint32 context;

    if (_current_socket_client >= 0) {
        client = _current_socket_client;
        context = _current_client_context;
    } else {
        client = _last_socket_client;
        context = _last_client_context;
    }

    if (client >= 0) {
        Socket client_socket (client);
        _send_transaction.clear ();
        _send_transaction.put_command (SCIM_TRANS_CMD_REPLY);
        _send_transaction.put_data ((uint32) context);
        _send_transaction.put_command (SCIM_TRANS_CMD_PANEL_REQUEST_HELP);
        _send_transaction.write_to_socket (client_socket);
    }
}

