/**
   * Perform a search over all child and sub orgs within the given organisation
   *
   * <p>If a search query is given it will be split by space and the key words searched in the
   * title, orgid, address, addressLine2 and postcode fields.
   *
   * @param q - search query, which is a space seperated list of key words. Optional
   * @param organisation - search is for orgs inside this
   * @param orgType - optional, if given results are limited to organisations of this type
   * @param session
   * @return
   */
  public static List<Organisation> search(
      String q, Organisation organisation, OrgType orgType, Session session) {
    Criteria crit = session.createCriteria(Organisation.class);
    crit.setCacheable(true);
    Disjunction notDeleted = Restrictions.disjunction();
    notDeleted.add(Restrictions.isNull("deleted"));
    notDeleted.add(Restrictions.eq("deleted", Boolean.FALSE));
    crit.add(notDeleted);

    if (q != null) {
      String[] arr = q.split(" ");
      Conjunction con = Restrictions.conjunction();
      for (String queryPart : arr) {
        Disjunction dis = Restrictions.disjunction();
        String s = "%" + queryPart + "%";
        dis.add(Restrictions.ilike("title", s));
        dis.add(Restrictions.ilike("orgId", s));
        dis.add(Restrictions.ilike("address", s));
        dis.add(Restrictions.ilike("addressLine2", s));
        dis.add(Restrictions.ilike("postcode", s));
        con.add(dis);
      }
      crit.add(con);
    }

    if (orgType != null) {
      crit.add(Restrictions.eq("orgType", orgType));
    }
    // TODO: add other properties like address
    Criteria critParentLink = crit.createCriteria("parentOrgLinks");
    critParentLink.add(Restrictions.eq("owner", organisation));
    crit.addOrder(Order.asc("title"));
    return DbUtils.toList(crit, Organisation.class);
  }
  private static void setAuthorizedSiteData(DetachedCriteria criteria, List<SiteData> sites) {
    Disjunction disjunction = Restrictions.disjunction();

    for (SiteData sd : sites) {
      Conjunction con = new Conjunction();
      con.add(Restrictions.eq("dpSiteName", sd.getSiteName()));
      con.add(Restrictions.eq("project", sd.getCollection()));
      disjunction.add(con);
    }
    criteria.add(disjunction);
  }
  public List<DmAccount> getListOwnerByPermittedAccount(
      String accountId, Integer permissionLevelStart) {
    DmAccount permittedAccount = null;
    if (accountId != null) {
      permittedAccount = new DmAccount();
      permittedAccount.setId(accountId);
    }

    List<DmAccount> ownerList = null;
    if (permittedAccount != null) {
      Criteria crit = getSession().createCriteria(DmFolder.class);
      crit.setProjection(Projections.distinct(Projections.property("owner")));
      crit.add(Restrictions.ne("owner", permittedAccount));
      //            crit.setProjection(Projections.property("owner"));

      //            crit.add(Restrictions.eq("owner", accountOwner));
      //            crit.add(Restrictions.isNull("parent"));
      //            crit.addOrder(Order.asc("name"));
      //            if (permissionLevelStart != null) {
      //                crit.createCriteria("permissionList").add(Restrictions.ge("permissionType",
      // permissionLevelStart));
      //            }
      //            Criterion permissionCrit = null;

      Conjunction conjunction = Restrictions.conjunction();
      if (permissionLevelStart != null) {
        conjunction.add(Restrictions.ge("permissionType", permissionLevelStart));
      }
      conjunction.add(Restrictions.eq("account", permittedAccount));

      crit.createCriteria("permissionList").add(conjunction);

      ownerList = crit.list();

      //            if (ownerList != null) {
      //                for (DmAccount owner : ownerList) {
      //                    System.out.println("name = " + owner.getName());
      //                }
      //            }
      // start - get children for each child (trigger lazy fetch)
      //            for (DmFolder folderTmp : folderList) {
      //                if (folderTmp.getChildList() != null) {
      //                    folderTmp.getChildList().size();
      //                }
      //            }
      // end - get children for each child (trigger lazy fetch)
    }

    return ownerList;
    //        return null;
  }
  /**
   * 解析一个条件成为符合Hibernate的Junction的实例条件
   *
   * @param condition
   * @param junction
   */
  public static void parseConditionToJunction(
      Condition condition, Junction junction, Class<?> persistentClass) {
    // 子条件
    List<Condition> subConditions = condition.getSubConditions();

    // 有子条件则进行遍历获取最终的条件
    if (null != subConditions && !subConditions.isEmpty()) {
      // 子条件当中的and条件集合
      List<Condition> andConditions = condition.getAndConditions();
      if (null != andConditions && !andConditions.isEmpty()) {
        // 创建一个and条件集合
        Conjunction conj = Restrictions.conjunction();
        // 添加到父条件中
        junction.add(conj);
        for (Condition andCondition : andConditions) {
          /*
           * 把每个条件看做是一个大的条件(包含 and 和 or 2个部分),
           * 然后使用disjunction连接条件集合来组合这个大条件的(and项 和 or项);
           * 因为and项和or项都已经被分为2个部分
           * ,而且又是用disjunction来组合,所以可以保证一个大条件只会被or连接符分隔成2个部分
           */
          Disjunction dj = Restrictions.disjunction();
          conj.add(dj);
          parseConditionToJunction(andCondition, dj, persistentClass);
        }
      }

      // 子条件当中的or条件集合
      List<Condition> orConditions = condition.getOrConditions();
      if (null != orConditions && !orConditions.isEmpty()) {
        // 创建一个or条件集合
        Disjunction disj = Restrictions.disjunction();
        // 添加到父条件中
        junction.add(disj);
        for (Condition orCondition : orConditions) {
          // 这里的实现原理与上面的andCondition的处理相同
          Disjunction dj = Restrictions.disjunction();
          disj.add(dj);
          parseConditionToJunction(orCondition, dj, persistentClass);
        }
      }
    } else {
      // 条件为最终条件,转换为符合Hibernate的条件,然后条件到条件集合中
      junction.add(condition.getCriterion(persistentClass));
    }
  }
  /**
   * Create the search criteria for a {@link Translation}.
   *
   * @param translations the translation to add to the criteria
   * @param ignoreCase flag indicating if case should be ignored during search
   * @param matchMode flag indicating the type of string pattern matching
   * @return the additional search parameters for the {@link Translation} fields
   */
  private Conjunction createTranslationConditions(
      SortedSet<Translation> translations, final boolean ignoreCase, final MatchMode matchMode) {
    Conjunction conjunction = null;
    if (translations != null && !translations.isEmpty()) {
      final Translation translation = translations.first();

      Example criterionTranslation = Example.create(translation);
      criterionTranslation.enableLike(matchMode);
      if (ignoreCase) {
        criterionTranslation.ignoreCase();
      }

      conjunction = conjunction();
      conjunction.add(criterionTranslation);

      addBundleCriteria(conjunction, translation.getBundle());
      addCountryCriteria(conjunction, translation.getCountry());
      addLanguageCriteria(conjunction, translation.getLanguage());
    }

    return conjunction;
  }
  public List<DmFolder> getSharedFirstLevelList(String accountSharedId, String accountOwnerId) {
    DmAccount permittedAccount = null;
    if (accountSharedId != null) {
      permittedAccount = new DmAccount();
      permittedAccount.setId(accountSharedId);
    }

    DmAccount ownerAccount = null;
    if (accountOwnerId != null) {
      ownerAccount = new DmAccount();
      ownerAccount.setId(accountOwnerId);
    }

    List<DmFolder> folderList = null;
    if (permittedAccount != null) {
      Criteria crit = getSession().createCriteria(DmFolderPermission.class);
      crit.setProjection(Projections.property("folder"));

      Conjunction conjunction = Restrictions.conjunction();
      //            conjunction.add(Restrictions.ge("permissionType",
      // ApplicationConstants.FOLDER_PERMISSION_MANAGER));
      conjunction.add(Restrictions.eq("account", permittedAccount));
      conjunction.add(Restrictions.ne("account", ownerAccount));
      crit.add(conjunction);

      crit.createAlias("folder", "folderShared", CriteriaSpecification.LEFT_JOIN);
      crit.add(Restrictions.eq("folderShared.owner", ownerAccount));

      crit.createAlias("folderShared.parent", "parentFolder", CriteriaSpecification.LEFT_JOIN);
      //            crit.createAlias("parentFolder.permissionList", "parentPermission");
      crit.createAlias(
          "parentFolder.permissionList", "parentPermission", CriteriaSpecification.LEFT_JOIN);

      //            DetachedCriteria subquery = DetachedCriteria.forClass(DmFolder.class,
      // "last_pos");
      DetachedCriteria subquery = DetachedCriteria.forClass(DmFolderPermission.class);
      subquery.setProjection(Projections.property("folder"));
      subquery.add(conjunction);

      Disjunction disjunction = Restrictions.disjunction();
      disjunction.add(Restrictions.isNull("folderShared.parent"));
      //            disjunction.add(Restrictions.isNull("parentFolder.permissionList"));
      //            disjunction.add(Restrictions.isNull("parentPermission.id"));
      //            disjunction.add(conjunction2);
      disjunction.add(Subqueries.propertyNotIn("folderShared.parent", subquery));

      //            crit.add(Subqueries.propertyNotIn("folderShared.parent", subquery));

      //            Conjunction conjunction2 = Restrictions.conjunction();
      //            conjunction2.add(Restrictions.eq("parentPermission.permissionType",
      // ApplicationConstants.FOLDER_PERMISSION_MANAGER));
      //            conjunction2.add(Restrictions.eq("parentPermission.account", permittedAccount));
      //
      //            Conjunction conjunction3 = Restrictions.conjunction();
      //            conjunction3.add(Restrictions.eq("parentPermission.permissionType",
      // ApplicationConstants.FOLDER_PERMISSION_MANAGER));
      //            conjunction3.add(Restrictions.eq("parentPermission.account", permittedAccount));

      //            disjunction.add(conjunction3);
      //            disjunction.add(Restrictions.ne("parentPermission.account", permittedAccount));
      //            disjunction.add(Restrictions.eq("parentPermission.permissionType",
      // ApplicationConstants.FOLDER_PERMISSION_MANAGER));

      //            disjunction.add(Restrictions.isNull("parentFolder.permissionList"));

      //            disjunction.add(Restrictions.eq("parentPermission.permissionType",
      // ApplicationConstants.FOLDER_PERMISSION_MANAGER));
      //            disjunction.add(Restrictions.ne("parentPermission.account", permittedAccount));

      crit.add(disjunction);

      folderList = crit.list();

      // start - get children for each child (trigger lazy fetch)
      for (DmFolder folderTmp : folderList) {
        if (folderTmp.getChildList() != null) {
          folderTmp.getChildList().size();
        }
      }
      // end - get children for each child (trigger lazy fetch)
    }

    return folderList;
  }