ToyRepeatedActionScheduler.cpp 5.79 KB
//
//  ToyRepeatedActionScheduler.cpp
//  SteveMaggieCpp
//
//  Created by Katarzyna Kalinowska-Górska on 27.05.2017.
//
//

#include <stdio.h>
#include "ToyRepeatedActionScheduler.h"
#include "ToyActionParser.h"
#include "ToyJSONParseUtils.h"
#include "ToyMiscUtils.h"
#include "ToyValueStorage.h"

void ToyRepeatedActionScheduler::clearAllScheduledActions(ActionParseDelegate* parseDelegate)
{
    for(auto pair : _scheduledActionsData){
        parseDelegate->unschedule(pair.second.callbackKey);
        ToyValueStorage::getInstance().removeStoredValue(pair.second.storedValueKey, parseDelegate->getToyValueStorageContainerName());
    }
    
    _scheduledActionsData.clear();
    _waitingFunctions.clear();
}

//todo write all the stuff we can put to the repeated saction e.g. stpCondition (??)
cocos2d::Action* ToyRepeatedActionScheduler::scheduleActionIfNeeded(const rapidjson::Value& jsonActionObject, ActionParseDelegate* parseDelegate, bool notifyDelegateWhenFinished){

    // if given action is a repeated action and it is not already scheduled
    if(this->isActionValidRepeatedAction(jsonActionObject)){
    
        std::string actionTag = jsonActionObject["repeatActionTag"].GetString();
        if(_scheduledActionsData.find(actionTag) == _scheduledActionsData.end()){
            
            auto storedValueKey = ToyValueStorage::getInstance().storeValue(jsonActionObject, parseDelegate->getToyValueStorageContainerName());
        
            auto repeatedFunction = [&](float dt, std::string pStoredValueKey, ActionParseDelegate* pParseDelegate, bool pNotifyDelegate){
                
                auto& actionParser = ToyActionParser::getInstance();
                auto storedJsonActionObject = ToyValueStorage::getInstance().getStoredValue(pStoredValueKey, pParseDelegate->getToyValueStorageContainerName());
                
                std::string stopCondition;
                if(ToyJSONParseUtils::hasMemberBool(*storedJsonActionObject, "stopCondition")){
                    stopCondition = ToyMiscUtils::boolToString((*storedJsonActionObject)["stopCondition"].GetBool());
                } else {
                    stopCondition = (*storedJsonActionObject)["stopCondition"].GetString();
                }
                
                std::string repeatActionTag = (*storedJsonActionObject)["repeatActionTag"].GetString();
                
                if(actionParser.checkCondition(stopCondition, pParseDelegate) == true){
                    pParseDelegate->unschedule(repeatActionTag);
                    _scheduledActionsData.erase(repeatActionTag);
                    ToyValueStorage::getInstance().removeStoredValue(pStoredValueKey, pParseDelegate->getToyValueStorageContainerName());
                
                } else {
                
                    auto repeatIntervalSeconds = (*storedJsonActionObject)["repeatIntervalSeconds"].GetFloat();
                    auto repeatTimeSinceUserInteraction = (*storedJsonActionObject)["repeatTimeSinceUserInteraction"].GetFloat();
                
                    auto now = cocos2d::utils::getTimeInMilliseconds();
                    auto timeSinceLastRun = _scheduledActionsData[repeatActionTag].lastTimeRun == -1 ? repeatIntervalSeconds + 1 : (now - _scheduledActionsData[repeatActionTag].lastTimeRun)/1000;

                    auto lastTouchTime = pParseDelegate->getLastScreenTouchTime();
                    auto timeSinceLastUserTouch = lastTouchTime == -1 ? repeatIntervalSeconds + 1 : (now - lastTouchTime)/1000.0;

                    if(_scheduledActionsData.find(repeatActionTag) != _scheduledActionsData.end() && (timeSinceLastRun >= repeatIntervalSeconds && timeSinceLastUserTouch >= repeatTimeSinceUserInteraction)){
                    
                        actionParser.parseAndRunAction(*storedJsonActionObject, pParseDelegate, pNotifyDelegate);
                        
                        if(_scheduledActionsData.find(repeatActionTag) != _scheduledActionsData.end()){
                             _scheduledActionsData[repeatActionTag].lastTimeRun = now;
                        }
                         
                    }
                }
            };
            
            std::function<void(float)> boundRepeatedFunction = std::bind(repeatedFunction, std::placeholders::_1, storedValueKey, parseDelegate, notifyDelegateWhenFinished);
            
            _waitingFunctions.insert({actionTag, boundRepeatedFunction});
            
            auto actionFunction = [&](std::string pStoredValueKey, std::string pActionTag, ActionParseDelegate* pParseDelegate){
//                log("scheduling repeated funciton");
                ScheduledActionsData data;
                data.lastTimeRun = -1;
                data.callbackKey = pActionTag;
                data.storedValueKey = pStoredValueKey;
                _scheduledActionsData[pActionTag] = data;
                if(_waitingFunctions.find(pActionTag) != _waitingFunctions.end()){
                    auto pRepeatedFunction = _waitingFunctions.at(pActionTag);
                    pParseDelegate->schedule(pRepeatedFunction, pActionTag, 1);
                    _waitingFunctions.erase(pActionTag);
                }
            };
            
            return ToyActionParser::getInstance().embedFunctionInAction(std::bind(actionFunction, storedValueKey, actionTag, parseDelegate), jsonActionObject, parseDelegate, notifyDelegateWhenFinished);
            
        }
    }
    
    return NULL;
}

bool ToyRepeatedActionScheduler::isActionValidRepeatedAction(const rapidjson::Value& jsonActionObject)
{ //todo maybe introduce such method to all parsed actions
    return ToyJSONParseUtils::checkMemberBool(jsonActionObject, "repeat", true) && ToyJSONParseUtils::hasMemberFloat(jsonActionObject, "repeatIntervalSeconds") && ToyJSONParseUtils::hasMemberString(jsonActionObject, "repeatActionTag");
}