/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
package org.apache.maven.archetype.common;

/*
 * $Id$
 */

// ---------------------------------/
// - Imported classes and packages -/
// ---------------------------------/

import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;

import org.apache.maven.archetype.common.util.Format;
import org.apache.maven.archetype.common.util.XMLOutputter;
import org.apache.maven.model.Activation;
import org.apache.maven.model.ActivationFile;
import org.apache.maven.model.ActivationOS;
import org.apache.maven.model.ActivationProperty;
import org.apache.maven.model.Build;
import org.apache.maven.model.BuildBase;
import org.apache.maven.model.CiManagement;
import org.apache.maven.model.ConfigurationContainer;
import org.apache.maven.model.Contributor;
import org.apache.maven.model.Dependency;
import org.apache.maven.model.DependencyManagement;
import org.apache.maven.model.DeploymentRepository;
import org.apache.maven.model.Developer;
import org.apache.maven.model.DistributionManagement;
import org.apache.maven.model.Exclusion;
import org.apache.maven.model.Extension;
import org.apache.maven.model.FileSet;
import org.apache.maven.model.IssueManagement;
import org.apache.maven.model.License;
import org.apache.maven.model.MailingList;
import org.apache.maven.model.Model;
import org.apache.maven.model.Notifier;
import org.apache.maven.model.Organization;
import org.apache.maven.model.Parent;
import org.apache.maven.model.PatternSet;
import org.apache.maven.model.Plugin;
import org.apache.maven.model.PluginConfiguration;
import org.apache.maven.model.PluginContainer;
import org.apache.maven.model.PluginExecution;
import org.apache.maven.model.PluginManagement;
import org.apache.maven.model.Prerequisites;
import org.apache.maven.model.Profile;
import org.apache.maven.model.Relocation;
import org.apache.maven.model.ReportPlugin;
import org.apache.maven.model.ReportSet;
import org.apache.maven.model.Reporting;
import org.apache.maven.model.Repository;
import org.apache.maven.model.RepositoryBase;
import org.apache.maven.model.RepositoryPolicy;
import org.apache.maven.model.Resource;
import org.apache.maven.model.Scm;
import org.apache.maven.model.Site;
import org.codehaus.plexus.util.xml.Xpp3Dom;
import org.jdom2.Content;
import org.jdom2.DefaultJDOMFactory;
import org.jdom2.Document;
import org.jdom2.Element;
import org.jdom2.Text;

/**
 * Class MavenJDOMWriter.
 */
public class MavenJDOMWriter {
    // --------------------------/
    // - Class/Member Variables -/
    // --------------------------/

    /**
     * Field factory.
     */
    private DefaultJDOMFactory factory;

    /**
     * Field lineSeparator.
     */
    private String lineSeparator;

    private static final String LS = System.getProperty("line.separator");

    // ----------------/
    // - Constructors -/
    // ----------------/

    public MavenJDOMWriter() {
        factory = new DefaultJDOMFactory();
        lineSeparator = "\n";
    } // -- org.apache.maven.model.io.jdom.MavenJDOMWriter()

    /**
     * Method write.
     *
     * @param project
     * @param stream
     * @param document
     * @deprecated
     */
    @Deprecated
    public void write(Model project, Document document, OutputStream stream) throws java.io.IOException {
        updateModel(project, new Counter(0), document.getRootElement());

        XMLOutputter outputter = new XMLOutputter();
        outputter.setFormat(Format.getPrettyFormat().setIndent("  ").setLineSeparator(LS));
        outputter.output(document, stream);
    } // -- void write(Model, Document, OutputStream)

    /**
     * Method write.
     *
     * @param project
     * @param writer
     * @param document
     */
    public void write(Model project, Document document, OutputStreamWriter writer) throws java.io.IOException {
        Format format = Format.getRawFormat().setEncoding(writer.getEncoding()).setLineSeparator(LS);
        write(project, document, writer, format);
    } // -- void write(Model, Document, OutputStreamWriter)

