/** @see Alignment#getPropertyCells(Cell, boolean, boolean) */
  @Override
  public Collection<? extends Cell> getPropertyCells(
      Cell typeCell, boolean includeDisabled, boolean ignoreEmptySource) {
    if (CellUtil.getFirstEntity(typeCell.getTarget()) == null) {
      if (CellUtil.getFirstEntity(typeCell.getSource()) == null) return Collections.emptySet();
      else if (!(typeCell.getSource().values().iterator().next() instanceof Type))
        throw new IllegalArgumentException("Given cell is not a type cell.");

      // query with sources only
      Collection<TypeEntityDefinition> sourceTypes = new ArrayList<TypeEntityDefinition>();
      Iterator<? extends Entity> it = typeCell.getSource().values().iterator();
      while (it.hasNext()) sourceTypes.add((TypeEntityDefinition) it.next().getDefinition());

      List<Cell> result = new ArrayList<Cell>();
      for (Cell cell : cells)
        if (!AlignmentUtil.isTypeCell(cell) && matchesSources(cell.getSource(), sourceTypes))
          result.add(cell);
      return result;
    }

    if (!AlignmentUtil.isTypeCell(typeCell))
      throw new IllegalArgumentException("Given cell is not a type cell.");

    List<Cell> result = new ArrayList<Cell>();

    TypeDefinition typeCellType =
        typeCell.getTarget().values().iterator().next().getDefinition().getType();

    // collect source entity definitions
    Collection<TypeEntityDefinition> sourceTypes = new ArrayList<TypeEntityDefinition>();
    // null check in case only target type is in question
    if (typeCell.getSource() != null) {
      Iterator<? extends Entity> it = typeCell.getSource().values().iterator();
      while (it.hasNext()) sourceTypes.add((TypeEntityDefinition) it.next().getDefinition());
    }

    while (typeCellType != null) {
      // select all cells of the target type
      for (Cell cell : cellsPerTargetType.get(typeCellType)) {
        // check all cells associated to the target type
        if (!AlignmentUtil.isTypeCell(cell)
            && (includeDisabled || !cell.getDisabledFor().contains(typeCell.getId()))) {
          // cell is a property cell that isn't disabled
          // the target type matches, too
          if (AlignmentUtil.isAugmentation(cell)
              || (ignoreEmptySource && sourceTypes.isEmpty())
              || matchesSources(cell.getSource(), sourceTypes)) {
            // cell matches on the source side, too
            result.add(cell);
          }
        }
      }

      // continue with super type for inheritance
      typeCellType = typeCellType.getSuperType();
    }

    return result;
  }
  /**
   * Add a cell to the various internal containers.
   *
   * @param cell the cell to add
   */
  private void internalAdd(Cell cell) {
    cells.add(cell);
    idToCell.put(cell.getId(), cell);

    // check if cell is a type cell
    if (AlignmentUtil.isTypeCell(cell)) {
      typeCells.add(cell);
    }

    // add to maps
    internalAddToMaps(cell.getSource(), cell);
    internalAddToMaps(cell.getTarget(), cell);
  }