/**
  * Filter the datatypes from dependency, remove those that already presents in datatypes from
  * context and are equal. Handles the case when for example 'main' module includes
  * 'dependency1'(with A, B datatypes) and 'dependency2' (with C datatype, and 'dependency2'
  * includes 'dependency1' itself). So to prevent adding datatypes A, B from 'dependency1' and
  * 'dependency2' we handle this case.
  *
  * @param dependencyDatatypes datatypes from dependency module
  * @param contextTypes datatypes already presented in the context
  * @return filtered dependency datatypes
  * @author DLiauchuk
  */
 private Map<String, IOpenClass> filterDependencyTypes(
     Map<String, IOpenClass> dependencyDatatypes, Map<String, IOpenClass> contextTypes) {
   Map<String, IOpenClass> filteredDependencyDatatypes = new HashMap<String, IOpenClass>();
   for (String key : dependencyDatatypes.keySet()) {
     IOpenClass dependencyDatatype = dependencyDatatypes.get(key);
     IOpenClass contextDatatype = contextTypes.get(key);
     if (!dependencyDatatype.equals(contextDatatype)) {
       filteredDependencyDatatypes.put(key, dependencyDatatype);
     }
   }
   return filteredDependencyDatatypes;
 }
  /*
   * (non-Javadoc)
   * @see org.openl.binding.INodeBinder#bind(org.openl.parser.ISyntaxNode, org.openl.env.IOpenEnv,
   * org.openl.binding.IBindingContext)
   */
  public IBoundNode bind(ISyntaxNode node, IBindingContext bindingContext) throws Exception {

    if (node.getNumberOfChildren() != 1) {
      BindHelper.processError("Suffix node should have 1 subnode", node, bindingContext);

      return new ErrorBoundNode(node);
    }

    int index = node.getType().lastIndexOf('.');
    String methodName = node.getType().substring(index + 1);
    IBoundNode[] children = bindChildren(node, bindingContext);

    if (!children[0].isLvalue()) {
      BindHelper.processError(
          "The node is not an Lvalue", children[0].getSyntaxNode(), bindingContext, false);

      return new ErrorBoundNode(node);
    }

    IOpenClass[] types = getTypes(children);
    IMethodCaller methodCaller =
        UnaryOperatorNodeBinder.findUnaryOperatorMethodCaller(methodName, types, bindingContext);

    if (methodCaller == null) {

      String message = UnaryOperatorNodeBinder.errorMsg(methodName, types[0]);
      BindHelper.processError(message, node, bindingContext);

      return new ErrorBoundNode(node);
    }

    IOpenClass methodType = methodCaller.getMethod().getType();

    if (ClassUtils.primitiveToWrapper(methodType.getInstanceClass())
        != ClassUtils.primitiveToWrapper(types[0].getInstanceClass())) {
      //        if (!methodCaller.getMethod().getType().equals(types[0])) {
      BindHelper.processError(
          "Suffix operator must return the same type as an argument", node, bindingContext);

      return new ErrorBoundNode(node);
    }

    return new SuffixNode(node, children, methodCaller);
  }
  /**
   * Generates interface class using methods and fields of given IOpenClass instance.
   *
   * @throws Exception if an error has occurred
   */
  public static Class<?> generateInterface(
      String className,
      IOpenClass openClass,
      ClassLoader classLoader,
      String[] includes,
      String[] excludes)
      throws Exception {

    if (openClass == null) {
      return generateInterface(className, EMPTY_RULES, classLoader);
    }

    List<RuleInfo> rules = new ArrayList<RuleInfo>();

    final Collection<IOpenMethod> methods = openClass.getMethods();
    for (IOpenMethod method : methods) {

      if (!isIgnoredMember(method)) {
        RuleInfo ruleInfo = getRuleInfoForMethod(method);
        boolean isMember = isMember(ruleInfo, includes, excludes);
        if (isMember) {
          rules.add(ruleInfo);
        }
      }
    }

    final Collection<IOpenField> fields = openClass.getFields().values();
    for (IOpenField field : fields) {

      if (!isIgnoredMember(field)) {

        if (field.isReadable()) {
          RuleInfo ruleInfo = getRuleInfoForField(field);
          boolean isMember = isMember(ruleInfo, includes, excludes);
          if (isMember) {
            rules.add(ruleInfo);
          }
        }
      }
    }

    return generateInterface(className, rules.toArray(new RuleInfo[rules.size()]), classLoader);
  }
 @Override
 public IOpenClass addType(String namespace, IOpenClass type) throws OpenLCompilationException {
   if (type instanceof CustomDynamicOpenClass) {
     CustomDynamicOpenClass customDynamicOpenClass = (CustomDynamicOpenClass) type;
     IOpenClass openClass = findType(namespace, type.getName());
     if (openClass == null) {
       return super.addType(namespace, customDynamicOpenClass.copy());
     } else {
       customDynamicOpenClass.updateOpenClass(openClass);
       return openClass;
     }
   } else {
     return super.addType(namespace, type);
   }
 }
  @SuppressWarnings("unchecked")
  public static IConditionEvaluator makeEvaluator(
      ICondition condition, IOpenClass methodType, IBindingContext bindingContext)
      throws SyntaxNodeException {

    IParameterDeclaration[] params = condition.getParams();

    switch (params.length) {
      case 1:
        IOpenClass paramType = params[0].getType();

        IOpenCast openCast = bindingContext.getCast(paramType, methodType);

        if (openCast != null) {
          return new EqualsIndexedEvaluator(openCast);
        }

        IAggregateInfo aggregateInfo = paramType.getAggregateInfo();

        if (aggregateInfo.isAggregate(paramType)
            && aggregateInfo.getComponentType(paramType).isAssignableFrom(methodType)) {
          return new ContainsInArrayIndexedEvaluator();
        }

        IRangeAdaptor<? extends Object, ? extends Comparable<?>> rangeAdaptor =
            getRangeAdaptor(methodType, paramType);

        if (rangeAdaptor != null) {
          return new RangeIndexedEvaluator(
              (IRangeAdaptor<Object, ? extends Comparable<Object>>) rangeAdaptor, 1);
        }

        if (JavaOpenClass.BOOLEAN.equals(methodType)
            || JavaOpenClass.getOpenClass(Boolean.class).equals(methodType)) {
          return new DefaultConditionEvaluator();
        }

        break;

      case 2:
        IOpenClass paramType0 = params[0].getType();
        IOpenClass paramType1 = params[1].getType();

        if (methodType == paramType0 && methodType == paramType1) {

          Class<?> clazz = methodType.getInstanceClass();

          if (clazz != short.class
              && clazz != byte.class
              && clazz != int.class
              && clazz != long.class
              && clazz != double.class
              && clazz != float.class
              && !Comparable.class.isAssignableFrom(clazz)) {
            String message = String.format("Type '%s' is not Comparable", methodType.getName());
            throw SyntaxNodeExceptionUtils.createError(
                message, null, null, condition.getSourceCodeModule());
          }

          return new RangeIndexedEvaluator(null, 2);
        }

        aggregateInfo = paramType1.getAggregateInfo();

        if (aggregateInfo.isAggregate(paramType1)
            && aggregateInfo.getComponentType(paramType1) == methodType) {

          BooleanTypeAdaptor booleanTypeAdaptor = BooleanAdaptorFactory.getAdaptor(paramType0);

          if (booleanTypeAdaptor != null) {
            return new ContainsInOrNotInArrayIndexedEvaluator(booleanTypeAdaptor);
          }
        }

        if (JavaOpenClass.BOOLEAN.equals(methodType)
            || JavaOpenClass.getOpenClass(Boolean.class).equals(methodType)) {
          return new DefaultConditionEvaluator();
        }

        break;
    }

    List<String> names = new ArrayList<String>();

    for (IParameterDeclaration parameterDeclaration : params) {

      String name = parameterDeclaration.getType().getName();
      names.add(name);
    }

    String parametersString = StringUtils.join(names, ",");

    String message =
        String.format(
            "Can not make a Condition Evaluator for parameter %s and [%s]",
            methodType.getName(), parametersString);

    throw SyntaxNodeExceptionUtils.createError(
        message, null, null, condition.getSourceCodeModule());
  }
 private static boolean isMethodTypeNumber(IOpenClass methodType) {
   return ClassUtils.isAssignable(methodType.getInstanceClass(), Number.class, true);
 }
 private static boolean isParameterIntRange(IOpenClass paramType) {
   return org.openl.rules.helpers.IntRange.class.equals(paramType.getInstanceClass());
 }
  private void addDataTables(CompiledOpenClass dependency) {
    IOpenClass openClass = dependency.getOpenClassWithErrors();

    Map<String, IOpenField> fieldsMap = openClass.getFields();

    Set<String> tableUrls = new HashSet<String>();
    Map<String, IOpenField> fields = getFields();
    for (IOpenField openField : fields.values()) {
      if (openField instanceof DataOpenField) {
        tableUrls.add(((DataOpenField) openField).getTableUri());
      }
    }
    for (String key : fieldsMap.keySet()) {
      IOpenField field = fieldsMap.get(key);
      if (field instanceof DataOpenField) {
        DataOpenField dataOpenField = (DataOpenField) field;
        try {
          String tableUrl = dataOpenField.getTableUri();
          // Test tables are added both as methods and variables.
          if (!tableUrls.contains(tableUrl) && !duplicatedMethodUrls.contains(tableUrl)) {
            boolean containsInDependency = false;
            if (VirtualSourceCodeModule.SOURCE_URI.equals(metaInfo.getSourceUrl())) {
              for (CompiledDependency d : getDependencies()) {
                IOpenClass dependentModuleClass = d.getCompiledOpenClass().getOpenClassWithErrors();
                if (dependentModuleClass instanceof XlsModuleOpenClass) {
                  if (((XlsModuleOpenClass) dependentModuleClass)
                      .duplicatedMethodUrls.contains(tableUrl)) {
                    containsInDependency = true;
                    break;
                  }
                }
              }
            }
            if (!containsInDependency) {
              addField(field);
              tableUrls.add(tableUrl);
            }
          }
        } catch (OpenlNotCheckedException e) {
          SyntaxNodeException error =
              SyntaxNodeExceptionUtils.createError(
                  e.getMessage(), e, dataOpenField.getTable().getTableSyntaxNode());
          addError(error);
        }
      }
    }

    if (openClass instanceof XlsModuleOpenClass) {
      XlsModuleOpenClass xlsModuleOpenClass = (XlsModuleOpenClass) openClass;
      if (xlsModuleOpenClass.getDataBase() != null) {
        for (ITable table : xlsModuleOpenClass.getDataBase().getTables()) {
          if (XlsNodeTypes.XLS_DATA.toString().equals(table.getTableSyntaxNode().getType())) {
            try {
              getDataBase().registerTable(table);
            } catch (DuplicatedTableException e) {
              addError(e);
            } catch (OpenlNotCheckedException e) {
              addError(e);
            }
          }
        }
      }
    }
  }