/*
 * Copyright 2000-2009 JetBrains s.r.o.
 *
 * 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 com.intellij.execution.junit2.ui.actions;

import com.intellij.execution.junit2.events.StateChangedEvent;
import com.intellij.execution.junit2.events.TestEvent;
import com.intellij.execution.junit2.TestProxy;
import com.intellij.execution.junit2.ui.model.JUnitAdapter;
import com.intellij.execution.junit2.ui.model.JUnitRunningModel;
import com.intellij.execution.junit2.ui.properties.JUnitConsoleProperties;
import com.intellij.execution.testframework.TestFrameworkPropertyListener;
import com.intellij.execution.testframework.actions.TestFrameworkActions;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.rt.execution.junit.states.PoolOfTestStates;

class RunningTestTracker extends JUnitAdapter implements TestFrameworkPropertyListener<Boolean> {
  private static final Logger LOG = Logger.getInstance("#com.intellij.execution.junit2.ui.actions.TrackRunningTestAction");

  private final JUnitRunningModel myModel;
  private TrackingPolicy myTrackingPolicy;
  private TestProxy myLastRan = null;

  private RunningTestTracker(final JUnitRunningModel model) {
    myModel = model;
    choosePolicy();
  }

  public void onChanged(final Boolean value) {
    choosePolicy();
    myTrackingPolicy.apply();
  }

  public void onTestChanged(final TestEvent event) {
    if (event instanceof StateChangedEvent) {
      final TestProxy proxy = event.getSource();
      if (proxy == myLastRan && !isRunningState(proxy)) myLastRan = null;
      if (proxy.isLeaf() && isRunningState(proxy)) myLastRan = proxy;
      myTrackingPolicy.applyTo(proxy);
    }
  }

  public static void install(final JUnitRunningModel model) {
    final RunningTestTracker testTracker = new RunningTestTracker(model);
    model.addListener(testTracker);
    TestFrameworkActions.addPropertyListener(JUnitConsoleProperties.TRACK_RUNNING_TEST, testTracker, model, false);
  }

  private static boolean isRunningState(final TestProxy test) {
    return test.getState().getMagnitude() == PoolOfTestStates.RUNNING_INDEX;
  }

  private abstract static class TrackingPolicy {
    protected abstract void applyTo(TestProxy test);
    protected abstract void apply();
  }

  private void choosePolicy() {
    final boolean shouldTrack = JUnitConsoleProperties.TRACK_RUNNING_TEST.value(myModel.getProperties());
    myTrackingPolicy = shouldTrack ? TRACK_RUNNING : DONT_TRACK;
  }

  private static final TrackingPolicy DONT_TRACK = new TrackingPolicy() {
    protected void applyTo(final TestProxy test) {}
    protected void apply() {}
  };

  private final TrackingPolicy TRACK_RUNNING = new TrackingPolicy() {
    protected void applyTo(final TestProxy test) {
      LOG.assertTrue(myModel != null);
      selectLastTest();
      if (!test.isLeaf() && test.getState().isPassed())
        myModel.collapse(test);
    }

    protected void apply() {
      LOG.assertTrue(myModel != null);
      selectLastTest();
    }

    private void selectLastTest() {
      if (myLastRan != null && isRunningState(myLastRan))
        myModel.selectTest(myLastRan);
    }
  };
}

@@ -1619,16 +1619,59 @@
  = null;
+%0A  private TestProxy myLastSelected = null;
 %0A%0A  priv
@@ -1866,32 +1866,172 @@
 y.apply();%0A  %7D%0A%0A
+  @Override%0A  public void onTestSelected(TestProxy test) %7B%0A    if (test != null && test.isLeaf()) %7B%0A      myLastSelected = test;%0A    %7D%0A  %7D%0A%0A
   public void on
@@ -2209,32 +2209,123 @@
 ingState(proxy))
+ %7B%0A        if (myLastSelected == proxy)%7B%0A          myLastSelected = null;%0A        %7D%0A       
  myLastRan = nul
@@ -2323,24 +2323,32 @@
 Ran = null;%0A
+      %7D%0A
       if (pr
@@ -3878,16 +3878,42 @@
 LastRan)
+ && myLastSelected == null
 )%0A      

stop tracking running test after user selects one