001/*
002 * ============================================================================
003 *  Copyright © 2002-2023 by Thomas Thrien.
004 *  All Rights Reserved.
005 * ============================================================================
006 *  Licensed to the public under the agreements of the GNU Lesser General Public
007 *  License, version 3.0 (the "License"). You may obtain a copy of the License at
008 *
009 *       http://www.gnu.org/licenses/lgpl.html
010 *
011 *  Unless required by applicable law or agreed to in writing, software
012 *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
013 *  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
014 *  License for the specific language governing permissions and limitations
015 *  under the License.
016 */
017
018package org.tquadrat.foundation.xml.builder.internal;
019
020import static java.lang.String.format;
021import static org.apiguardian.api.API.Status.INTERNAL;
022import static org.tquadrat.foundation.lang.CommonConstants.CHAR_HYPHEN;
023import static org.tquadrat.foundation.lang.CommonConstants.EMPTY_STRING;
024import static org.tquadrat.foundation.lang.Objects.requireNonNullArgument;
025import static org.tquadrat.foundation.util.StringUtils.isEmpty;
026import static org.tquadrat.foundation.util.StringUtils.isEmptyOrBlank;
027import static org.tquadrat.foundation.util.StringUtils.splitString;
028import static org.tquadrat.foundation.xml.builder.spi.SGMLPrinter.repeat;
029
030import java.util.Optional;
031
032import org.apiguardian.api.API;
033import org.tquadrat.foundation.annotation.ClassVersion;
034import org.tquadrat.foundation.xml.builder.spi.Element;
035
036/**
037 *  This class defines a SGML comment.
038 *
039 *  @extauthor Thomas Thrien - thomas.thrien@tquadrat.org
040 *  @version $Id: Comment.java 1071 2023-09-30 01:49:32Z tquadrat $
041 *  @since 0.0.5
042 *
043 *  @UMLGraph.link
044 */
045@ClassVersion( sourceVersion = "$Id: Comment.java 1071 2023-09-30 01:49:32Z tquadrat $" )
046@API( status = INTERNAL, since = "0.0.5" )
047public class Comment implements Element
048{
049        /*------------*\
050    ====** Attributes **=======================================================
051        \*------------*/
052    /**
053     *  The parent element for this comment.
054     */
055    private Element m_Parent;
056
057    /**
058     *  The text.
059     */
060    private final String m_Text;
061
062        /*------------------------*\
063    ====** Static Initialisations **===========================================
064        \*------------------------*/
065    /**
066     *  The hyphen replacement (escaped).
067     */
068    private static final String HYPHEN_REPLACEMENT;
069
070    static
071    {
072        HYPHEN_REPLACEMENT = format( "&#x%x;", (int) CHAR_HYPHEN );
073    }
074        /*--------------*\
075    ====** Constructors **=====================================================
076        \*--------------*/
077    /**
078     *  Creates a new {@code Comment} object.
079     *
080     *  @param  text    The text.
081     */
082    public Comment( final CharSequence text )
083    {
084        m_Text = requireNonNullArgument( text, "text" ).toString().intern();
085    }   //  Comment()
086
087        /*---------*\
088    ====** Methods **==========================================================
089        \*---------*/
090    /**
091     *  {@inheritDoc}
092     */
093    @Override
094    public final String getElementName() { return "[COMMENT]"; }
095
096    /**
097     *  {@inheritDoc}
098     */
099    @Override
100    public final Optional<Element> getParent() { return Optional.ofNullable( m_Parent ); }
101
102    /**
103     *  {@inheritDoc}
104     */
105    @Override
106    public final boolean isBlock() { return true; }
107
108    /**
109     *  {@inheritDoc}
110     */
111    @Override
112    public final <E extends Element> void setParent( final E parent ) { m_Parent = requireNonNullArgument( parent, "parent" ); }
113
114    /**
115     *  {@inheritDoc}
116     */
117    @SuppressWarnings( "UnnecessaryUnicodeEscape" )
118    @Override
119    public final String toString( final int indentationLevel, final boolean prettyPrint )
120    {
121        final var filler1 = prettyPrint ? "\n" + repeat( indentationLevel ) : EMPTY_STRING;
122        final String retValue;
123        if( isEmptyOrBlank( m_Text ) )
124        {
125            retValue = format( "%s<!-- -->", filler1 );
126        }
127        else
128        {
129            final var filler2 = isEmpty( filler1 ) ? " " : filler1;
130            final var buffer = new StringBuilder( m_Text.length() * 2 );
131            char character;
132            for( var i = 0; i < m_Text.length(); ++i )
133            {
134                character = m_Text.charAt( i );
135                if( character == '\u002D' )
136                {
137                    /*
138                     * A hyphen or minus sign (\u002D) in the comment text may
139                     * cause an issue when the resulting document is parsed.
140                     * Therefore, we replace it by another character that looks
141                     * similar, but is not interpreted by XML parsers.
142                     */
143                    buffer.append( HYPHEN_REPLACEMENT );
144                }
145                else
146                {
147                    buffer.append( character );
148                }
149            }
150
151            final var lines = splitString( buffer, '\n' );
152            buffer.setLength( 0 );
153            buffer.append( filler1 ).append( "<!--" );
154            for( final var line : lines )
155            {
156                buffer.append( filler2 ).append( line.trim() );
157            }
158            buffer.append( filler2 ).append( "-->" );
159            retValue = buffer.toString();
160        }
161
162        //---* Done *----------------------------------------------------------
163        return retValue;
164    }   //  toString()
165
166    /**
167     *  {@inheritDoc}
168     */
169    @Override
170    public final String toString() { return toString( 0, true ); }
171}
172//  class Comment
173
174/*
175 *  End of File
176 */