int LuaEngine::executeAccelerometerEvent(Node* pNode, Acceleration* pAccelerationValue)
{
    CCScriptEventListenersForEvent *listeners = getListeners(pNode, ACCELERATE_EVENT);
    if (!listeners) return 1;
    
    _stack->clean();
    LuaValueDict event;
    event["name"] = LuaValue::stringValue("changed");
    event["x"] = LuaValue::floatValue(pAccelerationValue->x);
    event["y"] = LuaValue::floatValue(pAccelerationValue->y);
    event["z"] = LuaValue::floatValue(pAccelerationValue->z);
    event["timestamp"] = LuaValue::floatValue(pAccelerationValue->timestamp);
    
    _stack->pushLuaValueDict(event);
    bool flagNeedClean = false;
    for (auto it=listeners->begin(); it!=listeners->end(); ++it) {
        if ((*it)->removed) {
            flagNeedClean = true;
            continue;
        }
        _stack->copyValue(1);
        _stack->executeFunctionByHandler((*it)->listener, 1);
        _stack->settop(1);
    }
    cleanListeners(listeners, pNode, flagNeedClean);
    return 0;
}
int LuaEngine::executeNodeEvent(Node* pNode, int nAction)
{
    CCScriptEventListenersForEvent *listeners = getListeners(pNode, NODE_EVENT);
    if (!listeners) return 1;
    
    LuaValueDict event;
    switch (nAction)
    {
        case kNodeOnEnter:
            event["name"] = LuaValue::stringValue("enter");
            break;
            
        case kNodeOnExit:
            event["name"] = LuaValue::stringValue("exit");
            break;
            
        case kNodeOnEnterTransitionDidFinish:
            event["name"] = LuaValue::stringValue("enterTransitionFinish");
            break;
            
        case kNodeOnExitTransitionDidStart:
            event["name"] = LuaValue::stringValue("exitTransitionStart");
            break;
            
        case kNodeOnCleanup:
            event["name"] = LuaValue::stringValue("cleanup");
            break;
            
        default:
            return 0;
    }
    
    _stack->clean();
    _stack->pushLuaValueDict(event);
    bool flagNeedClean = false;
    for (auto it=listeners->begin(); it!=listeners->end(); ++it)
    {
        if ((*it)->removed) {
            flagNeedClean = true;
            continue;
        }
        
        _stack->copyValue(1);
        _stack->executeFunctionByHandler((*it)->listener, 1);
        _stack->settop(1);
    }
    cleanListeners(listeners, pNode, flagNeedClean);
    _stack->clean();
    return 0;
}
int LuaEngine::executeNodeEnterFrameEvent(Node* pNode, float dt)
{
    CCScriptEventListenersForEvent *listeners = getListeners(pNode, NODE_ENTER_FRAME_EVENT);
    if (!listeners) return 1;
    
    bool flagNeedClean = false;
    for (auto it=listeners->begin(); it!=listeners->end(); ++it) {
        if ((*it)->removed) {
            flagNeedClean = true;
            continue;
        }
        _stack->pushFloat(dt);
        _stack->executeFunctionByHandler((*it)->listener, 1);
        _stack->clean();
    }
    cleanListeners(listeners, pNode, flagNeedClean);
    return 0;
}
int LuaEngine::executeKeypadEvent(Node* pNode, int eventType)
{
    CCScriptEventListenersForEvent *listeners = getListeners(pNode, KEYPAD_EVENT);
    if (!listeners) return 1;
    
    _stack->clean();
    LuaValueDict event;
    event["name"] = LuaValue::stringValue("clicked");
    switch (eventType)
    {
        case (int)EventKeyboard::KeyCode::KEY_BACK:
            event["key"] = LuaValue::stringValue("back");
            break;
            
        case (int)EventKeyboard::KeyCode::KEY_MENU:
            event["key"] = LuaValue::stringValue("menu");
            break;
            
        default:
            event["key"] = LuaValue::intValue(eventType);
            break;
    }
    
    _stack->pushLuaValueDict(event);
    bool flagNeedClean = false;
    for (auto it=listeners->begin(); it!=listeners->end(); ++it) {
        if ((*it)->removed) {
            flagNeedClean = true;
            continue;
        }
        _stack->copyValue(1);
        _stack->executeFunctionByHandler((*it)->listener, 1);
        _stack->settop(1);
    }
    cleanListeners(listeners, pNode, flagNeedClean);
    _stack->clean();
    return 0;
}
void CCScriptEventDispatcher::cleanRemovedEvents()
{
    if (!m_scriptEventListeners) return;

    CCScriptEventListenersForEvent eventsRemoved;
    CCScriptHandlePair *p;
    auto it = m_scriptEventListeners->begin();
    for (; it != m_scriptEventListeners->end(); ++it)
    {
        p = *it;
        if (p->removed)
        {
            eventsRemoved.pushBack(p);
        }
    }
    it = eventsRemoved.begin();
    for (; it!=eventsRemoved.end(); ++it)
    {
        p = *it;
        m_scriptEventListeners->eraseObject(p);
    }
    eventsRemoved.clear();
}
static CCScriptEventListenersForEvent* getListeners(Node* pNode, int evt)
{
    CCScriptEventListenersForEvent *listeners = pNode->getScriptEventDispatcher()->getAllScriptEventListeners();
    if (!listeners) return nullptr;
    long sz = listeners->size();
    if (sz<1) return nullptr;
    CCScriptEventListenersForEvent* pls = new CCScriptEventListenersForEvent(sz);
//    pls->reserve(sz);
    if (!pls) return nullptr;
    
    CCScriptHandlePair *p;
    auto it=listeners->begin();
    for (; it!=listeners->end(); ++it) {
        p = (*it);
        if (p->event==evt) {
            pls->pushBack(*it);
        }
    }

    return pls;
}
int LuaEngine::executeNodeTouchesEvent(Node* pNode, int eventType, const std::vector<Touch*>& touches, int phase)
{
    CCScriptEventListenersForEvent *listeners = getListeners(pNode, phase == NODE_TOUCH_CAPTURING_PHASE ? NODE_TOUCH_CAPTURE_EVENT : NODE_TOUCH_EVENT);
    if (!listeners) return 1;
    
    _stack->clean();
    LuaValueDict event;
    switch (eventType)
    {
        case CCTOUCHBEGAN:
            event["name"] = LuaValue::stringValue("began");
            break;
            
        case CCTOUCHMOVED:
            event["name"] = LuaValue::stringValue("moved");
            break;
            
        case CCTOUCHENDED:
            event["name"] = LuaValue::stringValue("ended");
            break;
            
        case CCTOUCHCANCELLED:
            event["name"] = LuaValue::stringValue("cancelled");
            break;
            
        case CCTOUCHADDED:
            event["name"] = LuaValue::stringValue("added");
            break;
            
        case CCTOUCHREMOVED:
            event["name"] = LuaValue::stringValue("removed");
            break;
            
        default:
            return 0;
    }
    
    event["mode"] = LuaValue::intValue((int)Touch::DispatchMode::ALL_AT_ONCE);
    switch (phase)
    {
        case NODE_TOUCH_CAPTURING_PHASE:
            event["phase"] = LuaValue::stringValue("capturing");
            break;
            
        case NODE_TOUCH_TARGETING_PHASE:
            event["phase"] = LuaValue::stringValue("targeting");
            break;
            
        default:
            event["phase"] = LuaValue::stringValue("unknown");
    }
    
    LuaValueDict points;
    Director* pDirector = Director::getInstance();
    char touchId[16];
    for (auto touchIt = touches.begin(); touchIt != touches.end(); ++touchIt)
    {
        LuaValueDict point;
        Touch* pTouch = (Touch*)*touchIt;
        sprintf(touchId, "%d", pTouch->getID());
        point["id"] = LuaValue::stringValue(touchId);
        
        const Point pt = pDirector->convertToGL(pTouch->getLocationInView());
        point["x"] = LuaValue::floatValue(pt.x);
        point["y"] = LuaValue::floatValue(pt.y);
        const Point prev = pDirector->convertToGL(pTouch->getPreviousLocationInView());
        point["prevX"] = LuaValue::floatValue(prev.x);
        point["prevY"] = LuaValue::floatValue(prev.y);
        
        points[touchId] = LuaValue::dictValue(point);
    }
    event["points"] = LuaValue::dictValue(points);
    _stack->pushLuaValueDict(event);
    
    bool flagNeedClean = false;
    for (auto it=listeners->begin(); it!=listeners->end(); ++it)
    {
        if ((*it)->removed) {
            flagNeedClean = true;
            continue;
        }
        
        _stack->copyValue(1);
        _stack->executeFunctionByHandler((*it)->listener, 1);
        _stack->settop(1);
    }
    
    cleanListeners(listeners, pNode, flagNeedClean);
    
    _stack->clean();
    
    return 1;
}
int LuaEngine::executeNodeTouchEvent(Node* pNode, int eventType, Touch *pTouch, int phase)
{
    CCScriptEventListenersForEvent *listeners = getListeners(pNode, (phase == NODE_TOUCH_CAPTURING_PHASE) ? NODE_TOUCH_CAPTURE_EVENT : NODE_TOUCH_EVENT);
    if (!listeners) return 1;
    
    _stack->clean();
    LuaValueDict event;
    switch (eventType)
    {
        case CCTOUCHBEGAN:
            event["name"] = LuaValue::stringValue("began");
            break;
            
        case CCTOUCHMOVED:
            event["name"] = LuaValue::stringValue("moved");
            break;
            
        case CCTOUCHENDED:
            event["name"] = LuaValue::stringValue("ended");
            break;
            
        case CCTOUCHCANCELLED:
            event["name"] = LuaValue::stringValue("cancelled");
            break;
            
        default:
            CCAssert(false, "INVALID touch event");
            return 0;
    }
    
    event["mode"] = LuaValue::intValue((int)Touch::DispatchMode::ONE_BY_ONE);
    switch (phase)
    {
        case NODE_TOUCH_CAPTURING_PHASE:
            event["phase"] = LuaValue::stringValue("capturing");
            break;
            
        case NODE_TOUCH_TARGETING_PHASE:
            event["phase"] = LuaValue::stringValue("targeting");
            break;
            
        default:
            event["phase"] = LuaValue::stringValue("unknown");
    }
    
    const Point pt = Director::getInstance()->convertToGL(pTouch->getLocationInView());
    event["x"] = LuaValue::floatValue(pt.x);
    event["y"] = LuaValue::floatValue(pt.y);
    const Point prev = Director::getInstance()->convertToGL(pTouch->getPreviousLocationInView());
    event["prevX"] = LuaValue::floatValue(prev.x);
    event["prevY"] = LuaValue::floatValue(prev.y);
    
    _stack->pushLuaValueDict(event);
    int ret = 1;
    bool flagNeedClean = false;
    for (auto it=listeners->begin(); it!=listeners->end(); ++it)
    {
        if ((*it)->removed) {
            flagNeedClean = true;
            continue;
        }
        
        if (eventType == CCTOUCHBEGAN)
        {
            // enable listener when touch began
            (*it)->enabled = true;
        }
        
        if ((*it)->enabled)
        {
            _stack->copyValue(1);
            int listenerRet = _stack->executeFunctionByHandler((*it)->listener, 1);
            if (listenerRet == 0)
            {
                if (phase == NODE_TOUCH_CAPTURING_PHASE && (eventType == CCTOUCHBEGAN || eventType == CCTOUCHMOVED))
                {
                    ret = 0;
                }
                else if (phase == NODE_TOUCH_TARGETING_PHASE && eventType == CCTOUCHBEGAN)
                {
                    // if listener return false when touch began, disable this listener
                    (*it)->enabled = false;
                    ret = 0;
                }
            }
            _stack->settop(1);
        }
    }
    
    cleanListeners(listeners, pNode, flagNeedClean);
    
    //CCLOG("executeNodeTouchEvent %p, ret = %d, event = %d, phase = %d", pNode, ret, eventType, phase);
    _stack->clean();
    
    return ret;
}