001package org.apache.maven.doxia.module.confluence.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 org.apache.maven.doxia.parser.ParseException;
023import org.apache.maven.doxia.util.ByLineSource;
024
025/**
026 * <p>ParagraphBlockParser class.</p>
027 */
028public class ParagraphBlockParser
029    implements BlockParser
030{
031    private BlockParser[] parsers;
032
033    /**
034     * <p>Constructor for ParagraphBlockParser.</p>
035     *
036     * @param parsers the parsers.
037     */
038    public ParagraphBlockParser( BlockParser[] parsers )
039    {
040        super();
041        this.parsers = parsers;
042    }
043
044    /** {@inheritDoc} */
045    public boolean accept( String line, ByLineSource source )
046    {
047        return true;
048    }
049
050    /**
051     * Visit the Block.
052     *
053     * @param line the line to visit.
054     * @param source the source.
055     * @param generateParagraphTags whether to generate a paragraph.
056     * @return the visited Block.
057     * @throws org.apache.maven.doxia.parser.ParseException if any.
058     */
059    public Block visit( String line, ByLineSource source, boolean generateParagraphTags )
060            throws ParseException
061    {
062        if ( generateParagraphTags )
063        {
064            return this.visit( line, source );
065        }
066        else
067        {
068            ChildBlocksBuilder builder = new ChildBlocksBuilder( line );
069            return new ParagraphBlock( builder.getBlocks(), generateParagraphTags );
070        }
071    }
072
073    /** {@inheritDoc} */
074    public Block visit( String line, ByLineSource source )
075        throws ParseException
076    {
077
078        ChildBlocksBuilder builder = new ChildBlocksBuilder( appendUntilEmptyLine( line, source ) );
079        return new ParagraphBlock( builder.getBlocks() );
080    }
081
082    /**
083     * Slurp lines from the source starting with the given line appending them together into a StringBuilder until an
084     * empty line is reached, and while the source contains more lines. The result can be passed to the
085     * {@link #getBlocks(String)} method.
086     *
087     * @param line the first line
088     * @param source the source to read new lines from
089     * @return a StringBuilder appended with lines
090     * @throws ParseException
091     */
092    private String appendUntilEmptyLine( String line, ByLineSource source )
093        throws ParseException
094    {
095        StringBuilder text = new StringBuilder();
096
097        do
098        {
099
100            if ( line.trim().length() == 0 )
101            {
102                break;
103            }
104
105            boolean accepted = false;
106            for ( BlockParser parser : parsers )
107            {
108                if ( parser.accept( line, source ) )
109                {
110                    accepted = true;
111                    break;
112                }
113            }
114            if ( accepted )
115            {
116                // Slightly fragile - if any of the parsers need to do this in order to decide whether to accept a line,
117                // then it will barf because of the contract of ByLineSource
118                source.ungetLine();
119                break;
120            }
121
122            if ( text.length() == 0 )
123            {
124                text.append( line.trim() );
125            }
126            else
127            {
128                text.append( " " ).append( line.trim() );
129            }
130
131        }
132        while ( ( line = source.getNextLine() ) != null );
133
134        return text.toString();
135    }
136
137}