/*
 * Copyright 2012-2014 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 jetbrains.jetpad.base;

import java.util.ArrayList;
import java.util.List;

public class SimpleAsync<ItemT> implements ManagedAsync<ItemT> {
  private ItemT mySuccessItem = null;
  private boolean mySucceeded = false;

  private Throwable myFailureThrowable = null;
  private boolean myFailed = false;

  private List<Handler<? super ItemT>> mySuccessHandlers = new ArrayList<>();
  private List<Handler<Throwable>> myFailureHandlers = new ArrayList<>();

  @Override
  public Registration onSuccess(final Handler<? super ItemT> successHandler) {
    if (mySucceeded) {
      successHandler.handle(mySuccessItem);
      return Registration.EMPTY;
    } else {
      if (!myFailed) {
        mySuccessHandlers.add(successHandler);
        return new Registration() {
          @Override
          public void remove() {
            mySuccessHandlers.remove(successHandler);
          }
        };
      } else {
        return Registration.EMPTY;
      }
    }
  }

  @Override
  public Registration onResult(Handler<? super ItemT> successHandler, final Handler<Throwable> failureHandler) {
    final Registration successRegistration = onSuccess(successHandler);
    final Registration failureRegistration = onFailure(failureHandler);
    return new Registration() {
      @Override
      public void remove() {
        successRegistration.remove();
        failureRegistration.remove();
      }
    };
  }

  @Override
  public Registration onFailure(final Handler<Throwable> failureHandler) {
    if (myFailed) {
      failureHandler.handle(myFailureThrowable);
      return Registration.EMPTY;
    } else {
      if (!mySucceeded) {
        myFailureHandlers.add(failureHandler);
        return new Registration() {
          @Override
          public void remove() {
            myFailureHandlers.remove(failureHandler);
          }
        };
      } else {
        return Registration.EMPTY;
      }
    }
  }

  @Override
  public void success(ItemT item) {
    if (alreadyHandled()) {
      throw new IllegalStateException();
    }

    for (Handler<? super ItemT> handler : mySuccessHandlers) {
      handler.handle(item);
    }
    clearHandlers();
    mySuccessItem = item;
    mySucceeded = true;
  }

  @Override
  public void failure(Throwable throwable) {
    if (alreadyHandled()) {
      throw new IllegalStateException();
    }

    for (Handler<Throwable> handler : myFailureHandlers) {
      handler.handle(throwable);
    }
    clearHandlers();
    myFailureThrowable = throwable;
    myFailed = true;
  }

  private void clearHandlers() {
    mySuccessHandlers = null;
    myFailureHandlers = null;
  }

  private boolean alreadyHandled() {
    return mySucceeded || myFailed;
  }
}
@@ -1142,32 +1142,62 @@
 ccessHandler) %7B%0A
+    if (alreadyHandled()) %7B%0A  
     if (mySuccee
@@ -1199,24 +1199,26 @@
 ucceeded) %7B%0A
+  
       succes
@@ -1245,24 +1245,32 @@
 ccessItem);%0A
+      %7D%0A
       return
@@ -1299,43 +1299,9 @@
    %7D
- else %7B%0A      if (!myFailed) %7B%0A    
+%0A
     
@@ -1335,36 +1335,32 @@
 ssHandler);%0A    
-   
- 
 return new Regis
@@ -1369,36 +1369,32 @@
 ation() %7B%0A      
-    
 @Override%0A      
@@ -1385,36 +1385,32 @@
 @Override%0A      
- 
-   
 public void remo
@@ -1410,32 +1410,71 @@
 id remove() %7B%0A  
+      if (mySuccessHandlers != null) %7B%0A
           mySucc
@@ -1521,72 +1521,9 @@
     
-  %7D%0A        %7D;%0A      %7D else %7B%0A        return Registration.EMPTY;
+%7D
 %0A   
@@ -1524,32 +1524,33 @@
  %7D%0A      %7D%0A    %7D
+;
 %0A  %7D%0A%0A  @Overrid
@@ -2060,32 +2060,62 @@
 ilureHandler) %7B%0A
+    if (alreadyHandled()) %7B%0A  
     if (myFailed
@@ -2114,24 +2114,26 @@
 myFailed) %7B%0A
+  
       failur
@@ -2165,24 +2165,32 @@
 Throwable);%0A
+      %7D%0A
       return
@@ -2219,46 +2219,9 @@
    %7D
- else %7B%0A      if (!mySucceeded) %7B%0A    
+%0A
     
@@ -2255,28 +2255,24 @@
 reHandler);%0A
-    
     return n
@@ -2297,20 +2297,16 @@
 %7B%0A      
-   
- 
 @Overrid
@@ -2307,20 +2307,16 @@
 verride%0A
-    
       pu
@@ -2334,24 +2334,63 @@
 emove() %7B%0A  
+      if (myFailureHandlers != null) %7B%0A
           my
@@ -2441,86 +2441,24 @@
     
-  %7D%0A  
+%7D%0A
       %7D
-;%0A  
+%0A
     %7D
- else %7B%0A        return Registration.EMPTY;%0A      %7D%0A    %7D
+;
 %0A  %7D
@@ -2574,33 +2574,32 @@
 eption();%0A    %7D%0A
-%0A
     for (Handler
@@ -2887,17 +2887,16 @@
 ;%0A    %7D%0A
-%0A
     for 

fix NPE at registration removal after success or failure of SimpleAsync