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 */
016package org.ametys.plugins.blog.repository;
017
018import java.util.ArrayList;
019import java.util.Collection;
020import java.util.Collections;
021import java.util.NoSuchElementException;
022import java.util.Set;
023
024import org.ametys.cms.repository.Content;
025import org.ametys.plugins.blog.BlogCacheManager;
026import org.ametys.plugins.blog.BlogCacheManager.Post;
027import org.ametys.plugins.explorer.resources.ResourceCollection;
028import org.ametys.plugins.repository.AmetysObject;
029import org.ametys.plugins.repository.AmetysObjectIterable;
030import org.ametys.plugins.repository.AmetysObjectIterator;
031import org.ametys.plugins.repository.AmetysObjectResolver;
032import org.ametys.plugins.repository.AmetysRepositoryException;
033import org.ametys.plugins.repository.CollectionIterable;
034import org.ametys.plugins.repository.EmptyIterable;
035import org.ametys.plugins.repository.UnknownAmetysObjectException;
036import org.ametys.plugins.repository.data.holder.ModelLessDataHolder;
037import org.ametys.plugins.repository.data.holder.impl.DefaultModelLessDataHolder;
038import org.ametys.plugins.repository.data.repositorydata.RepositoryData;
039import org.ametys.plugins.repository.data.repositorydata.impl.MemoryRepositoryData;
040import org.ametys.plugins.repository.data.type.RepositoryModelItemType;
041import org.ametys.runtime.plugin.component.AbstractThreadSafeComponentExtensionPoint;
042import org.ametys.web.repository.page.Page;
043import org.ametys.web.repository.page.PagesContainer;
044import org.ametys.web.repository.page.UnknownZoneException;
045import org.ametys.web.repository.page.Zone;
046import org.ametys.web.repository.site.Site;
047import org.ametys.web.repository.sitemap.Sitemap;
048import org.ametys.web.skin.SkinsManager;
049
050/**
051 * Virtual page representing the Post list page.
052 */
053public class VirtualPostsPage implements Page
054{
055    
056    /** The page name. */
057    public static final String NAME = "posts";
058    
059    private AmetysObjectResolver _resolver;
060    private BlogCacheManager _cacheManager;
061    private SkinsManager _skinsManager;
062    private PagesContainer _root;
063    private String _title;
064    private AbstractThreadSafeComponentExtensionPoint<RepositoryModelItemType> _pageDataTypeExtensionPoint;
065    private AbstractThreadSafeComponentExtensionPoint<RepositoryModelItemType> _zoneDataTypeExtensionPoint;
066    private AbstractThreadSafeComponentExtensionPoint<RepositoryModelItemType> _zoneItemDataTypeExtensionPoint;
067    
068    /**
069     * Constructor.
070     * @param resolver the {@link AmetysObjectResolver}.
071     * @param cacheManager the {@link AmetysObjectResolver}.
072     * @param skinsManager the skins manager
073     * @param root the blog root page.
074     * @param title the page's title.
075     * @param pageDataTypeExtensionPoint the extension point with available data types for pages
076     * @param zoneDataTypeExtensionPoint the extension point with available data types for zones
077     * @param zoneItemDataTypeExtensionPoint the extension point with available data types for zone items
078     */
079    public VirtualPostsPage(AmetysObjectResolver resolver, BlogCacheManager cacheManager, SkinsManager skinsManager, String title, PagesContainer root, AbstractThreadSafeComponentExtensionPoint<RepositoryModelItemType> pageDataTypeExtensionPoint, AbstractThreadSafeComponentExtensionPoint<RepositoryModelItemType> zoneDataTypeExtensionPoint, AbstractThreadSafeComponentExtensionPoint<RepositoryModelItemType> zoneItemDataTypeExtensionPoint)
080    {
081        _resolver = resolver;
082        _cacheManager = cacheManager;
083        _skinsManager = skinsManager;
084        _root = root;
085        _title = title;
086        
087        _pageDataTypeExtensionPoint = pageDataTypeExtensionPoint;
088        _zoneDataTypeExtensionPoint = zoneDataTypeExtensionPoint;
089        _zoneItemDataTypeExtensionPoint = zoneItemDataTypeExtensionPoint;
090    }
091    
092    @Override
093    public int getDepth() throws AmetysRepositoryException
094    {
095        int depth = 0;
096        if (_root instanceof Page)
097        {
098            depth = ((Page) _root).getDepth();
099        }
100        
101        return depth + 1;
102    }
103
104    @Override
105    public Set<String> getReferers() throws AmetysRepositoryException
106    {
107        return null;
108    }
109
110    @Override
111    public ResourceCollection getRootAttachments() throws AmetysRepositoryException
112    {
113        return null;
114    }
115
116    @Override
117    public String getTemplate() throws AmetysRepositoryException
118    {
119        return "";
120    }
121
122    @Override
123    public String getTitle() throws AmetysRepositoryException
124    {
125        return _title;
126    }
127    
128    @Override
129    public String getLongTitle() throws AmetysRepositoryException
130    {
131        return _title;
132    }
133
134    @Override
135    public PageType getType() throws AmetysRepositoryException
136    {
137        return PageType.NODE;
138    }
139
140    @Override
141    public String getURL() throws AmetysRepositoryException
142    {
143        throw new UnsupportedOperationException("getURL not supported on virtual blog pages");
144    }
145
146    @Override
147    public LinkType getURLType() throws AmetysRepositoryException
148    {
149        throw new UnsupportedOperationException("getURLType not supported on virtual blog pages");
150    }
151
152    @Override
153    public Zone getZone(String name) throws UnknownZoneException, AmetysRepositoryException
154    {
155        throw new UnknownZoneException("There is no zone on the blog years page.");
156    }
157
158    @Override
159    public AmetysObjectIterable< ? extends Zone> getZones() throws AmetysRepositoryException
160    {
161        return new EmptyIterable<>();
162    }
163
164    @Override
165    public boolean hasZone(String name) throws AmetysRepositoryException
166    {
167        return false;
168    }
169
170    @Override
171    public AmetysObjectIterable<? extends Page> getChildrenPages() throws AmetysRepositoryException
172    {
173        ArrayList<Page> children = new ArrayList<>();
174        
175        Collection<Post> posts = _cacheManager.getSortedPosts(getSiteName(), getSitemapName());
176        
177        for (Post post : posts)
178        {
179            Content postContent = _resolver.resolveById(post.getId());
180            
181            VirtualPostPage page = new VirtualPostPage(_resolver, _skinsManager, _root, postContent, NAME, _pageDataTypeExtensionPoint, _zoneDataTypeExtensionPoint, _zoneItemDataTypeExtensionPoint);
182            
183            children.add(page);
184        }
185        
186        // TODO
187        
188        return new CollectionIterable<>(children);
189    }
190
191    @Override
192    public AmetysObjectIterable< ? extends Page> getChildrenPages(boolean includeInvisiblePages) throws AmetysRepositoryException
193    {
194        return getChildrenPages();
195    }
196    
197    @Override
198    public Page getChildPageAt(int index) throws UnknownAmetysObjectException, AmetysRepositoryException
199    {
200        if (index < 0)
201        {
202            throw new AmetysRepositoryException("Child page index cannot be negative");
203        }
204        
205        AmetysObjectIterable< ? extends Page> childPages = getChildrenPages();
206        AmetysObjectIterator< ? extends Page> it = childPages.iterator();
207        
208        try
209        {
210            it.skip(index);
211            return it.next();
212        }
213        catch (NoSuchElementException e)
214        {
215            throw new UnknownAmetysObjectException("There's no child page at index " + index + " for page " + this.getId());
216        }
217    }
218    
219    @Override
220    public String getPathInSitemap() throws AmetysRepositoryException
221    {
222        StringBuilder path = new StringBuilder(_root.getPathInSitemap());
223        if (path.length() > 0)
224        {
225            path.append('/');
226        }
227        path.append(NAME);
228        
229        return path.toString();
230    }
231
232    @Override
233    public Site getSite() throws AmetysRepositoryException
234    {
235        return _root.getSite();
236    }
237
238    @Override
239    public String getSiteName() throws AmetysRepositoryException
240    {
241        return _root.getSiteName();
242    }
243
244    @Override
245    public Sitemap getSitemap() throws AmetysRepositoryException
246    {
247        return _root.getSitemap();
248    }
249
250    @Override
251    public String getSitemapName() throws AmetysRepositoryException
252    {
253        return _root.getSitemapName();
254    }
255
256    @SuppressWarnings("unchecked")
257    @Override
258    public <A extends AmetysObject> A getChild(String path) throws AmetysRepositoryException, UnknownAmetysObjectException
259    {
260        if (path.isEmpty())
261        {
262            throw new AmetysRepositoryException("Path must be non empty");
263        }
264        
265//        int slashPos = path.indexOf('/');
266//        int questionPos = path.indexOf('?', slashPos);
267//        int ampPos = path.indexOf('&', questionPos);
268            
269//        String childName = slashPos == -1 ? path : path.substring(0, slashPos);
270//        String rootId = path.substring(questionPos + "?rootId=".length(), ampPos);
271//        String postId = path.substring(ampPos + "&postId=".length());
272        
273        int slashPos = path.indexOf('/');
274        
275        String childName = slashPos == -1 ? path : path.substring(0, slashPos);
276        
277        Post post = _cacheManager.getPostByName(getSiteName(), getSitemapName(), childName);
278        if (post == null)
279        {
280            throw new UnknownAmetysObjectException(path + " is not a valid post page.");
281        }
282        
283        Content postContent = _resolver.resolveById(post.getId());
284        
285//        Content postContent = _resolver.resolveById(postId);
286        
287        VirtualPostPage page = new VirtualPostPage(_resolver, _skinsManager, _root, postContent, NAME, _pageDataTypeExtensionPoint, _zoneDataTypeExtensionPoint, _zoneItemDataTypeExtensionPoint);
288        
289        if (slashPos == -1)
290        {
291            return (A) page;
292        }
293        else
294        {
295            return (A) page.getChild(path.substring(slashPos + 1));
296        }
297    }
298
299    @SuppressWarnings("unchecked")
300    @Override
301    public AmetysObjectIterable<? extends AmetysObject> getChildren() throws AmetysRepositoryException
302    {
303        return getChildrenPages();
304    }
305
306    @Override
307    public boolean hasChild(String name) throws AmetysRepositoryException
308    {
309        return _cacheManager.hasPostByName(getSiteName(), getSitemapName(), name);
310    }
311    
312    @Override
313    public String getId() throws AmetysRepositoryException
314    {
315        return "blog-category://" + NAME + "?rootId=" + _root.getId();
316    }
317
318    @Override
319    public String getName() throws AmetysRepositoryException
320    {
321        return NAME;
322    }
323
324    @SuppressWarnings("unchecked")
325    @Override
326    public PagesContainer getParent() throws AmetysRepositoryException
327    {
328        return _root;
329    }
330
331    @Override
332    public String getParentPath() throws AmetysRepositoryException
333    {
334        return _root.getPath();
335    }
336
337    @Override
338    public String getPath() throws AmetysRepositoryException
339    {
340        StringBuilder buff = new StringBuilder(getParentPath());
341        if (!getParentPath().isEmpty())
342        {
343            buff.append('/');
344        }
345        buff.append(NAME);
346        
347        return buff.toString();
348    }
349
350    public ModelLessDataHolder getDataHolder()
351    {
352        RepositoryData repositoryData = new MemoryRepositoryData(getName());
353        return new DefaultModelLessDataHolder(_pageDataTypeExtensionPoint, repositoryData);
354    }
355
356    @Override
357    public Set<String> getTags() throws AmetysRepositoryException
358    {
359        return Collections.emptySet();
360    }
361    
362    @Override
363    public boolean isVisible() throws AmetysRepositoryException
364    {
365        return true;
366    }
367}