    /**
     * Method write.
     *
     * @param project
     * @param jdomFormat
     * @param writer
     * @param document
     */
    public void write(Model project, Document document, Writer writer, Format jdomFormat) throws java.io.IOException {
        updateModel(project, new Counter(0), document.getRootElement());

        XMLOutputter outputter = new XMLOutputter();
        outputter.setFormat(jdomFormat);
        outputter.output(document, writer);
    } // -- void write(Model, Document, Writer, Format)

    // -----------/
    // - Methods -/
    // -----------/

    /**
     * Method findAndReplaceProperties.
     *
     * @param counter
     * @param props
     * @param name
     * @param parent
     */
    protected void findAndReplaceProperties(Counter counter, Element parent, String name, Map props) {
        boolean shouldExist = (props != null) && !props.isEmpty();
        Element element = updateElement(counter, parent, name, shouldExist);
        if (shouldExist) {
            Iterator it = props.keySet().iterator();
            Counter innerCounter = new Counter(counter.getDepth() + 1);
            while (it.hasNext()) {
                String key = (String) it.next();
                findAndReplaceSimpleElement(innerCounter, element, key, (String) props.get(key), null);
            }

            List<String> lst = new ArrayList<>(props.keySet());
            it = element.getChildren().iterator();
            while (it.hasNext()) {
                Element elem = (Element) it.next();
                String key = elem.getName();
                if (!lst.contains(key)) {
                    it.remove();
                }
            }
        }
    } // -- Element findAndReplaceProperties(Counter, Element, String, Map)

    /**
     * Method findAndReplaceSimpleElement.
     *
     * @param counter
     * @param defaultValue
     * @param text
     * @param name
     * @param parent
     */
    protected void findAndReplaceSimpleElement(
            Counter counter, Element parent, String name, String text, String defaultValue) {
        if ((defaultValue != null) && (text != null) && defaultValue.equals(text)) {
            Element element = parent.getChild(name, parent.getNamespace());
            // if exist and is default value or if doesn't exist.. just keep the way it is..
            if (((element != null) && defaultValue.equals(element.getText())) || (element == null)) {
                return;
            }
        }

        boolean shouldExist = (text != null) && (text.trim().length() > 0);
        Element element = updateElement(counter, parent, name, shouldExist);
        if (shouldExist) {
            element.setText(text);
        }
    } // -- Element findAndReplaceSimpleElement(Counter, Element, String, String, String)

    /**
     * Method findAndReplaceSimpleLists.
     *
     * @param counter
     * @param childName
     * @param parentName
     * @param list
     * @param parent
     */
    protected void findAndReplaceSimpleLists(
            Counter counter, Element parent, Collection list, String parentName, String childName) {
        boolean shouldExist = (list != null) && (list.size() > 0);
        Element element = updateElement(counter, parent, parentName, shouldExist);
        if (shouldExist) {
            Iterator it = list.iterator();
            Iterator elIt =
                    element.getChildren(childName, element.getNamespace()).iterator();
            if (!elIt.hasNext()) {
                elIt = null;
            }

            Counter innerCount = new Counter(counter.getDepth() + 1);
            while (it.hasNext()) {
                String value = (String) it.next();
                Element el;
                if ((elIt != null) && elIt.hasNext()) {
                    el = (Element) elIt.next();
                    if (!elIt.hasNext()) {
                        elIt = null;
                    }
                } else {
                    el = factory.element(childName, element.getNamespace());
                    insertAtPreferredLocation(element, el, innerCount);
                }
                el.setText(value);
                innerCount.increaseCount();
            }
            if (elIt != null) {
                while (elIt.hasNext()) {
                    elIt.next();
                    elIt.remove();
                }
            }
        }
    } // -- Element findAndReplaceSimpleLists(Counter, Element, Collection, String, String)

