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.Locale;
036import java.util.Map;
037import java.util.ResourceBundle;
038import java.util.SortedSet;
039import java.util.TreeSet;
040
041/**
042 *  Creates a list of all weblog entries on a monthly basis.
043 *
044 *  <p>Parameters : </p>
045 *  <ul>
046 *  <li><b>page</b> - the page name</li>
047 *  </ul>
048 *
049 *  @since 1.9.21
050 */
051public class WeblogArchivePlugin implements Plugin {
052
053    /** Parameter name for setting the page.  Value is <tt>{@value}</tt>. */
054    public static final String PARAM_PAGE = "page";
055
056    private SimpleDateFormat m_monthUrlFormat;
057
058    @Override
059    public String getDisplayName(Locale locale) {
060        final ResourceBundle rb = ResourceBundle.getBundle(PluginManager.PLUGIN_I18N_RESOURCE, locale);
061        return rb.getString(this.getClass().getSimpleName());
062    } 
063    
064    /**
065     *  {@inheritDoc}
066     */
067    @Override
068    public String execute( final Context context, final Map< String, String > params ) throws PluginException {
069        final Engine engine = context.getEngine();
070
071        //  Parameters
072        String weblogName = params.get( PARAM_PAGE );
073
074        if( weblogName == null ) {
075            weblogName = context.getPage().getName();
076        }
077
078        final String pttrn = "'" + context.getURL( ContextEnum.PAGE_VIEW.getRequestContext(), weblogName,"weblog.startDate='ddMMyy'&amp;weblog.days=%d" ) + "'";
079        m_monthUrlFormat = new SimpleDateFormat( pttrn );
080
081        final StringBuilder sb = new StringBuilder();
082        sb.append( "<div class=\"weblogarchive\">\n" );
083
084        //  Collect months that have blog entries
085        final Collection< Calendar > months = collectMonths( engine, weblogName );
086        int year = 0;
087
088        //  Output proper HTML.
089        sb.append( "<ul>\n" );
090
091        if(!months.isEmpty()) {
092            year = ( months.iterator().next() ).get( Calendar.YEAR );
093            sb.append( "<li class=\"archiveyear\">" ).append( year ).append( "</li>\n" );
094        }
095
096        for( final Calendar cal : months ) {
097            if( cal.get( Calendar.YEAR ) != year ) {
098                year = cal.get( Calendar.YEAR );
099                sb.append( "<li class=\"archiveyear\">" ).append( year ).append( "</li>\n" );
100            }
101            sb.append( "  <li>" );
102            sb.append( getMonthLink( cal ) );
103            sb.append( "</li>\n" );
104        }
105
106        sb.append( "</ul>\n" );
107        sb.append( "</div>\n" );
108        return sb.toString();
109    }
110
111    private SortedSet< Calendar > collectMonths( final Engine engine, final String page ) {
112        final Comparator< Calendar > comp = new ArchiveComparator();
113        final TreeSet<Calendar> res = new TreeSet<>( comp );
114
115        final WeblogPlugin pl = new WeblogPlugin();
116
117        final List< Page > blogEntries = pl.findBlogEntries( engine, page, new Date(0L), new Date() );
118
119        for( final Page p : blogEntries ) {
120            // FIXME: Not correct, should parse page creation time.
121            final Date d = p.getLastModified();
122            final Calendar cal = Calendar.getInstance();
123            cal.setTime( d );
124            res.add( cal );
125        }
126
127        return res;
128    }
129
130    private String getMonthLink( final Calendar day )
131    {
132        final SimpleDateFormat monthfmt = new SimpleDateFormat( "MMMM" );
133        final String result;
134
135        if( m_monthUrlFormat == null ) {
136            result = monthfmt.format( day.getTime() );
137        } else {
138            final Calendar cal = (Calendar)day.clone();
139            final int firstDay = cal.getActualMinimum( Calendar.DATE );
140            final int lastDay  = cal.getActualMaximum( Calendar.DATE );
141
142            cal.set( Calendar.DATE, lastDay );
143            String url = m_monthUrlFormat.format( cal.getTime() );
144
145            url = TextUtil.replaceString( url, "%d", Integer.toString( lastDay-firstDay+1 ) );
146
147            result = "<a href=\""+url+"\">"+monthfmt.format(cal.getTime())+"</a>";
148        }
149
150        return result;
151
152    }
153
154
155    /**
156     * This is a simple comparator for ordering weblog archive entries.
157     * Two dates in the same month are considered equal.
158     */
159    private static class ArchiveComparator implements Comparator< Calendar > {
160
161        @Override
162        public int compare( final Calendar a, final Calendar b ) {
163            if( a == null || b == null ) {
164                throw new ClassCastException( "Invalid calendar supplied for comparison." );
165            }
166
167            if( a.get( Calendar.YEAR ) == b.get( Calendar.YEAR ) && a.get( Calendar.MONTH ) == b.get( Calendar.MONTH ) ) {
168                return 0;
169            }
170
171            //sort recent dates first
172            return b.getTime().before( a.getTime() ) ? -1 : 1;
173        }
174    }
175
176}