@Override
  public boolean hasChildren(Object element) {
    if (element instanceof FSTClass) {
      for (FSTRole role : ((FSTClass) element).getRoles()) {
        if (!role.getClassFragment().getMethods().isEmpty()
            || !role.getClassFragment().getFields().isEmpty()
            || !role.getDirectives().isEmpty()
            || !role.getInnerClasses().isEmpty()) {
          return true;
        }
      }
      return false;
    }

    if (element instanceof FSTMethod) {
      FSTMethod fstMethod = (FSTMethod) element;
      FSTRole role = fstMethod.getRole();
      return role.getMethods().contains(element) || !fstMethod.getFSTDirectives().isEmpty();
    }
    if (element instanceof FSTField) return false;

    if (element instanceof FSTInvariant) return true;

    if (element instanceof FSTDirective) {
      return ((FSTDirective) element).getRoleElementChildren().length != 0;
    }
    if (element instanceof FSTClassFragment) {
      FSTClassFragment innerClass = (FSTClassFragment) element;
      if (!innerClass.getMethods().isEmpty()
          || !innerClass.getFields().isEmpty()
          || !innerClass.getInnerClasses().isEmpty()) {
        return true;
      }
    }

    return false;
  }
  @Override
  public Object[] getChildren(Object parentElement) {
    Object[] obj = null;
    if (parentElement instanceof FSTClass) {
      // get all fields, methods, directives and invariants
      final TreeSet<FSTMethod> methods = new TreeSet<FSTMethod>();
      final TreeSet<FSTField> fields = new TreeSet<FSTField>();
      final TreeSet<FSTInvariant> invariants = new TreeSet<FSTInvariant>();
      final TreeSet<FSTDirective> directives = new TreeSet<FSTDirective>();
      final TreeSet<FSTClassFragment> innerClasses = new TreeSet<FSTClassFragment>();

      for (FSTRole role : ((FSTClass) parentElement).getRoles()) {
        invariants.addAll(role.getClassFragment().getInvariants());
        for (FSTMethod fstMethod : role.getMethods()) {
          if (fstMethod.getParent() instanceof FSTClassFragment) methods.add(fstMethod);
        }
        fields.addAll(role.getFields());
        TreeSet<FSTDirective> roleDirectives = role.getDirectives();
        for (FSTDirective directive : roleDirectives) {
          if (directive.getParent() == null) {
            directives.add(directive);
          }
        }
        innerClasses.addAll(role.getInnerClasses());
      }

      obj =
          new IRoleElement
              [methods.size()
                  + fields.size()
                  + invariants.size()
                  + directives.size()
                  + innerClasses.size()];
      int pos = 0;
      System.arraycopy(invariants.toArray(), 0, obj, pos, invariants.size());
      System.arraycopy(fields.toArray(), 0, obj, pos += invariants.size(), fields.size());
      System.arraycopy(methods.toArray(), 0, obj, pos += fields.size(), methods.size());
      System.arraycopy(directives.toArray(), 0, obj, pos += methods.size(), directives.size());
      System.arraycopy(
          innerClasses.toArray(), 0, obj, pos += directives.size(), innerClasses.size());

      return filter(obj);
    } else if (parentElement instanceof FSTMethod) {
      // get all the roles that belong to a method

      Set<FSTRole> roleList = new HashSet<FSTRole>();
      Set<FSTMethod> methods = new HashSet<FSTMethod>();
      for (FSTRole role : ((FSTMethod) parentElement).getRole().getFSTClass().getRoles()) {
        for (FSTMethod m : role.getAllMethods()) {
          if ( // m.isOwn(role.file) &&
          // ((FSTMethod)parentElement).isOwn(role.file) &&
          m.getFullName().equals(((FSTMethod) parentElement).getFullName())) {
            if (m.hasContract()) {
              roleList.add(
                  new FSTContractedRole(role.getFile(), role.getFeature(), role.getFSTClass()));
            } else {
              roleList.add(role);
            }
            methods.add(m);
            break;
          }
        }
      }

      List<String> featureOrder =
          CorePlugin.getFeatureProject(((FSTMethod) parentElement).getRole().getFile())
              .getFeatureModel()
              .getFeatureOrderList();

      if (((FSTMethod) parentElement).getFSTDirectives().size() == 0) {
        obj = new FSTRole[roleList.size()];
        int index = 0;
        for (String featureName : featureOrder) {

          for (Iterator<FSTRole> it = roleList.iterator(); it.hasNext(); ) {
            FSTRole next = it.next();
            if (next.getFeature().getName().equals(featureName)) {
              obj[index++] = next;
              it.remove();
              break;
            }
          }
        }
      } else {
        List<FSTDirective> dirs = new ArrayList<>();
        for (FSTRole role : roleList) {
          if (role.getMethods().contains(parentElement)) {
            // equals works correct?
            for (FSTMethod method : role.getMethods()) {
              if (method.equals(parentElement)) {
                dirs.addAll(method.getFSTDirectives());
                break;
              }
            }
          }
        }
        return dirs.toArray();
      }

    } else if (parentElement instanceof FSTInvariant) {
      // get all the roles that belong to an invariant
      LinkedList<FSTRole> roleList = new LinkedList<FSTRole>();
      for (FSTRole role : ((FSTInvariant) parentElement).getRole().getFSTClass().getRoles()) {
        for (FSTInvariant i : role.getClassFragment().getInvariants()) {
          if (((FSTInvariant) parentElement).getFullName().equals(i.getFullName())) {
            roleList.add(role);
            break;
          }
        }
      }

      return filter(roleList.toArray());
    } else if (parentElement instanceof FSTField) {
      // get all the roles that belong to a field
      LinkedList<FSTRole> roleList = new LinkedList<FSTRole>();
      for (FSTRole role : ((FSTField) parentElement).getRole().getFSTClass().getRoles()) {
        for (FSTField f : role.getAllFields()) {
          if (f.getFullName().equals(((FSTField) parentElement).getFullName())) {
            roleList.add(role);
            break;
          }
        }
      }
      return filter(roleList.toArray());
    } else if (parentElement instanceof FSTDirective) {
      return ((FSTDirective) parentElement).getRoleElementChildren();
    } else if (parentElement instanceof FSTClassFragment) {
      final TreeSet<FSTMethod> methods = new TreeSet<FSTMethod>();
      final TreeSet<FSTField> fields = new TreeSet<FSTField>();
      final TreeSet<FSTClassFragment> innerClasses = new TreeSet<FSTClassFragment>();
      final TreeSet<FSTInvariant> invariants = new TreeSet<FSTInvariant>();

      FSTClassFragment innerClassCast = (FSTClassFragment) parentElement;

      invariants.addAll(innerClassCast.getInvariants());
      LinkedList<FSTClassFragment> allFragments =
          innerClassCast.getRole().getAllEqualFSTFragments(innerClassCast);
      for (FSTClassFragment fstClassFragment : allFragments) {
        methods.addAll(fstClassFragment.getMethods());
        fields.addAll(fstClassFragment.getFields());
      }
      innerClasses.addAll(innerClassCast.getInnerClasses());

      obj =
          new IRoleElement
              [methods.size() + fields.size() + invariants.size() + innerClasses.size()];
      int pos = 0;
      System.arraycopy(invariants.toArray(), 0, obj, pos, invariants.size());
      System.arraycopy(fields.toArray(), 0, obj, pos += invariants.size(), fields.size());
      System.arraycopy(methods.toArray(), 0, obj, pos += fields.size(), methods.size());
      System.arraycopy(innerClasses.toArray(), 0, obj, pos += methods.size(), innerClasses.size());
    }

    return filter(obj);
  }