/*
 * This file is part of libtqtvd_astronav
 *
 * Copyright (C) 2008-2017 TQTVD Software
 * Copyright (C) 2017 Mirakulo Software (mirakulo@mirakulo.com)
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 * 02110-1301  USA
 */


#include <kjs/wk_config.h>
#include "BALConfiguration.h"
#include "BIEventLoop.h"
#include "BIKeyboardEvent.h"
#include <graphics/IntRect.h>
#include "BIWindow.h"
#include "BIWindowEvent.h"
#include "BCWindowEvent.h"
#include <graphics/BIWindowManager.h>
#include "BIPlayerEvent.h"
#include "BIObserverService.h"
#include <graphics/BIGraphicsDevice.h>
#include "BTLogHelper.h"            /* TIME() */
#include "BTDeviceChannel.h"
#include "BTTextLogFormatter.h"
#include "FrameLoaderClientBal.h"
#include "FrameLoader.h"
#include "DocumentLoader.h"
#include "CookieJar.h"
#include "Frame.h"
#include "KURL.h"
#include "SystemTime.h"         /* currentTime() */
#include "wtf/RefPtr.h"
#include <font/FontCache.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <math.h>
//#include <execinfo.h>
#include <string>

#include "AstroNavPlayer.h"
#include "AstroKeyCodes.h"

using namespace BAL;
using namespace TQTVD::InputManager;
using namespace WebCore;

#include <Cache.h>


IGraphicManagerAdapter * g_graphicManager = NULL;
pthread_mutex_t g_mutex_1 = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t g_mutex_2 = PTHREAD_MUTEX_INITIALIZER;
pthread_t  g_threadId = 0;
bool       g_exitFlag = false;
static bool g_bInit = false;
static int refCount = 0;
static BIEventLoop* g_eventLoop = 0;

pthread_mutex_t g_mutex_exit = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t  g_cond_exit = PTHREAD_COND_INITIALIZER;

#define LOCK_A    { TQDEBUG_DEBUG("===> LOCK_A"); pthread_mutex_lock(&g_mutex_1); }
#define UNLOCK_A  { TQDEBUG_DEBUG("===> UNLOCK_A"); pthread_mutex_unlock(&g_mutex_1); }

#define LOCK_B    { TQDEBUG_DEBUG("===> LOCK_B"); pthread_mutex_lock(&g_mutex_2); }
#define UNLOCK_B  { TQDEBUG_DEBUG("===> UNLOCK_B"); pthread_mutex_unlock(&g_mutex_2); }

#define UNLOCK_B_AND_BREAK      { UNLOCK_B; break; }
#define UNLOCK_B_AND_CONTINUE   { UNLOCK_B; usleep(20000); continue; }

namespace BAL {
BIPlayerEvent* createBIPlayerEvent(BIPlayerEvent::Action action, BIPlayerPtr player, BIPlayerArgs args);
}

