/**
   * This method substitutes variables with appropriate bindings
   *
   * @param op
   * @param bindingList
   * @return
   */
  public static List<Op> substitute(Op op, List<Binding> bindingList) {
    List<Op> opList = new ArrayList<Op>();
    // Want to avoid cost if the binding is empty
    // but the empty test is not zero-cost on non-empty things.
    if (isNotNeeded(bindingList)) {
      opList.add(op);
    } else {
      // get subop, substitute for all bindings and construct union
      // query
      if (OpService.class.isInstance(op)) {
        OpService serviceOp = (OpService) op;

        List<NumericBinding> numericBindings = constructNumericBindingList(bindingList);

        // control whether binding is a service (In other words, service
        // has
        // a variable (eg. SERVICE ?service0) and this binding is the
        // input
        // for it)
        if (controlWhetherBindingIsService(op, bindingList)) {
          List<Node> serviceList = generateServiceList(bindingList, serviceOp);
          List<List<NumericBinding>> unionGroups =
              generateUnionGroups(numericBindings, serviceOp, serviceList);
          for (int i = 0; i < unionGroups.size(); i++) {
            List<NumericBinding> unionGroup = unionGroups.get(i);
            Node serviceValue = serviceList.get(i);
            generateOpServices(serviceOp, unionGroup, opList, serviceValue);
          }
        } else {
          generateOpServices(serviceOp, numericBindings, opList, serviceOp.getService());
        }

        // opList.add(Transformer.transform(new OpSubstituteWorkerBound(
        // bindingList), op));
      }
    }
    filterIndex = 0;
    return opList;
  }
 /**
  * This method creates service value {@link Node} list searching in given bindingList.
  *
  * @param bindingList
  * @param serviceOp
  * @return
  */
 private static List<Node> generateServiceList(List<Binding> bindingList, OpService serviceOp) {
   List<Node> services = new ArrayList<Node>();
   for (int i = 0; i < bindingList.size(); i++) {
     BindingMap binding = (BindingMap) bindingList.get(i);
     // get service value
     Node serviceValue = binding.get((Var) serviceOp.getService());
     // add this service if services doesn't contain it.
     if (!services.contains(serviceValue)) {
       services.add(serviceValue);
     }
   }
   return services;
 }
  /**
   * This method creates {@link OpService} list using bindingList and given service value.
   *
   * @param serviceOp
   * @param bindingList
   * @param opList
   * @param serviceValue
   */
  private static void generateOpServices(
      OpService serviceOp, List<NumericBinding> bindingList, List<Op> opList, Node serviceValue) {
    // get sub op...
    Op serviceRootOp = serviceOp.getSubOp();
    // substitute sub op for each binding...
    List<Op> substitutedOpList = generateSubstitutedOps(bindingList, serviceRootOp);
    // control substituted op list size is greater than 1 to
    // decide
    // whether unioning ops is needed or not.
    if (substitutedOpList.size() > 1) {

      // generate op unions and add them to op list
      generateOpUnions(opList, substitutedOpList, serviceValue);
    } else {
      // create single op and add it to list
      opList.add(new OpService(serviceValue, substitutedOpList.get(0), false));
    }
  }
 /**
  * This method splits services as bindings would be ask to them.
  *
  * @param bindingList
  * @param serviceOp
  * @param serviceList
  * @return
  */
 private static List<List<NumericBinding>> generateUnionGroups(
     List<NumericBinding> bindingList, OpService serviceOp, List<Node> serviceList) {
   List<List<NumericBinding>> bindingUnionGroups = new ArrayList<List<NumericBinding>>();
   // generate Ops for each service value
   for (int j = 0; j < serviceList.size(); j++) {
     List<NumericBinding> bindingGroupToUnion = new ArrayList<NumericBinding>();
     Node currentService = serviceList.get(j);
     for (int i = 0; i < bindingList.size(); i++) {
       BindingMap binding = (BindingMap) bindingList.get(i).getBinding();
       Node serviceValue = binding.get((Var) serviceOp.getService());
       // if this serviceValue same as one with service list add it to
       // binding group.
       if (currentService.equals(serviceValue)) {
         bindingGroupToUnion.add(bindingList.get(i));
       }
     }
     bindingUnionGroups.add(bindingGroupToUnion);
   }
   return bindingUnionGroups;
 }
 @Override
 public Op transform(OpService op, Op sub) {
   super.transform(op, sub);
   Node n = substitute(op.getService(), binding);
   return new OpService(n, sub, false);
 }
 /**
  * This method controls whether given opService is variable or not.
  *
  * @param opService
  * @return
  */
 private static boolean isServiceVariable(OpService opService) {
   if (opService.getService().isURI()) {
     return false;
   }
   return true;
 }