/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/* $Id$ */

package org.apache.fop.render.rtf.rtflib.rtfdoc;

/*
 * This file is part of the RTF library of the FOP project, which was originally
 * created by Bertrand Delacretaz bdelacretaz@codeconsult.ch and by other
 * contributors to the jfor project (www.jfor.org), who agreed to donate jfor to
 * the FOP project.
 */

import java.util.StringTokenizer;

/**
 * <p>Collapses whitespace of an RtfContainer that contains RtfText elements.</p>
 *
 * <p>This work was authored by Bertrand Delacretaz (bdelacretaz@codeconsult.ch).</p>
 */

final class WhitespaceCollapser {

    private static final String SPACE = " ";
    private boolean lastEndSpace = true;

    /**
     * Remove extra whitespace in RtfText elements that are inside container.
     * @param c the container
     */
    WhitespaceCollapser(RtfContainer c) {
        // process all texts
        for (final Object kid : c.getChildren()) {
            if (kid instanceof RtfText) {
                RtfText current = (RtfText) kid;
                processText(current);
            } else if (kid instanceof RtfString) {
                RtfString current = (RtfString) kid;
                processString(current);
            } else {
                // if there is something between two texts, it counts for a space
                lastEndSpace = true;
            }
        }
    }

    /** @return last end space */
    public boolean getLastEndSpace() {
        return lastEndSpace;
    }

    /** process one RtfText from our container */
    private void processText(RtfText txt) {
        final String newString = processString(txt.getText());
        if (newString != null) {
            txt.setText(newString);
        }
    }

    /** process one RtfString from our container */
    private void processString(RtfString txt) {
        final String newString = processString(txt.getText());
        if (newString != null) {
            txt.setText(newString);
        }
    }

    /** process one String */
    private String processString(String txt) {
        final String orig = txt;

        // tokenize the text based on whitespace and regenerate it so as
        // to collapse multiple spaces into one
        if (orig == null) {
            return null;
        } else if (orig.length() > 0) {
            final boolean allSpaces = orig.trim().length() == 0;
            final boolean endSpace = allSpaces
                                     || Character.isWhitespace(orig.charAt(orig.length() - 1));
            final boolean beginSpace = Character.isWhitespace(orig.charAt(0));
            final StringBuffer sb = new StringBuffer(orig.length());

            // if text contains spaces only, keep at most one
            if (allSpaces) {
                if (!lastEndSpace) {
                    sb.append(SPACE);
                }
            } else {
                // TODO to be compatible with different Locales, should use Character.isWhitespace
                // instead of this limited list
                boolean first = true;
                final StringTokenizer stk = new StringTokenizer(txt, " \t\n\r");
                while (stk.hasMoreTokens()) {
                    if (first && beginSpace && !lastEndSpace) {
                        sb.append(SPACE);
                    }
                    first = false;

                    sb.append(stk.nextToken());
                    if (stk.hasMoreTokens() || endSpace) {
                        sb.append(SPACE);
                    }
                }
            }

            lastEndSpace = endSpace;
            return sb.toString();
        } else {
            return "";
        }
    }
}