    /**
     * Method findAndReplaceXpp3DOM.
     *
     * @param counter
     * @param dom
     * @param name
     * @param parent
     */
    protected void findAndReplaceXpp3DOM(Counter counter, Element parent, String name, Xpp3Dom dom) {
        boolean shouldExist = (dom != null) && ((dom.getChildCount() > 0) || (dom.getValue() != null));
        Element element = updateElement(counter, parent, name, shouldExist);
        if (shouldExist) {
            replaceXpp3DOM(element, dom, new Counter(counter.getDepth() + 1));
        }
    } // -- Element findAndReplaceXpp3DOM(Counter, Element, String, Xpp3Dom)

    /**
     * Method insertAtPreferredLocation.
     *
     * @param parent
     * @param counter
     * @param child
     */
    protected void insertAtPreferredLocation(Element parent, Element child, Counter counter) {
        int contentIndex = 0;
        int elementCounter = 0;
        Iterator it = parent.getContent().iterator();
        Text lastText = null;
        int offset = 0;
        while (it.hasNext() && (elementCounter <= counter.getCurrentIndex())) {
            Object next = it.next();
            offset = offset + 1;
            if (next instanceof Element) {
                elementCounter = elementCounter + 1;
                contentIndex = contentIndex + offset;
                offset = 0;
            }
            if ((next instanceof Text) && it.hasNext()) {
                lastText = (Text) next;
            }
        }
        if ((lastText != null) && (lastText.getTextTrim().length() == 0)) {
            lastText = (Text) lastText.clone();
        } else {
            StringBuilder starter = new StringBuilder(lineSeparator);
            for (int i = 0; i < counter.getDepth(); i++) {
                starter.append("  "); // TODO make settable?
            }
            lastText = factory.text(starter.toString());
        }
        if (parent.getContentSize() == 0) {
            Text finalText = (Text) lastText.clone();
            finalText.setText(
                    finalText.getText().substring(0, finalText.getText().length() - "  ".length()));
            parent.addContent(contentIndex, finalText);
        }
        parent.addContent(contentIndex, child);
        parent.addContent(contentIndex, lastText);
    } // -- void insertAtPreferredLocation(Element, Element, Counter)

    /**
     * Method iterateContributor.
     *
     * @param counter
     * @param childTag
     * @param parentTag
     * @param list
     * @param parent
     */
    protected void iterateContributor(
            Counter counter, Element parent, Collection list, String parentTag, String childTag) {
        boolean shouldExist = (list != null) && (list.size() > 0);
        Element element = updateElement(counter, parent, parentTag, shouldExist);
        if (shouldExist) {
            Iterator it = list.iterator();
            Iterator elIt =
                    element.getChildren(childTag, element.getNamespace()).iterator();
            if (!elIt.hasNext()) {
                elIt = null;
            }

            Counter innerCount = new Counter(counter.getDepth() + 1);
            while (it.hasNext()) {
                Contributor value = (Contributor) it.next();
                Element el;
                if ((elIt != null) && elIt.hasNext()) {
                    el = (Element) elIt.next();
                    if (!elIt.hasNext()) {
                        elIt = null;
                    }
                } else {
                    el = factory.element(childTag, element.getNamespace());
                    insertAtPreferredLocation(element, el, innerCount);
                }
                updateContributor(value, childTag, innerCount, el);
                innerCount.increaseCount();
            }
            if (elIt != null) {
                while (elIt.hasNext()) {
                    elIt.next();
                    elIt.remove();
                }
            }
        }
    } // -- void iterateContributor(Counter, Element, Collection, String,
    // String)

