/**
  * Will inject invocation code for a given function into a given piece of code.
  * Invocation code will be the instantiation of a \AppserverIo\Doppelgaenger\Entities\MethodInvocation object
  * as a basic representation of the given function
  *
  * @param string             $bucketData         Reference on the current bucket's data
  * @param FunctionDefinition $functionDefinition Definition of the function to inject invocation code into
  * @param array              $callbackChain      Chain of callbacks which is used to recursively chain calls
  *
  * @return boolean
  */
 protected function injectInvocationCode(&$bucketData, FunctionDefinition $functionDefinition, array $callbackChain)
 {
     // start building up the code
     $code = '
         ' . ReservedKeywords::METHOD_INVOCATION_OBJECT . ' = new \\AppserverIo\\Doppelgaenger\\Entities\\MethodInvocation(
         ';
     // add the original method call to the callback chain so it can be integrated, add it and add the context
     if ($functionDefinition->isStatic()) {
         $contextCode = '__CLASS__';
     } else {
         $contextCode = '$this';
     }
     // iterate the callback chain and build up the code but pop the first element as we will invoke it initially
     unset($callbackChain[0]);
     // empty chain? Add the original function at least
     if (empty($callbackChain)) {
         $callbackChain[] = array($functionDefinition->getStructureName(), $functionDefinition->getName());
     }
     $code .= '    array(';
     foreach ($callbackChain as $callback) {
         // do some brushing up for the structure
         $structure = $callback[0];
         if ($structure === $functionDefinition->getStructureName()) {
             $structure = $contextCode;
         }
         // also brush up the function call to direct to the original
         if ($callback[1] === $functionDefinition->getName()) {
             $callback[1] = $functionDefinition->getName() . ReservedKeywords::ORIGINAL_FUNCTION_SUFFIX;
         }
         $code .= 'array(' . $structure . ', \'' . $callback[1] . '\'),';
     }
     $code .= '),
     ';
     // continue with the access modifiers
     $code .= '        ' . $contextCode . ',
             ' . ($functionDefinition->isAbstract() ? 'true' : 'false') . ',
             ' . ($functionDefinition->isFinal() ? 'true' : 'false') . ',
             ' . ($functionDefinition->isStatic() ? 'true' : 'false') . ',
         ';
     // we have to build up manual parameter collection as func_get_args() only returns copies
     // @see http://php.net/manual/en/function.func-get-args.php
     $parametersCode = '    array(';
     foreach ($functionDefinition->getParameterDefinitions() as $parameterDefinition) {
         $name = $parameterDefinition->name;
         $parametersCode .= '\'' . substr($name, 1) . '\' => ' . $name . ',';
     }
     $parametersCode .= ')';
     $code .= '    \'' . $functionDefinition->getName() . '\',
         ' . $parametersCode . ',
             __CLASS__,
             \'' . $functionDefinition->getVisibility() . '\'
         );';
     // Insert the code
     $placeholder = Placeholders::FUNCTION_BEGIN . $functionDefinition->getName() . Placeholders::PLACEHOLDER_CLOSE;
     $bucketData = str_replace($placeholder, $placeholder . $code, $bucketData);
     return true;
 }