/*
 * Copyright 2000-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 com.intellij.openapi.application.impl;

import com.intellij.openapi.application.ModalityState;
import com.intellij.openapi.progress.ProgressIndicator;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;

import java.lang.ref.Reference;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;

public class ModalityStateEx extends ModalityState {
  private static final WeakReference[] EMPTY_REFS_ARRAY = new WeakReference[0];

  private final WeakReference[] myModalEntities;

  public ModalityStateEx() {
    this(EMPTY_REFS_ARRAY);
  }

  public ModalityStateEx(@NotNull Object[] modalEntities) {
    if (modalEntities.length > 0) {
      myModalEntities = new WeakReference[modalEntities.length];
      for (int i = 0; i < modalEntities.length; i++) {
        Object entity = modalEntities[i];
        myModalEntities[i] = new WeakReference<Object>(entity);
      }
    }
    else{
      myModalEntities = EMPTY_REFS_ARRAY;
    }
  }

  @NotNull
  public ModalityState appendProgress(@NotNull ProgressIndicator progress){
    return appendEntity(progress);
  }

  @NotNull
  ModalityStateEx appendEntity(@NotNull Object anEntity){
    List<Object> list = new ArrayList<Object>(myModalEntities.length+1);
    for (Reference modalEntity : myModalEntities) {
      Object entity = modalEntity.get();
      if (entity == null) continue;
      list.add(entity);
    }
    list.add(anEntity);
    return new ModalityStateEx(list.toArray());
  }

  private static boolean contains(WeakReference[] array, Object o){
    for (WeakReference reference : array) {
      Object o1 = reference.get();
      if (o1 == null) continue;
      if (o1.equals(o)) return true;
    }
    return false;
  }

  @Override
  public boolean dominates(@NotNull ModalityState anotherState){
    if (anotherState == ModalityState.any()) return false;
    
    for (WeakReference modalEntity : myModalEntities) {
      Object entity = modalEntity.get();
      if (entity == null) continue;
      if (!contains(((ModalityStateEx)anotherState).myModalEntities, entity)) return true; // I have entity which is absent in anotherState
    }
    return false;
  }

  boolean contains(@NotNull Object modalEntity) {
    return contains(myModalEntities, modalEntity);
  }

  @NonNls
  public String toString() {
    if (myModalEntities.length == 0) return "ModalityState.NON_MODAL";
    @NonNls StringBuilder buffer = new StringBuilder();
    buffer.append("ModalityState:");
    for (int i = 0; i < myModalEntities.length; i++) {
      Object entity = myModalEntities[i].get();
      if (i > 0) buffer.append(", ");
      buffer.append(entity);
    }
    return buffer.toString();
  }
}

@@ -753,16 +753,102 @@
 icator;%0A
+import com.intellij.util.Function;%0Aimport com.intellij.util.containers.ContainerUtil;%0A
 import o
@@ -927,40 +927,8 @@
 l;%0A%0A
-import java.lang.ref.Reference;%0A
 impo
@@ -1652,24 +1652,281 @@
 %0A    %7D%0A  %7D%0A%0A
+  private List%3CObject%3E getModalEntities() %7B%0A    return ContainerUtil.mapNotNull(myModalEntities, new Function%3CWeakReference, Object%3E() %7B%0A      @Override%0A      public Object fun(WeakReference reference) %7B%0A        return reference.get();%0A      %7D%0A    %7D);%0A  %7D%0A%0A
   @NotNull%0A 
@@ -2190,478 +2190,111 @@
     
-for (Reference modalEntity : myModalEntities) %7B%0A      Object entity = modalEntity.get();%0A      if (entity == null) continue;%0A      list.add(entity);%0A    %7D%0A    list.add(anEntity);%0A    return new ModalityStateEx(list.toArray());%0A  %7D%0A%0A  private static boolean contains(WeakReference%5B%5D array, Object o)%7B%0A    for (WeakReference reference : array) %7B%0A      Object o1 = reference.get();%0A      if (o1 == null) continue;%0A      if (o1.equals(o)) return true;%0A    %7D%0A    return false
+list.addAll(getModalEntities());%0A    list.add(anEntity);%0A    return new ModalityStateEx(list.toArray())
 ;%0A  
@@ -2436,52 +2436,77 @@
 se;%0A
-    
 %0A    
-for (WeakReference modalEntity : my
+List%3CObject%3E otherEntities = ((ModalityStateEx)anotherState).get
 Moda
@@ -2514,26 +2514,29 @@
 Entities
-) %7B
+();
 %0A    
-  
+for (
 Object e
@@ -2533,35 +2533,38 @@
  (Object entity 
-= m
+: getM
 odalEntity.get()
@@ -2560,122 +2560,51 @@
 ntit
-y.get();%0A      if (entity == null) continue;%0A      if (!contains(((ModalityStateEx)anotherState).myModalEntities, 
+ies()) %7B%0A      if (!otherEntities.contains(
 enti
@@ -2764,19 +2764,11 @@
 urn 
-contains(my
+get
 Moda
@@ -2776,18 +2776,28 @@
 Entities
-, 
+().contains(
 modalEnt
@@ -3219,11 +3219,434 @@
 g();%0A  %7D
+%0A%0A  @Override%0A  public boolean equals(Object o) %7B%0A    if (this == o) return true;%0A    if (!(o instanceof ModalityStateEx)) return false;%0A%0A    List%3CObject%3E entities = getModalEntities();%0A    if (entities.isEmpty()) return false; //%C2%A0e.g. NON_MODAL isn't equal to ANY%0A%0A    return entities.equals(((ModalityStateEx)o).getModalEntities());%0A  %7D%0A%0A  @Override%0A  public int hashCode() %7B%0A    return getModalEntities().hashCode();%0A  %7D
 %0A%7D%0A

add ModalityState.equals/hashCode