/*
 * Copyright 2000-2016 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.vcs.log.ui.frame;

import com.intellij.openapi.Disposable;
import com.intellij.openapi.ui.LoadingDecorator;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.NotNullComputable;
import com.intellij.ui.components.JBPanel;
import com.intellij.ui.components.panels.NonOpaquePanel;
import com.intellij.util.ui.AsyncProcessIcon;
import org.jetbrains.annotations.NotNull;

import javax.swing.*;
import java.awt.*;

public class ProgressStripe extends JBPanel {
  @NotNull
  private final JBPanel myPanel;
  private final NotNullComputable<MyLoadingDecorator> myCreateLoadingDecorator;
  protected MyLoadingDecorator myDecorator;

  public ProgressStripe(@NotNull JComponent targetComponent, @NotNull Disposable parent, int startDelayMs) {
    super(new BorderLayout());
    myPanel = new JBPanel(new BorderLayout());
    myPanel.setOpaque(false);
    myPanel.add(targetComponent);

    myCreateLoadingDecorator = () -> {
      Disposable disposable = Disposer.newDisposable();
      Disposer.register(parent, disposable);
      return new MyLoadingDecorator(targetComponent, myPanel, disposable, startDelayMs);
    };
    createLoadingDecorator();
  }

  @Override
  public void updateUI() {
    super.updateUI();
    if (myCreateLoadingDecorator != null) {
      if (myDecorator != null) {
        remove(myDecorator.getComponent());
        myDecorator.dispose();
      }
      createLoadingDecorator();
    }
  }

  private void createLoadingDecorator() {
    myDecorator = myCreateLoadingDecorator.compute();
    add(myDecorator.getComponent(), BorderLayout.CENTER);
    myDecorator.setLoadingText("");
  }

  public void startLoading() {
    myDecorator.startLoading(false);
  }

  public void startLoadingImmediately() {
    myDecorator.startLoadingImmediately();
  }

  public void stopLoading() {
    myDecorator.stopLoading();
  }

  private static class MyLoadingDecorator extends LoadingDecorator {
    @NotNull
    private final Disposable myDisposable;

    MyLoadingDecorator(@NotNull JComponent component,
                       @NotNull JPanel contentPanel,
                       @NotNull Disposable disposable,
                       int startDelayMs) {
      super(contentPanel, disposable, startDelayMs, false, ProgressStripeIcon.generateIcon(component));
      myDisposable = disposable;
    }

    public void startLoadingImmediately() {
      _startLoading(false);
    }

    @Override
    protected NonOpaquePanel customizeLoadingLayer(JPanel parent, JLabel text, AsyncProcessIcon icon) {
      parent.setLayout(new BorderLayout());

      NonOpaquePanel result = new NonOpaquePanel();
      result.setLayout(new BoxLayout(result, BoxLayout.Y_AXIS));
      result.add(icon);

      parent.add(result, BorderLayout.NORTH);

      return result;
    }

    public void dispose() {
      Disposer.dispose(myDisposable);
    }
  }
}

@@ -770,60 +770,8 @@
 er;%0A
-import com.intellij.openapi.util.NotNullComputable;%0A
 impo
@@ -1043,27 +1043,16 @@
 Panel %7B%0A
-  @NotNull%0A
   privat
@@ -1064,102 +1064,157 @@
 al J
-BPanel myPanel;%0A  private final NotNullComputable%3CMyLoadingDecorator%3E myCreateLoadingDecorator
+Component myTargetComponent;%0A  private final Disposable myDisposable;%0A  private final int myStartDelayMs;%0A%0A  @NotNull%0A  private final JBPanel myPanel
 ;%0A  
@@ -1518,345 +1518,513 @@
   my
-CreateLoadingDecorator = () -%3E %7B%0A      Disposable disposable = Disposer.newDisposable
+TargetComponent = targetComponent;%0A    myDisposable = parent;%0A    myStartDelayMs = startDelayMs;%0A%0A    createLoadingDecorator();%0A  %7D%0A%0A  @Override%0A  public void updateUI() %7B%0A    super.updateUI
 ();%0A
+%0A
     
-  Disposer.register(parent, disposable);%0A      return new MyLoadingDecorator(targetComponent, myPanel, disposable, startDelayMs);%0A    %7D;%0A    createLoadingDecorator();%0A  %7D%0A%0A  @Override%0A  public void updateUI() %7B%0A    super.updateUI();%0A    if (myC
+// can be null in super constructor.%0A    // can be disposed during dispose sequence (ThreeComponentsSplitter can trigger updateUI while removing contents of other toolwindows).%0A    if (myDisposable != null && !Disposer.isDisposed(myDisposable)) %7B%0A      createLoadingDecorator();%0A    %7D%0A  %7D%0A%0A  private void c
 reat
@@ -2036,38 +2036,29 @@
 ingDecorator
- != null
+(
 ) %7B%0A
-  
     if (myDe
@@ -2072,26 +2072,24 @@
  != null) %7B%0A
-  
       remove
@@ -2124,18 +2124,33 @@
 ;%0A      
-  
+Disposer.dispose(
 myDecora
@@ -2157,111 +2157,135 @@
 tor.
-d
+getD
 ispos
+abl
 e()
+)
 ;%0A    
- 
- 
 %7D
+%0A
 %0A    
-  createLoadingDecorator();%0A    %7D%0A  %7D%0A%0A  private void createLoadingDecorator() %7B
+Disposable disposable = Disposer.newDisposable();%0A    Disposer.register(myDisposable, disposable);
 %0A   
@@ -2303,16 +2303,14 @@
 r = 
-myCreate
+new My
 Load
@@ -2325,20 +2325,67 @@
 ator
-.compute(
+(myTargetComponent, myPanel, disposable, myStartDelayMs
 );%0A
+%0A
     
@@ -3650,26 +3650,51 @@
     
-public void d
+@NotNull%0A    public Disposable getD
 ispos
+abl
 e() 
@@ -3701,33 +3701,23 @@
 %7B%0A      
-Disposer.dispose(
+return 
 myDispos
@@ -3716,25 +3716,24 @@
 myDisposable
-)
 ;%0A    %7D%0A  %7D%0A

fix "Sorry but parent will never be disposed" error on project dispose