/*
 * 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.
 */

/* $Id: XMPHandler.java 426584 2006-07-28 16:01:47Z jeremias $ */

package org.apache.xmlgraphics.xmp;

import java.util.Stack;

import org.apache.xmlgraphics.util.QName;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.AttributesImpl;
import org.xml.sax.helpers.DefaultHandler;

/**
 * Passive XMP parser implemented as a SAX DefaultHandler. After the XML document has been parsed
 * the Metadata object can be retrieved.
 */
public class XMPHandler extends DefaultHandler {

    private Metadata meta;
    
    private StringBuffer content = new StringBuffer();
    //private Attributes lastAttributes;
    private Stack attributesStack = new Stack();
    //private Stack contextStack = new Stack();
    
    private QName currentPropertyName;
    private XMPProperty currentProperty;
    private XMPComplexValue currentComplexValue;
    
    /** @return the parsed metadata, available after the parsing. */
    public Metadata getMetadata() {
        return this.meta;
    }

    // --- Overrides ---
    
    /**
     * @see org.xml.sax.helpers.DefaultHandler#startElement(
     *      java.lang.String, java.lang.String, java.lang.String, org.xml.sax.Attributes)
     */
    public void startElement(String uri, String localName, String qName, Attributes attributes) 
                throws SAXException {
        super.startElement(uri, localName, qName, attributes);
        content.setLength(0); //Reset text buffer (see characters())
        attributesStack.push(new AttributesImpl(attributes));
        
        if (XMPConstants.XMP_NAMESPACE.equals(uri)) {
            if (!"xmpmeta".equals(localName)) {
                throw new SAXException("Expected x:xmpmeta element, not " + qName);
            }
            if (this.meta != null) {
                throw new SAXException("Invalid XMP document. Root already received earlier.");
            }
            this.meta = new Metadata();
        } else if (XMPConstants.RDF_NAMESPACE.equals(uri)) {
            if ("RDF".equals(localName)) {
                if (this.meta == null) {
                    this.meta = new Metadata();
                }
            } else if ("Description".equals(localName)) {
                if (currentPropertyName == null) {
                    //rdf:RDF is the parent
                    String about = attributes.getValue(XMPConstants.RDF_NAMESPACE, "about");
                } else {
                    //a structured property is the parent
                }
            } else if ("Seq".equals(localName)) {
                this.currentComplexValue = new XMPArray(XMPArrayType.SEQ);
            } else if ("Bag".equals(localName)) {
                this.currentComplexValue = new XMPArray(XMPArrayType.BAG);
            } else if ("Alt".equals(localName)) {
                this.currentComplexValue = new XMPArray(XMPArrayType.ALT);
            } else if ("li".equals(localName)) {
            }
        } else {
            this.currentPropertyName = new QName(uri, qName);
        }
    }
    
    /**
     * @see org.xml.sax.helpers.DefaultHandler#endElement(
     *      java.lang.String, java.lang.String, java.lang.String)
     */
    public void endElement(String uri, String localName, String qName) throws SAXException {
        Attributes atts = (Attributes)attributesStack.pop();
        if (XMPConstants.XMP_NAMESPACE.equals(uri)) {
            //nop
        } else if (XMPConstants.RDF_NAMESPACE.equals(uri)) {
            if ("li".equals(localName)) {
                String s = content.toString().trim();
                if (s.length() > 0) {
                    getCurrentArray().add(s);
                }
            } else {
                //nop
            }
        } else {
            if (this.currentComplexValue != null) {
                this.currentProperty = new XMPProperty(this.currentPropertyName, 
                                this.currentComplexValue);
                this.currentComplexValue = null;
            } else {
                String s = content.toString().trim();
                this.currentProperty = new XMPProperty(this.currentPropertyName, s);
                String lang = atts.getValue(XMPConstants.XML_NS, "lang");
                if (lang != null) {
                    this.currentProperty.setXMLLang(lang);
                }
            }
            this.meta.setProperty(this.currentProperty);
            this.currentProperty = null;
            this.currentPropertyName = null;
        }
        content.setLength(0); //Reset text buffer (see characters())
        super.endElement(uri, localName, qName);
    }

    private XMPArray getCurrentArray() {
        return (XMPArray)this.currentComplexValue;
    }

    /** @see org.xml.sax.ContentHandler#characters(char[], int, int) */
    public void characters(char[] ch, int start, int length) throws SAXException {
        content.append(ch, start, length);
    }

}
