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.odf.xslt;
017
018import java.util.ArrayList;
019import java.util.HashMap;
020import java.util.List;
021import java.util.Map;
022
023import org.apache.commons.lang.StringUtils;
024import org.w3c.dom.DOMException;
025import org.w3c.dom.Node;
026
027import org.ametys.core.util.dom.AbstractWrappingAmetysElement;
028import org.ametys.core.util.dom.AmetysAttribute;
029import org.ametys.odf.ProgramItem;
030import org.ametys.odf.course.Course;
031import org.ametys.odf.courselist.CourseList;
032import org.ametys.odf.program.Container;
033import org.ametys.odf.program.ProgramPart;
034import org.ametys.odf.program.SubProgram;
035import org.ametys.odf.program.TraversableProgramPart;
036import org.ametys.plugins.repository.AmetysObject;
037import org.ametys.plugins.repository.AmetysObjectResolver;
038
039/**
040 * DOM layer on structure of an ODF content.
041 * @param <T> The type of wrapped object
042 */
043public abstract class AbstractODFElement<T extends ProgramItem> extends AbstractWrappingAmetysElement<T>
044{
045    /** The children depth */
046    protected int _depth;
047    /** The Ametys object resolver */
048    protected AmetysObjectResolver _resolver;
049
050    /**
051     * Constructor.
052     * @param odfContent the underlying.
053     * @param depth Depth to SAX.
054     * @param parent Parent of the element
055     * @param resolver AmetysObjectResolver to find some elements by ID
056     */
057    public AbstractODFElement(T odfContent, int depth, AbstractODFElement<?> parent, AmetysObjectResolver resolver)
058    {
059        super(odfContent, parent);
060        _depth = depth;
061        _resolver = resolver;
062    }
063
064    @Override
065    public boolean hasChildNodes()
066    {
067        if (_depth == 0)
068        {
069            // Stop recursion
070            return false;
071        }
072        
073        if (_object instanceof CourseList)
074        {
075            return ((CourseList) _object).hasCourses();
076        }
077        else if (_object instanceof TraversableProgramPart)
078        {
079            return ((TraversableProgramPart) _object).hasProgramPartChildren();
080        }
081        else if (_object instanceof Course)
082        {
083            return ((Course) _object).hasCourseLists();
084        }
085        else
086        {
087            throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "hasChildNodes");
088        }
089    }
090    
091    @Override
092    public Node getFirstChild()
093    {
094        if (_object instanceof CourseList)
095        {
096            List<Course> courses = ((CourseList) _object).getCourses();
097            if (courses.size() > 0)
098            {
099                return new CourseElement(courses.get(0), 1, (CourseListElement) this, _resolver);
100            }
101        }
102        else if (_object instanceof TraversableProgramPart)
103        {
104            List<ProgramPart> children = ((TraversableProgramPart) _object).getProgramPartChildren();
105            if (children.size() > 0)
106            {
107                ProgramPart ao = children.get(0);
108                if (ao instanceof SubProgram)
109                {
110                    return new SubProgramElement((SubProgram) ao, _depth - 1, this, _resolver);
111                }
112                else if (ao instanceof Container)
113                {
114                    return new ContainerElement((Container) ao, _depth - 1, this, _resolver);
115                }
116                else if (ao instanceof CourseList)
117                {
118                    return new CourseListElement((CourseList) ao, _depth - 1, this, _resolver);
119                }
120            }
121            return null;
122        }
123        else if (_object instanceof Course)
124        {
125            List<CourseList> children = ((Course) _object).getCourseLists();
126            if (children.size() > 0)
127            {
128                CourseList ao = children.get(0);
129                return new CourseListElement(ao, _depth - 1, this, _resolver);
130            }
131        }
132        else
133        {
134            throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "getFirstChild");
135        }
136        
137        return null;
138    }
139    
140    @Override
141    public Node getNextSibling()
142    {
143        if (_parent == null)
144        {
145            return null;
146        }
147        
148        AmetysObject nextSibling = null;
149        
150        AbstractODFElement<?> parentElement = (AbstractODFElement<?>) _parent;
151        Object parent = parentElement.getWrappedObject();
152        if (parent instanceof ProgramPart)
153        {
154            List<AmetysObject> children = new ArrayList<>();
155            if (parent instanceof TraversableProgramPart)
156            {
157                children.addAll(((TraversableProgramPart) parent).getProgramPartChildren());
158            }
159            if (parent instanceof CourseList)
160            {
161                children.addAll(((CourseList) parent).getCourses());
162            }
163            
164            boolean isNext = false;
165            int count = 0;
166            
167            while (nextSibling == null && count < children.size())
168            {
169                if (isNext)
170                {
171                    nextSibling = children.get(count);
172                }
173                else if (_object.getId().equals(children.get(count).getId()))
174                {
175                    isNext = true;
176                }
177                count++;
178            }
179        }
180        else if (parent instanceof Course)
181        {
182            List<CourseList> children = ((Course) parent).getCourseLists();
183            
184            boolean isNext = false;
185            int count = 0;
186            
187            while (nextSibling == null && count < children.size())
188            {
189                if (isNext)
190                {
191                    nextSibling = children.get(count);
192                }
193                else if (_object.getId().equals(children.get(count).getId()))
194                {
195                    isNext = true;
196                }
197                count++;
198            }
199        }
200        else
201        {
202            throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "getNextSibling");
203        }
204        
205        if (nextSibling != null)
206        {
207            if (nextSibling instanceof SubProgram)
208            {
209                return new SubProgramElement((SubProgram) nextSibling, _depth, parentElement, _resolver);
210            }
211            else if (nextSibling instanceof Container)
212            {
213                return new ContainerElement((Container) nextSibling, _depth, parentElement, _resolver);
214            }
215            else if (nextSibling instanceof CourseList)
216            {
217                return new CourseListElement((CourseList) nextSibling, _depth, parentElement, _resolver);
218            }
219            else if (nextSibling instanceof Course)
220            {
221                return new CourseElement((Course) nextSibling, _depth, (CourseListElement) parentElement, _resolver);
222            }
223        }
224        
225        return null;
226    }
227    
228    @Override
229    protected Map<String, AmetysAttribute> _lookupAttributes()
230    {
231        Map<String, AmetysAttribute> result = new HashMap<>();
232        result.put("id", new AmetysAttribute("id", "id", null, _object.getId(), this));
233        
234        if (StringUtils.isNotEmpty(_object.getCode()))
235        {
236            result.put("code", new AmetysAttribute("code", "code", null, _object.getCode(), this));
237        }
238        if (StringUtils.isNotEmpty(_object.getCatalog()))
239        {
240            result.put("catalog", new AmetysAttribute("catalog", "catalog", null, _object.getCatalog(), this));
241        }
242        return result;
243    }
244}