/*
* Copyright (C) Chaperon. All rights reserved.
* -------------------------------------------------------------------------
* This software is published under the terms of the Apache Software License
* version 1.1, a copy of which has been included with this distribution in
* the LICENSE file.
*/
package net.sourceforge.chaperon.model.extended;
import net.sourceforge.chaperon.common.Decoder;
import net.sourceforge.chaperon.common.SortedCharSet;
import net.sourceforge.chaperon.model.Violations;
/**
* This class describes a pattern for a character class, which means the a character matches
* against a element of this class.
*
* @author <a href="mailto:stephan@apache.org">Stephan Michels</a>
* @version CVS $Id: CharacterClass.java,v 1.8 2004/01/07 08:28:49 benedikta Exp $
*/
public class CharacterClass extends Pattern
{
private SingleCharacter[] characters = new SingleCharacter[0];
private CharacterInterval[] intervals = new CharacterInterval[0];
private boolean exclusive = false;
/**
* Creates a pattern for a character class.
*/
public CharacterClass() {}
public void addSingleCharacter(SingleCharacter character)
{
if (character==null)
return;
SingleCharacter[] newCharacters = new SingleCharacter[characters.length+1];
System.arraycopy(characters, 0, newCharacters, 0, characters.length);
newCharacters[characters.length] = character;
characters = newCharacters;
}
public SingleCharacter getSingleCharacter(int index)
{
return characters[index];
}
public SingleCharacter[] getSingleCharacters()
{
return characters;
}
public int getSingleCharacterCount()
{
return characters.length;
}
public void addCharacterInterval(CharacterInterval interval)
{
if (interval==null)
return;
CharacterInterval[] newIntervals = new CharacterInterval[intervals.length+1];
System.arraycopy(intervals, 0, newIntervals, 0, intervals.length);
newIntervals[intervals.length] = interval;
intervals = newIntervals;
}
public CharacterInterval getCharacterInterval(int index)
{
return intervals[index];
}
public CharacterInterval[] getCharacterIntervals()
{
return intervals;
}
public int getCharacterIntervalCount()
{
return intervals.length;
}
/**
* If the comparing character must match to the elements, or should not match to the elements.
*
* @param exclusive If the character class should be exclusive.
*/
public void setExclusive(boolean exclusive)
{
this.exclusive = exclusive;
}
/**
* If this character class is exclusive
*
* @return If the character class should be exclusive.
*/
public boolean isExclusive()
{
return exclusive;
}
public boolean isNullable()
{
return false;
}
public PatternSet getFirstSet()
{
PatternSet set = new PatternSet();
set.addPattern(this);
return set;
}
public PatternSet getLastSet()
{
PatternSet set = new PatternSet();
set.addPattern(this);
return set;
}
public char[] getLimits()
{
SortedCharSet limits = new SortedCharSet();
for (int i = 0; i<characters.length; i++)
limits.addChar(characters[i].getLimits());
for (int i = 0; i<intervals.length; i++)
limits.addChar(intervals[i].getLimits());
return limits.getChar();
}
public boolean contains(char minimum, char maximum)
{
if (!exclusive)
{
for (int i = 0; i<characters.length; i++)
if (characters[i].contains(minimum, maximum))
return true;
for (int i = 0; i<intervals.length; i++)
if (intervals[i].contains(minimum, maximum))
return true;
return false;
}
for (int i = 0; i<characters.length; i++)
if (characters[i].contains(minimum, maximum))
return false;
for (int i = 0; i<intervals.length; i++)
if (intervals[i].contains(minimum, maximum))
return false;
return true;
}
public boolean contains(char c)
{
if (!exclusive)
{
for (int i = 0; i<characters.length; i++)
if (characters[i].contains(c))
return true;
for (int i = 0; i<intervals.length; i++)
if (intervals[i].contains(c))
return true;
return false;
}
for (int i = 0; i<characters.length; i++)
if (characters[i].contains(c))
return false;
for (int i = 0; i<intervals.length; i++)
if (intervals[i].contains(c))
return false;
return true;
}
public String getSymbol()
{
return null;
}
/**
* Create a clone of this pattern.
*
* @return Clone of this pattern.
*
* @throws CloneNotSupportedException If an exception occurs during the cloning.
*/
public String toString()
{
StringBuffer buffer = new StringBuffer();
buffer.append("[");
if (exclusive)
buffer.append("^");
for (int i = 0; i<characters.length; i++)
buffer.append(Decoder.decode(characters[i].getCharacter(), Decoder.CLASS));
for (int i = 0; i<intervals.length; i++)
{
buffer.append(Decoder.decode(intervals[i].getFirstCharacter().getCharacter(), Decoder.CLASS));
buffer.append("-");
buffer.append(Decoder.decode(intervals[i].getLastCharacter().getCharacter(), Decoder.CLASS));
}
buffer.append("]");
buffer.append("[");
buffer.append(index);
buffer.append("]");
return buffer.toString();
}
/**
* Create a clone of this pattern.
*
* @return Clone of this pattern.
*
* @throws CloneNotSupportedException If an exception occurs during the cloning.
*/
public Object clone()
{
CharacterClass clone = new CharacterClass();
for (int i = 0; i<characters.length; i++)
clone.addSingleCharacter(characters[i]);
for (int i = 0; i<intervals.length; i++)
clone.addCharacterInterval(intervals[i]);
clone.setExclusive(isExclusive());
return clone;
}
/**
* Validates this pattern.
*
* @return Return a list of violations, if this pattern isn't valid.
*/
public Violations validate()
{
Violations violations = new Violations();
if ((characters.length+intervals.length)==0)
violations.addViolation("Character class is empty", getLocation());
for (int i = 0; i<characters.length; i++)
violations.addViolations(characters[i].validate());
for (int i = 0; i<intervals.length; i++)
violations.addViolations(intervals[i].validate());
return violations;
}
}