001package org.apache.maven.doxia.module.twiki.parser;
002
003/*
004 * Licensed to the Apache Software Foundation (ASF) under one
005 * or more contributor license agreements.  See the NOTICE file
006 * distributed with this work for additional information
007 * regarding copyright ownership.  The ASF licenses this file
008 * to you under the Apache License, Version 2.0 (the
009 * "License"); you may not use this file except in compliance
010 * with the License.  You may obtain a copy of the License at
011 *
012 *   http://www.apache.org/licenses/LICENSE-2.0
013 *
014 * Unless required by applicable law or agreed to in writing,
015 * software distributed under the License is distributed on an
016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017 * KIND, either express or implied.  See the License for the
018 * specific language governing permissions and limitations
019 * under the License.
020 */
021
022import java.util.ArrayList;
023import java.util.Arrays;
024import java.util.List;
025import java.util.regex.Matcher;
026import java.util.regex.Pattern;
027
028import org.apache.maven.doxia.util.ByLineSource;
029import org.apache.maven.doxia.parser.ParseException;
030
031/**
032 * Parse paragraphs.
033 *
034 * @author Juan F. Codagnone
035 * @version $Id$
036 */
037public class ParagraphBlockParser
038    implements BlockParser
039{
040    /**
041     * pattern used to dectect end of paragraph
042     */
043    private final Pattern paragraphSeparator = Pattern.compile( "^(\\s*)$" );
044
045    /**
046     * {@link SectionBlockParser} to use. injected
047     */
048    private SectionBlockParser sectionParser;
049
050    /**
051     * {@link ListBlockParser} to use. injected
052     */
053    private GenericListBlockParser listParser;
054
055    /**
056     * {@link FormatedTextParser} to use. injected
057     */
058    private FormatedTextParser textParser;
059
060    /**
061     * {@link HRuleBlockParser} to use. injected
062     */
063    private HRuleBlockParser hrulerParser;
064
065    /**
066     * {@link TableBlockParser} to use. injected
067     */
068    private TableBlockParser tableBlockParser;
069
070    /**
071     *  {@link TableBlockParser} to use. injected
072     */
073    private VerbatimBlockParser verbatimParser;
074
075    /**
076     * no operation block
077     */
078    private static final NopBlock NOP = new NopBlock();
079
080    /** {@inheritDoc} */
081    public final boolean accept( final String line )
082    {
083        return !sectionParser.accept( line ) && !hrulerParser.accept( line ) && !verbatimParser.accept( line );
084    }
085
086    /**
087     * {@inheritDoc}
088     */
089    public final Block visit( final String line, final ByLineSource source )
090        throws ParseException
091    {
092        StringBuilder sb = new StringBuilder();
093        List<Block> childs = new ArrayList<Block>();
094
095        boolean sawText = false;
096
097        /*
098        * 1. Skip begininig new lines
099        * 2. Get the text, while \n\n is not found
100        */
101        boolean pre = false;
102        String l = line;
103        do
104        {
105            Matcher m = paragraphSeparator.matcher( l );
106
107            if ( m.lookingAt() )
108            {
109                if ( sawText )
110                {
111                    break;
112                }
113            }
114            else
115            {
116                sawText = true;
117
118                /* be able to parse lists / enumerations */
119                if ( listParser.accept( l ) )
120                {
121                    if ( sb.length() != 0 )
122                    {
123                        childs.addAll( Arrays.asList( textParser.parse( sb.toString().trim() ) ) );
124                        sb = new StringBuilder();
125                    }
126                    childs.add( listParser.visit( l, source ) );
127                }
128                else if ( tableBlockParser.accept( l ) )
129                {
130                    childs.add( tableBlockParser.visit( l, source ) );
131                }
132                else
133                {
134                    sb.append( l );
135                    // specific
136                    if ( l.indexOf( "<pre>" ) != -1 )
137                    {
138                        pre = true;
139                    }
140                    if ( l.indexOf( "</pre>" ) != -1 )
141                    {
142                        pre = false;
143                    }
144
145                    if ( !pre )
146                    {
147                        sb.append( " " );
148                    }
149                    else
150                    {
151                        // TODO use EOL
152                        sb.append( "\n" );
153                    }
154                }
155            }
156            l = source.getNextLine();
157        }
158        while ( l != null && accept( l ) );
159
160        if ( line != null )
161        {
162            source.ungetLine();
163        }
164
165        if ( sb.length() != 0 )
166        {
167            childs.addAll( Arrays.asList( textParser.parse( sb.toString().trim() ) ) );
168            sb = new StringBuilder();
169        }
170
171        if ( childs.size() == 0 )
172        {
173            return NOP;
174        }
175
176        return new ParagraphBlock( childs.toArray( new Block[] {} ) );
177    }
178
179    /**
180     * Sets the sectionParser.
181     *
182     * @param aSectionParser <code>SectionBlockParser</code> with the sectionParser.
183     */
184    public final void setSectionParser( final SectionBlockParser aSectionParser )
185    {
186        if ( aSectionParser == null )
187        {
188            throw new IllegalArgumentException( "arg can't be null" );
189        }
190        this.sectionParser = aSectionParser;
191    }
192
193    /**
194     * Sets the listParser.
195     *
196     * @param aListParser <code>ListBlockParser</code> with the listParser.
197     */
198    public final void setListParser( final GenericListBlockParser aListParser )
199    {
200        if ( aListParser == null )
201        {
202            throw new IllegalArgumentException( "arg can't be null" );
203        }
204
205        this.listParser = aListParser;
206    }
207
208    /**
209     * Sets the formatTextParser.
210     *
211     * @param aTextParser <code>FormatedTextParser</code>
212     *                   with the formatTextParser.
213     */
214    public final void setTextParser( final FormatedTextParser aTextParser )
215    {
216        if ( aTextParser == null )
217        {
218            throw new IllegalArgumentException( "arg can't be null" );
219        }
220        this.textParser = aTextParser;
221    }
222
223    /**
224     * Sets the hrulerParser.
225     *
226     * @param aHrulerParser <code>HRuleBlockParser</code> with the hrulerParser.
227     */
228    public final void setHrulerParser( final HRuleBlockParser aHrulerParser )
229    {
230        if ( aHrulerParser == null )
231        {
232            throw new IllegalArgumentException( "arg can't be null" );
233        }
234
235        this.hrulerParser = aHrulerParser;
236    }
237
238    /**
239     * <p>Setter for the field <code>tableBlockParser</code>.</p>
240     *
241     * @param aTableBlockParser Table parser to use
242     */
243    public final void setTableBlockParser( final TableBlockParser aTableBlockParser )
244    {
245        if ( aTableBlockParser == null )
246        {
247            throw new IllegalArgumentException( "arg can't be null" );
248        }
249
250        this.tableBlockParser = aTableBlockParser;
251    }
252
253    /**
254     * Sets the verbatimParser.
255     *
256     * @param aVerbatimParser <code>VerbatimBlockParser</code> with the verbatimParser.
257     * @since 1.1
258     */
259    public final void setVerbatimParser( final VerbatimBlockParser aVerbatimParser )
260    {
261        if ( aVerbatimParser == null )
262        {
263            throw new IllegalArgumentException( "arg can't be null" );
264        }
265        this.verbatimParser = aVerbatimParser;
266    }
267}