namespace AstroNav {

static void wait();
static void signal();

DLLEXPORT  void* handleEvent (void *p)
{
    BIEvent* aEvent = NULL;
    bool isEventValid = false;

    TQDEBUG_FUNC_IN;
    
    // Event loop
    while (true)
    {
        /***
         * Please, double check before removing the following LOCK. 
         * It is necessary to keep webkit internal state consistent, because
         * if an event is sent while a window is created or destroyed, u will
         * be in bad hands (unexpected behavior) LOL.
         * 
         * **/
        LOCK_B;
        if (g_exitFlag) {
            UNLOCK_B_AND_BREAK;
        }

        if (g_eventLoop) {
        	TQDEBUG_DEBUG("===> lets wait event");
            isEventValid = g_eventLoop->WaitEvent(aEvent);
            if (!isEventValid) {
                UNLOCK_B_AND_CONTINUE;
            }
            TQDEBUG_DEBUG("===> event pop up");
        }
        else {
            UNLOCK_B_AND_BREAK;
        }
        BIPlayerEvent* aPlayerEvent = aEvent->queryIsPlayerEvent();
        if (aPlayerEvent) {
            AstroNavPlayerPtr player = DYNAMIC_POINTER_CAST(AstroNavPlayer,
                    (IAstroNavPlayerPtr) aPlayerEvent->getPlayer());
            IAstroNavPlayerArgs *args = (IAstroNavPlayerArgs *) aPlayerEvent->getArgs();
            if (player) {
            	TQDEBUG_DEBUGF("<=== handleEvent thread player=%p", player.get());
                switch (aPlayerEvent->action()) {
                    case BIPlayerEvent::START:
                        player->play_(args);
                        break;
                    case BIPlayerEvent::STOP:
                        player->stop_();
                        break;
                }
            }
            delete aEvent;
            UNLOCK_B_AND_CONTINUE;
        }

        BIKeyboardEvent* aKeyboardEvent = aEvent->queryIsKeyboardEvent();
        if (aKeyboardEvent && aKeyboardEvent->virtualKeyCode() == BAL::BIKeyboardEvent::VK_ESCAPE) {
            delete aEvent;
            UNLOCK_B_AND_BREAK;
        }

        BIWindowEvent* aWindowEvent = aEvent->queryIsWindowEvent();
        if (aWindowEvent && aWindowEvent->type() == BAL::BIWindowEvent::QUIT) {
            delete aEvent;
            UNLOCK_B_AND_BREAK;
        }

        // In other cases, event is handled by frame
        getBIWindowManager()->handleEvent(aEvent);
        delete aEvent;
        UNLOCK_B_AND_CONTINUE;
    }

    deleteBIEventLoop();

    return NULL;
}

DLLEXPORT  AstroNavPlayer::AstroNavPlayer ( IGraphicManagerAdapter * gm,
                                    IAstroNavPlayerUpdateListenerWPtr listener,
                                    IAstroNavPlayerFileServerWPtr fileServer ,
                                    IAstroNavPlayerCoreServiceProviderWPtr coreServices ) :
                                    IAstroNavPlayer(), BIListener(),
                                    IMPLEMENT_ENABLE_SHARED_FROM_THIS(IAstroNavPlayer)
{

	TQDEBUG_FUNC_IN;

    LOCK_A;

    m_gm = gm;
    m_window = NULL;
    m_listener = listener;
    m_fileServerWrapper = new AstroNavPlayerFileServerWrapper(fileServer);
    m_coreServices = coreServices;
    m_targetSurface = m_internalSurface = NULL;
    m_width = m_height = 0;
    m_backgroundColor = 0; // default: transparent.
    m_status = STATE_READY;


    if (0 == refCount)  
    {
        LOCK_B;
        TQDEBUG_DEBUG("===> XHTMLPlayer engine initialization");

        int rc = pthread_cond_init(&g_cond_exit, (pthread_condattr_t *)NULL);
        if (rc != 0) {
        	TQDEBUG_ERROR( strerror(rc));
        }
        g_graphicManager = gm;

        if (!g_bInit) {
            m_gm = reinterpret_cast<IGraphicManagerAdapter *> ( getBIGraphicsDevice()->setSuperInterface (gm) );
            getBIGraphicsDevice()->setScreenLessMode(true);
            getBIGraphicsDevice()->initialize(1280, 720, 32);
            g_bInit = true;
        }

        getBIWindowManager();

        if(::WebCore::cookiesEnabled())
                getBICookieJar();

        if (g_eventLoop == NULL)
            g_eventLoop = getBIEventLoop();

        g_exitFlag = false;

        rc =  pthread_create(&g_threadId, NULL, &handleEvent, g_eventLoop);
        if (rc != 0) {
            TQDEBUG_ERROR( strerror(rc));
        }
        UNLOCK_B;
    }


    ++refCount;

    UNLOCK_A;
}


DLLEXPORT  AstroNavPlayer::~AstroNavPlayer ()
{
	TQDEBUG_FUNC_IN;

	if(g_exitFlag)
		return;

	LOCK_A;
	if(m_status != STATE_UNLOAD) {

		if(refCount ==0) {
			LOCK_B;
			stop_();
			UNLOCK_B;
			TQDEBUG_DEBUG("AstroNavPlayer object already unloaded.");
		} else {
			unload ();
			signal();
		}
	}
	UNLOCK_A;

}

DLLEXPORT  AstroNavPlayer::wait_func_t AstroNavPlayer::getWaitFunc()
{
    return wait;
}

static void wait()
{
	TQDEBUG_FUNC_IN;
    pthread_mutex_lock(&g_mutex_exit);
    if (0 == refCount) {
    	while (!g_exitFlag) {
    		TQDEBUG_DEBUG("Lets wait ");
    		pthread_cond_wait(&g_cond_exit, &g_mutex_exit);
    	}
    	g_exitFlag = false;
    }
    pthread_mutex_unlock(&g_mutex_exit);

}

static void signal()
{
	TQDEBUG_FUNC_IN;
    pthread_mutex_lock(&g_mutex_exit);
    if (0 == refCount) {
    	if (g_exitFlag)  {
            int rc = pthread_cond_signal(&g_cond_exit);
			if (rc != 0) {
				TQDEBUG_ERROR( strerror(rc));
			}

			rc = pthread_cond_destroy(&g_cond_exit);
			if (rc != 0) {
				TQDEBUG_ERROR( strerror(rc));
			}
    	}
    }
    pthread_mutex_unlock(&g_mutex_exit);


}

DLLEXPORT  void  AstroNavPlayer::update(void* sourceSurface, WebCore::IntRect srcRect, WebCore::IntRect targetRect)
{
   TQDEBUG_FUNC_IN;

   IGraphicManagerAdapterSurface* srcSurface = reinterpret_cast<IGraphicManagerAdapterSurface*>(sourceSurface);
   IAstroNavPlayerUpdateListenerPtr	listener = m_listener.lock();

   if ((m_status == STATE_PLAYING) && listener && m_targetSurface)
   {
       int srcX = srcRect.x();
       int srcY = srcRect.y();
       int srcW = srcRect.width();
       int srcH = srcRect.height();

       if ( targetRect.x() + srcW > m_width)
            srcW = m_width - targetRect.x();

       if ( targetRect.y() + srcH > m_height)
            srcH = m_height - targetRect.y();


       ARectangle gmSrcRect ( srcX, srcY, srcW, srcH );

       ////TQDEBUG_DEBUGF(" XHTMLPlayer::update w,h = (%d,%d)", srcW, srcH);
       ////TQDEBUG_DEBUGF(" XHTMLPlayer::update srcX, srcY = (%d,%d)", srcX, srcY);
       ////TQDEBUG_DEBUGF(" XHTMLPlayer::update targetX, targetY = (%d,%d)", targetRect.x(), targetRect.y());

       m_targetSurface->Blit( srcSurface, &gmSrcRect, targetRect.x(), targetRect.y(), 0xff );


       listener->updateCb(m_targetSurface, targetRect.x(), targetRect.y(), srcW, srcH);

   } else {
	   TQDEBUG_ERRORF("m_status = %d ", m_status);
   }

}

DLLEXPORT  IGraphicManagerAdapterSurface* AstroNavPlayer::createSurface( int width, int height )
{

    IGraphicManagerAdapterSurface *surface = NULL;

    if (m_gm)
    {
        surface = m_gm->CreateSurface( width, height, 32 );
        if (surface)
            surface->Clear (m_backgroundColor);
    }

    return surface;

}

DLLEXPORT  void AstroNavPlayer::releaseSurface( IGraphicManagerAdapterSurface* surface )
{
   if (surface)
	   m_gm->DestroySurface(surface);
}


//
//  blockling play is unsupported
//  x0,y0, w, h, are being ignored
// we paint to (0,0) and we get the h,w directly from the surface
//
DLLEXPORT void AstroNavPlayer::play(IGraphicManagerAdapterSurface * dest, std::string url, 
                                    int x0, int y0, int w, int h, std::string css)
{

	TQDEBUG_FUNC_IN;
	TQDEBUG_DEBUGF("===> XHTMLPlayer::play() surface=%p url='%s' css='%s' (x0,y0,w,h)=(%d,%d,%d,%d) ", dest, url.c_str(), css.c_str(), x0, y0, w, h);

    IAstroNavPlayerArgs *args = new IAstroNavPlayerArgs(dest, url , x0 , y0, w , h, css);
    IAstroNavPlayerPtr thiz = SHARED_FROM_THIS();
    if (g_eventLoop)
        g_eventLoop->PushEvent(createBIPlayerEvent(BIPlayerEvent::START, (BIPlayerPtr) thiz, (BIPlayerArgs) args));

}

void AstroNavPlayer::play_(IAstroNavPlayerArgs *args)
{
	TQDEBUG_FUNC_IN;
    if (( STATE_READY == m_status ) && ( args->dest ) && (! args->url.empty()))
    {
        m_status = STATE_NOT_READY;
        TQDEBUG_DEBUGF("===> XHTMLPlayer::play() surface=%p", args->dest);
        args->dest->GetSize(&m_width, &m_height);
        m_targetSurface = args->dest;

        m_window = (void *) getBIWindowManager()->openWindow (0, 0, m_width, m_height);
        ((BIWindow*)m_window)->setPlayer(this);

        getBIGraphicsDevice()->addUpdateListener(this);

        m_status = STATE_PLAYING;

		m_url = args->url;

        if (! args->css.empty())
            ((BIWindow*)m_window)->setURL(args->url.c_str(), args->css.c_str());
        else
            ((BIWindow*)m_window)->setURL(args->url.c_str());
    } else {
    	TQDEBUG_ERRORF("m_status = %d ", m_status);
    }

}

void AstroNavPlayer::setRect(int x, int y, int w, int h)
{
	TQDEBUG_FUNC_IN;
    if (getBIWindowManager()->activeWindow() == NULL) return;
    const BAL::BTWidget* wi = getBIWindowManager()->activeWindow()->widget();
    if (wi == NULL) return;
    BAL::BIWindowEvent* we = createBIWindowEvent(BIWindowEvent::RESIZE, false, WebCore::IntRect( x, y, w, h), wi);
    if (g_eventLoop)
        g_eventLoop->PushEvent((BAL::BIEvent*)we);

}

DLLEXPORT void AstroNavPlayer::stop ()
{
	TQDEBUG_FUNC_IN;

    IAstroNavPlayerPtr thiz = SHARED_FROM_THIS();
    if (g_eventLoop)
        g_eventLoop->PushEvent(createBIPlayerEvent(BIPlayerEvent::STOP, (BIPlayerPtr) thiz, 0));

}

DLLEXPORT void AstroNavPlayer::unload () {
	TQDEBUG_FUNC_IN;

	LOCK_A;
	if(m_fileServerWrapper)
		delete m_fileServerWrapper;

    --refCount;
    TQDEBUG_DEBUGF("refCount = %d", refCount);
    if (0 == refCount)
    {
    	g_exitFlag = true;
    	if (g_eventLoop) {
		    g_eventLoop->quit();
        }

		TQDEBUG_DEBUG("===> joing eventHandle thread");
		int rc = pthread_join(g_threadId, NULL);
        if (rc != 0) {
        	TQDEBUG_ERROR( strerror(rc));
        }
        TQDEBUG_DEBUG("eventHandle thread done");
        g_threadId = 0;

        if (g_eventLoop) {
            g_eventLoop = NULL;
        }
        stop_();

        // currently crashing.
        //BAL::BTFontCache::free_all_fonts ();

        cache()->setDisabled(true);
        cache()->setDisabled(false);

        g_graphicManager = NULL;

        getBIWindowManager()->closeAllWindows();
        deleteBIWindowManager();
        g_bInit = false;

#if 0
        getBIGraphicsDevice()->finalize();
        deleteBIGraphicsDevice();
#endif

        deleteBICookieJar(NULL);
        deleteBIObserverService();

    }
    m_status = STATE_UNLOAD;

	UNLOCK_A;
}

void AstroNavPlayer::stop_ ()
{
	TQDEBUG_FUNC_IN;

    if (m_status == STATE_PLAYING)
    {
        m_status = STATE_NOT_READY;


        getBIGraphicsDevice()->removeUpdateListener(this);

        ((BIWindow*)m_window)->mainFrame()->loader()->stopAllLoaders();
        ((BIWindow*)m_window)->mainFrame()->loader()->stopLoading(false);
        ((BIWindow*)m_window)->stop();
        // CloseURL should not be called directly, It will crash it document is not fully loaded.        
        //((BIWindow*)m_window)->mainFrame()->loader()->closeURL();
		((BIWindow*)m_window)->mainFrame()->loader()->cancelAndClear();
        ((BIWindow*)m_window)->setPlayer(NULL);
        getBIWindowManager()->closeWindow((BIWindow*)m_window);
        TQDEBUG_DEBUG("closed window.");

		m_window = NULL;

        m_targetSurface = NULL;
        m_width = m_height = 0;

        m_status = STATE_READY;

    }else{
    	TQDEBUG_ERRORF("m_status = %d ", m_status);
    }
}

DLLEXPORT  void AstroNavPlayer::setFocus(void)
{
    getBIWindowManager()->setActiveWindow((BIWindow *)m_window);
}
DLLEXPORT  bool AstroNavPlayer::hasFocus(void)
{
    return ( m_window == (void *) getBIWindowManager()->activeWindow() );
}
DLLEXPORT  void AstroNavPlayer::setBackgroundColor(RGBA32 color)
{
    getBIGraphicsDevice()->setBackgroundColor(color);
}
DLLEXPORT  RGBA32 AstroNavPlayer::getBackgroundColor(void)
{
    return getBIGraphicsDevice()->getBackgroundColor();
}
DLLEXPORT  void AstroNavPlayer::back()
{
	if (hasFocus())
	{
		m_targetSurface->Clear(m_backgroundColor);
   		((BIWindow*)m_window)->goBackOrForward(-1);
	}
}
DLLEXPORT  void AstroNavPlayer::forward()
{
	if (hasFocus())
	{
		m_targetSurface->Clear(m_backgroundColor);
   		((BIWindow*)m_window)->goBackOrForward(1);
	}
}
DLLEXPORT  void AstroNavPlayer::setURL(std::string url, std::string css)
{
	if (hasFocus())
	{
		m_url = url;
		((BIWindow*)m_window)->stop();
		m_targetSurface->Clear(m_backgroundColor);
        if (css.empty())
            ((BIWindow*)m_window)->setURL ((char *)url.c_str());
        else
            ((BIWindow*)m_window)->setURL ((char *)url.c_str(), (char *)css.c_str());
	}
}
DLLEXPORT  void AstroNavPlayer::reload()
{
	if (hasFocus())
	{
		m_targetSurface->Clear(m_backgroundColor);
		((BIWindow*)m_window)->mainFrame()->loader()->reload();
	}
}
DLLEXPORT  void AstroNavPlayer::cancel()
{
	if (hasFocus())
	{
		TQDEBUG_DEBUG("> AstroNavPlayer::cancel");
   		((BIWindow*)m_window)->mainFrame()->loader()->stopAllLoaders();
   		TQDEBUG_DEBUG("< AstroNavPlayer::cancel");
	}
}



DLLEXPORT  void AstroNavPlayer::mouseEventReceived (
	MouseButton mouseButton, MouseEventType type, int x, int y)
{
	TQDEBUG_FUNC_IN;

    BIMouseEvent* mouseEvent;
    BAL::BIMouseEvent::MouseEventType auxType = BAL::BIMouseEvent::MouseEventMoved;
    BAL::BIMouseEvent::MouseButton auxButton = BAL::BIMouseEvent::NoButton;
    bool bShiftKey  = false;
    bool bCtrlKey   = false;
    bool bAltKey    = false;
    bool bMetaKey  = false;
    int clickCount = 1;

	mouseEvent = createBIMouseEvent();

	switch (type)
	{
		case MouseEventMoved:
			auxType = BAL::BIMouseEvent::MouseEventMoved;
			break;
		case MouseEventPressed:
			auxType = BAL::BIMouseEvent::MouseEventPressed;
			break;
		case MouseEventReleased:
			auxType = BAL::BIMouseEvent::MouseEventReleased;
			break;
		case MouseEventScroll:
			auxType = BAL::BIMouseEvent::MouseEventScroll;
			break;
	}

	mouseEvent->setType(auxType);
	mouseEvent->setPos(x, y);

	switch (mouseButton)
	{
		case NoButton:
			auxButton = BAL::BIMouseEvent::NoButton;
			break;
		case LeftButton:
			auxButton = BAL::BIMouseEvent::LeftButton;
			break;
		case RightButton:
			auxButton = BAL::BIMouseEvent::RightButton;
			break;
		case MiddleButton:
			auxButton = BAL::BIMouseEvent::MiddleButton;
			break;
	}

	mouseEvent->setModifiers(auxButton, clickCount, bShiftKey, bCtrlKey, bAltKey, bMetaKey);

    if (g_eventLoop)
        g_eventLoop->PushEvent(mouseEvent);

}

DLLEXPORT  void AstroNavPlayer::rcEventReceived ( int aKeyCode)
{
    bool bIsKeyUp       = false;
    bool bShiftKey      = false;
    bool bCtrlKey       = false;
    bool bAltKey        = false;
    bool bMetaKey       = false;
    bool bAutoRepeat    = false;
    uint32_t virtualKey;
    UChar aSrc[2];

    TQDEBUG_FUNC_IN;

    if (hasFocus())
    {
        aSrc[0] = aKeyCode;
        aSrc[1] = 0;

        WebCore::String eventText(aSrc);
        WebCore::String eventUnmodifiedText(aSrc);
        WebCore::String eventKeyIdentifier;

        switch (aKeyCode)
        {
            // TODO: avanca para o hyperlink anterior.
            case IMKC_LEFT:
            case IMKC_UP:
                bShiftKey = true;
                virtualKey = BIKeyboardEvent::VK_TAB;
                eventKeyIdentifier = "Shift Tab";
                break;

            // TODO: avanca para o proximo hyperlink.
            case IMKC_RIGHT:
            case IMKC_DOWN:
//          case IMKC_TAB:
                virtualKey = BIKeyboardEvent::VK_TAB;
                eventKeyIdentifier = "Tab";
                break;

            // TODO: carrega o hyperlink que estava em foco.
            case IMKC_ENTER:
//          case IMKC_RETURN:
                virtualKey = BIKeyboardEvent::VK_RETURN;
                eventKeyIdentifier = "Enter";
                break;

            // TODO: qualquer outra tecla nao mapeda ainda.
            default:
                virtualKey = 0;
                eventKeyIdentifier = "Unknown";
                break;
        }

        if (g_eventLoop)
            g_eventLoop->PushEvent(BAL::createBIKeyboardEvent(eventText, eventUnmodifiedText, eventKeyIdentifier,
                        bIsKeyUp, bShiftKey, bCtrlKey, bAltKey, bMetaKey, bAutoRepeat, virtualKey));

        TQDEBUG_DEBUGF("XHTMLPlayer::rcEventReceived processig event VK=%d", virtualKey);

   } else {
	   TQDEBUG_DEBUG("XHTMLPlayer::rcEventReceived discarding event ");
   }

}

DLLEXPORT  void AstroNavPlayer::kbEventReceived ( int aKeyCode,  bool bShiftKey, bool bCtrlKey, bool bAltKey, bool bMetaKey)
{
    bool bIsKeyUp = false;
    bool bAutoRepeat    = false;
    uint32_t virtualKey;
    UChar aSrc[2];

    TQDEBUG_DEBUGF("==> XHTMLPlayer::kbEventReceived aKeyCode=%d", aKeyCode);

    if (hasFocus())
    {
        aSrc[0] = aKeyCode;
        aSrc[1] = 0;

        WebCore::String eventText(aSrc);
        WebCore::String eventUnmodifiedText(aSrc);
        WebCore::String eventKeyIdentifier;

	    virtualKey = aKeyCode;
	    eventKeyIdentifier = "Some Key";

        if (g_eventLoop)
            g_eventLoop->PushEvent(BAL::createBIKeyboardEvent(eventText, eventUnmodifiedText, eventKeyIdentifier,
                        bIsKeyUp, bShiftKey, bCtrlKey, bAltKey, bMetaKey, bAutoRepeat, virtualKey));

        //TQDEBUG_DEBUGF("XHTMLPlayer::kbEventReceived processig event VK=%d", virtualKey);

   } else {
       //TQDEBUG_DEBUG("XHTMLPlayer::kbEventReceived discarding event ");
   }

   //TQDEBUG_DEBUG("<== XHTMLPlayer::kbEventReceived ");
}

}


