package de.unisiegen.gtitool.core.entities;
import java.util.ArrayList;
import java.util.Iterator;
import javax.swing.event.EventListenerList;
import de.unisiegen.gtitool.core.entities.listener.ModifyStatusChangedListener;
import de.unisiegen.gtitool.core.entities.listener.PrettyStringChangedListener;
import de.unisiegen.gtitool.core.i18n.Messages;
import de.unisiegen.gtitool.core.parser.ParserOffset;
import de.unisiegen.gtitool.core.parser.style.PrettyPrintable;
import de.unisiegen.gtitool.core.parser.style.PrettyString;
import de.unisiegen.gtitool.core.parser.style.PrettyToken;
import de.unisiegen.gtitool.core.parser.style.Style;
import de.unisiegen.gtitool.core.parser.style.PrettyString.PrettyStringMode;
import de.unisiegen.gtitool.core.storage.Element;
import de.unisiegen.gtitool.core.storage.Modifyable;
import de.unisiegen.gtitool.core.storage.Storable;
import de.unisiegen.gtitool.core.storage.exceptions.StoreException;
/**
* The {@link DefaultProductionWord} entity.
*
* @author Christian Fehler
* @version $Id$
*/
public final class DefaultProductionWord implements ProductionWord
{
/**
* The serial version uid.
*/
private static final long serialVersionUID = -7575345248390546325L;
/**
* The {@link EventListenerList}.
*/
private EventListenerList listenerList = new EventListenerList ();
/**
* The offset of this {@link DefaultAlphabet} in the source code.
*
* @see #getParserOffset()
* @see #setParserOffset(ParserOffset)
*/
private ParserOffset parserOffset = NO_PARSER_OFFSET;
/**
* The {@link ProductionWordMember} list.
*/
private ArrayList < ProductionWordMember > productionWordMemberList;
/**
* The initial {@link ProductionWordMember} list.
*/
private ArrayList < ProductionWordMember > initialProductionWordMemberList;
/**
* The cached {@link PrettyString}.
*/
private PrettyString cachedPrettyString = null;
/**
* The {@link PrettyStringChangedListener}.
*/
private PrettyStringChangedListener prettyStringChangedListener;
/**
* Allocates a new {@link DefaultProductionWord}.
*/
public DefaultProductionWord ()
{
this.prettyStringChangedListener = new PrettyStringChangedListener ()
{
public void prettyStringChanged ()
{
firePrettyStringChanged ();
}
};
this.productionWordMemberList = new ArrayList < ProductionWordMember > ();
this.initialProductionWordMemberList = new ArrayList < ProductionWordMember > ();
resetModify ();
}
/**
* Allocates a new {@link DefaultProductionWord}.
*
* @param element The {@link Element}.
* @throws StoreException If the {@link Element} can not be parsed.
*/
public DefaultProductionWord ( Element element ) throws StoreException
{
this ();
// Check if the element is correct
if ( !element.getName ().equals ( "ProductionWord" ) ) //$NON-NLS-1$
{
throw new IllegalArgumentException ( "element " + Messages.QUOTE //$NON-NLS-1$
+ element.getName () + Messages.QUOTE + " is not a production word" ); //$NON-NLS-1$
}
// Element
for ( Element current : element.getElement () )
{
if ( current.getName ().equals ( "TerminalSymbol" ) ) //$NON-NLS-1$
{
add ( new DefaultTerminalSymbol ( current ) );
}
else if ( current.getName ().equals ( "NonterminalSymbol" ) ) //$NON-NLS-1$
{
add ( new DefaultNonterminalSymbol ( current ) );
}
else
{
throw new StoreException ( Messages
.getString ( "StoreException.AdditionalElement" ) ); //$NON-NLS-1$
}
}
// Attribute
if ( element.getAttribute ().size () > 0 )
{
throw new StoreException ( Messages
.getString ( "StoreException.AdditionalAttribute" ) ); //$NON-NLS-1$
}
resetModify ();
}
/**
* Allocates a new {@link DefaultProductionWord}.
*
* @param productionWordMembers The array of {@link ProductionWordMember}s.
*/
public DefaultProductionWord (
Iterable < ProductionWordMember > productionWordMembers )
{
this ();
// ProductionWordMember
if ( productionWordMembers == null )
{
throw new NullPointerException ( "production word members is null" ); //$NON-NLS-1$
}
add ( productionWordMembers );
resetModify ();
}
/**
* Allocates a new {@link DefaultProductionWord}.
*
* @param productionWordMembers The array of {@link ProductionWordMember}s.
*/
public DefaultProductionWord ( ProductionWordMember ... productionWordMembers )
{
this ();
// ProductionWordMember
if ( productionWordMembers == null )
{
throw new NullPointerException ( "production word members is null" ); //$NON-NLS-1$
}
add ( productionWordMembers );
resetModify ();
}
/**
* {@inheritDoc}
*
* @see ProductionWord#add(Iterable)
*/
public final void add (
Iterable < ProductionWordMember > productionWordMembers )
{
if ( productionWordMembers == null )
{
throw new NullPointerException ( "production word members is null" ); //$NON-NLS-1$
}
for ( ProductionWordMember current : productionWordMembers )
{
add ( current );
}
}
/**
* {@inheritDoc}
*
* @see ProductionWord#add(ProductionWordMember)
*/
public final void add ( ProductionWordMember productionWordMember )
{
// ProductionWordMember
if ( productionWordMember == null )
{
throw new NullPointerException ( "production word member is null" ); //$NON-NLS-1$
}
productionWordMember
.addPrettyStringChangedListener ( this.prettyStringChangedListener );
this.productionWordMemberList.add ( productionWordMember );
firePrettyStringChanged ();
}
/**
* {@inheritDoc}
*
* @see ProductionWord#add(ProductionWordMember[])
*/
public final void add ( ProductionWordMember ... productionWordMembers )
{
if ( productionWordMembers == null )
{
throw new NullPointerException ( "production word members is null" ); //$NON-NLS-1$
}
for ( ProductionWordMember current : productionWordMembers )
{
add ( current );
}
}
/**
* {@inheritDoc}
*
* @see Modifyable#addModifyStatusChangedListener(ModifyStatusChangedListener)
*/
public final void addModifyStatusChangedListener (
ModifyStatusChangedListener listener )
{
this.listenerList.add ( ModifyStatusChangedListener.class, listener );
}
/**
* {@inheritDoc}
*
* @see PrettyPrintable#addPrettyStringChangedListener(PrettyStringChangedListener)
*/
public final void addPrettyStringChangedListener (
PrettyStringChangedListener listener )
{
this.listenerList.add ( PrettyStringChangedListener.class, listener );
}
/**
* {@inheritDoc}
*
* @see Comparable#compareTo(Object)
*/
public final int compareTo ( ProductionWord other )
{
ArrayList < ProductionWordMember > firstList = new ArrayList < ProductionWordMember > ();
ArrayList < ProductionWordMember > secondList = new ArrayList < ProductionWordMember > ();
firstList.addAll ( this.productionWordMemberList );
secondList.addAll ( other.get () );
int minSize = firstList.size () < secondList.size () ? firstList.size ()
: secondList.size ();
for ( int i = 0 ; i < minSize ; i++ )
{
int compare = firstList.get ( i ).getName ().compareTo (
secondList.get ( i ).getName () );
if ( compare != 0 )
{
return compare;
}
}
if ( firstList.size () == secondList.size () )
{
return 0;
}
return firstList.size () < secondList.size () ? -1 : 1;
}
/**
* {@inheritDoc}
*
* @see Object#equals(Object)
*/
@Override
public final boolean equals ( Object other )
{
if ( other instanceof DefaultProductionWord )
{
DefaultProductionWord defaultProductionWord = ( DefaultProductionWord ) other;
return this.productionWordMemberList
.equals ( defaultProductionWord.productionWordMemberList );
}
return false;
}
/**
* Let the listeners know that the {@link PrettyString} has changed.
*/
protected final void firePrettyStringChanged ()
{
this.cachedPrettyString = null;
PrettyStringChangedListener [] listeners = this.listenerList
.getListeners ( PrettyStringChangedListener.class );
for ( PrettyStringChangedListener current : listeners )
{
current.prettyStringChanged ();
}
}
/**
* {@inheritDoc}
*
* @see ProductionWord#get()
*/
public final ArrayList < ProductionWordMember > get ()
{
return this.productionWordMemberList;
}
/**
* {@inheritDoc}
*
* @see ProductionWord#get(int)
*/
public final ProductionWordMember get ( int index )
{
return this.productionWordMemberList.get ( index );
}
/**
* {@inheritDoc}
*
* @see Storable#getElement()
*/
public final Element getElement ()
{
Element newElement = new Element ( "ProductionWord" ); //$NON-NLS-1$
for ( ProductionWordMember current : this.productionWordMemberList )
{
newElement.addElement ( current );
}
return newElement;
}
/**
* {@inheritDoc}
*
* @see de.unisiegen.gtitool.core.entities.ProductionWord#getNonterminals()
*/
public ArrayList < NonterminalSymbol > getNonterminals ()
{
ArrayList < NonterminalSymbol > symbols = new ArrayList < NonterminalSymbol > ();
for ( ProductionWordMember m : this.productionWordMemberList )
{
if ( m instanceof NonterminalSymbol )
{
symbols.add ( ( NonterminalSymbol ) m );
}
}
return symbols;
}
/**
* {@inheritDoc}
*
* @see Entity#getParserOffset()
*/
public final ParserOffset getParserOffset ()
{
return this.parserOffset;
}
/**
* {@inheritDoc}
*
* @see Entity#hashCode()
*/
@Override
public final int hashCode ()
{
return this.productionWordMemberList.hashCode ();
}
/**
* {@inheritDoc}
*
* @see Modifyable#isModified()
*/
public final boolean isModified ()
{
if ( !this.initialProductionWordMemberList
.equals ( this.productionWordMemberList ) )
{
return true;
}
return false;
}
/**
* {@inheritDoc}
*
* @see Iterable#iterator()
*/
public final Iterator < ProductionWordMember > iterator ()
{
return this.productionWordMemberList.iterator ();
}
/**
* {@inheritDoc}
*
* @see Modifyable#removeModifyStatusChangedListener(ModifyStatusChangedListener)
*/
public final void removeModifyStatusChangedListener (
ModifyStatusChangedListener listener )
{
this.listenerList.remove ( ModifyStatusChangedListener.class, listener );
}
/**
* {@inheritDoc}
*
* @see PrettyPrintable#removePrettyStringChangedListener(PrettyStringChangedListener)
*/
public final void removePrettyStringChangedListener (
PrettyStringChangedListener listener )
{
this.listenerList.remove ( PrettyStringChangedListener.class, listener );
}
/**
* {@inheritDoc}
*
* @see Modifyable#resetModify()
*/
public final void resetModify ()
{
this.initialProductionWordMemberList.clear ();
this.initialProductionWordMemberList
.addAll ( this.productionWordMemberList );
}
/**
* {@inheritDoc}
*
* @see Entity#setParserOffset(ParserOffset)
*/
public final void setParserOffset ( ParserOffset parserOffset )
{
this.parserOffset = parserOffset;
}
/**
* {@inheritDoc}
*
* @see ProductionWord#size()
*/
public final int size ()
{
return this.productionWordMemberList.size ();
}
/**
* {@inheritDoc}
*
* @see PrettyPrintable#toPrettyString()
*/
public final PrettyString toPrettyString ()
{
if ( ( this.cachedPrettyString == null )
|| PrettyString.MODE.equals ( PrettyStringMode.CACHING_OFF ) )
{
this.cachedPrettyString = new PrettyString ();
if ( this.productionWordMemberList.size () == 0 )
{
this.cachedPrettyString.add ( new PrettyToken (
"\u03B5", Style.TERMINAL_SYMBOL ) ); //$NON-NLS-1$
}
else
{
for ( ProductionWordMember current : this.productionWordMemberList )
{
this.cachedPrettyString.add ( current );
}
}
}
return this.cachedPrettyString;
}
/**
* {@inheritDoc}
*
* @see Entity#toString()
*/
@Override
public final String toString ()
{
StringBuilder result = new StringBuilder ();
if ( this.productionWordMemberList.size () == 0 )
{
result.append ( "\u03B5" ); //$NON-NLS-1$
}
else
{
for ( ProductionWordMember current : this.productionWordMemberList )
{
result.append ( current.getName () );
}
}
return result.toString ();
}
}