    /**
     * Method iterateDependency.
     *
     * @param counter
     * @param childTag
     * @param parentTag
     * @param list
     * @param parent
     */
    protected void iterateDependency(
            Counter counter, Element parent, Collection list, String parentTag, String childTag) {
        boolean shouldExist = (list != null) && (list.size() > 0);
        Element element = updateElement(counter, parent, parentTag, shouldExist);
        if (shouldExist) {
            Iterator it = list.iterator();
            Iterator elIt =
                    element.getChildren(childTag, element.getNamespace()).iterator();
            if (!elIt.hasNext()) {
                elIt = null;
            }

            Counter innerCount = new Counter(counter.getDepth() + 1);
            while (it.hasNext()) {
                Dependency value = (Dependency) it.next();
                Element el;
                if ((elIt != null) && elIt.hasNext()) {
                    el = (Element) elIt.next();
                    if (!elIt.hasNext()) {
                        elIt = null;
                    }
                } else {
                    el = factory.element(childTag, element.getNamespace());
                    insertAtPreferredLocation(element, el, innerCount);
                }
                updateDependency(value, childTag, innerCount, el);
                innerCount.increaseCount();
            }
            if (elIt != null) {
                while (elIt.hasNext()) {
                    elIt.next();
                    elIt.remove();
                }
            }
        }
    } // -- void iterateDependency(Counter, Element, java.util.Collection, String,
    // String)

    /**
     * Method iterateDeveloper.
     *
     * @param counter
     * @param childTag
     * @param parentTag
     * @param list
     * @param parent
     */
    protected void iterateDeveloper(
            Counter counter, Element parent, Collection list, String parentTag, String childTag) {
        boolean shouldExist = (list != null) && (list.size() > 0);
        Element element = updateElement(counter, parent, parentTag, shouldExist);
        if (shouldExist) {
            Iterator it = list.iterator();
            Iterator elIt =
                    element.getChildren(childTag, element.getNamespace()).iterator();
            if (!elIt.hasNext()) {
                elIt = null;
            }

            Counter innerCount = new Counter(counter.getDepth() + 1);
            while (it.hasNext()) {
                Developer value = (Developer) it.next();
                Element el;
                if ((elIt != null) && elIt.hasNext()) {
                    el = (Element) elIt.next();
                    if (!elIt.hasNext()) {
                        elIt = null;
                    }
                } else {
                    el = factory.element(childTag, element.getNamespace());
                    insertAtPreferredLocation(element, el, innerCount);
                }
                updateDeveloper(value, childTag, innerCount, el);
                innerCount.increaseCount();
            }
            if (elIt != null) {
                while (elIt.hasNext()) {
                    elIt.next();
                    elIt.remove();
                }
            }
        }
    } // -- void iterateDeveloper(Counter, Element, java.util.Collection, String,
    // String)

    /**
     * Method iterateExclusion.
     *
     * @param counter
     * @param childTag
     * @param parentTag
     * @param list
     * @param parent
     */
    protected void iterateExclusion(
            Counter counter, Element parent, Collection list, String parentTag, String childTag) {
        boolean shouldExist = (list != null) && (list.size() > 0);
        Element element = updateElement(counter, parent, parentTag, shouldExist);
        if (shouldExist) {
            Iterator it = list.iterator();
            Iterator elIt =
                    element.getChildren(childTag, element.getNamespace()).iterator();
            if (!elIt.hasNext()) {
                elIt = null;
            }

            Counter innerCount = new Counter(counter.getDepth() + 1);
            while (it.hasNext()) {
                Exclusion value = (Exclusion) it.next();
                Element el;
                if ((elIt != null) && elIt.hasNext()) {
                    el = (Element) elIt.next();
                    if (!elIt.hasNext()) {
                        elIt = null;
                    }
                } else {
                    el = factory.element(childTag, element.getNamespace());
                    insertAtPreferredLocation(element, el, innerCount);
                }
                updateExclusion(value, childTag, innerCount, el);
                innerCount.increaseCount();
            }
            if (elIt != null) {
                while (elIt.hasNext()) {
                    elIt.next();
                    elIt.remove();
                }
            }
        }
    } // -- void iterateExclusion(Counter, Element, Collection, String, String)

