blob: 8f3ca62fbec362eef7a66897ed51da7bd4d1a265 [file] [log] [blame]
/**************************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*************************************************************/
package org.apache.openoffice.ooxml.schema.automaton;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import java.util.Vector;
import org.apache.openoffice.ooxml.schema.model.base.QualifiedName;
/** Represents the set of states of a single complex type.
*
* Because states have to be unique, the state container is an object shared
* by all StateContext objects.
*
* There is a single start state but there can be more than one accepting state.
*/
public class StateContext
{
public StateContext (
final StateContainer aStateContainer,
final String sBaseStateName)
{
maStateContainer = aStateContainer;
maStates = new HashSet<>();
maStartState = GetOrCreateState(new QualifiedName(null, null, sBaseStateName), null);
maDisambiguateCounters = new HashMap<>();
}
public State CreateState (
final QualifiedName aBasename,
final String sSuffix)
{
final String sFullname = State.GetStateName(aBasename, sSuffix);
if (HasState(sFullname))
throw new RuntimeException("state with name '"+sFullname+"' can not be created because it already exists");
final State aState = new State(aBasename, sSuffix);
AddState(aState);
return aState;
}
public State CreateState (final String sBasename)
{
return CreateState(new QualifiedName(sBasename), null);
}
public State CreateState (
final State aState,
final String sSuffix)
{
if (sSuffix==null && aState.GetSuffix()==null)
return CreateState(aState.GetBasename(), null);
else if (sSuffix!=null && aState.GetSuffix()!=null)
return CreateState(aState.GetBasename(), aState.GetSuffix()+"_"+sSuffix);
else if (sSuffix != null)
return CreateState(aState.GetBasename(), sSuffix);
else
return CreateState(aState.GetBasename(), aState.GetSuffix());
}
public State GetState (
final QualifiedName aBasename,
final String sSuffix)
{
return maStateContainer.GetStateForFullname(State.GetStateName(aBasename, sSuffix));
}
public State GetOrCreateState (
final QualifiedName aBasename,
final String sSuffix)
{
State aState = GetState(aBasename, sSuffix);
if (aState == null)
{
aState = CreateState(aBasename, sSuffix);
AddState(aState);
}
return aState;
}
public State GetStartStateForTypeName (final QualifiedName aName)
{
return GetOrCreateState(aName, null);
}
public State CreateEndState ()
{
final State aEndState = CreateState(
maStartState.GetBasename(),
"end");
aEndState.SetIsAccepting();
return aEndState;
}
/** Some algorithms can not easily produce unique suffixes.
* Append an integer to the given suffix so that it becomes unique.
*/
public String GetUnambiguousSuffix (final QualifiedName aBasename, final String sSuffix)
{
String sStateName = State.GetStateName(aBasename, sSuffix);
if ( ! HasState(sStateName))
{
// The given suffix can be used without modification.
return sSuffix;
}
else
{
int nIndex = 2;
final Integer nDisambiguateCounter = maDisambiguateCounters.get(sStateName);
if (nDisambiguateCounter != null)
nIndex = nDisambiguateCounter+1;
maDisambiguateCounters.put(sStateName, nIndex);
return sSuffix + "_" + nIndex;
}
}
public boolean HasState (
final QualifiedName aBasename,
final String sSuffix)
{
return maStateContainer.HasState(State.GetStateName(aBasename, sSuffix));
}
/** Return whether a state with the given name already belongs to the state
* context.
*/
public boolean HasState (final String sFullname)
{
return maStateContainer.HasState(sFullname);
}
/** The start state is the state a parser is in initially.
*/
public State GetStartState ()
{
return maStartState;
}
public Iterable<State> GetAcceptingStates ()
{
final Vector<State> aAcceptingStates = new Vector<>();
for (final State aState : maStates)
if (aState.IsAccepting())
aAcceptingStates.add(aState);
return aAcceptingStates;
}
/** Add the given state to the state context.
*/
public void AddState (final State aState)
{
maStateContainer.AddState(aState);
maStates.add(aState);
}
public void RemoveState (final State aState)
{
maStateContainer.RemoveState(aState);
maStates.remove(aState);
}
public int GetStateCount ()
{
return maStates.size();
}
public Iterable<State> GetStatesSorted()
{
final Set<State> aSortedStates = new TreeSet<>();
aSortedStates.addAll(maStates);
return aSortedStates;
}
public Iterable<State> GetStates()
{
return maStates;
}
public int GetTransitionCount ()
{
int nStateCount = 0;
for (final State aState : maStates)
nStateCount += aState.GetTransitionCount();
return nStateCount;
}
private final StateContainer maStateContainer;
private final Set<State> maStates;
private final State maStartState;
private final Map<String,Integer> maDisambiguateCounters;
}