/*
 * $Header: /home/cvspublic/jakarta-slide/proposals/tamino/src/store/org/apache/slide/store/tamino/jdomobjects/XNodeRevisionDescriptors.java,v 1.3 2004/07/30 06:52:00 ozeigermann Exp $
 * $Revision: 1.3 $
 * $Date: 2004/07/30 06:52:00 $
 *
 * ====================================================================
 *
 * Copyright 1999-2004 The Apache Software Foundation.
 *
 * Licensed 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.slide.store.tamino.jdomobjects;

import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.Vector;
import org.apache.slide.content.NodeRevisionDescriptors;
import org.apache.slide.content.NodeRevisionNumber;
import org.apache.slide.util.XAssertionFailed;
import org.jdom.Element;

/**
 * Serialize NodeProperty objects to and from XML.
 *
 * @author martin.wallmer@softwareag.com
 *
 * @version $Revision: 1.3 $
 */
public class XNodeRevisionDescriptors implements XJdom {
    /**
     * returns the jdom aspect of this descriptors.
     *
     * @pre        revisionDescriptor != null
     * @post
     *
     * @return     Element representing this nodeRevisionDescriptor
     */
    public static Element toXml (NodeRevisionDescriptors revisionDescriptors) {
        if (revisionDescriptors == null) {
            throw new XAssertionFailed();
        }

        Element e = new Element (E_REVISION_DESCRIPTORS);
        e.setAttribute( A_IS_VERSIONED, String.valueOf(revisionDescriptors.isVersioned()) );
        e.addContent(toXmlLatestRevisionNumbersElement(revisionDescriptors));
        e.addContent(toXmlBranchListElement(revisionDescriptors));
        String initialRevision = revisionDescriptors.getInitialRevision().toString();
        Element initRevElement = new Element (E_INITIAL_REVISION);
        initRevElement.setAttribute(A_REVISION_NUMBER, initialRevision);
        e.addContent(initRevElement);

        return e;
    }

    public static void toStream (XmlStream xs, NodeRevisionDescriptors revisionDescriptors) {
        if (revisionDescriptors == null) {
            throw new XAssertionFailed();
        }
        
        xs.addStartElement(E_REVISION_DESCRIPTORS);
        xs.addAttribute(A_IS_VERSIONED, String.valueOf(revisionDescriptors.isVersioned()) );
        xs.addEndElement();
        toStreamLatestRevisionNumbersElement(xs, revisionDescriptors);
        toStreamBranchListElement(xs, revisionDescriptors);
        String initialRevision = revisionDescriptors.getInitialRevision().toString();
        xs.addStartElement(E_INITIAL_REVISION);
        xs.addAttribute(A_REVISION_NUMBER, initialRevision);
        xs.addEndElement();
        xs.addCloseElement(E_INITIAL_REVISION);
        xs.addCloseElement(E_REVISION_DESCRIPTORS);
    }

    /**
     * creates an Element with the latest Revision number of each branch.
     *
     */
    private static Element toXmlLatestRevisionNumbersElement (NodeRevisionDescriptors revisionDescriptors) {
        Element     latestRevisions = new Element (E_LATEST_LIST);
        Enumeration branchNames = revisionDescriptors.enumerateBranchNames();

        while (branchNames.hasMoreElements()) {
            Element latestRevElement = new Element (E_LATEST_REVISION);
            String branchName = (String)branchNames.nextElement();
            String number = revisionDescriptors.getLatestRevision(branchName).toString();
            latestRevElement.setAttribute (A_BRANCH_NAME, branchName);
            latestRevElement.setAttribute (A_REVISION_NUMBER, number);

            latestRevisions.addContent(latestRevElement);
        }

        return latestRevisions;
    }
    private static void toStreamLatestRevisionNumbersElement (XmlStream xs, NodeRevisionDescriptors revisionDescriptors) {
        xs.addStartElement(E_LATEST_LIST);
        xs.addEndElement();
        Enumeration branchNames = revisionDescriptors.enumerateBranchNames();

        while (branchNames.hasMoreElements()) {
            xs.addStartElement(E_LATEST_REVISION);
            String branchName = (String)branchNames.nextElement();
            String number = revisionDescriptors.getLatestRevision(branchName).toString();
            xs.addAttribute(A_BRANCH_NAME, branchName);
            xs.addAttribute(A_REVISION_NUMBER, number);
            xs.addEndElement();
            xs.addCloseElement(E_LATEST_REVISION);

        }
        xs.addCloseElement(E_LATEST_LIST);
    }


