001/*
002 *   Copyright (C) 2005 Christian Schulte <cs@schulte.it>
003 *   All rights reserved.
004 *
005 *   Redistribution and use in source and binary forms, with or without
006 *   modification, are permitted provided that the following conditions
007 *   are met:
008 *
009 *     o Redistributions of source code must retain the above copyright
010 *       notice, this list of conditions and the following disclaimer.
011 *
012 *     o Redistributions in binary form must reproduce the above copyright
013 *       notice, this list of conditions and the following disclaimer in
014 *       the documentation and/or other materials provided with the
015 *       distribution.
016 *
017 *   THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
018 *   INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
019 *   AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
020 *   THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY DIRECT, INDIRECT,
021 *   INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
022 *   NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
023 *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
024 *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
025 *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
026 *   THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
027 *
028 *   $JOMC: Section.java 5091 2016-04-04 15:40:17Z schulte $
029 *
030 */
031package org.jomc.util;
032
033import java.util.ArrayList;
034import java.util.List;
035
036/**
037 * Section of text.
038 *
039 * @author <a href="mailto:cs@schulte.it">Christian Schulte</a>
040 * @version $JOMC: Section.java 5091 2016-04-04 15:40:17Z schulte $
041 */
042public class Section
043{
044
045    /**
046     * Constant for the mode during parsing the head content of a section.
047     */
048    static final int MODE_HEAD = 1;
049
050    /**
051     * Constant for the mode during parsing the tail content of a section.
052     */
053    static final int MODE_TAIL = 2;
054
055    /**
056     * The current parsing mode.
057     */
058    private int mode = MODE_HEAD;
059
060    /**
061     * The name of this section.
062     */
063    private String name;
064
065    /**
066     * The parsed head content of this section.
067     */
068    private StringBuilder headContent;
069
070    /**
071     * The parsed tail content of this section.
072     */
073    private StringBuilder tailContent;
074
075    /**
076     * Line marking the start of this section.
077     */
078    private String startingLine;
079
080    /**
081     * Line marking the end of this section.
082     */
083    private String endingLine;
084
085    /**
086     * The child sections of this section.
087     */
088    private List<Section> sections;
089
090    /**
091     * Creates a new {@code Section} instance.
092     */
093    public Section()
094    {
095        super();
096    }
097
098    /**
099     * Gets the name of this section.
100     *
101     * @return The name of this section or {@code null}.
102     */
103    public String getName()
104    {
105        return this.name;
106    }
107
108    /**
109     * Sets the name of this section.
110     *
111     * @param value The new name of this section or {@code null}.
112     */
113    public void setName( final String value )
114    {
115        this.name = value;
116    }
117
118    /**
119     * Gets the line marking the start of this section.
120     *
121     * @return The line marking the start of this section.
122     */
123    public String getStartingLine()
124    {
125        return this.startingLine;
126    }
127
128    /**
129     * Sets the line marking the start of this section.
130     *
131     * @param value The new line marking the start of this section.
132     */
133    public void setStartingLine( final String value )
134    {
135        this.startingLine = value;
136    }
137
138    /**
139     * Gets the line marking the end of this section.
140     *
141     * @return The line marking the end of this section.
142     */
143    public String getEndingLine()
144    {
145        return this.endingLine;
146    }
147
148    /**
149     * Sets the line marking the end of this section.
150     *
151     * @param value The new line marking the end of this section.
152     */
153    public void setEndingLine( final String value )
154    {
155        this.endingLine = value;
156    }
157
158    /**
159     * Gets the content of this section preceding any child section content.
160     *
161     * @return The content of this section preceding any child section content.
162     */
163    public StringBuilder getHeadContent()
164    {
165        if ( this.headContent == null )
166        {
167            this.headContent = new StringBuilder( 512 );
168        }
169
170        return this.headContent;
171    }
172
173    /**
174     * Gets the content of this section succeeding any child section content.
175     *
176     * @return The content of this section succeeding any child section content.
177     */
178    public StringBuilder getTailContent()
179    {
180        if ( this.tailContent == null )
181        {
182            this.tailContent = new StringBuilder( 512 );
183        }
184
185        return this.tailContent;
186    }
187
188    /**
189     * Gets the child sections of this section.
190     * <p>
191     * This accessor method returns a reference to the live list, not a snapshot. Therefore any modification you make
192     * to the returned list will be present inside the object. This is why there is no {@code set} method for the
193     * sections property.
194     * </p>
195     *
196     * @return A list of child sections of this section.
197     */
198    public List<Section> getSections()
199    {
200        if ( this.sections == null )
201        {
202            this.sections = new ArrayList<Section>();
203        }
204
205        return this.sections;
206    }
207
208    /**
209     * Gets a child section matching a given name.
210     *
211     * @param sectionName The name of the section to return.
212     *
213     * @return The first child section matching {@code sectionName} or {@code null}, if no such section is found.
214     *
215     * @throws NullPointerException if {@code sectionName} is {@code null}.
216     */
217    public Section getSection( final String sectionName )
218    {
219        if ( sectionName == null )
220        {
221            throw new NullPointerException( "sectionName" );
222        }
223
224        return this.getSection( this, sectionName );
225    }
226
227    private Section getSection( final Section current, final String sectionName )
228    {
229        if ( sectionName.equals( current.getName() ) )
230        {
231            return current;
232        }
233
234        for ( final Section child : current.getSections() )
235        {
236            if ( sectionName.equals( child.getName() ) )
237            {
238                return child;
239            }
240
241            if ( child.getName() == null )
242            {
243                final Section section = child.getSection( sectionName );
244
245                if ( section != null )
246                {
247                    return section;
248                }
249            }
250        }
251
252        return null;
253    }
254
255    /**
256     * Gets the parsing mode of the instance.
257     *
258     * @return The parsing mode of the instance.
259     *
260     * @see #MODE_HEAD
261     * @see #MODE_TAIL
262     */
263    int getMode()
264    {
265        return this.mode;
266    }
267
268    /**
269     * Sets the parsing mode of the instance.
270     *
271     * @param value The new parsing mode of the instance.
272     *
273     * @see #MODE_HEAD
274     * @see #MODE_TAIL
275     */
276    void setMode( final int value )
277    {
278        this.mode = value;
279    }
280
281}