001/*
002    Licensed to the Apache Software Foundation (ASF) under one
003    or more contributor license agreements.  See the NOTICE file
004    distributed with this work for additional information
005    regarding copyright ownership.  The ASF licenses this file
006    to you under the Apache License, Version 2.0 (the
007    "License"); you may not use this file except in compliance
008    with the License.  You may obtain a copy of the License at
009
010       http://www.apache.org/licenses/LICENSE-2.0
011
012    Unless required by applicable law or agreed to in writing,
013    software distributed under the License is distributed on an
014    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015    KIND, either express or implied.  See the License for the
016    specific language governing permissions and limitations
017    under the License.
018 */
019package org.apache.wiki.plugin;
020
021import org.apache.wiki.api.core.Context;
022import org.apache.wiki.api.core.ContextEnum;
023import org.apache.wiki.api.core.Engine;
024import org.apache.wiki.api.core.Page;
025import org.apache.wiki.api.exceptions.PluginException;
026import org.apache.wiki.api.plugin.Plugin;
027import org.apache.wiki.util.TextUtil;
028
029import java.text.SimpleDateFormat;
030import java.util.Calendar;
031import java.util.Collection;
032import java.util.Comparator;
033import java.util.Date;
034import java.util.List;
035import java.util.Map;
036import java.util.SortedSet;
037import java.util.TreeSet;
038
039/**
040 *  Creates a list of all weblog entries on a monthly basis.
041 *
042 *  <p>Parameters : </p>
043 *  <ul>
044 *  <li><b>page</b> - the page name</li>
045 *  </ul>
046 *
047 *  @since 1.9.21
048 */
049public class WeblogArchivePlugin implements Plugin {
050
051    /** Parameter name for setting the page.  Value is <tt>{@value}</tt>. */
052    public static final String PARAM_PAGE = "page";
053
054    private SimpleDateFormat m_monthUrlFormat;
055
056    /**
057     *  {@inheritDoc}
058     */
059    @Override
060    public String execute( final Context context, final Map< String, String > params ) throws PluginException {
061        final Engine engine = context.getEngine();
062
063        //  Parameters
064        String weblogName = params.get( PARAM_PAGE );
065
066        if( weblogName == null ) {
067            weblogName = context.getPage().getName();
068        }
069
070        final String pttrn = "'" + context.getURL( ContextEnum.PAGE_VIEW.getRequestContext(), weblogName,"weblog.startDate='ddMMyy'&amp;weblog.days=%d" ) + "'";
071        m_monthUrlFormat = new SimpleDateFormat( pttrn );
072
073        final StringBuilder sb = new StringBuilder();
074        sb.append( "<div class=\"weblogarchive\">\n" );
075
076        //  Collect months that have blog entries
077        final Collection< Calendar > months = collectMonths( engine, weblogName );
078        int year = 0;
079
080        //  Output proper HTML.
081        sb.append( "<ul>\n" );
082
083        if( months.size() > 0 ) {
084            year = ( months.iterator().next() ).get( Calendar.YEAR );
085            sb.append( "<li class=\"archiveyear\">" ).append( year ).append( "</li>\n" );
086        }
087
088        for( final Calendar cal : months ) {
089            if( cal.get( Calendar.YEAR ) != year ) {
090                year = cal.get( Calendar.YEAR );
091                sb.append( "<li class=\"archiveyear\">" ).append( year ).append( "</li>\n" );
092            }
093            sb.append( "  <li>" );
094            sb.append( getMonthLink( cal ) );
095            sb.append( "</li>\n" );
096        }
097
098        sb.append( "</ul>\n" );
099        sb.append( "</div>\n" );
100        return sb.toString();
101    }
102
103    private SortedSet< Calendar > collectMonths( final Engine engine, final String page ) {
104        final Comparator< Calendar > comp = new ArchiveComparator();
105        final TreeSet<Calendar> res = new TreeSet<>( comp );
106
107        final WeblogPlugin pl = new WeblogPlugin();
108
109        final List< Page > blogEntries = pl.findBlogEntries( engine, page, new Date(0L), new Date() );
110
111        for( final Page p : blogEntries ) {
112            // FIXME: Not correct, should parse page creation time.
113            final Date d = p.getLastModified();
114            final Calendar cal = Calendar.getInstance();
115            cal.setTime( d );
116            res.add( cal );
117        }
118
119        return res;
120    }
121
122    private String getMonthLink( final Calendar day )
123    {
124        final SimpleDateFormat monthfmt = new SimpleDateFormat( "MMMM" );
125        final String result;
126
127        if( m_monthUrlFormat == null ) {
128            result = monthfmt.format( day.getTime() );
129        } else {
130            final Calendar cal = (Calendar)day.clone();
131            final int firstDay = cal.getActualMinimum( Calendar.DATE );
132            final int lastDay  = cal.getActualMaximum( Calendar.DATE );
133
134            cal.set( Calendar.DATE, lastDay );
135            String url = m_monthUrlFormat.format( cal.getTime() );
136
137            url = TextUtil.replaceString( url, "%d", Integer.toString( lastDay-firstDay+1 ) );
138
139            result = "<a href=\""+url+"\">"+monthfmt.format(cal.getTime())+"</a>";
140        }
141
142        return result;
143
144    }
145
146
147    /**
148     * This is a simple comparator for ordering weblog archive entries.
149     * Two dates in the same month are considered equal.
150     */
151    private static class ArchiveComparator implements Comparator< Calendar > {
152
153        @Override
154        public int compare( final Calendar a, final Calendar b ) {
155            if( a == null || b == null ) {
156                throw new ClassCastException( "Invalid calendar supplied for comparison." );
157            }
158
159            if( a.get( Calendar.YEAR ) == b.get( Calendar.YEAR ) && a.get( Calendar.MONTH ) == b.get( Calendar.MONTH ) ) {
160                return 0;
161            }
162
163            //sort recent dates first
164            return b.getTime().before( a.getTime() ) ? -1 : 1;
165        }
166    }
167
168}