001/*
002 * Shredzone Commons
003 *
004 * Copyright (C) 2012 Richard "Shred" Körber
005 *   http://commons.shredzone.org
006 *
007 * This program is free software: you can redistribute it and/or modify
008 * it under the terms of the GNU Library General Public License as
009 * published by the Free Software Foundation, either version 3 of the
010 * License, or (at your option) any later version.
011 *
012 * This program is distributed in the hope that it will be useful,
013 * but WITHOUT ANY WARRANTY; without even the implied warranty of
014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
015 * GNU General Public License for more details.
016 *
017 * You should have received a copy of the GNU Library General Public License
018 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
019 */
020package org.shredzone.commons.text.filter;
021
022import org.shredzone.commons.text.TextFilter;
023
024/**
025 * A filter that detects paragraphs and surrounds them with a HTML {@code &lt;p>}
026 * container. Paragraphs are separated by empty lines. Additionally, single EOLs can be
027 * replaced with {@code &lt;br />} tags.
028 * <p>
029 * This filter expects a normalized text (only LF is accepted as EOL marker, see
030 * {@link NormalizeFilter}).
031 *
032 * @author Richard "Shred" Körber
033 */
034public class ParagraphFilter implements TextFilter {
035
036    private boolean foldLines = true;
037
038    /**
039     * Also fold single EOL marker.
040     *
041     * @param foldLines
042     *            {@code true} to create {@code &lt;br />} tags for single EOL markers,
043     *            {@code false} to keep the EOL marker. Defaults to {@code true}.
044     */
045    public void setFoldLines(boolean foldLines) {
046        this.foldLines = foldLines;
047    }
048
049    @Override
050    public CharSequence apply(CharSequence text) {
051        StringBuilder sb = toStringBuilder(text);
052
053        sb.insert(0, "<p>").append("</p>");
054
055        int max = sb.length() - 3 - 4;
056        int ix = 3;
057
058        while (ix < max) {
059            if (sb.charAt(ix) == '\n') {
060                int lineEnd = ix + 1;
061                while (lineEnd < max && sb.charAt(lineEnd) == '\n') {
062                    lineEnd++;
063                }
064
065                if (lineEnd > ix + 1) {
066                    sb.replace(ix, lineEnd, "</p><p>");
067                    max += 7 - (lineEnd - ix);
068                    ix += 7;
069                } else if (foldLines) {
070                    sb.replace(ix, lineEnd, "<br />");
071                    max += 6 - (lineEnd - ix);
072                    ix += 6;
073                } else {
074                    ix++;
075                }
076            } else {
077                ix++;
078            }
079        }
080
081        return sb;
082    }
083
084}