001/*
002 *  Copyright 2011 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 */
016
017package org.ametys.web.repository.dom;
018
019import java.util.Iterator;
020
021import org.w3c.dom.Element;
022import org.w3c.dom.Node;
023
024import org.ametys.core.right.RightManager;
025import org.ametys.core.user.UserIdentity;
026import org.ametys.plugins.repository.AmetysObjectIterable;
027import org.ametys.plugins.repository.EmptyIterable;
028import org.ametys.plugins.repository.dom.AmetysObjectElement;
029import org.ametys.web.pageaccess.RestrictedPagePolicy;
030import org.ametys.web.renderingcontext.RenderingContext;
031import org.ametys.web.renderingcontext.RenderingContextHandler;
032import org.ametys.web.repository.page.Page;
033import org.ametys.web.repository.page.PagesContainer;
034
035/**
036 * DOM {@link Element} wrapping a {@link PagesContainer}.
037 * @param <A> the actual type of the wrapped {@link PagesContainer}.
038 */
039public abstract class AbstractPagesContainerElement<A extends PagesContainer> extends AmetysObjectElement<A>
040{
041    /** Prefix for sitemap namespace. */
042    public static final String NAMESPACE_PREFIX = "sitemap";
043    /** URI for sitemap namespace. */
044    public static final String NAMESPACE_URI = "http://www.ametys.org/inputdata/sitemap/3.0";
045
046    /** The right manager */
047    protected RightManager _rightManager;
048    /** The rendering context handler. */
049    protected RenderingContextHandler _renderingContextHandler;
050    /** The path of the wrapped page. */
051    protected String _currentPagePath;
052    /** The identity of the current user. */
053    protected UserIdentity _userIdentity;
054    /** the {@link RestrictedPagePolicy} of the current site. */
055    protected RestrictedPagePolicy _policy;
056    /** should child pages displays invisible page */
057    protected boolean _includeInvisiblePages;
058    /** The depth  of childs to display */
059    protected long _depth;
060    
061    private AmetysObjectIterable<? extends Page> _children;
062    
063    /**
064     * Constructor.
065     * @param pagesContainer the wrapped {@link PagesContainer}.
066     * @param rightManager the right manager
067     * @param currentPagePath the path of the current page, or null if none.
068     * @param renderingContextHandler the {@link RenderingContextHandler}.
069     * @param userIdentity the identity of the current user, or null if none.
070     * @param depth The depth to get. 1 for root pages, 0 for this node only, -1 for infinite.
071     * @param includeInvisiblePages Should return child invisible pages
072     */
073    public AbstractPagesContainerElement(A pagesContainer, RightManager rightManager, RenderingContextHandler renderingContextHandler, String currentPagePath, UserIdentity userIdentity, long depth, boolean includeInvisiblePages)
074    {
075        this(pagesContainer, null, rightManager, renderingContextHandler, currentPagePath, userIdentity, depth, includeInvisiblePages);
076    }
077    
078    /**
079     * Constructor.
080     * @param pagesContainer the wrapped {@link PagesContainer}.
081     * @param parent the parent container.
082     * @param rightManager the right manager
083     * @param currentPagePath the path of the current page, or null if none.
084     * @param renderingContextHandler the {@link RenderingContextHandler}.
085     * @param userIdentity the identity of the current user, or null if none.
086     * @param depth The depth to get. 1 for root pages, 0 for this node only, -1 for infinite.
087     * @param includeInvisiblePages Should return child invisible pages
088     */
089    public AbstractPagesContainerElement(A pagesContainer, AbstractPagesContainerElement<PagesContainer> parent, RightManager rightManager, RenderingContextHandler renderingContextHandler, String currentPagePath, UserIdentity userIdentity, long depth, boolean includeInvisiblePages)
090    {
091        super(pagesContainer, parent);
092        _rightManager = rightManager;
093        _renderingContextHandler = renderingContextHandler;
094        _currentPagePath = currentPagePath;
095        _userIdentity = userIdentity;
096        _policy = _object.getSite().getRestrictedPagePolicy();
097        _includeInvisiblePages = includeInvisiblePages;
098        _depth = depth;
099    }
100    
101    @Override
102    public String getNamespaceURI()
103    {
104        //return "http://www.ametys.org/inputdata/sitemap/3.0";
105        return null;
106    }
107    
108    AmetysObjectIterable<? extends Page> getChildren()
109    {
110        if (_depth == 0)
111        {
112            _children = new EmptyIterable<>();
113        }
114        else if (_children == null)
115        {
116            _children = _object.getChildrenPages(_includeInvisiblePages);
117        }
118        
119        return _children;
120    }
121    
122    @Override
123    public boolean hasChildNodes()
124    {
125        if (_depth == 0)
126        {
127            _children = new EmptyIterable<>();
128        }
129        else if (_children == null)
130        {
131            _children = _object.getChildrenPages(_includeInvisiblePages);
132        }
133        
134        return _children.iterator().hasNext();
135    }
136    
137    @SuppressWarnings("unchecked")
138    @Override
139    public Node getFirstChild()
140    {
141        if (_depth == 0)
142        {
143            _children = new EmptyIterable<>();
144        }
145        else if (_children == null)
146        {
147            _children = _object.getChildrenPages(_includeInvisiblePages);
148        }
149        
150        Iterator<? extends Page> it = _children.iterator();
151        
152        if (!it.hasNext())
153        {
154            return null;
155        }
156        
157        RenderingContext renderingContext = _renderingContextHandler.getRenderingContext();
158        boolean inBackOffice = renderingContext == RenderingContext.BACK || renderingContext == RenderingContext.PREVIEW;
159        
160        Page child = null;
161        
162        while (child == null && it.hasNext())
163        {
164            Page page = it.next();
165            if (inBackOffice || _policy == RestrictedPagePolicy.DISPLAYED || _rightManager.hasReadAccess(_userIdentity, page))
166            {
167                child = page;
168            }
169        }
170        
171        return child == null ? null : new PageElement(child, (AbstractPagesContainerElement<PagesContainer>) this, _rightManager, _renderingContextHandler, _currentPagePath, _userIdentity, Math.max(_depth - 1, -1), _includeInvisiblePages);
172    }
173    
174    @SuppressWarnings("unchecked")
175    @Override
176    public Node getNextSibling()
177    {
178        if (_parent == null)
179        {
180            return null;
181        }
182        
183        AmetysObjectIterable<? extends Page> children = ((AbstractPagesContainerElement<PagesContainer>) _parent).getChildren();
184        
185        RenderingContext renderingContext = _renderingContextHandler.getRenderingContext();
186        boolean inBackOffice = renderingContext == RenderingContext.BACK || renderingContext == RenderingContext.PREVIEW;
187        
188        boolean isNext = false;
189        Page nextSibling = null;
190        Iterator<? extends Page> it = children.iterator();
191        
192        while (nextSibling == null && it.hasNext())
193        {
194            Page child = it.next();
195            
196            if (isNext && (inBackOffice || _policy == RestrictedPagePolicy.DISPLAYED || _rightManager.hasReadAccess(_userIdentity, child)))
197            {
198                nextSibling = child;
199            }
200            else if (_object.getId().equals(child.getId()))
201            {
202                isNext = true;
203            }
204        }
205        
206        return nextSibling == null ? null : new PageElement(nextSibling, (AbstractPagesContainerElement<PagesContainer>) _parent, _rightManager, _renderingContextHandler, _currentPagePath, _userIdentity, _depth, _includeInvisiblePages);
207    }
208}