001/*
002 *  Copyright 2015 Anyware Services
003 *
004 *  Licensed under the Apache License, Version 2.0 (the "License");
005 *  you may not use this file except in compliance with the License.
006 *  You may obtain a copy of the License at
007 *
008 *      http://www.apache.org/licenses/LICENSE-2.0
009 *
010 *  Unless required by applicable law or agreed to in writing, software
011 *  distributed under the License is distributed on an "AS IS" BASIS,
012 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 *  See the License for the specific language governing permissions and
014 *  limitations under the License.
015 */
016package org.ametys.core.util.dom;
017
018import java.util.ArrayList;
019import java.util.Collections;
020import java.util.HashMap;
021import java.util.List;
022import java.util.Map;
023import java.util.Map.Entry;
024
025import org.w3c.dom.Element;
026import org.w3c.dom.Node;
027import org.w3c.dom.NodeList;
028
029/**
030 * DOM Layer over a Map. Only String, List<Object> and Map<String, Object> values are allowed (recursively).
031 */
032public class MapElement extends AbstractAmetysElement
033{
034    private Map<String, ? extends Object> _values;
035    private Map<String, String> _attributes;
036    
037    /**
038     * Constructor.
039     * @param tagName the tag name.
040     * @param values the values.
041     */
042    public MapElement(String tagName, Map<String, ? extends Object> values)
043    {
044        this(tagName, Collections.emptyMap(), values);
045    }
046    
047    /**
048     * Constructor.
049     * @param tagName the tag name.
050     * @param attributes The attributes names and values.
051     * @param values the values.
052     */
053    public MapElement(String tagName, Map<String, String> attributes, Map<String, ? extends Object> values)
054    {
055        super(tagName);
056        _values = values;
057        _attributes = attributes;
058    }
059    
060    /**
061     * Constructor.
062     * @param tagName the tag name.
063     * @param values the values.
064     * @param parent the parent {@link Element} if any.
065     */
066    public MapElement(String tagName, Map<String, ? extends Object> values, Element parent)
067    {
068        super(tagName, parent);
069        _values = values;
070    }
071    
072    /**
073     * Constructor.
074     * @param tagName the tag name.
075     * @param attributes The attributes names and values.
076     * @param values the values.
077     * @param parent the parent {@link Element} if any.
078     */
079    public MapElement(String tagName, Map<String, String> attributes, Map<String, ? extends Object> values, Element parent)
080    {
081        super(tagName, parent);
082        _values = values;
083        _attributes = attributes;
084    }
085    
086
087    @Override
088    protected Map<String, AmetysAttribute> _lookupAttributes()
089    {
090        Map<String, AmetysAttribute> attrs = new HashMap<>();
091        
092        if (_attributes != null)
093        {
094            for (String name : _attributes.keySet())
095            {
096                attrs.put(name, new AmetysAttribute(name, name, null, _attributes.get(name), this));
097            }
098        }
099        
100        return attrs;
101    }
102    
103    @Override
104    public Node getFirstChild()
105    {
106        NodeList list = getChildNodes();
107        
108        if (list.getLength() == 0)
109        {
110            return null;
111        }
112        
113        return list.item(0);
114    }
115    
116    @Override
117    @SuppressWarnings("unchecked")
118    protected NodeList _getChildNodes()
119    {
120        List<Element> list = new ArrayList<>();
121        
122        if (_values != null)
123        {
124            for (Entry<String, ? extends Object> entry : _values.entrySet())
125            {
126                Object rawValue = entry.getValue();
127                List<Object> values = new ArrayList<>();
128                if (rawValue instanceof List)
129                {
130                    values.addAll((List) rawValue);
131                }
132                else
133                {
134                    values.add(rawValue);
135                }
136                
137                for (Object value : values)
138                {
139                    Object realValue = value;
140                    Map<String, String> attributes = null;
141                    if (value instanceof MapNode)
142                    {
143                        realValue = ((MapNode) value).getValue();
144                        attributes = ((MapNode) value).getAttributes();
145                    }
146                    
147                    if (realValue == null)
148                    {
149                        list.add(new StringElement(entry.getKey(), attributes, "", this));
150                    }
151                    else if (realValue instanceof String)
152                    {
153                        list.add(new StringElement(entry.getKey(), attributes, (String) realValue, this));
154                    }
155                    else if (realValue instanceof Map)
156                    {
157                        list.add(new MapElement(entry.getKey(), attributes, (Map<String, ? extends Object>) realValue, this));
158                    }
159                    else
160                    {
161                        throw new IllegalArgumentException("MapElement only handles String, List<Object> or Map<String, Object> recursively");
162                    }
163                }
164            }
165        }
166        
167        return new AmetysNodeList(list);
168    }
169    
170    /**
171     * This class represents a element 
172     *
173     */
174    public static class MapNode
175    {
176        private Object _value;
177        private Map<String, String> _attrs;
178
179        /**
180         * Constructor
181         * @param value The value
182         * @param attributes The attributes
183         */
184        public MapNode (Object value, Map<String, String> attributes)
185        {
186            _value = value;
187            _attrs = attributes;
188        }
189        
190        /**
191         * Get the attributes
192         * @return the attributes
193         */
194        public Map<String, String> getAttributes()
195        {
196            return _attrs;
197        }
198        
199        /**
200         * Get the value
201         * @return the value
202         */
203        public Object getValue ()
204        {
205            return _value;
206        }
207    }
208}