void onSharedSuccess(const std::string& message)
    {
        LuaStack* stack = LUAENGINE->getLuaStack();

        LuaValueDict dict;
        dict.insert(std::make_pair("name", LuaValue::stringValue("onSharedSuccess")));
        dict.insert(std::make_pair("data", LuaValue::stringValue(message)));
        stack->pushLuaValueDict(dict);
        stack->executeFunctionByHandler(mLuaHandler, 1);
    }
 void onGetUserInfo( const sdkbox::FBGraphUser& user ) {
     LuaStack* stack = LUAENGINE->getLuaStack();
     
     LuaValueDict dict;
     dict.insert(std::make_pair("name", LuaValue::stringValue("onGetUserInfo")));
     dict.insert(std::make_pair("data", FBGraphUserToLua(user)));
     
     stack->pushLuaValueDict(dict);
     stack->executeFunctionByHandler(mLuaHandler, 1);
 }
 void invokeLuaHandler(const char* func, const char* name) {
     LuaStack* stack = LUAENGINE->getLuaStack();
     LuaValueDict dict;
     dict.insert(std::make_pair("func", LuaValue::stringValue(func)));
     if (nullptr != name) {
         dict.insert(std::make_pair("name", LuaValue::stringValue(name)));
     }
     stack->pushLuaValueDict(dict);
     stack->executeFunctionByHandler(mLuaHandler, 1);
 }
    void onSharedCancel()
    {
        LuaStack* stack = LUAENGINE->getLuaStack();

        LuaValueDict dict;
        dict.insert(std::make_pair("name", LuaValue::stringValue("onSharedCancel")));
        dict.insert(std::make_pair("data", LuaValue::stringValue("{}")));
        stack->pushLuaValueDict(dict);
        stack->executeFunctionByHandler(mLuaHandler, 1);
    }
    void onRestoreComplete(bool ok, const std::string& msg)
    {
        LuaStack* stack = LUAENGINE->getLuaStack();

        LuaValueDict dict;
        dict.insert(std::make_pair("event", LuaValue::stringValue("onRestoreComplete")));
        dict.insert(std::make_pair("ok", LuaValue::booleanValue(ok)));
        dict.insert(std::make_pair("msg", LuaValue::stringValue(msg)));
        stack->pushLuaValueDict(dict);
        stack->executeFunctionByHandler(mLuaHandler, 1);
    }
    void onLogin(bool isLogin, const std::string& error)
    {
        LuaStack* stack = LUAENGINE->getLuaStack();

        LuaValueDict dict;
        dict.insert(std::make_pair("name", LuaValue::stringValue("onLogin")));
        dict.insert(std::make_pair("isLoggedIn", LuaValue::booleanValue(isLogin)));
        dict.insert(std::make_pair("data", LuaValue::stringValue(error)));
        stack->pushLuaValueDict(dict);
        stack->executeFunctionByHandler(mLuaHandler, 1);
    }
 void onInviteFriendsWithInviteIdsResult(bool ok, const std::string& msg)
 {
     LuaStack* stack = LUAENGINE->getLuaStack();
     
     LuaValueDict dict;
     dict.insert(std::make_pair("name", LuaValue::stringValue("onInviteFriendsWithInviteIdsResult")));
     dict.insert(std::make_pair("ok", LuaValue::booleanValue(ok)));
     dict.insert(std::make_pair("data", LuaValue::stringValue(msg)));
     stack->pushLuaValueDict(dict);
     stack->executeFunctionByHandler(mLuaHandler, 1);
 }
    void onAPI(const std::string& tag, const std::string& jsonData)
    {
        LuaStack* stack = LUAENGINE->getLuaStack();

        LuaValueDict dict;
        dict.insert(std::make_pair("name", LuaValue::stringValue("onAPI")));
        dict.insert(std::make_pair("tag", LuaValue::stringValue(tag)));
        dict.insert(std::make_pair("data", LuaValue::stringValue(jsonData)));
        stack->pushLuaValueDict(dict);
        stack->executeFunctionByHandler(mLuaHandler, 1);
    }
    virtual void onAdAction( const std::string& ad_unit_id, const std::string& zone_place_location, sdkbox::AdActionType action_type) {
        LuaStack* stack = LUAENGINE->getLuaStack();

        LuaValueDict dict;
        dict.insert(std::make_pair("name", LuaValue::stringValue("onAdAction")));
        dict.insert(std::make_pair("ad_unit_id", LuaValue::stringValue(ad_unit_id)));
        dict.insert(std::make_pair("ad_name", LuaValue::stringValue(zone_place_location)));
        dict.insert(std::make_pair("ad_action_type", LuaValue::intValue((int)action_type)));
        stack->pushLuaValueDict(dict);
        stack->executeFunctionByHandler(mLuaHandler, 1);
    }
    virtual void onAchievementUnlockError( const std::string& achievement_name, int error_code, const std::string& error_description ) {
        LuaStack* stack = LUAENGINE->getLuaStack();

        LuaValueDict dict;
        dict.insert(std::make_pair("name", LuaValue::stringValue(__FUNCTION__)));
        dict.insert(std::make_pair("achievement_name", LuaValue::stringValue(achievement_name)));
        dict.insert(std::make_pair("error_code", LuaValue::intValue(error_code)));
        dict.insert(std::make_pair("error_description", LuaValue::stringValue(error_description)));
        stack->pushLuaValueDict(dict);
        stack->executeFunctionByHandler(mLuaHandler, 1);
    }
    virtual void onAchievementUnlocked( const std::string& achievement_name, bool newlyUnlocked ) {

        LuaStack* stack = LUAENGINE->getLuaStack();

        LuaValueDict dict;
        dict.insert(std::make_pair("name", LuaValue::stringValue("onAchievementUnlocked")));
        dict.insert(std::make_pair("achievement_name", LuaValue::stringValue(achievement_name)));
        dict.insert(std::make_pair("newlyUnlocked", LuaValue::booleanValue(newlyUnlocked)));
        stack->pushLuaValueDict(dict);
        stack->executeFunctionByHandler(mLuaHandler, 1);
    }
    void onFailToOpenInterstitial(const char *placement, const char *errorMessage) {
        LuaStack* stack = LUAENGINE->getLuaStack();
        LuaValueDict dict;

        dict.insert(std::make_pair("event", LuaValue::stringValue("onFailToOpenInterstitial")));
        dict.insert(std::make_pair("placement", LuaValue::stringValue(placement)));
        dict.insert(std::make_pair("errorMessage", LuaValue::stringValue(errorMessage)));

        stack->pushLuaValueDict(dict);
        stack->executeFunctionByHandler(mLuaHandler, 1);
    }
    void onRequestOpenURL(const char *placement, const char *URL) {
        LuaStack* stack = LUAENGINE->getLuaStack();
        LuaValueDict dict;

        dict.insert(std::make_pair("event", LuaValue::stringValue("onRequestOpenURL")));
        dict.insert(std::make_pair("placement", LuaValue::stringValue(placement)));
        dict.insert(std::make_pair("URL", LuaValue::stringValue(URL)));

        stack->pushLuaValueDict(dict);
        stack->executeFunctionByHandler(mLuaHandler, 1);
    }
    virtual void onRevealError( const std::string& reveal_name, int error_code, const std::string& error_description ) {
        LuaStack* stack = LUAENGINE->getLuaStack();

        LuaValueDict dict;
        dict.insert(std::make_pair("name", LuaValue::stringValue("onRevealError")));
        dict.insert(std::make_pair("reveal_name", LuaValue::stringValue(reveal_name)));
        dict.insert(std::make_pair("error_code", LuaValue::intValue(error_code)));
        dict.insert(std::make_pair("error_description", LuaValue::stringValue(error_description)));
        stack->pushLuaValueDict(dict);
        stack->executeFunctionByHandler(mLuaHandler, 1);
    }
    virtual void onIncrementalAchievementStep( const std::string& achievement_name, double step ) {

        LuaStack* stack = LUAENGINE->getLuaStack();

        LuaValueDict dict;
        dict.insert(std::make_pair("name", LuaValue::stringValue("onIncrementalAchievementStep")));
        dict.insert(std::make_pair("achievement_name", LuaValue::stringValue(achievement_name)));
        dict.insert(std::make_pair("step", LuaValue::floatValue(step)));
        stack->pushLuaValueDict(dict);
        stack->executeFunctionByHandler(mLuaHandler, 1);
    }
    virtual void onMyScore( const std::string& leaderboard_name, int time_span, int collection_type, long score ) {
        LuaStack* stack = LUAENGINE->getLuaStack();

        LuaValueDict dict;
        dict.insert(std::make_pair("name", LuaValue::stringValue("onMyScore")));
        dict.insert(std::make_pair("leaderboard_name", LuaValue::stringValue(leaderboard_name)));
        dict.insert(std::make_pair("time_span", LuaValue::intValue(time_span)));
        dict.insert(std::make_pair("collection_type", LuaValue::intValue(collection_type)));
        dict.insert(std::make_pair("score", LuaValue::intValue(score)));
        stack->pushLuaValueDict(dict);
        stack->executeFunctionByHandler(mLuaHandler, 1);
    }
    virtual void onGameData(const std::string& action, const std::string& name, const std::string& data, const std::string& error) {
        LuaStack* stack = LUAENGINE->getLuaStack();

        LuaValueDict dict;
        dict.insert(std::make_pair("name", LuaValue::stringValue("onGameData")));
        dict.insert(std::make_pair("action", LuaValue::stringValue(action)));
        dict.insert(std::make_pair("save_name", LuaValue::stringValue(name)));
        dict.insert(std::make_pair("data", LuaValue::stringValue(data)));
        dict.insert(std::make_pair("error", LuaValue::stringValue(error)));
        stack->pushLuaValueDict(dict);
        stack->executeFunctionByHandler(mLuaHandler, 1);
    };
    virtual void onSetStepsError( const std::string& step_name, double steps, int error_code, const std::string& error_description ) {
        LuaStack* stack = LUAENGINE->getLuaStack();

        LuaValueDict dict;
        dict.insert(std::make_pair("name", LuaValue::stringValue("onSetStepsError")));
        dict.insert(std::make_pair("step_name", LuaValue::stringValue(step_name)));
        dict.insert(std::make_pair("steps", LuaValue::floatValue(steps)));
        dict.insert(std::make_pair("error_code", LuaValue::intValue(error_code)));
        dict.insert(std::make_pair("error_description", LuaValue::stringValue(error_description)));
        stack->pushLuaValueDict(dict);
        stack->executeFunctionByHandler(mLuaHandler, 1);
    }
    void onRequestPurchase(const char *placement, const char *name, const char *productId, int quantity, const char *campaignId, const char *contentId) {
        LuaStack* stack = LUAENGINE->getLuaStack();
        LuaValueDict dict;

        dict.insert(std::make_pair("event", LuaValue::stringValue("onRequestPurchase")));
        dict.insert(std::make_pair("placement", LuaValue::stringValue(placement)));
        dict.insert(std::make_pair("name", LuaValue::stringValue(name)));
        dict.insert(std::make_pair("productId", LuaValue::stringValue(productId)));
        dict.insert(std::make_pair("quantity", LuaValue::intValue(quantity)));
        dict.insert(std::make_pair("campaignId", LuaValue::stringValue(campaignId)));
        dict.insert(std::make_pair("contentId", LuaValue::stringValue(contentId)));

        stack->pushLuaValueDict(dict);
        stack->executeFunctionByHandler(mLuaHandler, 1);
    }
    virtual void onPlayerCenteredScores( const std::string& leaderboard_name,
                                        int time_span,
                                        int collection_type,
                                        const std::string& json_with_score_entries ) {
        LuaStack* stack = LUAENGINE->getLuaStack();

        LuaValueDict dict;
        dict.insert(std::make_pair("name", LuaValue::stringValue("onPlayerCenteredScores")));
        dict.insert(std::make_pair("leaderboard_name", LuaValue::stringValue(leaderboard_name)));
        dict.insert(std::make_pair("time_span", LuaValue::intValue(time_span)));
        dict.insert(std::make_pair("collection_type", LuaValue::intValue(collection_type)));
        dict.insert(std::make_pair("json_with_score_entries", LuaValue::stringValue(json_with_score_entries)));
        stack->pushLuaValueDict(dict);
        stack->executeFunctionByHandler(mLuaHandler, 1);
    }
    virtual void onPlayerCenteredScoresError( const std::string& leaderboard_name,
                                             int time_span,
                                             int collection_type,
                                             int error_code,
                                             const std::string& error_description) {
        LuaStack* stack = LUAENGINE->getLuaStack();

        LuaValueDict dict;
        dict.insert(std::make_pair("name", LuaValue::stringValue("onPlayerCenteredScoresError")));
        dict.insert(std::make_pair("leaderboard_name", LuaValue::stringValue(leaderboard_name)));
        dict.insert(std::make_pair("time_span", LuaValue::intValue(time_span)));
        dict.insert(std::make_pair("collection_type", LuaValue::intValue(collection_type)));
        dict.insert(std::make_pair("error_code", LuaValue::intValue(error_code)));
        dict.insert(std::make_pair("error_description", LuaValue::stringValue(error_description)));
        stack->pushLuaValueDict(dict);
        stack->executeFunctionByHandler(mLuaHandler, 1);
    }
 void onRequestInvitableFriends(const sdkbox::FBInvitableFriendsInfo& invitable_friends_and_pagination ) {
     LuaStack* stack = LUAENGINE->getLuaStack();
     
     LuaValueDict dict;
     dict.insert(std::make_pair("name", LuaValue::stringValue("onRequestInvitableFriends")));
     dict.insert(std::make_pair("users", FBUserListToLua(invitable_friends_and_pagination)));
     
     LuaValueDict urls;
     urls.insert(std::make_pair("next_cursor", LuaValue::stringValue(invitable_friends_and_pagination.getNextCursor())));
     urls.insert(std::make_pair("prev_cursor", LuaValue::stringValue(invitable_friends_and_pagination.getPrevCursor())));
     urls.insert(std::make_pair("next_url", LuaValue::stringValue(invitable_friends_and_pagination.getNextURL())));
     urls.insert(std::make_pair("prev_url", LuaValue::stringValue(invitable_friends_and_pagination.getPrevURL())));
     dict.insert(std::make_pair("urls", LuaValue::dictValue(urls)));
     
     stack->pushLuaValueDict(dict);
     stack->executeFunctionByHandler(mLuaHandler, 1);
 }
    virtual void onRewardAction(
        const std::string& ad_unit_id,
        const std::string& zone_place_location,
        float reward_amount,
        bool reward_succeed) {

        LuaStack* stack = LUAENGINE->getLuaStack();

        LuaValueDict dict;
        dict.insert(std::make_pair("name", LuaValue::stringValue("onRewardAction")));
        dict.insert(std::make_pair("ad_unit_id", LuaValue::stringValue(ad_unit_id)));
        dict.insert(std::make_pair("ad_name", LuaValue::stringValue(zone_place_location)));
        dict.insert(std::make_pair("reward_amount", LuaValue::floatValue(reward_amount)));
        dict.insert(std::make_pair("reward_succeed", LuaValue::booleanValue(reward_succeed)));
        stack->pushLuaValueDict(dict);
        stack->executeFunctionByHandler(mLuaHandler, 1);

    }
    void onRequestRewards(const char *placement, std::vector<sdkbox::ValuePotionReward> rewards) {
        LuaStack* stack = LUAENGINE->getLuaStack();
        LuaValueArray array;

        for (int i = 0; i < rewards.size(); i++) {
            LuaValueDict rewardDict;
            rewardDict.insert(std::make_pair("name", LuaValue::stringValue(rewards[i].name)));
            rewardDict.insert(std::make_pair("quantity", LuaValue::intValue(rewards[i].quantity)));
            array.push_back(LuaValue::dictValue(rewardDict));
        }

        LuaValueDict dict;

        dict.insert(std::make_pair("event", LuaValue::stringValue("onRequestRewards")));
        dict.insert(std::make_pair("placement", LuaValue::stringValue(placement)));
        dict.insert(std::make_pair("rewards", LuaValue::arrayValue(array)));

        stack->pushLuaValueDict(dict);
        stack->executeFunctionByHandler(mLuaHandler, 1);
    }
    virtual void onScoreSubmitted(
        const std::string& leaderboard_name,
        long score,
        bool alltime,
        bool week,
        bool day) {

        LuaStack* stack = LUAENGINE->getLuaStack();

        LuaValueDict dict;
        dict.insert(std::make_pair("name", LuaValue::stringValue("onScoreSubmitted")));
        dict.insert(std::make_pair("leaderboard_name", LuaValue::stringValue(leaderboard_name)));
        dict.insert(std::make_pair("score", LuaValue::intValue(score)));
        dict.insert(std::make_pair("alltime_best", LuaValue::booleanValue(alltime)));
        dict.insert(std::make_pair("weekly_best", LuaValue::booleanValue(week)));
        dict.insert(std::make_pair("daily_best", LuaValue::booleanValue(day)));
        stack->pushLuaValueDict(dict);
        stack->executeFunctionByHandler(mLuaHandler, 1);

    }
    virtual void onLoadGameData(const sdkbox::SavedGameData* savedData, const std::string& error) {
        LuaStack* stack = LUAENGINE->getLuaStack();

        LuaValueDict dict;
        dict.insert(std::make_pair("name", LuaValue::stringValue("onLoadGameData")));
        dict.insert(std::make_pair("error", LuaValue::stringValue(error)));
        stack->pushLuaValueDict(dict);

        if (nullptr != savedData && 0 == error.size()) {
            lua_State* ls = stack->getLuaState();
            lua_pushstring(ls, "savedData"); /* L: table key */
            lua_newtable(ls); /* L: table key table */

            lua_pushstring(ls, "name"); /* L: table key table "name" */
            lua_pushstring(ls, savedData->name.c_str()); /* L: table key table "name" namevalue */
            lua_rawset(ls, -3); /* L: table key table */

            lua_pushstring(ls, "deviceName"); /* L: table key table "deviceName" */
            lua_pushstring(ls, savedData->deviceName.c_str()); /* L: table key table "deviceName" deviceNameValue */
            lua_rawset(ls, -3); /* L: table key table */

            lua_pushstring(ls, "lastModifiedTimestamp"); /* L: table key table "lastModifiedTimestamp" */
            lua_pushnumber(ls, savedData->lastModifiedTimestamp); /* L: table key table "lastModifiedTimestamp" timestamp */
            lua_rawset(ls, -3); /* L: table key table */

            lua_pushstring(ls, "dataLength"); /* L: table key table "dataLength" */
            lua_pushnumber(ls, savedData->dataLength); /* L: table key table "dataLength" length */
            lua_rawset(ls, -3); /* L: table key table */

            lua_pushstring(ls, "data"); /* L: table key table "data" */
            lua_pushlstring(ls, (const char*)savedData->data, savedData->dataLength); /* L: table key table "data" datavalue */
            lua_rawset(ls, -3); /* L: table key table */

            lua_rawset(ls, -3); /* L: table*/
        }

        stack->executeFunctionByHandler(mLuaHandler, 1);
    }
