@Override
 public boolean containsObstacle(Obstacle obstacle) {
   return kb.containsObstacle(obstacle);
 }
 @Override
 public synchronized void addThreat(Threat threat) {
   kb.addThreat(threat);
   this.need_to_assign_role = true;
 }
 @Override
 public boolean containsThreat(Threat threat) {
   return kb.containsThreat(threat);
 }
 @Override
 public void addObstacle(Obstacle obs) {
   kb.addObstacle(obs);
 }
 @Override
 public void addConflict(Conflict conflict) {
   kb.addConflict(conflict);
 }
 @Override
 public void setConflicts(ArrayList<Conflict> conflicts) {
   kb.setConflicts(conflicts);
 }
 @Override
 public void setThreats(ArrayList<Threat> threats) {
   kb.setThreats(threats);
   this.need_to_assign_role = true;
 }
 @Override
 public void setObstacles(ArrayList<Obstacle> obstacles) {
   kb.setObstacles(obstacles);
 }
 @Override
 public synchronized ArrayList<Threat> getThreats() {
   return kb.getThreats();
 }
 @Override
 public synchronized ArrayList<Conflict> getConflicts() {
   return kb.getConflicts();
 }
 /** @return */
 @Override
 public synchronized ArrayList<Obstacle> getObstacles() {
   return kb.getObstacles();
 }
  /**
   * assign role for uavs with subteam (size=this.subteam_size), considering the special case:
   * attacker i should be assigned with role i. Other role should be assigned to the nearest uav
   *
   * @param assigned_attacker_index
   * @param assigned_role_index
   */
  private void roleAssignForAttackerWithSubTeam(
      int assigned_attacker_index, int assigned_role_index) {
    TreeSet<Integer> assigned_attacker = new TreeSet<>();
    ArrayList<Threat> threats = kb.getThreats();
    ArrayList<AttackerModel> attackersList = ReadAttackers.getAttackers();
    int threat_num = threats.size();
    int attacker_num = HandleTree.attackersNode.getChildCount();

    for (int i = 0; i < threat_num; i++) {
      Threat threat = threats.get(i);
      if (!threat.isEnabled()) {
        continue;
      }
      Set<Integer> attackers_locked = getLockedAttackers();
      if (attackers_locked == null) {
        attackers_locked = new TreeSet<>();
      }
      assigned_attacker.addAll(attackers_locked);
      // manually assign
      if (threat.getIndex() == assigned_role_index) {
        for (AttackerModel attacker : attackersList) {
          synchronized (attacker) {
            if (attacker == null || !attacker.isOnline()) {
              continue;
            }
          }
          if (assigned_attacker_index == attacker.getIndex()) {
            if (attacker.getTarget_indicated_by_role() == null
                || attacker.getTarget_indicated_by_role().getIndex() != threat.getIndex()) {
              attacker.setFlightMode(CC_StaticInitConfig.FLYING_MODE);
            }
            attackerUtils.update.setTarget_indicated_by_role(threat, attacker);
            attackerUtils.update.setSpeed(CC_StaticInitConfig.SPEED_OF_ATTACKER_ON_TASK, attacker);
            attackerUtils.update.setReplan(true, attacker);
            assigned_attacker.add(assigned_attacker_index);
            break;
          }
        }
        continue;
      }

      int remained_team_size = this.sub_team_size - attackers_locked.size();
      ArrayList<AttackerModel> attacker_arr_to_assign = new ArrayList<>();
      ArrayList<Float> attacker_dist_to_assign = new ArrayList<>();
      for (AttackerModel current_attacker : attackersList) {

        if (!current_attacker.isEnduranceCapReachable(threat)) {
          continue;
        }
        if (assigned_attacker_index == current_attacker.getIndex()) {
          continue;
        }
        if (!current_attacker.isOnline()) {
          continue;
        }
        if (attackers_locked.contains(current_attacker.getIndex())) {
          continue;
        }
        if (assigned_attacker.contains(current_attacker.getIndex())) {
          continue;
        }

        float dist_between_uav_and_role =
            DistanceUtil.distanceBetween(
                current_attacker.getCenterCoordinates(), threat.getCoordinates());
        int index_to_insert = 0;
        boolean attacker_added = false;
        for (float attacker_dist : attacker_dist_to_assign) {
          if (dist_between_uav_and_role < attacker_dist) {
            attacker_added = true;
            break;
          }
          index_to_insert++;
        }
        if (attacker_added) {
          attacker_dist_to_assign.add(index_to_insert, dist_between_uav_and_role);
          attacker_arr_to_assign.add(index_to_insert, current_attacker);

          if (attacker_dist_to_assign.size() > remained_team_size) {
            attacker_dist_to_assign.remove(remained_team_size);
            attacker_arr_to_assign.remove(remained_team_size);
          }
        } else if (attacker_dist_to_assign.size() < remained_team_size) {
          attacker_dist_to_assign.add(dist_between_uav_and_role);
          attacker_arr_to_assign.add(current_attacker);
        }
      }

      if (attacker_arr_to_assign.size() >= remained_team_size) {
        for (AttackerModel attacker : attacker_arr_to_assign) {
          if (attacker.getFlightMode() == CC_StaticInitConfig.TARGET_LOCKED_MODE) {
            continue;
          }
          assigned_attacker.add(attacker.getIndex());
          attackerUtils.update.setTarget_indicated_by_role(threat, attacker);
          attackerUtils.update.setSpeed(CC_StaticInitConfig.SPEED_OF_ATTACKER_ON_TASK, attacker);
          attackerUtils.update.setReplan(true, attacker);
          attackerUtils.update.setFlightMode(CC_StaticInitConfig.FLYING_MODE, attacker);
        }
      }
    }

    for (AttackerModel current_attacker : attackersList) {
      if (current_attacker.getFlightMode() == CC_StaticInitConfig.TARGET_LOCKED_MODE) {
        continue;
      }
      if (!assigned_attacker.contains(current_attacker.getIndex())
          && current_attacker.getTarget_indicated_by_role() != null
          && current_attacker.getTarget_indicated_by_role().getIndex() != -1) {
        float[] dummy_threat_coord = current_attacker.getUavPositionInBaseStation();
        Threat dummy_threat = new Threat(-1, dummy_threat_coord, 0, ThreatType.DUMMY);
        attackerUtils.update.setTarget_indicated_by_role(dummy_threat, current_attacker);
        attackerUtils.update.setReplan(true, current_attacker);
        attackerUtils.update.setSpeed(CC_StaticInitConfig.SPEED_OF_ATTACKER_IDLE, current_attacker);
        attackerUtils.update.setFlightMode(CC_StaticInitConfig.FLYING_MODE, current_attacker);
      }
    }
    need_to_assign_role = false;
  }