/**
   * INTERNAL: Iterate the non-containment nodes and copy all uni/bi-directional properties on the
   * copy.
   *
   * @param doMap
   * @param ncPropMap
   */
  private void processNonContainmentNodesPrivate(HashMap doMap, HashMap ncPropMap) {
    // for the doMap and ncPropMap we can either deep copy them all now or each one during
    // rereferencing later
    // iterate nc property map and set bidirectional/unidirectional properties that are in scope
    for (Iterator ncIterator = ncPropMap.keySet().iterator();
        ncIterator.hasNext(); ) { // p.142 limit scope of while by using for
      // get current source dataobject (the one we will set properties on)
      DataObject sourceDO = (DataObject) ncIterator.next();

      // get the list of properties for the current do
      ArrayList aList = (ArrayList) ncPropMap.get(sourceDO);

      // iterate property list
      for (Iterator propIterator = aList.iterator();
          propIterator.hasNext(); ) { // p.142 limit scope of while by using for
        // get current property
        SDOProperty aProperty = (SDOProperty) propIterator.next();

        /*
         * Stored in the map we have
         * doMap: (a=key, a'=value)
         * ncPropMap (a=key, (list of props)=value
         * We get the copy from the doMap
         * We get the copy of the source by doing a get on the current source do
         */

        // get original object that sourceDO points to via current property
        Object targetDO = sourceDO.get(aProperty);

        // flag whether the property is inside the copy tree
        boolean isPropertyInsideCopyTreeScope = false;

        // get sourceDO copy that we will be setting the property on
        DataObject sourceDOCopy = null;

        // lookup copy of targetDO in map
        Object targetDOCopy = null;

        /*
         * Handle 1-n many case
         * For containment=true
         *   the DO's will be cached previously, and both bidirectional (one) and unidirectional
         *   properties will set the copy on the copy object
         * For containment=false
         *   the DO's will not be cached (outside the tree), only unidirectional properties
         *   will be set using the original list
         */
        if (aProperty.isMany()) {
          // create new list to hold copied list items
          ListWrapper targetList = (ListWrapper) targetDO;

          // get source\DO copy that we will be setting the property on
          sourceDOCopy = (DataObject) doMap.get(sourceDO);

          // lookup copy of targetDO in map
          targetDOCopy = new ArrayList();
          for (int i = 0, size = targetList.size(); i < size; i++) {
            // get sourceDO key - used as a lookup in our doMap
            DataObject sourceDOCopyKey = (DataObject) targetList.get(i);
            DataObject sourceDOCopyValue = (DataObject) doMap.get(sourceDOCopyKey);

            // add copy to new list
            if (sourceDOCopyValue != null) {
              // bidirectional/unidirectional inside copy tree - use copy object
              ((List) targetDOCopy).add(sourceDOCopyValue);
            } else {
              // non-containment properties are not cached - store original for unidirectional
              // targetDOCopy.add(sourceDOCopyKey);
            }
          }

          // check if the target copies are in our map (inside copy tree scope)
          // when containment = false then targetDOCopy is empty
          // Assume: all items in the list share the same property
          isPropertyInsideCopyTreeScope = ((List) targetDOCopy).size() > 0;
        } else {
          // handle 1-1 DataObject
          // lookup copy of targetDO in map
          targetDOCopy = doMap.get(targetDO);

          // get sourceDO copy that we will be setting the property on
          sourceDOCopy = (DataObject) doMap.get(sourceDO);

          // check if the target copy is in our map (inside copy tree scope)
          isPropertyInsideCopyTreeScope = targetDOCopy != null;
        }

        // set nc property if we are in the copy tree
        // check if the target copy is in our map (inside copy tree scope)
        if (isPropertyInsideCopyTreeScope) {
          ((SDODataObject) sourceDOCopy).set(aProperty, targetDOCopy, false);
        } else {
          // only set unidirectional properties
          if (null == aProperty.getOpposite()) {
            // spec 3.9.4 set property to original object when unidirectional
            ((SDODataObject) sourceDOCopy).set(aProperty, targetDO, false);
          }
        }
      }
    }
  }