private void chooseTokenFlow(BaseElement element, Token token, boolean processElementItself) {

    if (processElementItself) {
      nextElement = element;
    } else {
      if (element.getOutFlows().size() > 1) {
        chooseFlowBasedOnPropablity(
            element,
            new IChoosenFlow() {
              @Override
              public void process(SequenceFlow flow) {
                nextElement = flow.getTarget();
              }
            });
      } else {
        nextElement = element.getOutFlows().get(0).getTarget();
      }
    }

    logger.debug("Chosen flow: " + nextElement.getName());

    if (nextElement instanceof Task) {
      Task targetTask = (Task) nextElement;
      token.task = targetTask;
      ResourceTypeVariant resourceTypeVariant = targetTask.getVariant();
      tokensWaiting.get(resourceTypeVariant).add(token);
    } else if (nextElement instanceof Gateway) {
      chooseTokenFlow(nextElement, token);
    } else if (nextElement instanceof ParallelGateway) {
      ParallelGateway parallelGateway = (ParallelGateway) nextElement;
      if (parallelGateway.isDiverging()) {
        for (SequenceFlow flow : parallelGateway.getOutFlows()) {
          MultiToken subToken = new MultiToken();
          subToken.originalToken = token;
          chooseTokenFlow(flow.getTarget(), subToken, true);
        }
      } else {
        Map<Token, Integer> arrivedTokensMap = arrivedTokens.get(parallelGateway);
        Token originalToken = ((MultiToken) token).originalToken;
        Integer arrivedTokensNumber = arrivedTokensMap.get(originalToken);
        if (arrivedTokensNumber == null) {
          arrivedTokensNumber = Integer.valueOf(0);
        }
        if (arrivedTokensNumber == parallelGateway.getInFlows().size() - 1) {
          chooseTokenFlow(parallelGateway, originalToken);
        } else {
          arrivedTokensMap.put(originalToken, arrivedTokensNumber + 1);
        }
      }
    } else if (nextElement instanceof EndEvent) {
      token.endTime = currentTime;
      tokensFinished++;
      logger.debug(
          tokensFinished
              + ". token finished at "
              + currentTime
              + " in "
              + (token.endTime - token.startTime));
    }
  }
 private void chooseFlowBasedOnPropablity(BaseElement baseElement, IChoosenFlow choosenFlowImpl) {
   int sum = 0;
   for (SequenceFlow flow : baseElement.getOutFlows()) {
     sum += flow.getPropability();
   }
   int rnd = random.nextInt(sum);
   sum = 0;
   for (SequenceFlow flow : baseElement.getOutFlows()) {
     sum += flow.getPropability();
     if (rnd < sum) {
       choosenFlowImpl.process(flow);
       return;
     }
   }
 }