protected LocalFactory buildLocalFactoryRecursively(
      Container container, FactoryDefinition definition) {
    LocalFactory factory = null;

    try {
      List<LocalFactory> argumentFactories =
          buildLocalFactories(container, definition.getInstantiationArgFactories());

      // todo get this from castings in factory definition. Casting will
      // force a specific return type.
      Class<?>[] forcedArgumentTypes = getForcedArgumentTypes(argumentFactories, definition);

      if (definition.isConstructorFactory()) { // constructor factory
        factory =
            builder.createConstructorFactory(
                definition.getIdentifierOwnerClass(), argumentFactories, forcedArgumentTypes);
      } else if (definition.isStaticMethodFactory()) {
        // method invocation factory
        factory =
            builder.createStaticMethodFactory(
                definition.getIdentifier(),
                definition.getIdentifierOwnerClass(),
                argumentFactories,
                forcedArgumentTypes);
      } else if (definition.isInstanceMethodFactory()) {
        LocalFactory methodInvocationTargetFactory =
            buildLocalFactoryRecursively(container, definition.getIdentifierTargetFactory());
        factory =
            builder.createInstanceMethodFactory(
                definition.getIdentifier(),
                methodInvocationTargetFactory,
                argumentFactories,
                forcedArgumentTypes);
      } else if (definition.isInstanceFieldFactory()) {
        LocalFactory fieldTargetFactory =
            buildLocalFactoryRecursively(container, definition.getIdentifierTargetFactory());
        factory = builder.createFieldFactory(definition.getIdentifier(), fieldTargetFactory);
      } else if (definition.isStaticFieldFactory()) {
        factory =
            builder.createFieldFactory(
                definition.getIdentifier(), definition.getIdentifierOwnerClass());
      } else if (definition.isInstanceFieldAssignmentFactory()) {
        LocalFactory assignmentTargetFactory =
            buildLocalFactoryRecursively(container, definition.getIdentifierTargetFactory());
        factory =
            builder.createFieldAssignmentFactory(
                definition.getIdentifier(), assignmentTargetFactory, argumentFactories.get(0));
      } else if (definition.isStaticFieldAssignmentFactory()) {
        factory =
            builder.createFieldAssignmentFactory(
                definition.getIdentifier(),
                definition.getIdentifierOwnerClass(),
                argumentFactories.get(0));
      } else if (definition.isFactoryCallFactory()) { // existing factory
        // reference
        if (container.getFactory(definition.getIdentifier()) == null)
          throw new ParserException(
              "ScriptFactoryBuilder",
              "UNKNOWN_FACTORY",
              "Error in factory definition ["
                  + definition.getRoot().getName()
                  + "]: Unknown Factory: "
                  + definition.getIdentifier());
        factory =
            new InputAdaptingFactory(
                container.getFactory(definition.getIdentifier()), argumentFactories);
      } else if (definition.isFactoryFactory()) {
        factory = new FactoryFactory(container, definition.getIdentifier());
      } else if (definition.isCollectionFactory()) {
        factory = new CollectionFactory(argumentFactories);
      } else if (definition.isMapFactory()) {
        List<LocalFactory> keyFactories =
            buildLocalFactories(container, definition.getInstantiationArgKeyFactories());
        factory = new MapFactory(keyFactories, argumentFactories);

        if (definition.isLocalizedMap()) {
          ((MapFactory) factory).setFactoryMap(true);
          GlobalFactory<?> localeFactory = container.getFactory("locale");
          if (localeFactory == null) {
            new ParserException(
                "ScriptFactoryBuilder",
                "NO_LOCALE_FACTORY_FOUND",
                "Error in factory definition "
                    + definition.getRoot().getName()
                    + ": No 'locale' factory found. "
                    + "A 'locale' factory must be present in order to use localized resource factories");
          }
          factory = new LocalizedResourceFactory(factory, localeFactory);
        }
      } else if (definition.isValueFactory()) { // value factory
        if (isString(definition.getIdentifier()))
          factory =
              new ValueFactory(
                  definition.getIdentifier().substring(1, definition.getIdentifier().length() - 1));
        else if ("null".equals(definition.getIdentifier())) {
          factory = new ValueFactory(null);
        } else factory = new ValueFactory(definition.getIdentifier());
      } else if (definition.isInputParameterFactory()) { // input
        // consuming
        // factory
        factory = new InputConsumerFactory(Integer.parseInt(definition.getIdentifier()));
      } else if (definition.isLocalProductFactory()) {
        factory =
            new LocalProductConsumerFactory(
                definition.getLocalProductType(), definition.getLocalProductIndex());
      }

      // only local factories with a name (named local factories) can be
      // something else than "new instance"
      // factories.
      if (definition.isNamedLocalFactory()) {
        if (definition.isSingleton()) {
          factory = new LocalSingletonFactory(factory);
        } else if (definition.isThreadSingleton()) {
          factory = new LocalThreadSingletonFactory(factory);
        } else if (definition.isFlyweight()) {
          factory = new LocalFlyweightFactory(factory);
        }

        factory = new LocalProductProducerFactory(factory, definition.getLocalProductIndex());
        definition.setLocalProductType(definition.getName(), factory.getReturnType());
      }

      return factory;
    } catch (ContainerException e) {
      if (e.getCode().indexOf("ScriptFactoryBuilder") == -1) {
        e.addInfo(
            "ScriptFactoryBuilder",
            "ERROR_CREATING_FACTORY",
            "Error in factory definition " + definition.getRoot().getName());
      }
      throw e;
    }
  }