// Copyright 2013 Daniel de Kok
//
// Licensed 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 eu.danieldk.dictomaton;

import java.util.Map.Entry;
import java.util.TreeMap;

class State {
    private final TreeMap<Character, State> transitions;
    private boolean d_final;
    private boolean d_recomputeHash;
    private int d_cachedHash;

    public State() {
        transitions = new TreeMap<Character, State>();
        d_final = false;
        d_recomputeHash = true;
    }

    public void addTransition(Character c, State s) {
        transitions.put(c, s);
        d_recomputeHash = true;
    }

    @Override
    public int hashCode() {
        if (!d_recomputeHash)
            return d_cachedHash;

        final int prime = 31;
        int result = 1;
        result = prime * result + (d_final ? 1231 : 1237);
        result = prime * result
                + ((transitions == null) ? 0 : transitions.hashCode());

        d_recomputeHash = false;
        d_cachedHash = result;

        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;

        if (obj == null)
            return false;

        if (getClass() != obj.getClass())
            return false;

        State other = (State) obj;
        if (d_final != other.d_final)
            return false;
        if (transitions == null) {
            if (other.transitions != null)
                return false;
        } else if (!transitions.equals(other.transitions))
            return false;
        return true;
    }

    public boolean isFinal() {
        return d_final;
    }

    public boolean hasOutgoing() {
        return transitions.size() != 0;
    }

    public State lastState() {
        Entry<Character, State> last = transitions.lastEntry();
        if (last == null)
            return null;

        return last.getValue();
    }

    public void setLastState(State s) {
        Entry<Character, State> entry = transitions.lastEntry();
        transitions.put(entry.getKey(), s);
        d_recomputeHash = true;
    }

    public TreeMap<Character, State> transitions() {
        return transitions;
    }

    public State move(Character c) {
        return transitions.get(c);
    }

    void setFinal(boolean finalState) {
        d_final = finalState;
        d_recomputeHash = true;
    }
}

@@ -617,16 +617,65 @@
 maton;%0A%0A
+import java.util.Iterator;%0Aimport java.util.Map;%0A
 import j
@@ -694,16 +694,16 @@
 .Entry;%0A
-
 import j
@@ -1466,10 +1466,9 @@
 ions
-.h
+H
 ashC
@@ -2017,19 +2017,25 @@
    %7D
- else if (!
+%0A%0A        return 
 tran
@@ -2071,55 +2071,8 @@
 ons)
-)%0A            return false;%0A        return true
 ;%0A  
@@ -2831,16 +2831,16 @@
 lState;%0A
-
         
@@ -2868,11 +2868,892 @@
 e;%0A    %7D
+%0A%0A    /**%0A     * Return the hashcode 'computed' by %7B@link Object#hashCode()%7D.%0A     * @return The hashcode.%0A     */%0A    private int objectHashCode() %7B%0A        return super.hashCode();%0A    %7D%0A%0A    /**%0A     * Compute the hashcode for transitions. We do not rely on the%7B@link java.util.TreeMap#hashCode()%7D,%0A     * because it will recursively compute the hashcodes of the to-states, which is not necessary since%0A     * two states are only identical when they have the same symbols leading to exactly the same objects.%0A     *%0A     * @return%0A     */%0A    private int transitionsHashCode() %7B%0A        int hc = 0;%0A%0A        Iterator%3CEntry%3CCharacter, State%3E%3E iter = transitions.entrySet().iterator();%0A        while (iter.hasNext()) %7B%0A            Entry%3CCharacter, State%3E e = iter.next();%0A            hc += e.getKey().hashCode() + e.getValue().objectHashCode();%0A        %7D%0A%0A        return hc;%0A    %7D
 %0A%7D%0A

Improve State hashing performance.