1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements.  See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership.  The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License.  You may obtain a copy of the License at
10 *
11 *   http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied.  See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21 
22 package org.apache.openoffice.ooxml.schema.automaton;
23 
24 import java.util.HashMap;
25 import java.util.HashSet;
26 import java.util.Map;
27 import java.util.Set;
28 import java.util.TreeSet;
29 import java.util.Vector;
30 
31 import org.apache.openoffice.ooxml.schema.model.base.QualifiedName;
32 
33 /** Represents the set of states of a single complex type.
34  *
35  *  Because states have to be unique, the state container is an object shared
36  *  by all StateContext objects.
37  *
38  *  There is a single start state but there can be more than one accepting state.
39  */
40 public class StateContext
41 {
StateContext( final StateContainer aStateContainer, final String sBaseStateName)42     public StateContext (
43         final StateContainer aStateContainer,
44         final String sBaseStateName)
45     {
46         maStateContainer = aStateContainer;
47         maStates = new HashSet<>();
48         maStartState = GetOrCreateState(new QualifiedName(null, null, sBaseStateName), null);
49         maDisambiguateCounters = new HashMap<>();
50     }
51 
52 
53 
54 
CreateState( final QualifiedName aBasename, final String sSuffix)55     public State CreateState (
56         final QualifiedName aBasename,
57         final String sSuffix)
58     {
59         final String sFullname = State.GetStateName(aBasename, sSuffix);
60         if (HasState(sFullname))
61             throw new RuntimeException("state with name '"+sFullname+"' can not be created because it already exists");
62         final State aState = new State(aBasename, sSuffix);
63         AddState(aState);
64         return aState;
65     }
66 
67 
68 
CreateState(final String sBasename)69     public State CreateState (final String sBasename)
70     {
71         return CreateState(new QualifiedName(sBasename), null);
72     }
73 
74 
75 
76 
CreateState( final State aState, final String sSuffix)77     public State CreateState (
78         final State aState,
79         final String sSuffix)
80     {
81         if (sSuffix==null && aState.GetSuffix()==null)
82             return CreateState(aState.GetBasename(), null);
83         else if (sSuffix!=null && aState.GetSuffix()!=null)
84             return CreateState(aState.GetBasename(), aState.GetSuffix()+"_"+sSuffix);
85         else if (sSuffix != null)
86             return CreateState(aState.GetBasename(), sSuffix);
87         else
88             return CreateState(aState.GetBasename(), aState.GetSuffix());
89     }
90 
91 
92 
93 
GetState( final QualifiedName aBasename, final String sSuffix)94     public State GetState (
95         final QualifiedName aBasename,
96         final String sSuffix)
97     {
98         return maStateContainer.GetStateForFullname(State.GetStateName(aBasename, sSuffix));
99     }
100 
101 
102 
103 
GetOrCreateState( final QualifiedName aBasename, final String sSuffix)104     public State GetOrCreateState (
105         final QualifiedName aBasename,
106         final String sSuffix)
107     {
108         State aState = GetState(aBasename, sSuffix);
109         if (aState == null)
110         {
111             aState = CreateState(aBasename, sSuffix);
112             AddState(aState);
113         }
114         return aState;
115     }
116 
117 
118 
119 
GetStartStateForTypeName(final QualifiedName aName)120     public State GetStartStateForTypeName (final QualifiedName aName)
121     {
122         return GetOrCreateState(aName, null);
123     }
124 
125 
126 
127 
CreateEndState()128     public State CreateEndState ()
129     {
130         final State aEndState = CreateState(
131             maStartState.GetBasename(),
132             "end");
133         aEndState.SetIsAccepting();
134         return aEndState;
135     }
136 
137 
138 
139     /** Some algorithms can not easily produce unique suffixes.
140      *  Append an integer to the given suffix so that it becomes unique.
141      */
GetUnambiguousSuffix(final QualifiedName aBasename, final String sSuffix)142     public String GetUnambiguousSuffix (final QualifiedName aBasename, final String sSuffix)
143     {
144         String sStateName = State.GetStateName(aBasename, sSuffix);
145         if ( ! HasState(sStateName))
146         {
147             // The given suffix can be used without modification.
148             return sSuffix;
149         }
150         else
151         {
152             int nIndex = 2;
153             final Integer nDisambiguateCounter = maDisambiguateCounters.get(sStateName);
154             if (nDisambiguateCounter != null)
155                 nIndex = nDisambiguateCounter+1;
156             maDisambiguateCounters.put(sStateName, nIndex);
157 
158             return sSuffix + "_" + nIndex;
159         }
160     }
161 
162 
163 
164 
HasState( final QualifiedName aBasename, final String sSuffix)165     public boolean HasState (
166         final QualifiedName aBasename,
167         final String sSuffix)
168     {
169         return maStateContainer.HasState(State.GetStateName(aBasename, sSuffix));
170     }
171 
172 
173 
174 
175     /** Return whether a state with the given name already belongs to the state
176      *  context.
177      */
HasState(final String sFullname)178     public boolean HasState (final String sFullname)
179     {
180         return maStateContainer.HasState(sFullname);
181     }
182 
183 
184 
185 
186     /** The start state is the state a parser is in initially.
187      */
GetStartState()188     public State GetStartState ()
189     {
190         return maStartState;
191     }
192 
193 
194 
195 
GetAcceptingStates()196     public Iterable<State> GetAcceptingStates ()
197     {
198         final Vector<State> aAcceptingStates = new Vector<>();
199         for (final State aState : maStates)
200             if (aState.IsAccepting())
201                 aAcceptingStates.add(aState);
202         return aAcceptingStates;
203     }
204 
205 
206 
207 
208     /** Add the given state to the state context.
209      */
AddState(final State aState)210     public void AddState (final State aState)
211     {
212         maStateContainer.AddState(aState);
213         maStates.add(aState);
214     }
215 
216 
217 
218 
RemoveState(final State aState)219     public void RemoveState (final State aState)
220     {
221         maStateContainer.RemoveState(aState);
222         maStates.remove(aState);
223     }
224 
225 
226 
227 
GetStateCount()228     public int GetStateCount ()
229     {
230         return maStates.size();
231     }
232 
233 
234 
235 
GetStatesSorted()236     public Iterable<State> GetStatesSorted()
237     {
238         final Set<State> aSortedStates = new TreeSet<>();
239         aSortedStates.addAll(maStates);
240         return aSortedStates;
241     }
242 
243 
244 
245 
GetStates()246     public Iterable<State> GetStates()
247     {
248         return maStates;
249     }
250 
251 
252 
253 
GetTransitionCount()254     public int GetTransitionCount ()
255     {
256         int nStateCount = 0;
257         for (final State aState : maStates)
258             nStateCount += aState.GetTransitionCount();
259         return nStateCount;
260     }
261 
262 
263 
264 
265     private final StateContainer maStateContainer;
266     private final Set<State> maStates;
267     private final State maStartState;
268     private final Map<String,Integer> maDisambiguateCounters;
269 }
270