@Override
  public void remove(DMSFile entity) {
    // remove all children
    if (entity.getIsDirectory() == Boolean.TRUE) {
      final List<DMSFile> children = all().filter("self.parent.id = ?", entity.getId()).fetch();
      for (DMSFile child : children) {
        if (child != entity) {
          remove(child);
          ;
        }
      }
    }

    // remove attached file
    if (entity.getMetaFile() != null) {
      final MetaFile metaFile = entity.getMetaFile();
      long count = attachments.all().filter("self.metaFile = ?", metaFile).count();
      if (count == 1) {
        final MetaAttachment attachment =
            attachments.all().filter("self.metaFile = ?", metaFile).fetchOne();
        attachments.remove(attachment);
      }
      count = all().filter("self.metaFile = ?", metaFile).count();
      if (count == 1) {
        entity.setMetaFile(null);
        try {
          metaFiles.delete(metaFile);
        } catch (IOException e) {
          throw new PersistenceException(e);
        }
      }
    }

    super.remove(entity);
  }
 private boolean canOffline(DMSFile file, User user) {
   return file.getIsDirectory() != Boolean.TRUE
       && file.getMetaFile() != null
       && dmsPermissions
               .all()
               .filter("self.file = ? AND self.value = 'OFFLINE' AND self.user = ?", file, user)
               .count()
           > 0;
 }
  @Override
  public DMSFile save(DMSFile entity) {

    final DMSFile parent = entity.getParent();
    final Model related = findRelated(entity);
    final boolean isAttachment = related != null && entity.getMetaFile() != null;

    // if new attachment, save attachment reference
    if (isAttachment) {
      // remove old attachment if file is moved
      MetaAttachment attachmentOld =
          attachments
              .all()
              .filter(
                  "self.metaFile.id = ? AND self.objectId != ? AND self.objectName != ?",
                  entity.getMetaFile().getId(),
                  related.getId(),
                  related.getClass().getName())
              .fetchOne();
      if (attachmentOld != null) {
        System.err.println("OLD: " + attachmentOld);
        attachments.remove(attachmentOld);
      }

      MetaAttachment attachment =
          attachments
              .all()
              .filter(
                  "self.metaFile.id = ? AND self.objectId = ? AND self.objectName = ?",
                  entity.getMetaFile().getId(),
                  related.getId(),
                  related.getClass().getName())
              .fetchOne();
      if (attachment == null) {
        attachment = metaFiles.attach(entity.getMetaFile(), related);
        attachments.save(attachment);
      }
    }

    // if not an attachment or has parent, do nothing
    if (parent != null || related == null) {
      return super.save(entity);
    }

    // create parent folders

    Mapper mapper = Mapper.of(related.getClass());
    String homeName = null;
    try {
      homeName = mapper.getNameField().get(related).toString();
    } catch (Exception e) {
    }
    if (homeName == null) {
      homeName = Strings.padStart("" + related.getId(), 5, '0');
    }

    DMSFile dmsRoot =
        all()
            .filter(
                "(self.relatedId is null OR self.relatedId = 0) AND self.relatedModel = ? and self.isDirectory = true",
                entity.getRelatedModel())
            .fetchOne();

    final Inflector inflector = Inflector.getInstance();

    if (dmsRoot == null) {
      dmsRoot = new DMSFile();
      dmsRoot.setFileName(
          inflector.pluralize(inflector.humanize(related.getClass().getSimpleName())));
      dmsRoot.setRelatedModel(entity.getRelatedModel());
      dmsRoot.setIsDirectory(true);
      dmsRoot = super.save(dmsRoot); // should get id before it's child
    }

    DMSFile dmsHome = new DMSFile();
    dmsHome.setFileName(homeName);
    dmsHome.setRelatedId(entity.getRelatedId());
    dmsHome.setRelatedModel(entity.getRelatedModel());
    dmsHome.setParent(dmsRoot);
    dmsHome.setIsDirectory(true);
    dmsHome = super.save(dmsHome); // should get id before it's child

    entity.setParent(dmsHome);

    return super.save(entity);
  }
  @Override
  public Map<String, Object> populate(Map<String, Object> json, Map<String, Object> context) {
    final DMSFile file = findFrom(json);
    if (file == null) {
      return json;
    }

    boolean isFile = file.getIsDirectory() != Boolean.TRUE;
    LocalDateTime dt = file.getUpdatedOn();
    if (dt == null) {
      dt = file.getCreatedOn();
    }

    final User user = AuthUtils.getUser();
    final MetaFile metaFile = file.getMetaFile();

    boolean canShare =
        file.getCreatedBy() == user
            || security.isPermitted(AccessType.CREATE, DMSFile.class, file.getId())
            || dmsPermissions
                    .all()
                    .filter(
                        "self.file = ? AND self.value = 'FULL' AND (self.user = ? OR self.group = ?)",
                        file,
                        user,
                        user.getGroup())
                    .count()
                > 0;

    json.put("typeIcon", isFile ? "fa fa-file" : "fa fa-folder");
    json.put("downloadIcon", "fa fa-download");
    json.put("detailsIcon", "fa fa-info-circle");

    json.put("canShare", canShare);
    json.put("canWrite", canCreate(file));

    if (canOffline(file, user)) {
      json.put("offline", true);
    }

    json.put("lastModified", dt);
    json.put("createdOn", file.getCreatedOn());
    json.put("createdBy", file.getCreatedBy());
    json.put("updatedBy", file.getUpdatedBy());
    json.put("updatedOn", file.getUpdatedOn());

    if ("html".equals(file.getContentType())) {
      json.put("fileType", "text/html");
      json.put("contentType", "html");
      json.put("typeIcon", "fa fa-file-text-o");
      json.remove("downloadIcon");
    }
    if ("spreadsheet".equals(file.getContentType())) {
      json.put("fileType", "text/json");
      json.put("contentType", "spreadsheet");
      json.put("typeIcon", "fa fa-file-excel-o");
      json.remove("downloadIcon");
    }

    if (metaFile != null) {

      String fileType = metaFile.getFileType();
      String fileIcon = "fa-file-o";

      switch (fileType) {
        case "application/msword":
        case "application/vnd.openxmlformats-officedocument.wordprocessingml.document":
        case "application/vnd.oasis.opendocument.text":
          fileIcon = "fa-file-word-o";
          break;
        case "application/vnd.ms-excel":
        case "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet":
        case "application/vnd.oasis.opendocument.spreadsheet":
          fileIcon = "fa-file-excel-o";
          break;
        case "application/pdf":
          fileIcon = "fa-file-pdf-o";
          break;
        case "application/zip":
        case "application/gzip":
          fileIcon = "fa-file-archive-o";
          break;
        default:
          String type = metaFile.getFileType();
          if (type != null) {
            if (type.startsWith("text")) fileIcon = "fa-file-text-o";
            if (type.startsWith("image")) fileIcon = "fa-file-image-o";
            if (type.startsWith("video")) fileIcon = "fa-file-video-o";
          }
          break;
      }

      json.put("fileType", fileType);
      json.put("typeIcon", "fa " + fileIcon);
    }

    if (file.getTags() != null) {
      final List<Object> tags = new ArrayList<>();
      for (DMSFileTag tag : file.getTags()) {
        tags.add(Resource.toMap(tag, "id", "code", "name", "style"));
      }
      json.put("tags", tags);
    }

    return json;
  }