001/*
002 * This library is part of OpenCms -
003 * the Open Source Content Management System
004 *
005 * Copyright (C) Alkacon Software (http://www.alkacon.com)
006 *
007 * This library is free software; you can redistribute it and/or
008 * modify it under the terms of the GNU Lesser General Public
009 * License as published by the Free Software Foundation; either
010 * version 2.1 of the License, or (at your option) any later version.
011 *
012 * This library is distributed in the hope that it will be useful,
013 * but WITHOUT ANY WARRANTY; without even the implied warranty of
014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015 * Lesser General Public License for more details.
016 *
017 * For further information about Alkacon Software, please see the
018 * company website: http://www.alkacon.com
019 *
020 * For further information about OpenCms, please see the
021 * project website: http://www.opencms.org
022 *
023 * You should have received a copy of the GNU Lesser General Public
024 * License along with this library; if not, write to the Free Software
025 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
026 */
027
028package org.opencms.acacia.client;
029
030import org.opencms.acacia.shared.CmsContentDefinition;
031import org.opencms.acacia.shared.CmsType;
032
033import java.util.ArrayList;
034import java.util.HashMap;
035import java.util.List;
036import java.util.Map;
037import java.util.function.Consumer;
038
039/**
040 * The root attribute handler.<p>
041 */
042public class CmsRootHandler implements I_CmsAttributeHandler {
043
044    /** The sub handlers. */
045    protected List<Map<String, CmsAttributeHandler>> m_handlers;
046
047    /** The attribute handler by id. */
048    private Map<String, CmsAttributeHandler> m_handlerById;
049
050    /**
051     * Constructor.<p>
052     */
053    public CmsRootHandler() {
054
055        m_handlers = new ArrayList<Map<String, CmsAttributeHandler>>();
056        m_handlers.add(new HashMap<String, CmsAttributeHandler>());
057        m_handlerById = new HashMap<String, CmsAttributeHandler>();
058    }
059
060    /**
061     * Clears the handler hierarchy.
062     */
063    public void clearHandlers() {
064
065        for (Map<String, CmsAttributeHandler> handlers : m_handlers) {
066            for (CmsAttributeHandler handler : handlers.values()) {
067                handler.clearHandlers();
068            }
069            handlers.clear();
070        }
071        m_handlers.clear();
072        m_handlers.add(new HashMap<String, CmsAttributeHandler>());
073        m_handlerById.clear();
074    }
075
076    /**
077     * @see org.opencms.acacia.client.I_CmsAttributeHandler#collectSimplePath(org.opencms.acacia.client.I_CmsAttributeHandler)
078     */
079    public String collectSimplePath(I_CmsAttributeHandler childHandler) {
080
081        return "";
082    }
083
084    /**
085     * Ensures attribute handler maps are available up to the specified index.<p>
086     * This is required during inline editing, where only a fragment of the handlers data structure is build and used.<p>
087     *
088     * @param index the index of the currently edited attribute
089     */
090    public void ensureHandlers(int index) {
091
092        if (m_handlers.size() <= index) {
093            // make sure the handler maps are available
094            // this may be necessary
095            for (int i = m_handlers.size(); i <= index; i++) {
096                insertHandlers(i);
097            }
098        }
099    }
100
101    /**
102     * @see org.opencms.acacia.client.I_CmsAttributeHandler#getAttributeName()
103     */
104    public String getAttributeName() {
105
106        throw new UnsupportedOperationException();
107    }
108
109    /**
110     * @see org.opencms.acacia.client.I_CmsAttributeHandler#getChildHandler(java.lang.String, int)
111     */
112    public CmsAttributeHandler getChildHandler(String attributeName, int index) {
113
114        CmsAttributeHandler result = null;
115        if (m_handlers.size() > index) {
116            result = m_handlers.get(index).get(attributeName);
117        } else {
118            return null;
119        }
120        if (result == null) {
121            for (Map.Entry<String, CmsAttributeHandler> entry : m_handlers.get(index).entrySet()) {
122                String key = entry.getKey();
123                int opencmsPos = key.indexOf("opencms://");
124                if (opencmsPos > 0) {
125                    String reducedKey = key.substring(opencmsPos);
126                    if (reducedKey.equals(attributeName)) {
127                        result = entry.getValue();
128                        break;
129                    }
130                }
131            }
132        }
133        return result;
134    }
135
136    /**
137     * @see org.opencms.acacia.client.I_CmsAttributeHandler#getChildHandlerBySimpleName(java.lang.String, int)
138     */
139    public CmsAttributeHandler getChildHandlerBySimpleName(String name, int index) {
140
141        if (m_handlers.size() > index) {
142            for (String attributeName : m_handlers.get(index).keySet()) {
143                if (attributeName.equals(name) || attributeName.endsWith(name)) {
144                    return m_handlers.get(index).get(attributeName);
145                }
146            }
147        }
148        return null;
149    }
150
151    /**
152     * Returns the handler for the given id.<p>
153     *
154     * @param entityId the entity id
155     * @param attributeName the attribute name
156     *
157     * @return the handler
158     */
159    public CmsAttributeHandler getHandlerById(String entityId, String attributeName) {
160
161        return m_handlerById.get(entityId + "/" + attributeName);
162    }
163
164    /**
165     * Returns the attribute handler for the given path.<p>
166     *
167     * @param pathNames the path names
168     *
169     * @return the attribute handler
170     */
171    public CmsAttributeHandler getHandlerByPath(String[] pathNames) {
172
173        I_CmsAttributeHandler handler = this;
174        int index = 0;
175        for (int i = 0; i < pathNames.length; i++) {
176
177            String attributeName = pathNames[i];
178            int nextIndex = CmsContentDefinition.extractIndex(attributeName);
179            attributeName = CmsContentDefinition.removeIndex(attributeName);
180            if ((handler instanceof CmsAttributeHandler)
181                && ((CmsAttributeHandler)handler).getAttributeType().isChoice()) {
182                // in case of a choice attribute, skip to the next path name
183                attributeName = CmsType.CHOICE_ATTRIBUTE_NAME;
184
185                i++;
186                if (i < pathNames.length) {
187                    nextIndex = CmsContentDefinition.extractIndex(pathNames[i]);
188                }
189            }
190
191            handler = handler.getChildHandler(attributeName, index);
192            index = nextIndex;
193        }
194
195        return (CmsAttributeHandler)handler;
196    }
197
198    /**
199     * Returns the attribute handler to the given simple path.<p>
200     *
201     * @param pathNames the simple path elements
202     *
203     * @return the attribute handler
204     */
205    public CmsAttributeHandler getHandlersBySimplePath(String[] pathNames) {
206
207        I_CmsAttributeHandler handler = this;
208        int index = 0;
209        for (int i = 0; i < pathNames.length; i++) {
210            String attributeName = pathNames[i];
211            int nextIndex = CmsContentDefinition.extractIndex(attributeName);
212            if (nextIndex > 0) {
213                nextIndex--;
214            }
215            attributeName = CmsContentDefinition.removeIndex(attributeName);
216            if ((handler instanceof CmsAttributeHandler)
217                && ((CmsAttributeHandler)handler).getAttributeType().isChoice()) {
218                // in case of a choice attribute, skip to the next level
219                attributeName = CmsType.CHOICE_ATTRIBUTE_NAME;
220            }
221            handler = handler.getChildHandlerBySimpleName(attributeName, index);
222            index = nextIndex;
223        }
224        return (CmsAttributeHandler)handler;
225    }
226
227    /**
228     * @see org.opencms.acacia.client.I_CmsAttributeHandler#insertHandlers(int)
229     */
230    public void insertHandlers(int index) {
231
232        if (index <= m_handlers.size()) {
233            m_handlers.add(index, new HashMap<String, CmsAttributeHandler>());
234        } else {
235            throw new IndexOutOfBoundsException("index of " + index + " too big, current size: " + m_handlers.size());
236        }
237    }
238
239    /**
240     * @see org.opencms.acacia.client.I_CmsAttributeHandler#removeHandlers(int)
241     */
242    public void removeHandlers(int index) {
243
244        m_handlers.remove(index);
245    }
246
247    /**
248     * @see org.opencms.acacia.client.I_CmsAttributeHandler#setHandler(int, java.lang.String, org.opencms.acacia.client.CmsAttributeHandler)
249     */
250    public void setHandler(int index, String attributeName, CmsAttributeHandler handler) {
251
252        m_handlers.get(index).put(attributeName, handler);
253        handler.setParentHandler(this);
254        setHandlerById(attributeName, handler);
255    }
256
257    /**
258     * @see org.opencms.acacia.client.I_CmsAttributeHandler#setHandlerById(java.lang.String, org.opencms.acacia.client.CmsAttributeHandler)
259     */
260    public void setHandlerById(String attributeName, CmsAttributeHandler handler) {
261
262        m_handlerById.put(handler.getEntityId() + "/" + attributeName, handler);
263    }
264
265    /**
266     * Recruses over all child handlers of this handler and passes them to a callback.<p>
267     *
268     * @param handler the handler whose child handlers should be processed
269     */
270    public void visit(Consumer<I_CmsAttributeHandler> handler) {
271
272        handler.accept(this);
273        for (CmsAttributeHandler child : m_handlerById.values()) {
274            child.visit(handler);
275        }
276    }
277
278    /**
279     * Initializes the sub handlers maps for the given value count.<p>
280     *
281     * @param count the value count
282     */
283    protected void initHandlers(int count) {
284
285        if (count == 0) {
286            m_handlers.clear();
287        } else {
288            while (m_handlers.size() < count) {
289                m_handlers.add(new HashMap<String, CmsAttributeHandler>());
290            }
291        }
292        m_handlerById.clear();
293    }
294}