content: package allen.town.podcast.parser.feed.namespace;
  
  import android.text.TextUtils;
  import android.util.Log;
  
  import allen.town.podcast.model.feed.FeedFunding;
  import allen.town.podcast.parser.feed.HandlerState;
  import allen.town.podcast.parser.feed.element.AtomText;
  import allen.town.podcast.parser.feed.util.DateUtils;
  import allen.town.podcast.parser.feed.util.SyndStringUtils;
  import org.xml.sax.Attributes;
  
  import allen.town.podcast.model.feed.FeedItem;
  import allen.town.podcast.model.feed.FeedMedia;
  import allen.town.podcast.parser.feed.element.SyndElement;
  import allen.town.podcast.parser.feed.util.MimeTypeUtils;
  
  public class Atom extends Namespace {
      private static final String TAG = "NSAtom";
      public static final String NSTAG = "atom";
      public static final String NSURI = "http://www.w3.org/2005/Atom";
  
      private static final String FEED = "feed";
      private static final String ID = "id";
      private static final String TITLE = "title";
      private static final String ENTRY = "entry";
      private static final String LINK = "link";
      private static final String UPDATED = "updated";
      private static final String AUTHOR = "author";
      private static final String AUTHOR_NAME = "name";
      private static final String CONTENT = "content";
      private static final String SUMMARY = "summary";
      private static final String IMAGE_LOGO = "logo";
      private static final String IMAGE_ICON = "icon";
      private static final String SUBTITLE = "subtitle";
      private static final String PUBLISHED = "published";
  
      private static final String TEXT_TYPE = "type";
      // Link
      private static final String LINK_HREF = "href";
      private static final String LINK_REL = "rel";
      private static final String LINK_TYPE = "type";
      private static final String LINK_TITLE = "title";
      private static final String LINK_LENGTH = "length";
      // rel-values
      private static final String LINK_REL_ALTERNATE = "alternate";
      private static final String LINK_REL_ARCHIVES = "archives";
      private static final String LINK_REL_ENCLOSURE = "enclosure";
      private static final String LINK_REL_PAYMENT = "payment";
      private static final String LINK_REL_NEXT = "next";
      // type-values
      private static final String LINK_TYPE_ATOM = "application/atom+xml";
      private static final String LINK_TYPE_HTML = "text/html";
      private static final String LINK_TYPE_XHTML = "application/xml+xhtml";
  
      private static final String LINK_TYPE_RSS = "application/rss+xml";
  
      /**
       * Regexp to test whether an Element is a Text Element.
       */
      private static final String isText = TITLE + "|" + CONTENT + "|"
              + SUBTITLE + "|" + SUMMARY;
  
      private static final String isFeed = FEED + "|" + Rss20.CHANNEL;
      private static final String isFeedItem = ENTRY + "|" + Rss20.ITEM;
  
      @Override
      public SyndElement handleElementStart(String localName, HandlerState state,
                                            Attributes attributes) {
          if (ENTRY.equals(localName)) {
              state.setCurrentItem(new FeedItem());
              state.getItems().add(state.getCurrentItem());
              state.getCurrentItem().setFeed(state.getFeed());
          } else if (localName.matches(isText)) {
              String type = attributes.getValue(TEXT_TYPE);
              return new AtomText(localName, this, type);
          } else if (LINK.equals(localName)) {
              String href = attributes.getValue(LINK_HREF);
              String rel = attributes.getValue(LINK_REL);
              SyndElement parent = state.getTagstack().peek();
              if (parent.getName().matches(isFeedItem)) {
                  if (rel == null || LINK_REL_ALTERNATE.equals(rel)) {
                      state.getCurrentItem().setLink(href);
                  } else if (LINK_REL_ENCLOSURE.equals(rel)) {
                      String strSize = attributes.getValue(LINK_LENGTH);
                      long size = 0;
                      try {
                          if (strSize != null) {
                              size = Long.parseLong(strSize);
                          }
                      } catch (NumberFormatException e) {
                          Log.d(TAG, "Length attribute could not be parsed.");
                      }
                      String mimeType = MimeTypeUtils.getMimeType(attributes.getValue(LINK_TYPE), href);
  
                      FeedItem currItem = state.getCurrentItem();
                      if (MimeTypeUtils.isMediaFile(mimeType) && currItem != null && !currItem.hasMedia()) {
                          currItem.setMedia(new FeedMedia(currItem, href, size, mimeType));
                      }
                  } else if (LINK_REL_PAYMENT.equals(rel)) {
                      state.getCurrentItem().setPaymentLink(href);
                  }
              } else if (parent.getName().matches(isFeed)) {
                  if (rel == null || LINK_REL_ALTERNATE.equals(rel)) {
                      String type = attributes.getValue(LINK_TYPE);
                      /*
                       * Use as link if a) no type-attribute is given and
                       * feed-object has no link yet b) type of link is
                       * LINK_TYPE_HTML or LINK_TYPE_XHTML
                       */
                      if (state.getFeed() != null &&
                          ((type == null && state.getFeed().getLink() == null) ||
                              (LINK_TYPE_HTML.equals(type) || LINK_TYPE_XHTML.equals(type)))) {
                          state.getFeed().setLink(href);
                      } else if (LINK_TYPE_ATOM.equals(type) || LINK_TYPE_RSS.equals(type)) {
                          // treat as podlove alternate feed
                          String title = attributes.getValue(LINK_TITLE);
                          if (TextUtils.isEmpty(title)) {
                              title = href;
                          }
                          state.addAlternateFeedUrl(title, href);
                      }
                  } else if (LINK_REL_ARCHIVES.equals(rel) && state.getFeed() != null) {
                      String type = attributes.getValue(LINK_TYPE);
                      if (LINK_TYPE_ATOM.equals(type) || LINK_TYPE_RSS.equals(type)) {
                          String title = attributes.getValue(LINK_TITLE);
                          if (TextUtils.isEmpty(title)) {
                              title = href;
                          }
                          state.addAlternateFeedUrl(title, href);
                      } else if (LINK_TYPE_HTML.equals(type) || LINK_TYPE_XHTML.equals(type)) {
                          //A Link such as to a directory such as iTunes
                      }
                  } else if (LINK_REL_PAYMENT.equals(rel) && state.getFeed() != null) {
                      state.getFeed().addPayment(new FeedFunding(href, ""));
                  } else if (LINK_REL_NEXT.equals(rel) && state.getFeed() != null) {
                      state.getFeed().setPaged(true);
                      state.getFeed().setNextPageLink(href);
                  }
              }
          }
          return new SyndElement(localName, this);
      }
  
      @Override
      public void handleElementEnd(String localName, HandlerState state) {
          if (ENTRY.equals(localName)) {
              if (state.getCurrentItem() != null &&
                      state.getTempObjects().containsKey(Itunes.DURATION)) {
                  FeedItem currentItem = state.getCurrentItem();
                  if (currentItem.hasMedia()) {
                      Integer duration = (Integer) state.getTempObjects().get(Itunes.DURATION);
                      currentItem.getMedia().setDuration(duration);
                  }
                  state.getTempObjects().remove(Itunes.DURATION);
              }
              state.setCurrentItem(null);
          }
  
          if (state.getTagstack().size() >= 2) {
              AtomText textElement = null;
              String contentRaw;
              if (state.getContentBuf() != null) {
                  contentRaw = state.getContentBuf().toString();
              } else {
                  contentRaw = "";
              }
              String content = SyndStringUtils.trimAllWhitespace(contentRaw);
              SyndElement topElement = state.getTagstack().peek();
              String top = topElement.getName();
              SyndElement secondElement = state.getSecondTag();
              String second = secondElement.getName();
  
              if (top.matches(isText)) {
                  textElement = (AtomText) topElement;
                  textElement.setContent(content);
              }
  
              if (ID.equals(top)) {
                  if (FEED.equals(second) && state.getFeed() != null) {
                      state.getFeed().setFeedIdentifier(contentRaw);
                  } else if (ENTRY.equals(second) && state.getCurrentItem() != null) {
                      state.getCurrentItem().setItemIdentifier(contentRaw);
                  }
              } else if (TITLE.equals(top) && textElement != null) {
                  if (FEED.equals(second) && state.getFeed() != null) {
                      state.getFeed().setTitle(textElement.getProcessedContent());
                  } else if (ENTRY.equals(second) && state.getCurrentItem() != null) {
                      state.getCurrentItem().setTitle(textElement.getProcessedContent());
                  }
              } else if (SUBTITLE.equals(top) && FEED.equals(second) && textElement != null &&
                  state.getFeed() != null) {
                  state.getFeed().setDescription(textElement.getProcessedContent());
              } else if (CONTENT.equals(top) && ENTRY.equals(second) && textElement != null &&
                  state.getCurrentItem() != null) {
                  state.getCurrentItem().setDescriptionIfLonger(textElement.getProcessedContent());
              } else if (SUMMARY.equals(top) && ENTRY.equals(second) && textElement != null
                      && state.getCurrentItem() != null) {
                  state.getCurrentItem().setDescriptionIfLonger(textElement.getProcessedContent());
              } else if (UPDATED.equals(top) && ENTRY.equals(second) && state.getCurrentItem() != null &&
                  state.getCurrentItem().getPubDate() == null) {
                  state.getCurrentItem().setPubDate(DateUtils.parseOrNullIfFuture(content));
              } else if (PUBLISHED.equals(top) && ENTRY.equals(second) && state.getCurrentItem() != null) {
                  state.getCurrentItem().setPubDate(DateUtils.parseOrNullIfFuture(content));
              } else if (IMAGE_LOGO.equals(top) && state.getFeed() != null && state.getFeed().getImageUrl() == null) {
                  state.getFeed().setImageUrl(content);
              } else if (IMAGE_ICON.equals(top) && state.getFeed() != null) {
                  state.getFeed().setImageUrl(content);
              } else if (AUTHOR_NAME.equals(top) && AUTHOR.equals(second) &&
                      state.getFeed() != null && state.getCurrentItem() == null) {
                  String currentName = state.getFeed().getAuthor();
                  if (currentName == null) {
                      state.getFeed().setAuthor(content);
                  } else {
                      state.getFeed().setAuthor(currentName + ", " + content);
                  }
              }
          }
      }
  }
  