001package org.apache.maven.doxia.module.confluence.parser.table;
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.io.StringReader;
023import java.util.ArrayList;
024import java.util.LinkedList;
025import java.util.List;
026
027import org.apache.maven.doxia.module.confluence.ConfluenceMarkup;
028import org.apache.maven.doxia.module.confluence.parser.Block;
029import org.apache.maven.doxia.module.confluence.parser.BlockParser;
030import org.apache.maven.doxia.module.confluence.parser.BoldBlock;
031import org.apache.maven.doxia.module.confluence.parser.FigureBlockParser;
032import org.apache.maven.doxia.module.confluence.parser.ParagraphBlockParser;
033import org.apache.maven.doxia.module.confluence.parser.SectionBlockParser;
034import org.apache.maven.doxia.module.confluence.parser.list.ListBlockParser;
035import org.apache.maven.doxia.parser.ParseException;
036import org.apache.maven.doxia.util.ByLineReaderSource;
037import org.apache.maven.doxia.util.ByLineSource;
038import org.codehaus.plexus.util.StringUtils;
039
040/**
041 * Parse tables
042 *
043 * @author Juan F. Codagnone
044 */
045public class TableBlockParser
046    implements BlockParser
047{
048    private static final String EMPTY_STRING = "";
049
050    private static final String ANY_CHARACTER = ".*";
051
052    private static final String ESCAPE_CHARACTER = "\\";
053
054    private BlockParser[] parsers;
055
056    /**
057     * Default constructor TableBlockParser.
058     */
059    public TableBlockParser()
060    {
061        BlockParser headingParser = new SectionBlockParser();
062        BlockParser figureParser = new FigureBlockParser();
063        BlockParser listParser = new ListBlockParser();
064
065        BlockParser[] subparsers = new BlockParser[] { headingParser, figureParser, listParser };
066        BlockParser paragraphParser = new ParagraphBlockParser( subparsers );
067
068        this.parsers = new BlockParser[] { headingParser, figureParser, listParser, paragraphParser };
069
070    }
071
072    /** {@inheritDoc} */
073    public boolean accept( String line, ByLineSource source )
074    {
075        return line.startsWith( "|" );
076    }
077
078    /** {@inheritDoc} */
079    public Block visit( String line, ByLineSource source )
080        throws ParseException
081    {
082        if ( !accept( line, source ) )
083        {
084            throw new IllegalAccessError( "call accept before this ;)" );
085        }
086
087        List<Block> rows = new ArrayList<>();
088
089        String l = line;
090
091        do
092        {
093            l = l.substring( 0, l.lastIndexOf( "|" ) );
094
095            List<Block> cells = new ArrayList<>();
096
097            if ( l.startsWith( "||" ) )
098            {
099                String[] text = StringUtils.split( l, "||" );
100
101                for ( String s : text )
102                {
103                    List<Block> textBlocks = new ArrayList<>();
104
105                    textBlocks.add( parseLine( s, new ByLineReaderSource( new StringReader( EMPTY_STRING ) ) ) );
106
107                    List<Block> blocks = new ArrayList<>();
108
109                    blocks.add( new BoldBlock( textBlocks ) );
110
111                    cells.add( new TableCellHeaderBlock( blocks ) );
112                }
113            }
114            else
115            {
116                int it = 0;
117                String[] text = StringUtils.split( l, "|" );
118                List<String> texts = new LinkedList<>();
119
120                while ( it < text.length )
121                {
122                    if ( text[it].matches( ANY_CHARACTER + ESCAPE_CHARACTER + ConfluenceMarkup.LINK_START_MARKUP
123                        + ANY_CHARACTER )
124                        && !text[it].matches( ANY_CHARACTER + ESCAPE_CHARACTER + ConfluenceMarkup.LINK_END_MARKUP
125                            + ANY_CHARACTER ) )
126                    {
127                        texts.add( text[it] + ConfluenceMarkup.TABLE_CELL_MARKUP + text[it + 1] );
128                        it += 2;
129                        continue;
130                    }
131                    texts.add( text[it] );
132                    it++;
133                }
134
135                for ( String pText : texts )
136                {
137                    List<Block> blocks = new ArrayList<>();
138
139                    blocks.add( parseLine( pText, new ByLineReaderSource( new StringReader( EMPTY_STRING ) ) ) );
140
141                    cells.add( new TableCellBlock( blocks ) );
142                }
143            }
144
145            rows.add( new TableRowBlock( cells ) );
146        }
147        while ( ( l = source.getNextLine() ) != null && accept( l, source ) );
148
149        assert rows.size() >= 1;
150
151        return new TableBlock( rows );
152    }
153
154    private Block parseLine( String text, ByLineSource source )
155        throws ParseException
156    {
157        if ( text.length() > 0 )
158        {
159            for ( BlockParser parser : parsers )
160            {
161                if ( parser.accept( text, source ) )
162                {
163                    if ( parser instanceof ParagraphBlockParser )
164                    {
165                        return ( (ParagraphBlockParser) parser ).visit( text, source, false );
166                    }
167                    else
168                    {
169                        return parser.visit( text, source );
170                    }
171                }
172            }
173        }
174        return null;
175    }
176}