001////////////////////////////////////////////////////////////////////////////////
002// checkstyle: Checks Java source code for adherence to a set of rules.
003// Copyright (C) 2001-2014  Oliver Burn
004//
005// This library is free software; you can redistribute it and/or
006// modify it under the terms of the GNU Lesser General Public
007// License as published by the Free Software Foundation; either
008// version 2.1 of the License, or (at your option) any later version.
009//
010// This library is distributed in the hope that it will be useful,
011// but WITHOUT ANY WARRANTY; without even the implied warranty of
012// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
013// Lesser General Public License for more details.
014//
015// You should have received a copy of the GNU Lesser General Public
016// License along with this library; if not, write to the Free Software
017// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
018////////////////////////////////////////////////////////////////////////////////
019package com.puppycrawl.tools.checkstyle.checks.indentation;
020
021import java.util.BitSet;
022
023/**
024 * Encapsulates representation of notion of expected indentation levels.
025 * Provide a way to have multiple accaptable levels.
026 *
027 * @author o_sukhodolsky
028 */
029public class IndentLevel
030{
031    /** set of acceptable indentation levels. */
032    private final BitSet levels = new BitSet();
033
034    /**
035     * Creates new instance with one accaptable indentation level.
036     * @param indent accaptable indentation level.
037     */
038    public IndentLevel(int indent)
039    {
040        levels.set(indent);
041    }
042
043    /**
044     * Creates new instance for nested structure.
045     * @param base parent's level
046     * @param offsets offsets from parent's level.
047     */
048    public IndentLevel(IndentLevel base, int... offsets)
049    {
050        final BitSet src = base.levels;
051        for (int i = src.nextSetBit(0); i >= 0; i = src.nextSetBit(i + 1)) {
052            for (int offset : offsets) {
053                levels.set(i + offset);
054            }
055        }
056    }
057
058    /**
059     * Checks wether we have more than one level.
060     * @return wether we have more than one level.
061     */
062    public final boolean isMultiLevel()
063    {
064        return levels.cardinality() > 1;
065    }
066
067    /**
068     * Checks if given indentation is acceptable.
069     * @param indent indentation to check.
070     * @return true if given indentation is acceptable,
071     *         false otherwise.
072     */
073    public boolean accept(int indent)
074    {
075        return levels.get(indent);
076    }
077
078    /**
079     * @param indent indentation to check.
080     * @return true if <code>indent</code> less then minimal of
081     *         acceptable indentation levels, false otherwise.
082     */
083    public boolean gt(int indent)
084    {
085        return levels.nextSetBit(0) > indent;
086    }
087
088    /**
089     * Adds one more acceptable indentation level.
090     * @param indent new acceptable indentation.
091     */
092    public void addAcceptedIndent(int indent)
093    {
094        levels.set(indent);
095    }
096
097    /**
098     * Adds one more acceptable indentation level.
099     * @param indent new acceptable indentation.
100     */
101    public void addAcceptedIndent(IndentLevel indent)
102    {
103        levels.or(indent.levels);
104    }
105
106    /**
107     * Returns first indentation level.
108     * @return indentation level.
109     */
110    public int getFirstIndentLevel()
111    {
112        return levels.nextSetBit(0);
113    }
114
115    /**
116     * Returns last indentation level.
117     * @return indentation level.
118     */
119    public int getLastIndentLevel()
120    {
121        return levels.length() - 1;
122    }
123
124    @Override
125    public String toString()
126    {
127        if (levels.cardinality() == 1) {
128            return String.valueOf(levels.nextSetBit(0));
129        }
130        final StringBuilder sb = new StringBuilder();
131        for (int i = levels.nextSetBit(0); i >= 0;
132            i = levels.nextSetBit(i + 1))
133        {
134            if (sb.length() > 0) {
135                sb.append(", ");
136            }
137            sb.append(i);
138        }
139        return sb.toString();
140    }
141}