001// ***************************************************************************************************************************
002// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
003// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
004// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance            *
005// * with the License.  You may obtain a copy of the License at                                                              *
006// *                                                                                                                         *
007// *  http://www.apache.org/licenses/LICENSE-2.0                                                                             *
008// *                                                                                                                         *
009// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an  *
010// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
011// * specific language governing permissions and limitations under the License.                                              *
012// ***************************************************************************************************************************
013package org.apache.juneau.dto.html5;
014
015import static org.apache.juneau.xml.annotation.XmlFormat.*;
016
017import java.util.*;
018
019import org.apache.juneau.*;
020import org.apache.juneau.annotation.*;
021import org.apache.juneau.internal.*;
022import org.apache.juneau.xml.annotation.*;
023
024/**
025 * A subclass of HTML elements that contain mixed content (elements and text).
026 *
027 * <h5 class='section'>See Also:</h5>
028 * <ul class='doctree'>
029 *    <li class='link'>{@doc juneau-dto.HTML5}
030 * </ul>
031 */
032public class HtmlElementMixed extends HtmlElement {
033
034   private LinkedList<Object> children;
035
036   /**
037    * The children of this element.
038    *
039    * @return The children of this element.
040    */
041   @Xml(format=MIXED)
042   @BeanProperty(beanDictionary=HtmlBeanDictionary.class, name="c")
043   public LinkedList<Object> getChildren() {
044      return children;
045   }
046
047   /**
048    * Sets the children of this element.
049    *
050    * @param children The new children of this element.
051    * @return This object (for method chaining).
052    */
053   @BeanProperty("c")
054   public HtmlElement setChildren(LinkedList<Object> children) {
055      this.children = children;
056      return this;
057   }
058
059   /**
060    * Returns the child node at the specified index.
061    *
062    * @param index The index of the node in the list of children.
063    * @return The child node, or <jk>null</jk> if it doesn't exist.
064    */
065   public Object getChild(int index) {
066      return (children == null || children.size() <= index || index < 0 ? null : children.get(index));
067   }
068
069   /**
070    * Returns the child node at the specified address.
071    *
072    * <p>
073    * Indexes are zero-indexed.
074    *
075    * <p>
076    * For example, calling <code>getChild(1,2,3);</code> will return the 4th child of the 3rd child of the 2nd child.
077    *
078    * @param index The child indexes.
079    * @return The child node, or <jk>null</jk> if it doesn't point to a valid child.
080    */
081   public Object getChild(int...index) {
082      if (index.length == 0)
083         return null;
084      if (index.length == 1)
085         return getChild(index[0]);
086      Object c = this;
087      for (int i = 0; i < index.length; i++) {
088         if (c instanceof HtmlElementMixed)
089            c = ((HtmlElementMixed)c).getChild(index[i]);
090         else if (c instanceof HtmlElementContainer)
091            c = ((HtmlElementContainer)c).getChild(index[i]);
092         else
093            return null;
094      }
095      return c;
096   }
097
098   /**
099    * Returns the child node at the specified index.
100    *
101    * @param type The class type of the node.
102    * @param index The index of the node in the list of children.
103    * @return The child node, or <jk>null</jk> if it doesn't exist.
104    * @throws InvalidDataConversionException If node is not the expected type.
105    */
106   public <T> T getChild(Class<T> type, int index) {
107      return (
108         children == null || children.size() <= index || index < 0
109         ? null
110         : ObjectUtils.toType(children.get(index), type)
111      );
112   }
113
114   /**
115    * Adds one or more child elements to this element.
116    *
117    * @param children
118    *    The children to add as child elements.
119    *    Can be a mixture of strings and {@link HtmlElement} objects.
120    *    Can also be containers of strings and elements.
121    * @return This object (for method chaining).
122    */
123   public HtmlElement children(Object...children) {
124      if (children.length != 0)
125         for (Object c : children)
126            child(c);
127      return this;
128   }
129
130   /**
131    * Adds a child element to this element.
132    *
133    * @param child
134    *    The child to add as a child element.
135    *    Can be a string or {@link HtmlElement}.
136    *    Can also be a container of strings and elements.
137    * @return This object (for method chaining).
138    */
139   public HtmlElement child(Object child) {
140      if (this.children == null)
141         this.children = new LinkedList<>();
142      if (child instanceof Collection)
143         this.children.addAll((Collection<?>)child);
144      else
145         this.children.add(child);
146      return this;
147   }
148}