public final class

GDataParser

extends Object
implements ContentHandler
/*
 * Copyright (C) 2009 The Android Open Source Project
 *
 * 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 com.cooliris.picasa;

import org.xml.sax.Attributes;
import org.xml.sax.ContentHandler;
import org.xml.sax.Locator;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.AttributesImpl;

import android.text.format.Time;

public final class GDataParser implements ContentHandler {
    public static final String APP_NAMESPACE = "http://www.w3.org/2007/app";
    public static final String ATOM_NAMESPACE = "http://www.w3.org/2005/Atom";
    public static final String GD_NAMESPACE = "http://schemas.google.com/g/2005";
    public static final String GPHOTO_NAMESPACE = "http://schemas.google.com/photos/2007";
    public static final String MEDIA_RSS_NAMESPACE = "http://search.yahoo.com/mrss/";
    public static final String GML_NAMESPACE = "http://www.opengis.net/gml";
    private static final String FEED_ELEMENT = "feed";
    private static final String ENTRY_ELEMENT = "entry";

    private static final int STATE_DOCUMENT = 0;
    private static final int STATE_FEED = 1;
    private static final int STATE_ENTRY = 2;

    private static final int NUM_LEVELS = 5;

    private Entry mEntry = null;
    private EntryHandler mHandler = null;
    private int mState = STATE_DOCUMENT;
    private int mLevel = 0;
    private String[] mUri = new String[NUM_LEVELS];
    private String[] mName = new String[NUM_LEVELS];
    private AttributesImpl[] mAttributes = new AttributesImpl[NUM_LEVELS];
    private final StringBuilder mValue = new StringBuilder(128);

    public interface EntryHandler {
        void handleEntry(Entry entry);
    }

    public GDataParser() {
        AttributesImpl[] attributes = mAttributes;
        for (int i = 0; i != NUM_LEVELS; ++i) {
            attributes[i] = new AttributesImpl();
        }
    }

    public void setEntry(Entry entry) {
        mEntry = entry;
    }

    public void setHandler(EntryHandler handler) {
        mHandler = handler;
    }

    public static long parseAtomTimestamp(String timestamp) {
        Time time = new Time();
        time.parse3339(timestamp);
        return time.toMillis(true);
    }

    public void startElement(String uri, String localName, String qName, Attributes attrs) throws SAXException {
        switch (mState) {
        case STATE_DOCUMENT:
            // Expect an atom:feed element.
            if (uri.equals(ATOM_NAMESPACE) && localName.equals(FEED_ELEMENT)) {
                mState = STATE_FEED;
            } else {
                throw new SAXException();
            }
            break;
        case STATE_FEED:
            // Expect a feed property element or an atom:entry element.
            if (uri.equals(ATOM_NAMESPACE) && localName.equals(ENTRY_ELEMENT)) {
                mState = STATE_ENTRY;
                mEntry.clear();
            } else {
                startProperty(uri, localName, attrs);
            }
            break;
        case STATE_ENTRY:
            startProperty(uri, localName, attrs);
            break;
        }
    }

    public void endElement(String uri, String localName, String qName) throws SAXException {
        if (mLevel > 0) {
            // Handle property exit.
            endProperty();
        } else {
            // Handle state exit.
            switch (mState) {
            case STATE_DOCUMENT:
                throw new SAXException();
            case STATE_FEED:
                mState = STATE_DOCUMENT;
                break;
            case STATE_ENTRY:
                mState = STATE_FEED;
                mHandler.handleEntry(mEntry);
                break;
            }
        }
    }

    private void startProperty(String uri, String localName, Attributes attrs) {
        // Push element information onto the property stack.
        int level = mLevel + 1;
        mLevel = level;
        mValue.setLength(0);
        mUri[level] = uri;
        mName[level] = localName;
        mAttributes[level].setAttributes(attrs);
    }

    private void endProperty() {
        // Apply property to the entry, then pop the stack.
        int level = mLevel;
        mEntry.setPropertyFromXml(mUri[level], mName[level], mAttributes[level], mValue.toString());
        mLevel = level - 1;
    }

    public void characters(char[] ch, int start, int length) throws SAXException {
        mValue.append(ch, start, length);
    }

    public void ignorableWhitespace(char[] ch, int start, int length) throws SAXException {
        // Ignored.
    }

    public void processingInstruction(String target, String data) throws SAXException {
        // Ignored.
    }

    public void setDocumentLocator(Locator locator) {
        // Ignored.
    }

    public void skippedEntity(String name) throws SAXException {
        // Ignored.
    }

    public void startDocument() throws SAXException {
        // Ignored.
    }

    public void endDocument() throws SAXException {
        // Ignored.
    }

    public void startPrefixMapping(String prefix, String uri) throws SAXException {
        // Ignored.
    }

    public void endPrefixMapping(String prefix) throws SAXException {
        // Ignored.
    }
}