int executeSpineEvent(LuaSkeletonAnimation* skeletonAnimation, int handler, spEventType eventType, int trackIndex , int loopCount = 0, spEvent* event = nullptr )
{
    if (nullptr == skeletonAnimation || 0 == handler)
        return 0;
    
    LuaStack* stack = LuaEngine::getInstance()->getLuaStack();
    if (nullptr == stack)
        return 0;
    
    lua_State* L = LuaEngine::getInstance()->getLuaStack()->getLuaState();
    if (nullptr == L)
        return 0;
    
    int ret = 0;
    
    spTrackEntry* entry = spAnimationState_getCurrent(skeletonAnimation->getState(), trackIndex);
    std::string animationName = (entry && entry->animation) ? entry->animation->name : "";
    std::string eventTypeName = "";
    
    switch (eventType) {
        case spEventType::SP_ANIMATION_START:
            {
                eventTypeName = "start";
            }
            break;
        case spEventType::SP_ANIMATION_END:
            {
                eventTypeName = "end";
            }
            break;
        case spEventType::SP_ANIMATION_COMPLETE:
            {
                eventTypeName = "complete";
            }
            break;
        case spEventType::SP_ANIMATION_EVENT:
            {
                eventTypeName = "event";
            }
            break;
            
        default:
            break;
    }
    
    LuaValueDict spineEvent;
    spineEvent.insert(spineEvent.end(), LuaValueDict::value_type("type", LuaValue::stringValue(eventTypeName)));
    spineEvent.insert(spineEvent.end(), LuaValueDict::value_type("trackIndex", LuaValue::intValue(trackIndex)));
    spineEvent.insert(spineEvent.end(), LuaValueDict::value_type("animation", LuaValue::stringValue(animationName)));
    spineEvent.insert(spineEvent.end(), LuaValueDict::value_type("loopCount", LuaValue::intValue(loopCount)));
    
    if (nullptr != event)
    {
        LuaValueDict eventData;
        eventData.insert(eventData.end(), LuaValueDict::value_type("name", LuaValue::stringValue(event->data->name)));
        eventData.insert(eventData.end(), LuaValueDict::value_type("intValue", LuaValue::intValue(event->intValue)));
        eventData.insert(eventData.end(), LuaValueDict::value_type("floatValue", LuaValue::floatValue(event->floatValue)));
        eventData.insert(eventData.end(), LuaValueDict::value_type("stringValue", LuaValue::stringValue(event->stringValue)));
        spineEvent.insert(spineEvent.end(), LuaValueDict::value_type("eventData", LuaValue::dictValue(eventData)));
    }
    
    stack->pushLuaValueDict(spineEvent);
    ret = stack->executeFunctionByHandler(handler, 1);
    return ret;
}
static int SendSpineEventToLua(int nHandler, spine::SkeletonAnimation* node, int trackIndex, spEventType type, spEvent* event, int loopCount)
{
    if (nHandler <= 0) {
        return 0;
    }

    if (NULL == ScriptEngineManager::getInstance()->getScriptEngine()) {
        return 0;
    }

    LuaStack *pStack = LuaEngine::getInstance()->getLuaStack();
    if (NULL == pStack) {
        return 0;
    }

    lua_State *tolua_s = pStack->getLuaState();
    if (NULL == tolua_s) {
        return 0;
    }

    int nRet = 0;

	spTrackEntry* entry = spAnimationState_getCurrent(node->state, trackIndex);
	std::string animationName = (entry && entry->animation) ? entry->animation->name : "";
	std::string eventType = "";

	switch (type) {
	case ANIMATION_START:
		eventType = "start";
		break;
	case ANIMATION_END:
		eventType = "end";
		break;
	case ANIMATION_COMPLETE:
		eventType = "complete";
		break;
	case ANIMATION_EVENT:
		eventType = "event";
		break;
	}

	LuaValueDict spineEvent;
	spineEvent.insert(spineEvent.end(), LuaValueDict::value_type("type", LuaValue::stringValue(eventType)));
	spineEvent.insert(spineEvent.end(), LuaValueDict::value_type("trackIndex", LuaValue::intValue(trackIndex)));
	spineEvent.insert(spineEvent.end(), LuaValueDict::value_type("animation", LuaValue::stringValue(animationName)));
	spineEvent.insert(spineEvent.end(), LuaValueDict::value_type("loopCount", LuaValue::intValue(loopCount)));

	if (NULL != event) {
		LuaValueDict eventData;
		eventData.insert(eventData.end(), LuaValueDict::value_type("name", LuaValue::stringValue(event->data->name)));
		eventData.insert(eventData.end(), LuaValueDict::value_type("intValue", LuaValue::intValue(event->intValue)));
		eventData.insert(eventData.end(), LuaValueDict::value_type("floatValue", LuaValue::floatValue(event->floatValue)));
		eventData.insert(eventData.end(), LuaValueDict::value_type("stringValue", LuaValue::stringValue(event->stringValue)));
		spineEvent.insert(spineEvent.end(), LuaValueDict::value_type("eventData", LuaValue::dictValue(eventData)));
	}

	pStack->pushLuaValueDict(spineEvent);
    nRet = pStack->executeFunctionByHandler(nHandler, 1);
    pStack->clean();
    return nRet;

}