    /**
     * Method iterateExtension.
     *
     * @param counter
     * @param childTag
     * @param parentTag
     * @param list
     * @param parent
     */
    protected void iterateExtension(
            Counter counter, Element parent, Collection list, String parentTag, String childTag) {
        boolean shouldExist = (list != null) && (list.size() > 0);
        Element element = updateElement(counter, parent, parentTag, shouldExist);
        if (shouldExist) {
            Iterator it = list.iterator();
            Iterator elIt =
                    element.getChildren(childTag, element.getNamespace()).iterator();
            if (!elIt.hasNext()) {
                elIt = null;
            }

            Counter innerCount = new Counter(counter.getDepth() + 1);
            while (it.hasNext()) {
                Extension value = (Extension) it.next();
                Element el;
                if ((elIt != null) && elIt.hasNext()) {
                    el = (Element) elIt.next();
                    if (!elIt.hasNext()) {
                        elIt = null;
                    }
                } else {
                    el = factory.element(childTag, element.getNamespace());
                    insertAtPreferredLocation(element, el, innerCount);
                }
                updateExtension(value, childTag, innerCount, el);
                innerCount.increaseCount();
            }
            if (elIt != null) {
                while (elIt.hasNext()) {
                    elIt.next();
                    elIt.remove();
                }
            }
        }
    } // -- void iterateExtension(Counter, Element, Collection, String, String)

    /**
     * Method iterateLicense.
     *
     * @param counter
     * @param childTag
     * @param parentTag
     * @param list
     * @param parent
     */
    protected void iterateLicense(Counter counter, Element parent, Collection list, String parentTag, String childTag) {
        boolean shouldExist = (list != null) && (list.size() > 0);
        Element element = updateElement(counter, parent, parentTag, shouldExist);
        if (shouldExist) {
            Iterator it = list.iterator();
            Iterator elIt =
                    element.getChildren(childTag, element.getNamespace()).iterator();
            if (!elIt.hasNext()) {
                elIt = null;
            }

            Counter innerCount = new Counter(counter.getDepth() + 1);
            while (it.hasNext()) {
                License value = (License) it.next();
                Element el;
                if ((elIt != null) && elIt.hasNext()) {
                    el = (Element) elIt.next();
                    if (!elIt.hasNext()) {
                        elIt = null;
                    }
                } else {
                    el = factory.element(childTag, element.getNamespace());
                    insertAtPreferredLocation(element, el, innerCount);
                }
                updateLicense(value, childTag, innerCount, el);
                innerCount.increaseCount();
            }
            if (elIt != null) {
                while (elIt.hasNext()) {
                    elIt.next();
                    elIt.remove();
                }
            }
        }
    } // -- void iterateLicense(Counter, Element, java.util.Collection, String,
    // String)

    /**
     * Method iterateMailingList.
     *
     * @param counter
     * @param childTag
     * @param parentTag
     * @param list
     * @param parent
     */
    protected void iterateMailingList(
            Counter counter, Element parent, java.util.Collection list, String parentTag, String childTag) {
        boolean shouldExist = (list != null) && (list.size() > 0);
        Element element = updateElement(counter, parent, parentTag, shouldExist);
        if (shouldExist) {
            Iterator it = list.iterator();
            Iterator elIt =
                    element.getChildren(childTag, element.getNamespace()).iterator();
            if (!elIt.hasNext()) {
                elIt = null;
            }

            Counter innerCount = new Counter(counter.getDepth() + 1);
            while (it.hasNext()) {
                MailingList value = (MailingList) it.next();
                Element el;
                if ((elIt != null) && elIt.hasNext()) {
                    el = (Element) elIt.next();
                    if (!elIt.hasNext()) {
                        elIt = null;
                    }
                } else {
                    el = factory.element(childTag, element.getNamespace());
                    insertAtPreferredLocation(element, el, innerCount);
                }
                updateMailingList(value, childTag, innerCount, el);
                innerCount.increaseCount();
            }
            if (elIt != null) {
                while (elIt.hasNext()) {
                    elIt.next();
                    elIt.remove();
                }
            }
        }
    } // -- void iterateMailingList(Counter, Element, java.util.Collection, String,
    // String)

