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