content: package net.csdn.mongo.association;
  
  import net.csdn.common.reflect.ReflectHelper;
  import net.csdn.mongo.Criteria;
  import net.csdn.mongo.Document;
  
  import java.util.List;
  import java.util.Map;
  
  import static net.csdn.common.collections.WowCollections.isEmpty;
  import static net.csdn.common.collections.WowCollections.list;
  import static net.csdn.common.collections.WowCollections.map;
  
  /**
   * User: WilliamZhu
   * Date: 12-10-17
   * Time: 上午10:09
   */
  public class HasManyAssociation implements Association {
  
      private Class kclass;
      private String foreignKey;
      private Document document;
      private String name;
  
      private List<Document> documentList = list();
  
  
      public HasManyAssociation(String name, Options options) {
          kclass = options.kClass();
          foreignKey = options.foreignKey();
          this.name = name;
  
      }
  
      private HasManyAssociation(Class kclass, String foreignKey, Document document) {
          this.kclass = kclass;
          this.foreignKey = foreignKey;
          this.document = document;
  
      }
  
  
      @Override
      public Association build(Map params) {
          Document child = (Document) ReflectHelper.staticMethod(kclass, "create", params);
          documentList.add(child);
          return this;
      }
  
      @Override
      public Association remove(Document document) {
          documentList.remove(document);
          document.remove();
          return this;
      }
  
      @Override
      public void save() {
          document.save();
          for (Document subDoc : documentList) {
              subDoc.attributes().put(foreignKey, document.attributes().get("_id"));
              subDoc.save();
              Map<String, Association> associationMap = subDoc.associations();
              //cascade save
              for (Map.Entry<String, Association> entry : associationMap.entrySet()) {
                  if (entry.getValue() instanceof HasManyAssociation || entry.getValue() instanceof HasOneAssociation) {
                      entry.getValue().save();
                  }
              }
          }
      }
  
  
      private Criteria filter() {
          return new Criteria(kclass).where(map(foreignKey, document.attributes().get("_id")));
      }
  
      public Criteria where(Map conditions) {
          return filter().where(conditions);
      }
  
      public Criteria select(List fieldNames) {
          return filter().select(fieldNames);
      }
  
      public Criteria order(Map orderBy) {
          return filter().order(orderBy);
      }
  
      public Criteria skip(int skip) {
          return filter().skip(skip);
      }
  
      public Criteria limit(int limit) {
          return filter().limit(limit);
      }
  
      public int count() {
          return filter().count();
      }
  
      public Criteria in(Map in) {
          return filter().in(in);
      }
  
      public Criteria not(Map not) {
          return filter().not(not);
      }
  
      public Criteria notIn(Map notIn) {
          return filter().notIn(notIn);
      }
  
      public <T> T findById(Object id) {
          return filter().findById(id);
      }
  
      @Override
      public <T> T findOne() {
          List<T> items = findAll();
          if (isEmpty(items)) return null;
          return items.get(0);
      }
  
      public <T> List<T> find(List list) {
          return filter().find(list);
      }
  
      public <T> List<T> findAll() {
          return filter().findAll();
      }
  
  
      @Override
      public Association doNotUseMePlease_newMe(Document document) {
          HasManyAssociation instanceHasManyAssociation = new HasManyAssociation(this.kclass, this.foreignKey, document);
          document.associations().put(name, instanceHasManyAssociation);
          return instanceHasManyAssociation;
      }
  }
  