    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.render;
    020
    021import org.apache.wiki.api.core.Context;
    022import org.apache.wiki.parser.PluginContent;
    023import org.apache.wiki.parser.WikiDocument;
    024import org.jdom2.Content;
    025import org.jdom2.Element;
    026import org.jdom2.Text;
    027
    028import java.util.ArrayList;
    029import java.util.List;
    030import java.util.stream.Collectors;
    031import java.util.stream.IntStream;
    032
    033/**
    034 *  Implements DOM-to-Creole rendering.
    035 *  <p>
    036 *  FIXME: This class is not yet completely done.
    037 *
    038 */
    039public class CreoleRenderer extends WikiRenderer {
    040
    041    private static final String IMG_START = "{{";
    042    private static final String IMG_END = "}}";
    043    private static final String PLUGIN_START = "<<";
    044    private static final String PLUGIN_END = ">>";
    045    private static final String HREF_START = "[[";
    046    private static final String HREF_DELIMITER = "|";
    047    private static final String HREF_END = "]]";
    048    private static final String PRE_START = "{{{";
    049    private static final String PRE_END = "}}}";
    050    private static final String PLUGIN_IMAGE = "Image";
    051    private static final String PARAM_SRC = "src";
    052    private static final String HREF_ATTRIBUTE = "href";
    053    private static final String ONE_SPACE = " ";
    054    private static final String EMPTY_STRING = "";
    055    private static final String LINEBREAK = "\n";
    056    private static final String LI = "li";
    057    private static final String UL = "ul";
    058    private static final String OL = "ol";
    059    private static final String P  = "p";
    060    private static final String A  = "a";
    061    private static final String PRE = "pre";
    062
    063    /**
    064     * Contains element, start markup, end markup
    065     */
    066    private static final String[] ELEMENTS = {
    067       "i" , "//"    , "//",
    068       "b" , "**"    , "**",
    069       "h2", "== "   , " ==",
    070       "h3", "=== "  , " ===",
    071       "h4", "==== " , " ====",
    072       "hr", "----"  , EMPTY_STRING,
    073       "tt", "<<{{>>", "<<}}>>"
    074    };
    075
    076    private int m_listCount;
    077    private char m_listChar = 'x';
    078
    079    private final List< PluginContent > m_plugins = new ArrayList<>();
    080
    081    /**
    082     *  Creates a new Creole Renderer.
    083     */
    084    public CreoleRenderer( final Context ctx, final WikiDocument doc )
    085    {
    086        super( ctx, doc );
    087    }
    088
    089    /**
    090     * Renders an element into the StringBuilder given
    091     * @param ce element to render
    092     * @param sb stringbuilder holding the element render
    093     */
    094    private void renderElement( final Element ce, final StringBuilder sb ) {
    095        String endEl = EMPTY_STRING;
    096        for( int i = 0; i < ELEMENTS.length; i+=3 ) {
    097            if( ELEMENTS[i].equals(ce.getName()) ) {
    098                sb.append( ELEMENTS[i+1] );
    099                endEl = ELEMENTS[i+2];
    100            }
    101        }
    102
    103        if( UL.equals(ce.getName()) ) {
    104            m_listCount++;
    105            m_listChar = '*';
    106        } else if( OL.equals(ce.getName()) ) {
    107            m_listCount++;
    108            m_listChar = '#';
    109        } else if( LI.equals(ce.getName()) ) {
    110            sb.append(IntStream.range(0, m_listCount).mapToObj(i -> String.valueOf(m_listChar)).collect(Collectors.joining("", "", ONE_SPACE)));
    111        } else if( A.equals( ce.getName() ) ) {
    112            final String href = ce.getAttributeValue( HREF_ATTRIBUTE );
    113            final String text = ce.getText();
    114
    115            if( href.equals( text ) ) {
    116                sb.append( HREF_START ).append( href ).append( HREF_END );
    117            } else {
    118                sb.append( HREF_START ).append( href ).append( HREF_DELIMITER ).append( text ).append( HREF_END);
    119            }
    120            // Do not render anything else
    121            return;
    122        } else if( PRE.equals( ce.getName() ) ) {
    123            sb.append( PRE_START );
    124            sb.append( ce.getText() );
    125            sb.append( PRE_END );
    126
    127            return;
    128        }
    129
    130        //  Go through the children
    131        for( final Content c : ce.getContent() ) {
    132            if( c instanceof PluginContent ) {
    133                final PluginContent pc = ( PluginContent )c;
    134
    135                if( pc.getPluginName().equals( PLUGIN_IMAGE ) ) {
    136                    sb.append( IMG_START ).append( pc.getParameter( PARAM_SRC ) ).append( IMG_END );
    137                } else {
    138                    m_plugins.add(pc);
    139                    sb.append( PLUGIN_START ).append( pc.getPluginName() ).append( ONE_SPACE ).append( m_plugins.size() ).append( PLUGIN_END );
    140                }
    141            } else if( c instanceof Text ) {
    142                sb.append( ( ( Text )c ).getText() );
    143            } else if( c instanceof Element ) {
    144                renderElement( ( Element )c, sb );
    145            }
    146        }
    147
    148        if( UL.equals( ce.getName() ) || OL.equals( ce.getName() ) ) {
    149            m_listCount--;
    150        } else if( P.equals( ce.getName() ) ) {
    151            sb.append( LINEBREAK );
    152        }
    153
    154        sb.append(endEl);
    155    }
    156
    157    /**
    158     *  {@inheritDoc}
    159     */
    160    @Override
    161    public String getString() {
    162        final StringBuilder sb = new StringBuilder(1000);
    163        final Element ce = m_document.getRootElement();
    164
    165        //  Traverse through the entire tree of everything.
    166        renderElement( ce, sb );
    167        return sb.toString();
    168    }
    169
    170}