    /**
     * creates an Element with all successors of each branch.
     * A branch is identified by the first NodeRevisionNumber of the branch
     */
    private static Element toXmlBranchListElement(NodeRevisionDescriptors revisionDescriptors) {
        Element branchListElement = new Element (E_BRANCHLIST);

        Enumeration branchKeys = revisionDescriptors.enumerateRevisionNumbers();
        while (branchKeys.hasMoreElements()) {
            Element branchElement = new Element (E_BRANCH);
            branchListElement.addContent(branchElement);
            NodeRevisionNumber number = (NodeRevisionNumber) branchKeys.nextElement();

            branchElement.setAttribute(A_REVISION_NUMBER, number.toString());

            Enumeration successors = revisionDescriptors.getSuccessors(number);
            while (successors.hasMoreElements()) {
                Element successorElement = new Element (E_SUCCESSOR);
                String sNumber = ((NodeRevisionNumber)successors.nextElement()).toString();
                successorElement.setAttribute( A_REVISION_NUMBER, sNumber);
                branchElement.addContent(successorElement);
            }
        }

        return branchListElement;
    }

    private static void toStreamBranchListElement(XmlStream xs, NodeRevisionDescriptors revisionDescriptors) {
        xs.addStartElement(E_BRANCHLIST);
        xs.addEndElement();

        Enumeration branchKeys = revisionDescriptors.enumerateRevisionNumbers();
        while (branchKeys.hasMoreElements()) {
            xs.addStartElement(E_BRANCH);
            NodeRevisionNumber number = (NodeRevisionNumber) branchKeys.nextElement();

            xs.addAttribute(A_REVISION_NUMBER, number.toString());
            xs.addEndElement();

            Enumeration successors = revisionDescriptors.getSuccessors(number);
            while (successors.hasMoreElements()) {
                xs.addStartElement(E_SUCCESSOR);
                String sNumber = ((NodeRevisionNumber)successors.nextElement()).toString();
                xs.addAttribute(A_REVISION_NUMBER, sNumber);
                xs.addEndElement();
                xs.addCloseElement(E_SUCCESSOR);
            }
            xs.addCloseElement(E_BRANCH);
        }
        xs.addCloseElement(E_BRANCHLIST);
    }


    //--  from xml

    /**
     * retrieves the revisions aspect of this resource.
     *
     * @pre        object != null
     * @post
     *
     * @return     the revisions aspect of this resource
     */
    public static NodeRevisionDescriptors toSlideExtract (Element root) {
        Element jdomAspect;

        jdomAspect = root.getChild (E_REVISION_DESCRIPTORS);
        if (jdomAspect == null) {
            return null;
        } else {
            return XNodeRevisionDescriptors.toSlide(jdomAspect);
        }
    }

    /**
     * creates the slide aspect of this NodeRevisionDescriptors
     */
    public static NodeRevisionDescriptors toSlide (Element jdomAspect) {
        if (jdomAspect == null) {
            throw new XAssertionFailed();
        }
        String s = jdomAspect.getChild(E_INITIAL_REVISION).getAttributeValue(A_REVISION_NUMBER);
        NodeRevisionNumber initRev = new NodeRevisionNumber (s);

        // workingRevisions currently not used, not null!
        Hashtable workingRevisions = new Hashtable ();

        Hashtable branches = branches (jdomAspect.getChild (E_BRANCHLIST));
        Hashtable latestRevisionNumbers =
            latestRevisionNumbers (jdomAspect.getChild (E_LATEST_LIST));

        String isVersionedStr = jdomAspect.getAttributeValue( A_IS_VERSIONED );
        // Note: the next yields false if string is null:
        boolean isVersioned = (new Boolean(isVersionedStr)).booleanValue();

        return new NodeRevisionDescriptors (null, initRev,
                                            workingRevisions,
                                            latestRevisionNumbers,
                                            branches, isVersioned);
    }

    /**
     * creates a hashtable with the latest revision for each branch
     *
     * @param lastRevElement
     *
     * @return hashtable with all branches
     */
    private static Hashtable latestRevisionNumbers (Element lastRevElement) {
        Hashtable latestRevisionNumbers = new Hashtable ();

        List latestList = lastRevElement.getChildren ();
        Iterator it = latestList.iterator();
        while (it.hasNext()) {
            Element latestRevisionElement = (Element)it.next();
            String branch = latestRevisionElement.getAttributeValue (A_BRANCH_NAME);
            String number = latestRevisionElement.getAttributeValue (A_REVISION_NUMBER);
            latestRevisionNumbers.put (branch, new NodeRevisionNumber (number));
        }
        return latestRevisionNumbers;
    }

    /**
     * creates a hashtable with all branches from branchListElement
     *
     * @param branchListElement
     *
     * @return hashtable with all branches
     */
    private static Hashtable branches (Element branchListElement) {
        Hashtable branches = new Hashtable ();

        Iterator branchIterator = branchListElement.getChildren (E_BRANCH).iterator();
        while (branchIterator.hasNext()) {
            Element branchElement = (Element)branchIterator.next();
            String key = branchElement.getAttributeValue (A_REVISION_NUMBER);
            List successorList = branchElement.getChildren (E_SUCCESSOR);
            Vector successors = new Vector (successorList.size());

            Iterator it = successorList.iterator();
            while (it.hasNext()) {
                Element successorElement = (Element)it.next();
                String number = successorElement.getAttributeValue(A_REVISION_NUMBER);
                successors.add (new NodeRevisionNumber (number));
            }

            branches.put (new NodeRevisionNumber (key), successors);
        }

        return branches;
    }
}

