001    /*
002     *   Copyright (c) 2009 The JOMC Project
003     *   Copyright (c) 2005 Christian Schulte <cs@jomc.org>
004     *   All rights reserved.
005     *
006     *   Redistribution and use in source and binary forms, with or without
007     *   modification, are permitted provided that the following conditions
008     *   are met:
009     *
010     *     o Redistributions of source code must retain the above copyright
011     *       notice, this list of conditions and the following disclaimer.
012     *
013     *     o Redistributions in binary form must reproduce the above copyright
014     *       notice, this list of conditions and the following disclaimer in
015     *       the documentation and/or other materials provided with the
016     *       distribution.
017     *
018     *   THIS SOFTWARE IS PROVIDED BY THE JOMC PROJECT AND CONTRIBUTORS "AS IS"
019     *   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
020     *   THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
021     *   PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE JOMC PROJECT OR
022     *   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
023     *   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
024     *   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
025     *   OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
026     *   WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
027     *   OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
028     *   ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
029     *
030     *   $Id: Section.java 509 2009-09-21 13:54:49Z schulte2005 $
031     *
032     */
033    package org.jomc.util;
034    
035    import java.util.HashMap;
036    import java.util.LinkedList;
037    import java.util.List;
038    import java.util.Map;
039    
040    /**
041     * Section of text.
042     *
043     * @author <a href="mailto:cs@jomc.org">Christian Schulte</a>
044     * @version $Id: Section.java 509 2009-09-21 13:54:49Z schulte2005 $
045     */
046    public class Section
047    {
048    
049        /** The name of this section. */
050        private String name;
051    
052        /** The level of this section. */
053        private int level;
054    
055        /** The parsed head content of this section. */
056        private Map<Integer, StringBuilder> headContent;
057    
058        /** The parsed tail content of this section. */
059        private Map<Integer, StringBuilder> tailContent;
060    
061        /** Line marking the start of this section. */
062        private Map<Integer, String> startingLine;
063    
064        /** Line marking the end of this section. */
065        private Map<Integer, String> endingLine;
066    
067        /** The child sections of this section. */
068        private Map<Integer, List<Section>> children;
069    
070        /** Creates a new {@code Section} instance. */
071        public Section()
072        {
073            super();
074        }
075    
076        /**
077         * Gets the name of this section.
078         *
079         * @return The name of this section.
080         */
081        public String getName()
082        {
083            return this.name;
084        }
085    
086        /**
087         * Sets the name of this section.
088         *
089         * @param value The name of this section.
090         */
091        public void setName( final String value )
092        {
093            this.name = value;
094        }
095    
096        /**
097         * Gets the line marking the start of this section.
098         *
099         * @return The line marking the start of this section.
100         */
101        public String getStartingLine()
102        {
103            if ( this.startingLine == null )
104            {
105                this.startingLine = new HashMap<Integer, String>();
106            }
107    
108            return this.startingLine.get( this.level );
109        }
110    
111        /**
112         * Sets the line marking the start of this section.
113         *
114         * @param value The line marking the start of this section.
115         */
116        public void setStartingLine( final String value )
117        {
118            if ( this.startingLine == null )
119            {
120                this.startingLine = new HashMap<Integer, String>();
121            }
122    
123            this.startingLine.put( this.level, value );
124        }
125    
126        /**
127         * Gets the line marking the end of this section.
128         *
129         * @return The line marking the end of this section.
130         */
131        public String getEndingLine()
132        {
133            if ( this.endingLine == null )
134            {
135                this.endingLine = new HashMap<Integer, String>();
136            }
137    
138            return this.endingLine.get( this.level );
139        }
140    
141        /**
142         * Sets the line marking the end of this section.
143         *
144         * @param value The line marking the end of this section.
145         */
146        public void setEndingLine( final String value )
147        {
148            if ( this.endingLine == null )
149            {
150                this.endingLine = new HashMap<Integer, String>();
151            }
152    
153            this.endingLine.put( this.level, value );
154        }
155    
156        /**
157         * Gets the parsed head content of this section.
158         *
159         * @return The parsed head content of this section.
160         */
161        public StringBuilder getHeadContent()
162        {
163            if ( this.headContent == null )
164            {
165                this.headContent = new HashMap<Integer, StringBuilder>();
166            }
167    
168            StringBuilder b = this.headContent.get( this.level );
169            if ( b == null )
170            {
171                b = new StringBuilder();
172                this.headContent.put( this.level, b );
173            }
174    
175            return b;
176        }
177    
178        /**
179         * Gets the parsed tail content of this section.
180         *
181         * @return The parsed tail content of this section.
182         */
183        public StringBuilder getTailContent()
184        {
185            if ( this.tailContent == null )
186            {
187                this.tailContent = new HashMap<Integer, StringBuilder>();
188            }
189    
190            StringBuilder b = this.tailContent.get( this.level );
191            if ( b == null )
192            {
193                b = new StringBuilder();
194                this.tailContent.put( this.level, b );
195            }
196    
197            return b;
198        }
199    
200        /**
201         * Gets all sections recursively.
202         *
203         * @return A list of all sections collected recursively.
204         */
205        public List<Section> getSections()
206        {
207            return collectSections( this, new LinkedList<Section>() );
208        }
209    
210        /** Constant for the mode when parsing the head of a section. */
211        static final int MODE_HEAD = 1;
212    
213        /** Constant for the mode when parsing the tail of a section. */
214        static final int MODE_TAIL = 2;
215    
216        /** The current parsing mode. */
217        private int mode = MODE_HEAD;
218    
219        /**
220         * Gets the level of the section.
221         *
222         * @return The level of the section.
223         */
224        int getLevel()
225        {
226            return this.level;
227        }
228    
229        /**
230         * Sets the level of the section.
231         *
232         * @param value The new level of the section.
233         */
234        void setLevel( final int value )
235        {
236            this.level = value;
237        }
238    
239        /**
240         * Gets the mode of the section.
241         *
242         * @return The mode of the section.
243         */
244        int getMode()
245        {
246            return this.mode;
247        }
248    
249        /**
250         * Sets the mode of the section.
251         *
252         * @param value The new mode of the section.
253         */
254        void setMode( final int value )
255        {
256            this.mode = value;
257        }
258    
259        /**
260         * Adds content to the section.
261         *
262         * @param content The content to add.
263         *
264         * @see #getMode()
265         * @see #getLevel()
266         */
267        void addContent( final String content )
268        {
269            if ( this.mode == MODE_HEAD )
270            {
271                this.getHeadContent().append( content );
272            }
273            else if ( this.mode == MODE_TAIL )
274            {
275                this.getTailContent().append( content );
276            }
277        }
278    
279        /**
280         * Gets the child sections of this section.
281         *
282         * @return The child sections of this section.
283         */
284        List<Section> getChildren()
285        {
286            if ( this.children == null )
287            {
288                this.children = new HashMap<Integer, List<Section>>();
289            }
290    
291            List<Section> c = this.children.get( this.level );
292            if ( c == null )
293            {
294                c = new LinkedList<Section>();
295                this.children.put( this.level, c );
296            }
297    
298            return c;
299        }
300    
301        /**
302         * Collects sections recursively.
303         *
304         * @param section A section to collect child sections of.
305         * @param sections A list to add any child sections to.
306         *
307         * @return {@code sections} with any child sections of {@code section} added.
308         */
309        private static List<Section> collectSections( final Section section, final List<Section> sections )
310        {
311            sections.add( section );
312            final int l = section.getLevel();
313            for ( int i = 0; i <= l; i++ )
314            {
315                section.setLevel( i );
316                for ( Section child : section.getChildren() )
317                {
318                    collectSections( child, sections );
319                }
320            }
321            section.setLevel( l );
322            return sections;
323        }
324    
325    }