content: /*
   * Copyright 2014 Jacob Klinker
   *
   * 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.android.mms.dom.smil;
  
  import org.w3c.dom.DOMException;
  import org.w3c.dom.Element;
  import org.w3c.dom.Node;
  import org.w3c.dom.NodeList;
  import org.w3c.dom.events.DocumentEvent;
  import org.w3c.dom.events.Event;
  import org.w3c.dom.smil.ElementSequentialTimeContainer;
  import org.w3c.dom.smil.ElementTime;
  import org.w3c.dom.smil.SMILDocument;
  import org.w3c.dom.smil.SMILElement;
  import org.w3c.dom.smil.SMILLayoutElement;
  import org.w3c.dom.smil.TimeList;
  
  import com.android.mms.dom.DocumentImpl;
  import com.android.mms.dom.events.EventImpl;
  
  public class SmilDocumentImpl extends DocumentImpl implements SMILDocument, DocumentEvent {
      /*
       * The sequential time container cannot be initialized here because the real container
       * is body, which hasn't been created yet. It will be initialized when the body has
       * already been created. Please see getBody().
       */
      ElementSequentialTimeContainer mSeqTimeContainer;
  
      public final static String SMIL_DOCUMENT_START_EVENT = "SmilDocumentStart";
      public final static String SMIL_DOCUMENT_END_EVENT = "SimlDocumentEnd";
  
      /*
       * Internal methods
       */
      public SmilDocumentImpl() {
          super();
      }
  
      /*
       * ElementSequentialTimeContainer stuff
       */
  
      public NodeList getActiveChildrenAt(float instant) {
          return mSeqTimeContainer.getActiveChildrenAt(instant);
      }
  
      public NodeList getTimeChildren() {
          return mSeqTimeContainer.getTimeChildren();
      }
  
      public boolean beginElement() {
          return mSeqTimeContainer.beginElement();
      }
  
      public boolean endElement() {
          return mSeqTimeContainer.endElement();
      }
  
      public TimeList getBegin() {
          return mSeqTimeContainer.getBegin();
      }
  
      public float getDur() {
          return mSeqTimeContainer.getDur();
      }
  
      public TimeList getEnd() {
          return mSeqTimeContainer.getEnd();
      }
  
      public short getFill() {
          return mSeqTimeContainer.getFill();
      }
  
      public short getFillDefault() {
          return mSeqTimeContainer.getFillDefault();
      }
  
      public float getRepeatCount() {
          return mSeqTimeContainer.getRepeatCount();
      }
  
      public float getRepeatDur() {
          return mSeqTimeContainer.getRepeatDur();
      }
  
      public short getRestart() {
          return mSeqTimeContainer.getRestart();
      }
  
      public void pauseElement() {
          mSeqTimeContainer.pauseElement();
      }
  
      public void resumeElement() {
          mSeqTimeContainer.resumeElement();
      }
  
      public void seekElement(float seekTo) {
          mSeqTimeContainer.seekElement(seekTo);
      }
  
      public void setBegin(TimeList begin) throws DOMException {
          mSeqTimeContainer.setBegin(begin);
      }
  
      public void setDur(float dur) throws DOMException {
          mSeqTimeContainer.setDur(dur);
      }
  
      public void setEnd(TimeList end) throws DOMException {
          mSeqTimeContainer.setEnd(end);
      }
  
      public void setFill(short fill) throws DOMException {
          mSeqTimeContainer.setFill(fill);
      }
  
      public void setFillDefault(short fillDefault) throws DOMException {
          mSeqTimeContainer.setFillDefault(fillDefault);
      }
  
      public void setRepeatCount(float repeatCount) throws DOMException {
          mSeqTimeContainer.setRepeatCount(repeatCount);
      }
  
      public void setRepeatDur(float repeatDur) throws DOMException {
          mSeqTimeContainer.setRepeatDur(repeatDur);
      }
  
      public void setRestart(short restart) throws DOMException {
          mSeqTimeContainer.setRestart(restart);
      }
  
      /*
       * Document Interface
       */
  
      @Override
      public Element createElement(String tagName) throws DOMException {
          // Find the appropriate class for this element
          tagName = tagName.toLowerCase();
          if (tagName.equals("text") ||
                  tagName.equals("img") ||
                  tagName.equals("video")) {
              return new SmilRegionMediaElementImpl(this, tagName);
          } else if (tagName.equals("audio")) {
              return new SmilMediaElementImpl(this, tagName);
          } else if (tagName.equals("layout")) {
              return new SmilLayoutElementImpl(this, tagName);
          } else if (tagName.equals("root-layout")) {
              return new SmilRootLayoutElementImpl(this, tagName);
          } else if (tagName.equals("region")) {
              return new SmilRegionElementImpl(this, tagName);
          } else if (tagName.equals("ref")) {
              return new SmilRefElementImpl(this, tagName);
          } else if (tagName.equals("par")) {
              return new SmilParElementImpl(this, tagName);
          } else if (tagName.equals("vcard")) {
              return new SmilRegionMediaElementImpl(this, tagName);
          } else {
              // This includes also the structural nodes SMIL,
              // HEAD, BODY, for which no specific types are defined.
              return new SmilElementImpl(this, tagName);
          }
      }
  
      @Override
      public SMILElement getDocumentElement() {
          Node rootElement = getFirstChild();
          if (rootElement == null || !(rootElement instanceof SMILElement)) {
              // The root doesn't exist. Create a new one.
              rootElement = createElement("smil");
              appendChild(rootElement);
          }
  
          return (SMILElement) rootElement;
      }
  
      /*
       * SMILElement Interface
       */
  
      public SMILElement getHead() {
          Node rootElement = getDocumentElement();
          Node headElement = rootElement.getFirstChild();
          if (headElement == null || !(headElement instanceof SMILElement)) {
              // The head doesn't exist. Create a new one.
              headElement = createElement("head");
              rootElement.appendChild(headElement);
          }
  
          return (SMILElement) headElement;
      }
  
      public SMILElement getBody() {
          Node rootElement = getDocumentElement();
          Node headElement = getHead();
          Node bodyElement = headElement.getNextSibling();
          if (bodyElement == null || !(bodyElement instanceof SMILElement)) {
              // The body doesn't exist. Create a new one.
              bodyElement = createElement("body");
              rootElement.appendChild(bodyElement);
          }
  
          // Initialize the real sequential time container, which is body.
          mSeqTimeContainer = new ElementSequentialTimeContainerImpl((SMILElement) bodyElement) {
              public NodeList getTimeChildren() {
                  return getBody().getElementsByTagName("par");
              }
  
              public boolean beginElement() {
                  Event startEvent = createEvent("Event");
                  startEvent.initEvent(SMIL_DOCUMENT_START_EVENT, false, false);
                  dispatchEvent(startEvent);
                  return true;
              }
  
              public boolean endElement() {
                  Event endEvent = createEvent("Event");
                  endEvent.initEvent(SMIL_DOCUMENT_END_EVENT, false, false);
                  dispatchEvent(endEvent);
                  return true;
              }
  
              public void pauseElement() {
                  // TODO Auto-generated method stub
  
              }
  
              public void resumeElement() {
                  // TODO Auto-generated method stub
  
              }
  
              public void seekElement(float seekTo) {
                  // TODO Auto-generated method stub
  
              }
  
              ElementTime getParentElementTime() {
                  return null;
              }
          };
  
          return (SMILElement) bodyElement;
      }
  
      public SMILLayoutElement getLayout() {
          Node headElement = getHead();
          Node layoutElement = null;
  
          // Find the layout element under <code>HEAD</code>
          layoutElement = headElement.getFirstChild();
          while ((layoutElement != null) && !(layoutElement instanceof SMILLayoutElement)) {
              layoutElement = layoutElement.getNextSibling();
          }
  
          if (layoutElement == null) {
              // The layout doesn't exist. Create a default one.
              layoutElement = new SmilLayoutElementImpl(this, "layout");
              headElement.appendChild(layoutElement);
          }
          return (SMILLayoutElement) layoutElement;
      }
  
      /*
       * DocumentEvent Interface
       */
      public Event createEvent(String eventType) throws DOMException {
          if ("Event".equals(eventType)) {
              return new EventImpl();
          } else {
              throw new DOMException(DOMException.NOT_SUPPORTED_ERR,
                         "Not supported interface");
          }
      }
  }
  