/**
   * Clones this Element, the datasource and the private stylesheet of this Element. The clone does
   * no longer have a parent, as the old parent would not recognize that new object anymore.
   *
   * @return a clone of this Element.
   */
  public Element clone() {
    try {
      final Element e = (Element) super.clone();
      e.style = (InternalElementStyleSheet) style.clone();
      e.datasource = datasource.clone();
      e.parent = null;
      e.style.updateElementReference(e);
      e.elementContext = null;

      if (attributeExpressions != null) {
        e.attributes = attributes.clone();
        e.attributeExpressions = attributeExpressions.clone();
        final String[] namespaces = e.attributeExpressions.getNameSpaces();
        for (int i = 0; i < namespaces.length; i++) {
          final String namespace = namespaces[i];
          final Map<String, Expression> attrsNs = attributeExpressions.getAttributes(namespace);
          for (final Map.Entry<String, Expression> entry : attrsNs.entrySet()) {
            final Expression exp = entry.getValue();
            e.attributeExpressions.setAttribute(
                namespace, entry.getKey(), (Expression) exp.clone());
          }
        }
      } else {
        if (e.cachedAttributes != null) {
          e.attributes = attributes;
          e.copyOnWrite = true;
          copyOnWrite = true;
        } else {
          e.copyOnWrite = false;
          e.attributes = attributes.clone();
        }
      }

      if (styleExpressions != null) {
        e.styleExpressions = (HashMap<StyleKey, Expression>) styleExpressions.clone();
        for (final Map.Entry<StyleKey, Expression> entry : e.styleExpressions.entrySet()) {
          final Expression exp = entry.getValue();
          entry.setValue((Expression) exp.clone());
        }
      }
      return e;
    } catch (CloneNotSupportedException cne) {
      throw new IllegalStateException(cne);
    }
  }
  /**
   * Creates a deep copy of this element and regenerates all instance-ids.
   *
   * @param preserveElementInstanceIds defines whether this call generates new instance-ids for the
   *     derived elements. Instance-IDs are used by the report processor to recognize reoccurring
   *     elements and must not changed within the report run. Outside of the report processors new
   *     instance ids should be generated at all times to separate instances and to make them
   *     uniquely identifiable.
   * @return the copy of the element.
   */
  public Element derive(final boolean preserveElementInstanceIds) {
    try {
      final Element e = (Element) super.clone();
      e.elementContext = null;
      if (preserveElementInstanceIds == false) {
        e.treeLock = new InstanceID();
      }

      e.style = (InternalElementStyleSheet) style.derive(preserveElementInstanceIds);
      e.datasource = datasource.clone();
      e.parent = null;
      e.style.updateElementReference(e);
      e.attributes = attributes.clone();
      e.copyOnWrite = false;
      final ElementMetaData metaData = e.getMetaData();
      final String[] namespaces = e.attributes.getNameSpaces();
      for (int i = 0; i < namespaces.length; i++) {
        final String namespace = namespaces[i];
        final Map attrsNs = attributes.getAttributes(namespace);
        final Iterator it = attrsNs.entrySet().iterator();
        while (it.hasNext()) {
          final Map.Entry entry = (Map.Entry) it.next();
          final Object value = entry.getValue();

          final String name = (String) entry.getKey();
          final AttributeMetaData data = metaData.getAttributeDescription(namespace, name);
          if (data == null) {
            if (logger.isDebugEnabled()) {
              logger.debug(
                  getElementTypeName()
                      + ": Attribute "
                      + namespace
                      + "|"
                      + name
                      + " is not listed in the metadata.");
            }
          }
          if (value instanceof Cloneable) {
            e.attributes.setAttribute(namespace, name, ObjectUtilities.clone(value));
          } else if (data == null || data.isComputed() == false || data.isDesignTimeValue()) {
            e.attributes.setAttribute(namespace, name, value);
          } else {
            e.attributes.setAttribute(namespace, name, null);
          }
        }
      }
      if (e.cachedAttributes != null
          && e.attributes.getChangeTracker() != e.cachedAttributes.getChangeTracker()) {
        e.cachedAttributes = null;
      }

      if (attributeExpressions != null) {
        e.attributeExpressions = attributeExpressions.clone();
        final String[] attrExprNamespaces = e.attributeExpressions.getNameSpaces();
        for (int i = 0; i < attrExprNamespaces.length; i++) {
          final String namespace = attrExprNamespaces[i];
          final Map attrsNs = attributeExpressions.getAttributes(namespace);
          final Iterator it = attrsNs.entrySet().iterator();
          while (it.hasNext()) {
            final Map.Entry entry = (Map.Entry) it.next();
            final Expression exp = (Expression) entry.getValue();
            e.attributeExpressions.setAttribute(
                namespace, (String) entry.getKey(), exp.getInstance());
          }
        }
      }

      if (styleExpressions != null) {
        //noinspection unchecked
        e.styleExpressions = (HashMap<StyleKey, Expression>) styleExpressions.clone();
        final Iterator<Map.Entry<StyleKey, Expression>> styleExpressionsIt =
            e.styleExpressions.entrySet().iterator();
        while (styleExpressionsIt.hasNext()) {
          final Map.Entry<StyleKey, Expression> entry = styleExpressionsIt.next();
          final Expression exp = entry.getValue();
          entry.setValue(exp.getInstance());
        }
      }
      return e;
    } catch (CloneNotSupportedException cne) {
      throw new IllegalStateException(cne);
    }
  }