    /**
     * Method iterateNotifier.
     *
     * @param counter
     * @param childTag
     * @param parentTag
     * @param list
     * @param parent
     */
    protected void iterateNotifier(
            Counter counter, Element parent, java.util.Collection list, String parentTag, String childTag) {
        boolean shouldExist = (list != null) && (list.size() > 0);
        Element element = updateElement(counter, parent, parentTag, shouldExist);
        if (shouldExist) {
            Iterator it = list.iterator();
            Iterator elIt =
                    element.getChildren(childTag, element.getNamespace()).iterator();
            if (!elIt.hasNext()) {
                elIt = null;
            }

            Counter innerCount = new Counter(counter.getDepth() + 1);
            while (it.hasNext()) {
                Notifier value = (Notifier) it.next();
                Element el;
                if ((elIt != null) && elIt.hasNext()) {
                    el = (Element) elIt.next();
                    if (!elIt.hasNext()) {
                        elIt = null;
                    }
                } else {
                    el = factory.element(childTag, element.getNamespace());
                    insertAtPreferredLocation(element, el, innerCount);
                }
                updateNotifier(value, childTag, innerCount, el);
                innerCount.increaseCount();
            }
            if (elIt != null) {
                while (elIt.hasNext()) {
                    elIt.next();
                    elIt.remove();
                }
            }
        }
    } // -- void iterateNotifier(Counter, Element, java.util.Collection, String,
    // String)

    /**
     * Method iteratePlugin.
     *
     * @param counter
     * @param childTag
     * @param parentTag
     * @param list
     * @param parent
     */
    protected void iteratePlugin(
            Counter counter, Element parent, java.util.Collection list, String parentTag, String childTag) {
        boolean shouldExist = (list != null) && (list.size() > 0);
        Element element = updateElement(counter, parent, parentTag, shouldExist);
        if (shouldExist) {
            Iterator it = list.iterator();
            Iterator elIt =
                    element.getChildren(childTag, element.getNamespace()).iterator();
            if (!elIt.hasNext()) {
                elIt = null;
            }

            Counter innerCount = new Counter(counter.getDepth() + 1);
            while (it.hasNext()) {
                Plugin value = (Plugin) it.next();
                Element el;
                if ((elIt != null) && elIt.hasNext()) {
                    el = (Element) elIt.next();
                    if (!elIt.hasNext()) {
                        elIt = null;
                    }
                } else {
                    el = factory.element(childTag, element.getNamespace());
                    insertAtPreferredLocation(element, el, innerCount);
                }
                updatePlugin(value, childTag, innerCount, el);
                innerCount.increaseCount();
            }
            if (elIt != null) {
                while (elIt.hasNext()) {
                    elIt.next();
                    elIt.remove();
                }
            }
        }
    } // -- void iteratePlugin(Counter, Element, java.util.Collection, String,
    // String)

    /**
     * Method iteratePluginExecution.
     *
     * @param counter
     * @param childTag
     * @param parentTag
     * @param list
     * @param parent
     */
    protected void iteratePluginExecution(
            Counter counter, Element parent, java.util.Collection list, String parentTag, String childTag) {
        boolean shouldExist = (list != null) && (list.size() > 0);
        Element element = updateElement(counter, parent, parentTag, shouldExist);
        if (shouldExist) {
            Iterator it = list.iterator();
            Iterator elIt =
                    element.getChildren(childTag, element.getNamespace()).iterator();
            if (!elIt.hasNext()) {
                elIt = null;
            }

            Counter innerCount = new Counter(counter.getDepth() + 1);
            while (it.hasNext()) {
                PluginExecution value = (PluginExecution) it.next();
                Element el;
                if ((elIt != null) && elIt.hasNext()) {
                    el = (Element) elIt.next();
                    if (!elIt.hasNext()) {
                        elIt = null;
                    }
                } else {
                    el = factory.element(childTag, element.getNamespace());
                    insertAtPreferredLocation(element, el, innerCount);
                }
                updatePluginExecution(value, childTag, innerCount, el);
                innerCount.increaseCount();
            }
            if (elIt != null) {
                while (elIt.hasNext()) {
                    elIt.next();
                    elIt.remove();
                }
            }
        }
    } // -- void iteratePluginExecution(Counter, Element, java.util.Collection, String,
    // String)

