gt:         return (mRoot != null) ? mRoot : EMPTY_PLAYLIST;
context: /*-
   *  Copyright (C) 2011 Peter Baldwin
   *
   *  This program is free software: you can redistribute it and/or modify
   *  it under the terms of the GNU General Public License as published by
   *  the Free Software Foundation, either version 3 of the License, or
   *  (at your option) any later version.
   *
   *  This program is distributed in the hope that it will be useful,
   *  but WITHOUT ANY WARRANTY; without even the implied warranty of
   *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   *  GNU General Public License for more details.
   *
   *  You should have received a copy of the GNU General Public License
   *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
   */
  
  package org.peterbaldwin.vlcremote.net;
  
  import android.text.Html;
  
  import org.peterbaldwin.vlcremote.model.Playlist;
  import org.peterbaldwin.vlcremote.model.Track;
  import org.xml.sax.Attributes;
  import org.xml.sax.ContentHandler;
  import org.xml.sax.Locator;
  import org.xml.sax.SAXException;
  
  import java.io.IOException;
  import java.net.URLConnection;
  import java.util.Stack;
  
  final class PlaylistContentHandler extends XmlContentHandler<Playlist> implements ContentHandler {
  
      private static final String[] TEXT_ELEMENTS = {
              "title", "artist", "genre", "copyright", "album", "track", "description", "rating",
              "date", "url", "language", "now_playing", "publisher", "encoded_by", "art_url",
              "track_id"
      };
  
      private static final Playlist EMPTY_PLAYLIST = new Playlist(1, "Undefined");
  
      private final Stack<Playlist> mNodeStack;
  
      private final StringBuilder mBuilder;
  
      private Playlist mRoot;
  
      private boolean mCapture = false;
  
      private Track mTrack;
  
      private boolean mFlatten = true;
  
      public PlaylistContentHandler() {
          mNodeStack = new Stack<Playlist>();
          mBuilder = new StringBuilder();
      }
  
      private static String unescape(CharSequence text) {
          // TODO: Do this more efficiently
          return Html.fromHtml(text.toString()).toString();
      }
  
      private static boolean isTextElement(String localName) {
          for (int i = 0; i < TEXT_ELEMENTS.length; i++) {
              if (TEXT_ELEMENTS[i].equals(localName)) {
                  return true;
              }
          }
          return false;
      }
  
      private static Playlist createPlaylist(Attributes attributes) {
          int id = Integer.parseInt(attributes.getValue("", "id"));
          String name = attributes.getValue("", "name");
          return new Playlist(id, name);
      }
  
      private static Track createTrack(Attributes attributes) {
          Track track = new Track();
  
          int id = Integer.parseInt(attributes.getValue("", "id"));
          track.setId(id);
  
          boolean current = "current".equals(attributes.getValue("", "current"));
          track.setCurrent(current);
  
          String uri = attributes.getValue("", "uri");
          track.setUri(uri);
  
          String name = attributes.getValue("", "name");
          track.setName(name);
  
          long duration = Long.parseLong(attributes.getValue("", "duration"));
          track.setDuration(duration);
  
          return track;
      }
  
      /**
       * {@inheritDoc}
       */
      public void startElement(String uri, String localName, String name, Attributes attributes)
              throws SAXException {
          if ("leaf".equals(localName)) {
              mTrack = createTrack(attributes);
              if ("vlc://nop".equals(attributes.getValue("uri"))) {
                  // Don't include nop tracks in the output
              } else {
                  if (mFlatten) {
                      mRoot.add(mTrack);
                  } else {
                      mNodeStack.peek().add(mTrack);
                  }
              }
          } else if ("node".equals(localName)) {
              Playlist playlist = createPlaylist(attributes);
              if (mNodeStack.isEmpty()) {
                  mRoot = playlist;
              } else if (!mFlatten) {
                  mNodeStack.peek().add(playlist);
              }
              mNodeStack.push(playlist);
          } else if (mTrack != null && isTextElement(localName)) {
              mBuilder.setLength(0);
              mCapture = true;
          }
      }
  
      private String getText() {
          if (mBuilder.length() == 0) {
              return null;
          } else {
              if (mBuilder.indexOf("&") != -1) {
                  // Text is escaped twice so that it can be used in HTML.
                  return unescape(mBuilder);
              } else {
                  return mBuilder.toString();
              }
          }
      }
  
      /**
       * {@inheritDoc}
       */
      public void endElement(String uri, String localName, String name) throws SAXException {
          if ("node".equals(localName)) {
              mNodeStack.pop();
          } else if ("leaf".equals(localName)) {
              mTrack = null;
          } else if (mTrack != null) {
              if ("title".equals(localName)) {
                  mTrack.setTitle(getText());
              } else if ("artist".equals(localName)) {
                  mTrack.setArtist(getText());
              } else if ("genre".equals(localName)) {
                  mTrack.setGenre(getText());
              } else if ("copyright".equals(localName)) {
                  mTrack.setCopyright(getText());
              } else if ("album".equals(localName)) {
                  mTrack.setAlbum(getText());
              } else if ("track".equals(localName)) {
                  mTrack.setTrack(getText());
              } else if ("description".equals(localName)) {
                  mTrack.setDescription(getText());
              } else if ("rating".equals(localName)) {
                  mTrack.setRating(getText());
              } else if ("date".equals(localName)) {
                  mTrack.setDate(getText());
              } else if ("url".equals(localName)) {
                  mTrack.setUrl(getText());
              } else if ("language".equals(localName)) {
                  mTrack.setLanguage(getText());
              } else if ("now_playing".equals(localName)) {
                  mTrack.setNowPlaying(getText());
              } else if ("publisher".equals(localName)) {
                  mTrack.setPublisher(getText());
              } else if ("encoded_by".equals(localName)) {
                  mTrack.setEncodedBy(getText());
              } else if ("art_url".equals(localName)) {
                  mTrack.setArtUrl(getText());
              } else if ("track_id".equals(localName)) {
                  mTrack.setTrackId(getText());
              }
          }
          mCapture = false;
      }
  
      /**
       * {@inheritDoc}
       */
      public void characters(char[] ch, int start, int length) throws SAXException {
          if (mCapture) {
              mBuilder.append(ch, start, length);
          }
      }
  
      /**
       * {@inheritDoc}
       */
      public void endDocument() throws SAXException {
  
      }
  
      /**
       * {@inheritDoc}
       */
      public void endPrefixMapping(String prefix) throws SAXException {
      }
  
      /**
       * {@inheritDoc}
       */
      public void ignorableWhitespace(char[] ch, int start, int length) throws SAXException {
      }
  
      /**
       * {@inheritDoc}
       */
      public void processingInstruction(String target, String data) throws SAXException {
      }
  
      /**
       * {@inheritDoc}
       */
      public void setDocumentLocator(Locator locator) {
      }
  
      /**
       * {@inheritDoc}
       */
      public void skippedEntity(String name) throws SAXException {
      }
  
      /**
       * {@inheritDoc}
       */
      public void startDocument() throws SAXException {
      }
  
      /**
       * {@inheritDoc}
       */
      public void startPrefixMapping(String prefix, String uri) throws SAXException {
      }
  
      @Override
      public Object getContent(URLConnection connection) throws IOException {
          parse(connection, this);
  