001////////////////////////////////////////////////////////////////////////////////
002// checkstyle: Checks Java source code for adherence to a set of rules.
003// Copyright (C) 2001-2015 the original author or authors.
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////////////////////////////////////////////////////////////////////////////////
019
020package com.puppycrawl.tools.checkstyle.checks.indentation;
021
022import java.util.BitSet;
023
024/**
025 * Encapsulates representation of notion of expected indentation levels.
026 * Provide a way to have multiple acceptable levels.
027 *
028 * @author o_sukhodolsky
029 */
030public class IndentLevel {
031    /** Set of acceptable indentation levels. */
032    private final BitSet levels = new BitSet();
033
034    /**
035     * Creates new instance with one acceptable indentation level.
036     * @param indent acceptable indentation level.
037     */
038    public IndentLevel(int indent) {
039        levels.set(indent);
040    }
041
042    /**
043     * Creates new instance for nested structure.
044     * @param base parent's level
045     * @param offsets offsets from parent's level.
046     */
047    public IndentLevel(IndentLevel base, int... offsets) {
048        final BitSet src = base.levels;
049        for (int i = src.nextSetBit(0); i >= 0; i = src.nextSetBit(i + 1)) {
050            for (int offset : offsets) {
051                levels.set(i + offset);
052            }
053        }
054    }
055
056    /**
057     * Checks whether we have more than one level.
058     * @return whether we have more than one level.
059     */
060    public final boolean isMultiLevel() {
061        return levels.cardinality() > 1;
062    }
063
064    /**
065     * Checks if given indentation is acceptable.
066     * @param indent indentation to check.
067     * @return true if given indentation is acceptable,
068     *         false otherwise.
069     */
070    public boolean isAcceptable(int indent) {
071        return levels.get(indent);
072    }
073
074    /**
075     * @param indent indentation to check.
076     * @return true if {@code indent} less then minimal of
077     *         acceptable indentation levels, false otherwise.
078     */
079    public boolean isGreaterThan(int indent) {
080        return levels.nextSetBit(0) > indent;
081    }
082
083    /**
084     * Adds one more acceptable indentation level.
085     * @param indent new acceptable indentation.
086     */
087    public void addAcceptedIndent(int indent) {
088        levels.set(indent);
089    }
090
091    /**
092     * Adds one more acceptable indentation level.
093     * @param indent new acceptable indentation.
094     */
095    public void addAcceptedIndent(IndentLevel indent) {
096        levels.or(indent.levels);
097    }
098
099    /**
100     * Returns first indentation level.
101     * @return indentation level.
102     */
103    public int getFirstIndentLevel() {
104        return levels.nextSetBit(0);
105    }
106
107    /**
108     * Returns last indentation level.
109     * @return indentation level.
110     */
111    public int getLastIndentLevel() {
112        return levels.length() - 1;
113    }
114
115    @Override
116    public String toString() {
117        if (levels.cardinality() == 1) {
118            return String.valueOf(levels.nextSetBit(0));
119        }
120        final StringBuilder sb = new StringBuilder();
121        for (int i = levels.nextSetBit(0); i >= 0;
122            i = levels.nextSetBit(i + 1)) {
123            if (sb.length() > 0) {
124                sb.append(", ");
125            }
126            sb.append(i);
127        }
128        return sb.toString();
129    }
130}