/*
 * 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.commons.scxml.model;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;

import org.apache.commons.scxml.SCXMLHelper;

/**
 * A helper class for this SCXML implementation that represents the
 * path taken to transition from one TransitionTarget to another in
 * the SCXML document.
 *
 * The Path consists of the &quot;up segment&quot; that traces up to
 * the least common ancestor and a &quot;down segment&quot; that traces
 * down to the target of the Transition.
 *
 */
public class Path implements Serializable {

    /**
     * Serial version UID.
     */
    private static final long serialVersionUID = 1L;

    /**
     * The list of TransitionTargets in the &quot;up segment&quot;.
     */
    private List<TransitionTarget> upSeg = new ArrayList<TransitionTarget>();

    /**
     * The list of TransitionTargets in the &quot;down segment&quot;.
     */
    private List<TransitionTarget> downSeg = new ArrayList<TransitionTarget>();

    /**
     * &quot;Lowest&quot; state which is not being exited nor entered by
     * the transition.
     */
    private State scope = null;

    /**
     * Whether the path crosses region border(s).
     */
    private boolean crossRegion = false;

    /**
     * Constructor.
     *
     * @param source The source TransitionTarget
     * @param target The target TransitionTarget
     */
    Path(final TransitionTarget source, final TransitionTarget target) {
        if (target == null) {
            //a local "stay" transition
            scope = (State) source;
            //all segments remain empty
        } else {
            TransitionTarget tt = SCXMLHelper.getLCA(source, target);
            if (tt != null) {
                if (tt instanceof State) {
                    scope = (State) tt;
                } else {
                    scope = tt.getParentState();
                }
                if (scope == source || scope == target) {
                    scope = scope.getParentState();
                }
            }
            tt = source;
            while (tt != scope) {
                upSeg.add(tt);
                if (tt instanceof State) {
                    State st = (State) tt;
                    if (st.isRegion()) {
                        crossRegion = true;
                    }
                }
                tt = tt.getParent();
            }
            tt = target;
            while (tt != scope) {
                downSeg.add(0, tt);
                if (tt instanceof State) {
                    State st = (State) tt;
                    if (st.isRegion()) {
                        crossRegion = true;
                    }
                }
                tt = tt.getParent();
            }
        }
    }

    /**
     * Does this &quot;path&quot; cross regions.
     *
     * @return true when the path crosses a region border(s)
     * @see State#isRegion()
     */
    public final boolean isCrossRegion() {
        return crossRegion;
    }

    /**
     * Get the list of regions exited.
     *
     * @return List a list of exited regions sorted bottom-up;
     *         no order defined for siblings
     * @see State#isRegion()
     */
    public final List<State> getRegionsExited() {
        List<State> ll = new LinkedList<State>();
        for (Iterator i = upSeg.iterator(); i.hasNext();) {
            Object o = i.next();
            if (o instanceof State) {
                State st = (State) o;
                if (st.isRegion()) {
                    ll.add(st);
                }
            }
        }
        return ll;
    }

    /**
     * Get the list of regions entered.
     *
     * @return List a list of entered regions sorted top-down; no order
     *         defined for siblings
     * @see State#isRegion()
     */
    public final List<State> getRegionsEntered() {
        List<State> ll = new LinkedList<State>();
        for (Iterator i = downSeg.iterator(); i.hasNext();) {
            Object o = i.next();
            if (o instanceof State) {
                State st = (State) o;
                if (st.isRegion()) {
                    ll.add(st);
                }
            }
        }
        return ll;
    }

    /**
     * Get the farthest state from root which is not being exited
     * nor entered by the transition (null if scope is document root).
     *
     * @return State scope of the transition path, null means global transition
     *         (SCXML document level) Scope is the least state which is not
     *         being exited nor entered by the transition.
     */
    public final State getScope() {
        return scope;
    }

    /**
     * Get the upward segment.
     *
     * @return List upward segment of the path up to the scope
     */
    public final List<TransitionTarget> getUpwardSegment() {
        return upSeg;
    }

    /**
     * Get the downward segment.
     *
     * @return List downward segment from the scope to the target
     */
    public final List<TransitionTarget> getDownwardSegment() {
        return downSeg;
    }
}


@@ -897,35 +897,8 @@
 st;%0A
-import java.util.Iterator;%0A
 impo
@@ -4148,87 +4148,38 @@
 or (
-Iterator i = upSeg.iterator(); i.hasNext();) %7B%0A            Object o = i.next();
+TransitionTarget tt : upSeg) %7B
 %0A   
@@ -4183,33 +4183,34 @@
             if (
-o
+tt
  instanceof Stat
@@ -4241,33 +4241,34 @@
 te st = (State) 
-o
+tt
 ;%0A              
@@ -4708,89 +4708,40 @@
 or (
-Iterator i = downSeg.iterator(); i.hasNext();) %7B%0A            Object o = i.next();
+TransitionTarget tt : downSeg) %7B
 %0A   
@@ -4753,17 +4753,18 @@
     if (
-o
+tt
  instanc
@@ -4811,17 +4811,18 @@
 (State) 
-o
+tt
 ;%0A      

Use for-each to reduce clutter.