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 java.io.IOException;
022import java.util.ArrayList;
023import java.util.Iterator;
024import java.util.List;
025
026import org.apache.wiki.WikiContext;
027import org.apache.wiki.parser.PluginContent;
028import org.apache.wiki.parser.WikiDocument;
029import org.jdom2.Content;
030import org.jdom2.Element;
031import org.jdom2.Text;
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 = 0;
077    private char m_listChar = 'x';
078
079    private List<PluginContent> m_plugins = new ArrayList<PluginContent>();
080
081    /**
082     *  Creates a new Creole Renderer.
083     *
084     */
085    public CreoleRenderer( WikiContext ctx, WikiDocument doc )
086    {
087        super( ctx, doc );
088    }
089
090    /**
091     * Renders an element into the StringBuilder given
092     * @param ce
093     * @param sb
094     */
095    private void renderElement( Element ce, StringBuilder sb )
096    {
097        String endEl = EMPTY_STRING;
098        for( int i = 0; i < ELEMENTS.length; i+=3 )
099        {
100            if( ELEMENTS[i].equals(ce.getName()) )
101            {
102                sb.append( ELEMENTS[i+1] );
103                endEl = ELEMENTS[i+2];
104            }
105        }
106
107        if( UL.equals(ce.getName()) )
108        {
109            m_listCount++;
110            m_listChar = '*';
111        }
112        else if( OL.equals(ce.getName()) )
113        {
114            m_listCount++;
115            m_listChar = '#';
116        }
117        else if( LI.equals(ce.getName()) )
118        {
119            for(int i = 0; i < m_listCount; i++ ) sb.append( m_listChar );
120            sb.append( ONE_SPACE );
121        }
122        else if( A.equals(ce.getName()) )
123        {
124            String href = ce.getAttributeValue( HREF_ATTRIBUTE );
125            String text = ce.getText();
126
127            if( href.equals(text) )
128            {
129                sb.append( HREF_START + href + HREF_END );
130            }
131            else
132            {
133                sb.append( HREF_START + href+ HREF_DELIMITER + text +HREF_END);
134            }
135            // Do not render anything else
136            return;
137        }
138        else if( PRE.equals(ce.getName()) )
139        {
140            sb.append( PRE_START );
141            sb.append( ce.getText() );
142            sb.append( PRE_END );
143
144            return;
145        }
146
147        //
148        //  Go through the children
149        //
150        for( Iterator< Content > i = ce.getContent().iterator(); i.hasNext(); )
151        {
152            Content c = i.next();
153
154            if( c instanceof PluginContent )
155            {
156                PluginContent pc = (PluginContent)c;
157
158                if( pc.getPluginName().equals( PLUGIN_IMAGE ) )
159                {
160                    sb.append( IMG_START + pc.getParameter( PARAM_SRC ) + IMG_END );
161                }
162                else
163                {
164                    m_plugins.add(pc);
165                    sb.append( PLUGIN_START + pc.getPluginName() + ONE_SPACE + m_plugins.size() + PLUGIN_END );
166                }
167            }
168            else if( c instanceof Text )
169            {
170                sb.append( ((Text)c).getText() );
171            }
172            else if( c instanceof Element )
173            {
174                renderElement( (Element)c, sb );
175            }
176        }
177
178        if( UL.equals( ce.getName() ) || OL.equals( ce.getName() ) )
179        {
180            m_listCount--;
181        }
182        else if( P.equals( ce.getName() ) )
183        {
184            sb.append( LINEBREAK );
185        }
186
187        sb.append(endEl);
188    }
189
190    /**
191     *  {@inheritDoc}
192     */
193    public String getString() throws IOException
194    {
195        StringBuilder sb = new StringBuilder(1000);
196
197        Element ce = m_document.getRootElement();
198
199        //
200        //  Traverse through the entire tree of everything.
201        //
202
203        renderElement( ce, sb );
204
205        return sb.toString();
206    }
207
208}