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.Collections;
020import java.util.NoSuchElementException;
021import java.util.Set;
022import java.util.SortedSet;
023import java.util.TreeSet;
024
025import org.ametys.core.util.I18nUtils;
026import org.ametys.plugins.blog.BlogCacheManager;
027import org.ametys.plugins.blog.BlogConstants;
028import org.ametys.plugins.explorer.resources.ResourceCollection;
029import org.ametys.plugins.repository.AmetysObject;
030import org.ametys.plugins.repository.AmetysObjectIterable;
031import org.ametys.plugins.repository.AmetysObjectIterator;
032import org.ametys.plugins.repository.AmetysObjectResolver;
033import org.ametys.plugins.repository.AmetysRepositoryException;
034import org.ametys.plugins.repository.CollectionIterable;
035import org.ametys.plugins.repository.UnknownAmetysObjectException;
036import org.ametys.plugins.repository.metadata.CompositeMetadata;
037import org.ametys.runtime.i18n.I18nizableText;
038import org.ametys.web.repository.page.Page;
039import org.ametys.web.repository.page.PagesContainer;
040import org.ametys.web.repository.page.Zone;
041import org.ametys.web.repository.site.Site;
042import org.ametys.web.repository.sitemap.Sitemap;
043import org.ametys.web.site.SiteConfigurationExtensionPoint;
044import org.ametys.web.skin.Skin;
045import org.ametys.web.skin.SkinsManager;
046
047/**
048 * Virtual page representing a year page.
049 */
050public class VirtualYearPage extends AbstractBlogPage
051{
052    private AmetysObjectResolver _resolver;
053    private BlogCacheManager _cacheManager;
054    private I18nUtils _i18nUtils;
055    private String _i18nCatalogue;
056    private SiteConfigurationExtensionPoint _siteConf;
057    private PagesContainer _root;
058    private int _year;
059    private String _title;
060    private SkinsManager _skinsManager;
061    
062    /**
063     * Constructor.
064     * @param resolver the {@link AmetysObjectResolver}.
065     * @param cacheManager the {@link BlogCacheManager}.
066     * @param skinsManager the {@link SkinsManager}
067     * @param i18nCache the i18n utils
068     * @param i18nCatalogue the i18n catalogue.
069     * @param siteConf The site configuration
070     * @param year the year
071     * @param title the page's title.
072     * @param root the blog root page.
073     */
074    public VirtualYearPage(AmetysObjectResolver resolver, BlogCacheManager cacheManager, SkinsManager skinsManager, I18nUtils i18nCache,  String i18nCatalogue, SiteConfigurationExtensionPoint siteConf, int year, String title, PagesContainer root)
075    {
076        _resolver = resolver;
077        _cacheManager = cacheManager;
078        _skinsManager = skinsManager;
079        _i18nUtils = i18nCache;
080        _i18nCatalogue = i18nCatalogue;
081        _siteConf = siteConf;
082        _root = root;
083        _year = year;
084        _title = title;
085    }
086    
087    /**
088     * Get the page's year.
089     * @return the year.
090     */
091    public int getYear()
092    {
093        return _year;
094    }
095    
096    @Override
097    public int getDepth() throws AmetysRepositoryException
098    {
099        int depth = 0;
100        if (_root instanceof Page)
101        {
102            depth = ((Page) _root).getDepth();
103        }
104        
105        return depth + 2;
106    }
107
108    @Override
109    public Set<String> getReferers() throws AmetysRepositoryException
110    {
111        return null;
112    }
113
114    @Override
115    public ResourceCollection getRootAttachments() throws AmetysRepositoryException
116    {
117        return null;
118    }
119    
120    @Override
121    public String getTitle() throws AmetysRepositoryException
122    {
123        return _title;
124    }
125    
126    @Override
127    public String getLongTitle() throws AmetysRepositoryException
128    {
129        return _title;
130    }
131    
132    @Override
133    public String getURL() throws AmetysRepositoryException
134    {
135        throw new UnsupportedOperationException("getURL not supported on virtual blog pages");
136    }
137
138    @Override
139    public LinkType getURLType() throws AmetysRepositoryException
140    {
141        throw new UnsupportedOperationException("getURLType not supported on virtual blog pages");
142    }
143    
144    @Override
145    protected Zone getDefaultZone()
146    {
147        Long max = _siteConf.getValueAsLong(getSiteName(), "posts-service-max-count");
148        int maxCount = max != null ? max.intValue() : BlogConstants.DEFAULT_POST_COUNT_PER_PAGE;
149        
150        return new PostListZone(this, "", maxCount);
151    }
152    
153    @Override
154    public AmetysObjectIterable<? extends Page> getChildrenPages() throws AmetysRepositoryException
155    {
156        ArrayList<Page> children = new ArrayList<>();
157        
158        SortedSet<Integer> months = new TreeSet<>(Collections.reverseOrder());
159        months.addAll(_cacheManager.getMonths(getSiteName(), getSitemapName(), _year));
160        
161        for (Integer month : months)
162        {
163            I18nizableText monthText = new I18nizableText(_i18nCatalogue, "PLUGINS_BLOG_PAGE_MONTH_" + String.format("%02d", month));
164            
165            String title = _i18nUtils.translate(monthText, getSitemapName());
166            
167            VirtualMonthPage page = new VirtualMonthPage(_resolver, _cacheManager, _skinsManager, _siteConf, _year, month, title, _root);
168            
169            children.add(page);
170        }
171        
172        return new CollectionIterable<>(children);
173    }
174    
175    @Override
176    public AmetysObjectIterable< ? extends Page> getChildrenPages(boolean includeInvisiblePages) throws AmetysRepositoryException
177    {
178        return getChildrenPages();
179    }
180    
181    @Override
182    public Page getChildPageAt(int index) throws UnknownAmetysObjectException, AmetysRepositoryException
183    {
184        if (index < 0)
185        {
186            throw new AmetysRepositoryException("Child page index cannot be negative");
187        }
188        
189        AmetysObjectIterable< ? extends Page> childPages = getChildrenPages();
190        AmetysObjectIterator< ? extends Page> it = childPages.iterator();
191        
192        try
193        {
194            it.skip(index);
195            return it.next();
196        }
197        catch (NoSuchElementException e)
198        {
199            throw new UnknownAmetysObjectException("There's no child page at index " + index + " for page " + this.getId());
200        }
201    }
202
203    @Override
204    public String getPathInSitemap() throws AmetysRepositoryException
205    {
206        StringBuilder buff = new StringBuilder(_root.getPathInSitemap());
207        if (buff.length() > 0)
208        {
209            buff.append('/');
210        }
211        buff.append(VirtualYearsPage.NAME).append('/').append(_year);
212        
213        return buff.toString();
214    }
215
216    @Override
217    public Site getSite() throws AmetysRepositoryException
218    {
219        return _root.getSite();
220    }
221
222    @Override
223    public String getSiteName() throws AmetysRepositoryException
224    {
225        return _root.getSiteName();
226    }
227
228    @Override
229    public Sitemap getSitemap() throws AmetysRepositoryException
230    {
231        return _root.getSitemap();
232    }
233
234    @Override
235    public String getSitemapName() throws AmetysRepositoryException
236    {
237        return _root.getSitemapName();
238    }
239
240    @SuppressWarnings("unchecked")
241    @Override
242    public <A extends AmetysObject> A getChild(String path) throws AmetysRepositoryException, UnknownAmetysObjectException
243    {
244        if (path.isEmpty())
245        {
246            throw new AmetysRepositoryException("Path must be non empty");
247        }
248        
249        int slashPos = path.indexOf('/');
250        
251        String childName = slashPos == -1 ? path : path.substring(0, slashPos);
252        
253        int month;
254        try
255        {
256            month = Integer.parseInt(childName);
257        }
258        catch (NumberFormatException e)
259        {
260            throw new AmetysRepositoryException(childName + " is not a valid month page.", e);
261        }
262        
263        I18nizableText monthText = new I18nizableText(_i18nCatalogue, "PLUGINS_BLOG_PAGE_MONTH_" + String.format("%02d", month));
264        
265        String title = _i18nUtils.translate(monthText, getSitemapName());
266        
267        VirtualMonthPage page = new VirtualMonthPage(_resolver, _cacheManager, _skinsManager, _siteConf, _year, month, title, _root);
268        
269        if (slashPos == -1)
270        {
271            return (A) page;
272        }
273        else
274        {
275            return (A) page.getChild(path.substring(slashPos + 1));
276        }
277    }
278
279    @SuppressWarnings("unchecked")
280    @Override
281    public AmetysObjectIterable<? extends AmetysObject> getChildren() throws AmetysRepositoryException
282    {
283        return getChildrenPages();
284    }
285
286    @Override
287    public boolean hasChild(String name) throws AmetysRepositoryException
288    {
289        try
290        {
291            int month = Integer.parseInt(name);
292            
293            return _cacheManager.hasMonth(getSiteName(), getSitemapName(), _year, month);
294        }
295        catch (NumberFormatException e)
296        {
297            // Ignore.
298        }
299        
300        return false;
301    }
302    
303    @Override
304    public String getId() throws AmetysRepositoryException
305    {
306        return "blog-year://" + _year + "?rootId=" + _root.getId();
307    }
308
309    @Override
310    public String getName() throws AmetysRepositoryException
311    {
312        return Integer.toString(_year);
313    }
314
315    @SuppressWarnings("unchecked")
316    @Override
317    public PagesContainer getParent() throws AmetysRepositoryException
318    {
319        return _root;
320    }
321
322    @Override
323    public String getParentPath() throws AmetysRepositoryException
324    {
325        StringBuilder path = new StringBuilder(_root.getPath());
326        if (path.length() > 0)
327        {
328            path.append('/');
329        }
330        
331        path.append(VirtualYearsPage.NAME);
332        
333        return path.toString();
334    }
335
336    @Override
337    public String getPath() throws AmetysRepositoryException
338    {
339        return getParentPath() + "/" + _year;
340    }
341
342    @Override
343    public CompositeMetadata getMetadataHolder()
344    {
345        return new StaticCompositeMetadata();
346    }
347
348    @Override
349    public Set<String> getTags() throws AmetysRepositoryException
350    {
351        return Collections.emptySet();
352    }
353    
354    @Override
355    public String getTemplate() throws AmetysRepositoryException
356    {
357        Skin skin = _skinsManager.getSkin(getSite().getSkinId());
358        
359        if (skin.getTemplate(BLOG_YEAR_TEMPLATE) != null)
360        {
361            return BLOG_YEAR_TEMPLATE;
362        }
363        
364        return super.getTemplate();
365    }
366    
367    @Override
368    public boolean isVisible() throws AmetysRepositoryException
369    {
370        return true;
371    }
372}