    /**
     * Method iterateProfile.
     *
     * @param counter
     * @param childTag
     * @param parentTag
     * @param list
     * @param parent
     */
    protected void iterateProfile(
            Counter counter, Element parent, java.util.Collection list, String parentTag, String childTag) {
        boolean shouldExist = (list != null) && (list.size() > 0);
        Element element = updateElement(counter, parent, parentTag, shouldExist);
        if (shouldExist) {
            Iterator it = list.iterator();
            Iterator elIt =
                    element.getChildren(childTag, element.getNamespace()).iterator();
            if (!elIt.hasNext()) {
                elIt = null;
            }

            Counter innerCount = new Counter(counter.getDepth() + 1);
            while (it.hasNext()) {
                Profile value = (Profile) it.next();
                Element el;
                if ((elIt != null) && elIt.hasNext()) {
                    el = (Element) elIt.next();
                    if (!elIt.hasNext()) {
                        elIt = null;
                    }
                } else {
                    el = factory.element(childTag, element.getNamespace());
                    insertAtPreferredLocation(element, el, innerCount);
                }
                updateProfile(value, childTag, innerCount, el);
                innerCount.increaseCount();
            }
            if (elIt != null) {
                while (elIt.hasNext()) {
                    elIt.next();
                    elIt.remove();
                }
            }
        }
    } // -- void iterateProfile(Counter, Element, java.util.Collection, String,
    // String)

    /**
     * Method iterateReportPlugin.
     *
     * @param counter
     * @param childTag
     * @param parentTag
     * @param list
     * @param parent
     */
    protected void iterateReportPlugin(
            Counter counter, Element parent, java.util.Collection list, String parentTag, String childTag) {
        boolean shouldExist = (list != null) && (list.size() > 0);
        Element element = updateElement(counter, parent, parentTag, shouldExist);
        if (shouldExist) {
            Iterator it = list.iterator();
            Iterator elIt =
                    element.getChildren(childTag, element.getNamespace()).iterator();
            if (!elIt.hasNext()) {
                elIt = null;
            }

            Counter innerCount = new Counter(counter.getDepth() + 1);
            while (it.hasNext()) {
                ReportPlugin value = (ReportPlugin) it.next();
                Element el;
                if ((elIt != null) && elIt.hasNext()) {
                    el = (Element) elIt.next();
                    if (!elIt.hasNext()) {
                        elIt = null;
                    }
                } else {
                    el = factory.element(childTag, element.getNamespace());
                    insertAtPreferredLocation(element, el, innerCount);
                }
                updateReportPlugin(value, childTag, innerCount, el);
                innerCount.increaseCount();
            }
            if (elIt != null) {
                while (elIt.hasNext()) {
                    elIt.next();
                    elIt.remove();
                }
            }
        }
    } // -- void iterateReportPlugin(Counter, Element, java.util.Collection, String,
    // String)

    /**
     * Method iterateReportSet.
     *
     * @param counter
     * @param childTag
     * @param parentTag
     * @param list
     * @param parent
     */
    protected void iterateReportSet(
            Counter counter, Element parent, java.util.Collection list, String parentTag, String childTag) {
        boolean shouldExist = (list != null) && (list.size() > 0);
