1/*
2 * Copyright (C) 2007 Esmertec AG.
3 * Copyright (C) 2007 The Android Open Source Project
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 *      http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18package com.android.mms.dom.smil;
19
20import org.w3c.dom.DOMException;
21import org.w3c.dom.Element;
22import org.w3c.dom.Node;
23import org.w3c.dom.NodeList;
24import org.w3c.dom.events.DocumentEvent;
25import org.w3c.dom.events.Event;
26import org.w3c.dom.smil.ElementSequentialTimeContainer;
27import org.w3c.dom.smil.ElementTime;
28import org.w3c.dom.smil.SMILDocument;
29import org.w3c.dom.smil.SMILElement;
30import org.w3c.dom.smil.SMILLayoutElement;
31import org.w3c.dom.smil.TimeList;
32
33import com.android.mms.dom.DocumentImpl;
34import com.android.mms.dom.events.EventImpl;
35
36public class SmilDocumentImpl extends DocumentImpl implements SMILDocument, DocumentEvent {
37    /*
38     * The sequential time container cannot be initialized here because the real container
39     * is body, which hasn't been created yet. It will be initialized when the body has
40     * already been created. Please see getBody().
41     */
42    ElementSequentialTimeContainer mSeqTimeContainer;
43
44    public final static String SMIL_DOCUMENT_START_EVENT = "SmilDocumentStart";
45    public final static String SMIL_DOCUMENT_END_EVENT = "SimlDocumentEnd";
46
47    /*
48     * Internal methods
49     */
50    public SmilDocumentImpl() {
51        super();
52    }
53
54    /*
55     * ElementSequentialTimeContainer stuff
56     */
57
58    public NodeList getActiveChildrenAt(float instant) {
59        return mSeqTimeContainer.getActiveChildrenAt(instant);
60    }
61
62    public NodeList getTimeChildren() {
63        return mSeqTimeContainer.getTimeChildren();
64    }
65
66    public boolean beginElement() {
67        return mSeqTimeContainer.beginElement();
68    }
69
70    public boolean endElement() {
71        return mSeqTimeContainer.endElement();
72    }
73
74    public TimeList getBegin() {
75        return mSeqTimeContainer.getBegin();
76    }
77
78    public float getDur() {
79        return mSeqTimeContainer.getDur();
80    }
81
82    public TimeList getEnd() {
83        return mSeqTimeContainer.getEnd();
84    }
85
86    public short getFill() {
87        return mSeqTimeContainer.getFill();
88    }
89
90    public short getFillDefault() {
91        return mSeqTimeContainer.getFillDefault();
92    }
93
94    public float getRepeatCount() {
95        return mSeqTimeContainer.getRepeatCount();
96    }
97
98    public float getRepeatDur() {
99        return mSeqTimeContainer.getRepeatDur();
100    }
101
102    public short getRestart() {
103        return mSeqTimeContainer.getRestart();
104    }
105
106    public void pauseElement() {
107        mSeqTimeContainer.pauseElement();
108    }
109
110    public void resumeElement() {
111        mSeqTimeContainer.resumeElement();
112    }
113
114    public void seekElement(float seekTo) {
115        mSeqTimeContainer.seekElement(seekTo);
116    }
117
118    public void setBegin(TimeList begin) throws DOMException {
119        mSeqTimeContainer.setBegin(begin);
120    }
121
122    public void setDur(float dur) throws DOMException {
123        mSeqTimeContainer.setDur(dur);
124    }
125
126    public void setEnd(TimeList end) throws DOMException {
127        mSeqTimeContainer.setEnd(end);
128    }
129
130    public void setFill(short fill) throws DOMException {
131        mSeqTimeContainer.setFill(fill);
132    }
133
134    public void setFillDefault(short fillDefault) throws DOMException {
135        mSeqTimeContainer.setFillDefault(fillDefault);
136    }
137
138    public void setRepeatCount(float repeatCount) throws DOMException {
139        mSeqTimeContainer.setRepeatCount(repeatCount);
140    }
141
142    public void setRepeatDur(float repeatDur) throws DOMException {
143        mSeqTimeContainer.setRepeatDur(repeatDur);
144    }
145
146    public void setRestart(short restart) throws DOMException {
147        mSeqTimeContainer.setRestart(restart);
148    }
149
150    /*
151     * Document Interface
152     */
153
154    @Override
155    public Element createElement(String tagName) throws DOMException {
156        // Find the appropriate class for this element
157        tagName = tagName.toLowerCase();
158        if (tagName.equals("text") ||
159                tagName.equals("img") ||
160                tagName.equals("video")) {
161            return new SmilRegionMediaElementImpl(this, tagName);
162        } else if (tagName.equals("audio")) {
163            return new SmilMediaElementImpl(this, tagName);
164        } else if (tagName.equals("layout")) {
165            return new SmilLayoutElementImpl(this, tagName);
166        } else if (tagName.equals("root-layout")) {
167            return new SmilRootLayoutElementImpl(this, tagName);
168        } else if (tagName.equals("region")) {
169            return new SmilRegionElementImpl(this, tagName);
170        } else if (tagName.equals("ref")) {
171            return new SmilRefElementImpl(this, tagName);
172        } else if (tagName.equals("par")) {
173            return new SmilParElementImpl(this, tagName);
174        } else {
175            // This includes also the structural nodes SMIL,
176            // HEAD, BODY, for which no specific types are defined.
177            return new SmilElementImpl(this, tagName);
178        }
179    }
180
181    @Override
182    public SMILElement getDocumentElement() {
183        Node rootElement = getFirstChild();
184        if (rootElement == null || !(rootElement instanceof SMILElement)) {
185            // The root doesn't exist. Create a new one.
186            rootElement = createElement("smil");
187            appendChild(rootElement);
188        }
189
190        return (SMILElement) rootElement;
191    }
192
193    /*
194     * SMILElement Interface
195     */
196
197    public SMILElement getHead() {
198        Node rootElement = getDocumentElement();
199        Node headElement = rootElement.getFirstChild();
200        if (headElement == null || !(headElement instanceof SMILElement)) {
201            // The head doesn't exist. Create a new one.
202            headElement = createElement("head");
203            rootElement.appendChild(headElement);
204        }
205
206        return (SMILElement) headElement;
207    }
208
209    public SMILElement getBody() {
210        Node rootElement = getDocumentElement();
211        Node headElement = getHead();
212        Node bodyElement = headElement.getNextSibling();
213        if (bodyElement == null || !(bodyElement instanceof SMILElement)) {
214            // The body doesn't exist. Create a new one.
215            bodyElement = createElement("body");
216            rootElement.appendChild(bodyElement);
217        }
218
219        // Initialize the real sequential time container, which is body.
220        mSeqTimeContainer = new ElementSequentialTimeContainerImpl((SMILElement) bodyElement) {
221            public NodeList getTimeChildren() {
222                return getBody().getElementsByTagName("par");
223            }
224
225            public boolean beginElement() {
226                Event startEvent = createEvent("Event");
227                startEvent.initEvent(SMIL_DOCUMENT_START_EVENT, false, false);
228                dispatchEvent(startEvent);
229                return true;
230            }
231
232            public boolean endElement() {
233                Event endEvent = createEvent("Event");
234                endEvent.initEvent(SMIL_DOCUMENT_END_EVENT, false, false);
235                dispatchEvent(endEvent);
236                return true;
237            }
238
239            public void pauseElement() {
240                // TODO Auto-generated method stub
241
242            }
243
244            public void resumeElement() {
245                // TODO Auto-generated method stub
246
247            }
248
249            public void seekElement(float seekTo) {
250                // TODO Auto-generated method stub
251
252            }
253
254            ElementTime getParentElementTime() {
255                return null;
256            }
257        };
258
259        return (SMILElement) bodyElement;
260    }
261
262    public SMILLayoutElement getLayout() {
263        Node headElement = getHead();
264        Node layoutElement = null;
265
266        // Find the layout element under <code>HEAD</code>
267        layoutElement = headElement.getFirstChild();
268        while ((layoutElement != null) && !(layoutElement instanceof SMILLayoutElement)) {
269            layoutElement = layoutElement.getNextSibling();
270        }
271
272        if (layoutElement == null) {
273            // The layout doesn't exist. Create a default one.
274            layoutElement = new SmilLayoutElementImpl(this, "layout");
275            headElement.appendChild(layoutElement);
276        }
277        return (SMILLayoutElement) layoutElement;
278    }
279
280    /*
281     * DocumentEvent Interface
282     */
283    public Event createEvent(String eventType) throws DOMException {
284        if ("Event".equals(eventType)) {
285            return new EventImpl();
286        } else {
287            throw new DOMException(DOMException.NOT_SUPPORTED_ERR,
288                       "Not supported interface");
289        }
290    }
291}
292