package allen.town.podcast.parser.feed;

import android.util.Log;

import allen.town.podcast.parser.feed.util.TypeGetter;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

import allen.town.podcast.model.feed.Feed;
import allen.town.podcast.parser.feed.namespace.Content;
import allen.town.podcast.parser.feed.namespace.DublinCore;
import allen.town.podcast.parser.feed.namespace.Itunes;
import allen.town.podcast.parser.feed.namespace.Media;
import allen.town.podcast.parser.feed.namespace.Rss20;
import allen.town.podcast.parser.feed.namespace.SimpleChapters;
import allen.town.podcast.parser.feed.namespace.Namespace;
import allen.town.podcast.parser.feed.namespace.PodcastIndex;
import allen.town.podcast.parser.feed.element.SyndElement;
import allen.town.podcast.parser.feed.namespace.Atom;

/** Superclass for all SAX Handlers which process Syndication formats */
public class SyndHandler extends DefaultHandler {
    private static final String TAG = "SyndHandler";
    private static final String DEFAULT_PREFIX = "";
    public final HandlerState state;

    public SyndHandler(Feed feed, TypeGetter.Type type) {
        state = new HandlerState(feed);
        if (type == TypeGetter.Type.RSS20 || type == TypeGetter.Type.RSS091) {
            state.defaultNamespaces.push(new Rss20());
        }
    }

    @Override
    public void startElement(String uri, String localName, String qualifiedName,
            Attributes attributes) throws SAXException {
        state.contentBuf = new StringBuilder();
        Namespace handler = getHandlingNamespace(uri, qualifiedName);
        if (handler != null) {
            SyndElement element = handler.handleElementStart(localName, state,
                    attributes);
            state.tagstack.push(element);

        }
    }

    @Override
    public void characters(char[] ch, int start, int length)
            throws SAXException {
        if (!state.tagstack.empty()) {
            if (state.getTagstack().size() >= 2) {
                if (state.contentBuf != null) {
                    state.contentBuf.append(ch, start, length);
                }
            }
        }
    }

    @Override
    public void endElement(String uri, String localName, String qualifiedName)
            throws SAXException {
        Namespace handler = getHandlingNamespace(uri, qualifiedName);
        if (handler != null) {
            handler.handleElementEnd(localName, state);
            state.tagstack.pop();

        }
        state.contentBuf = null;

    }

    @Override
    public void endPrefixMapping(String prefix) throws SAXException {
        if (state.defaultNamespaces.size() > 1 && prefix.equals(DEFAULT_PREFIX)) {
            state.defaultNamespaces.pop();
        }
    }

    @Override
    public void startPrefixMapping(String prefix, String uri)
            throws SAXException {
        // Find the right namespace
        if (!state.namespaces.containsKey(uri)) {
            if (uri.equals(Atom.NSURI)) {
                if (prefix.equals(DEFAULT_PREFIX)) {
                    state.defaultNamespaces.push(new Atom());
                } else if (prefix.equals(Atom.NSTAG)) {
                    state.namespaces.put(uri, new Atom());
                    Log.d(TAG, "Recognized Atom namespace");
                }
            } else if (uri.equals(Content.NSURI)
                    && prefix.equals(Content.NSTAG)) {
                state.namespaces.put(uri, new Content());
                Log.d(TAG, "Recognized Content namespace");
            } else if (uri.equals(Itunes.NSURI)
                    && prefix.equals(Itunes.NSTAG)) {
                state.namespaces.put(uri, new Itunes());
                Log.d(TAG, "Recognized ITunes namespace");
            } else if (uri.equals(SimpleChapters.NSURI)
                    && prefix.matches(SimpleChapters.NSTAG)) {
                state.namespaces.put(uri, new SimpleChapters());
                Log.d(TAG, "Recognized SimpleChapters namespace");
            } else if (uri.equals(Media.NSURI)
                    && prefix.equals(Media.NSTAG)) {
                state.namespaces.put(uri, new Media());
                Log.d(TAG, "Recognized media namespace");
            } else if (uri.equals(DublinCore.NSURI)
                    && prefix.equals(DublinCore.NSTAG)) {
                state.namespaces.put(uri, new DublinCore());
                Log.d(TAG, "Recognized DublinCore namespace");
            } else if (uri.equals(PodcastIndex.NSURI) || uri.equals(PodcastIndex.NSURI2)
                    && prefix.equals(PodcastIndex.NSTAG)) {
                state.namespaces.put(uri, new PodcastIndex());
                Log.d(TAG, "Recognized PodcastIndex namespace");
            }
        }
    }

    private Namespace getHandlingNamespace(String uri, String qualifiedName) {
        Namespace handler = state.namespaces.get(uri);
        if (handler == null && !state.defaultNamespaces.empty()
                && !qualifiedName.contains(":")) {
            handler = state.defaultNamespaces.peek();
        }
        return handler;
    }

    @Override
    public void endDocument() throws SAXException {
        super.endDocument();
        state.getFeed().setItems(state.getItems());
    }

    public HandlerState getState() {
        return state;
    }

}
