/**
* AnalyzerBeans
* Copyright (C) 2014 Neopost - Customer Information Management
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.eobjects.analyzer.beans.stringpattern;
import java.util.Arrays;
import org.apache.metamodel.util.EqualsBuilder;
public class TokenPatternSymbolImpl implements TokenPatternSymbol {
private static final long serialVersionUID = 1L;
private final TokenType _tokenType;
private int _length;
private boolean _upperCaseOnly = false;
private boolean _lowerCaseOnly = false;
private boolean _negative = false;
private boolean _decimal = false;
private char _decimalSeparator;
private char _minusSign;
private String _symbolicString;
public TokenPatternSymbolImpl(Token prototypeToken, TokenizerConfiguration configuration) {
_tokenType = prototypeToken.getType();
_length = prototypeToken.length();
switch (_tokenType) {
case TEXT:
if (configuration.isDiscriminateTextCase()) {
_upperCaseOnly = Character.isUpperCase(prototypeToken.charAt(0));
_lowerCaseOnly = !_upperCaseOnly;
}
break;
case NUMBER:
if (configuration.isDiscriminateDecimalNumbers()) {
Character decimalSeparator = configuration.getDecimalSeparator();
if (decimalSeparator != null) {
_decimalSeparator = decimalSeparator.charValue();
_decimal = prototypeToken.getString().indexOf(_decimalSeparator) != -1;
}
}
if (configuration.isDiscriminateNegativeNumbers()) {
Character minusSign = configuration.getMinusSign();
if (minusSign != null) {
_minusSign = minusSign.charValue();
_negative = (_minusSign == prototypeToken.charAt(0));
}
}
break;
case DELIM:
_symbolicString = prototypeToken.getString();
break;
case WHITESPACE:
if (configuration.isDiscriminateWhiteSpaces()) {
_symbolicString = prototypeToken.getString();
}
break;
case PREDEFINED:
if (prototypeToken instanceof PredefinedToken) {
PredefinedToken pt = (PredefinedToken) prototypeToken;
_symbolicString = '[' + pt.getPredefinedTokenDefintion().getName() + ']';
} else {
_symbolicString = prototypeToken.getString();
}
break;
case MIXED:
break;
default:
throw new UnsupportedOperationException("Unsupported token type: " + _tokenType);
}
}
@Override
public String toSymbolicString() {
if (_symbolicString != null) {
return _symbolicString;
}
char c = getSymbolicChar();
char[] result = new char[_length];
Arrays.fill(result, c);
if (isNegative()) {
result[0] = _minusSign;
}
if (isDecimal()) {
result[_length - 2] = _decimalSeparator;
}
return String.valueOf(result);
}
private char getSymbolicChar() {
switch (_tokenType) {
case TEXT:
if (isUpperCaseOnly()) {
return 'A';
}
return 'a';
case NUMBER:
return '#';
case WHITESPACE:
return ' ';
case MIXED:
return '?';
default:
throw new UnsupportedOperationException("No symbolic char for token type: " + _tokenType);
}
}
@Override
public TokenType getTokenType() {
return _tokenType;
}
@Override
public boolean isUpperCaseOnly() {
return _upperCaseOnly;
}
@Override
public boolean isLowerCaseOnly() {
return _lowerCaseOnly;
}
@Override
public boolean isDecimal() {
return _decimal;
}
@Override
public boolean isNegative() {
return _negative;
}
@Override
public boolean matches(Token token, TokenizerConfiguration configuration) {
if (EqualsBuilder.equals(_tokenType, token.getType())) {
if (configuration.isDistriminateTokenLength(_tokenType)) {
if (toSymbolicString().length() != token.getString().length()) {
// not a match, based on length
return false;
}
}
switch (_tokenType) {
case TEXT:
return matchesText(token, configuration);
case NUMBER:
return matchesNumber(token, configuration);
case DELIM:
return matchesDelim(token, configuration);
case WHITESPACE:
return matchesWhitespace(token, configuration);
case MIXED:
return matchesMixed(token, configuration);
case PREDEFINED:
return matchesPredefined(token);
default:
throw new UnsupportedOperationException("Unsupported token type for matching: " + _tokenType);
}
}
return false;
}
private boolean matchesPredefined(Token token) {
if (token instanceof PredefinedToken) {
PredefinedToken pt = (PredefinedToken) token;
String name = pt.getPredefinedTokenDefintion().getName();
return _symbolicString.equals('[' + name + ']');
} else {
return _symbolicString.equals(token.getString());
}
}
private boolean matchesText(Token token, TokenizerConfiguration configuration) {
boolean discriminateTextCase = configuration.isDiscriminateTextCase();
if (discriminateTextCase) {
// if 'discriminateTextCase' is true then we can assume that all the
// characters are either upper or lower case. Thus it is only
// nescesary to check a single character from each string
String str2 = token.getString();
char char2 = str2.charAt(0);
boolean upperCase = Character.isUpperCase(char2);
boolean caseMatches = isUpperCaseOnly() == upperCase;
if (!caseMatches) {
return false;
}
if (upperCase && !configuration.isUpperCaseExpandable()) {
// the token is not expandable, we need to verify same length
return str2.length() == _length;
}
if (!upperCase && !configuration.isLowerCaseExpandable()) {
// the token is not expandable, we need to verify same length
return str2.length() == _length;
}
return true;
}
return true;
}
private boolean matchesNumber(Token token, TokenizerConfiguration configuration) {
boolean discriminateNegativeNumbers = configuration.isDiscriminateNegativeNumbers();
boolean discriminateDecimalNumbers = configuration.isDiscriminateDecimalNumbers();
if (!discriminateDecimalNumbers && !discriminateNegativeNumbers) {
return true;
}
String str2 = token.getString();
Character minusSign = configuration.getMinusSign();
if (discriminateNegativeNumbers && minusSign != null) {
boolean negative1 = isNegative();
boolean negative2 = EqualsBuilder.equals(minusSign, str2.charAt(0));
if (negative1 != negative2) {
return false;
}
}
Character decimalSeparator = configuration.getDecimalSeparator();
if (discriminateDecimalNumbers && decimalSeparator != null) {
boolean decimal1 = isDecimal();
boolean decimal2 = str2.indexOf(decimalSeparator.charValue()) != -1;
if (decimal1 != decimal2) {
return false;
}
}
return true;
}
private boolean matchesDelim(Token token, TokenizerConfiguration configuration) {
return toSymbolicString().equals(token.getString());
}
private boolean matchesWhitespace(Token token, TokenizerConfiguration configuration) {
if (configuration.isDiscriminateWhiteSpaces()) {
return toSymbolicString().equals(token.getString());
}
return true;
}
private boolean matchesMixed(Token token, TokenizerConfiguration configuration) {
return true;
}
@Override
public int length() {
return _length;
}
@Override
public boolean isExpandable() {
return _symbolicString == null;
}
@Override
public void expandLenght(int amount) {
_length += amount;
}
}