package net.miginfocom.swing;

import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Insets;
import java.awt.LayoutManager;
import java.awt.LayoutManager2;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.io.ObjectStreamException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.IdentityHashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import javax.swing.JComponent;
import javax.swing.JEditorPane;
import javax.swing.JTextArea;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
import net.miginfocom.layout.AC;
import net.miginfocom.layout.BoundSize;
import net.miginfocom.layout.CC;
import net.miginfocom.layout.ComponentWrapper;
import net.miginfocom.layout.ConstraintParser;
import net.miginfocom.layout.ContainerWrapper;
import net.miginfocom.layout.Grid;
import net.miginfocom.layout.LC;
import net.miginfocom.layout.LayoutCallback;
import net.miginfocom.layout.LayoutUtil;
import net.miginfocom.layout.PlatformDefaults;
import net.miginfocom.layout.UnitValue;

public final class MigLayout implements LayoutManager2, Externalizable {
   private final Map<Component, Object> scrConstrMap;
   private Object layoutConstraints;
   private Object colConstraints;
   private Object rowConstraints;
   private transient ContainerWrapper cacheParentW;
   private final transient Map<ComponentWrapper, CC> ccMap;
   private transient Timer debugTimer;
   private transient LC lc;
   private transient AC colSpecs;
   private transient AC rowSpecs;
   private transient Grid grid;
   private transient int lastModCount;
   private transient int lastHash;
   private transient Dimension lastInvalidSize;
   private transient boolean lastWasInvalid;
   private transient Dimension lastParentSize;
   private transient ArrayList<LayoutCallback> callbackList;
   private transient boolean dirty;
   private long lastSize;

   public MigLayout() {
      this("", "", "");
   }

   public MigLayout(String var1) {
      this(var1, "", "");
   }

   public MigLayout(String var1, String var2) {
      this(var1, var2, "");
   }

   public MigLayout(String var1, String var2, String var3) {
      this.scrConstrMap = new IdentityHashMap(8);
      this.layoutConstraints = "";
      this.colConstraints = "";
      this.rowConstraints = "";
      this.cacheParentW = null;
      this.ccMap = new HashMap(8);
      this.debugTimer = null;
      this.lc = null;
      this.colSpecs = null;
      this.rowSpecs = null;
      this.grid = null;
      this.lastModCount = PlatformDefaults.getModCount();
      this.lastHash = -1;
      this.lastInvalidSize = null;
      this.lastWasInvalid = false;
      this.lastParentSize = null;
      this.callbackList = null;
      this.dirty = true;
      this.lastSize = 0L;
      this.setLayoutConstraints(var1);
      this.setColumnConstraints(var2);
      this.setRowConstraints(var3);
   }

   public MigLayout(LC var1) {
      this((LC)var1, (AC)null, (AC)null);
   }

   public MigLayout(LC var1, AC var2) {
      this((LC)var1, (AC)var2, (AC)null);
   }

   public MigLayout(LC var1, AC var2, AC var3) {
      this.scrConstrMap = new IdentityHashMap(8);
      this.layoutConstraints = "";
      this.colConstraints = "";
      this.rowConstraints = "";
      this.cacheParentW = null;
      this.ccMap = new HashMap(8);
      this.debugTimer = null;
      this.lc = null;
      this.colSpecs = null;
      this.rowSpecs = null;
      this.grid = null;
      this.lastModCount = PlatformDefaults.getModCount();
      this.lastHash = -1;
      this.lastInvalidSize = null;
      this.lastWasInvalid = false;
      this.lastParentSize = null;
      this.callbackList = null;
      this.dirty = true;
      this.lastSize = 0L;
      this.setLayoutConstraints(var1);
      this.setColumnConstraints(var2);
      this.setRowConstraints(var3);
   }

   public Object getLayoutConstraints() {
      return this.layoutConstraints;
   }

   public void setLayoutConstraints(Object var1) {
      if (var1 != null && !(var1 instanceof String)) {
         if (!(var1 instanceof LC)) {
            throw new IllegalArgumentException("Illegal constraint type: " + var1.getClass().toString());
         }

         this.lc = (LC)var1;
      } else {
         var1 = ConstraintParser.prepare((String)var1);
         this.lc = ConstraintParser.parseLayoutConstraint((String)var1);
      }

      this.layoutConstraints = var1;
      this.dirty = true;
   }

   public Object getColumnConstraints() {
      return this.colConstraints;
   }

   public void setColumnConstraints(Object var1) {
      if (var1 != null && !(var1 instanceof String)) {
         if (!(var1 instanceof AC)) {
            throw new IllegalArgumentException("Illegal constraint type: " + var1.getClass().toString());
         }

         this.colSpecs = (AC)var1;
      } else {
         var1 = ConstraintParser.prepare((String)var1);
         this.colSpecs = ConstraintParser.parseColumnConstraints((String)var1);
      }

      this.colConstraints = var1;
      this.dirty = true;
   }

   public Object getRowConstraints() {
      return this.rowConstraints;
   }

   public void setRowConstraints(Object var1) {
      if (var1 != null && !(var1 instanceof String)) {
         if (!(var1 instanceof AC)) {
            throw new IllegalArgumentException("Illegal constraint type: " + var1.getClass().toString());
         }

         this.rowSpecs = (AC)var1;
      } else {
         var1 = ConstraintParser.prepare((String)var1);
         this.rowSpecs = ConstraintParser.parseRowConstraints((String)var1);
      }

      this.rowConstraints = var1;
      this.dirty = true;
   }

   public Map<Component, Object> getConstraintMap() {
      return new IdentityHashMap(this.scrConstrMap);
   }

   public void setConstraintMap(Map<Component, Object> var1) {
      this.scrConstrMap.clear();
      this.ccMap.clear();
      Iterator var2 = var1.entrySet().iterator();

      while(var2.hasNext()) {
         Entry var3 = (Entry)var2.next();
         this.setComponentConstraintsImpl((Component)var3.getKey(), var3.getValue(), true);
      }

   }

   public Object getComponentConstraints(Component var1) {
      synchronized(var1.getParent().getTreeLock()) {
         return this.scrConstrMap.get(var1);
      }
   }

   public void setComponentConstraints(Component var1, Object var2) {
      this.setComponentConstraintsImpl(var1, var2, false);
   }

   private void setComponentConstraintsImpl(Component var1, Object var2, boolean var3) {
      Container var4 = var1.getParent();
      synchronized(var4 != null ? var4.getTreeLock() : new Object()) {
         if (!var3 && !this.scrConstrMap.containsKey(var1)) {
            throw new IllegalArgumentException("Component must already be added to parent!");
         } else {
            SwingComponentWrapper var6 = new SwingComponentWrapper(var1);
            if (var2 != null && !(var2 instanceof String)) {
               if (!(var2 instanceof CC)) {
                  throw new IllegalArgumentException("Constraint must be String or ComponentConstraint: " + var2.getClass().toString());
               }

               this.scrConstrMap.put(var1, var2);
               this.ccMap.put(var6, (CC)var2);
            } else {
               String var7 = ConstraintParser.prepare((String)var2);
               this.scrConstrMap.put(var1, var2);
               this.ccMap.put(var6, ConstraintParser.parseComponentConstraint(var7));
            }

            this.dirty = true;
         }
      }
   }

   public boolean isManagingComponent(Component var1) {
      return this.scrConstrMap.containsKey(var1);
   }

   public void addLayoutCallback(LayoutCallback var1) {
      if (var1 == null) {
         throw new NullPointerException();
      } else {
         if (this.callbackList == null) {
            this.callbackList = new ArrayList(1);
         }

         this.callbackList.add(var1);
      }
   }

   public void removeLayoutCallback(LayoutCallback var1) {
      if (this.callbackList != null) {
         this.callbackList.remove(var1);
      }

   }

   private void setDebug(ComponentWrapper var1, boolean var2) {
      if (var2 && (this.debugTimer == null || this.debugTimer.getDelay() != this.getDebugMillis())) {
         if (this.debugTimer != null) {
            this.debugTimer.stop();
         }

         ContainerWrapper var3 = var1.getParent();
         final Component var4 = var3 != null ? (Component)var3.getComponent() : null;
         this.debugTimer = new Timer(this.getDebugMillis(), new MigLayout.MyDebugRepaintListener());
         if (var4 != null) {
            SwingUtilities.invokeLater(new Runnable() {
               public void run() {
                  Container var1 = var4.getParent();
                  if (var1 != null) {
                     if (var1 instanceof JComponent) {
                        ((JComponent)var1).revalidate();
                     } else {
                        var4.invalidate();
                        var1.validate();
                     }
                  }

               }
            });
         }

         this.debugTimer.setInitialDelay(100);
         this.debugTimer.start();
      } else if (!var2 && this.debugTimer != null) {
         this.debugTimer.stop();
         this.debugTimer = null;
      }

   }

   private boolean getDebug() {
      return this.debugTimer != null;
   }

   private int getDebugMillis() {
      int var1 = LayoutUtil.getGlobalDebugMillis();
      return var1 > 0 ? var1 : this.lc.getDebugMillis();
   }

   private void checkCache(Container var1) {
      if (var1 != null) {
         if (this.dirty) {
            this.grid = null;
         }

         this.cleanConstraintMaps(var1);
         int var2 = PlatformDefaults.getModCount();
         if (this.lastModCount != var2) {
            this.grid = null;
            this.lastModCount = var2;
         }

         if (!var1.isValid()) {
            if (!this.lastWasInvalid) {
               this.lastWasInvalid = true;
               int var3 = 0;
               boolean var4 = false;

               for(Iterator var5 = this.ccMap.keySet().iterator(); var5.hasNext(); var3 += 285134905) {
                  ComponentWrapper var6 = (ComponentWrapper)var5.next();
                  Object var7 = var6.getComponent();
                  if (var7 instanceof JTextArea || var7 instanceof JEditorPane) {
                     var4 = true;
                  }

                  var3 ^= var6.getLayoutHashCode();
               }

               if (var4) {
                  this.resetLastInvalidOnParent(var1);
               }

               if (var3 != this.lastHash) {
                  this.grid = null;
                  this.lastHash = var3;
               }

               Dimension var9 = var1.getSize();
               if (this.lastInvalidSize == null || !this.lastInvalidSize.equals(var9)) {
                  if (this.grid != null) {
                     this.grid.invalidateContainerSize();
                  }

                  this.lastInvalidSize = var9;
               }
            }
         } else {
            this.lastWasInvalid = false;
         }

         ContainerWrapper var8 = this.checkParent(var1);
         this.setDebug(var8, this.getDebugMillis() > 0);
         if (this.grid == null) {
            this.grid = new Grid(var8, this.lc, this.rowSpecs, this.colSpecs, this.ccMap, this.callbackList);
         }

         this.dirty = false;
      }
   }

   private void cleanConstraintMaps(Container var1) {
      HashSet var2 = new HashSet(Arrays.asList(var1.getComponents()));
      Iterator var3 = this.ccMap.entrySet().iterator();

      while(var3.hasNext()) {
         Component var4 = (Component)((ComponentWrapper)((Entry)var3.next()).getKey()).getComponent();
         if (!var2.contains(var4)) {
            var3.remove();
            this.scrConstrMap.remove(var4);
         }
      }

   }

   private void resetLastInvalidOnParent(Container var1) {
      for(; var1 != null; var1 = var1.getParent()) {
         LayoutManager var2 = var1.getLayout();
         if (var2 instanceof MigLayout) {
            ((MigLayout)var2).lastWasInvalid = false;
         }
      }

   }

   private ContainerWrapper checkParent(Container var1) {
      if (var1 == null) {
         return null;
      } else {
         if (this.cacheParentW == null || this.cacheParentW.getComponent() != var1) {
            this.cacheParentW = new SwingContainerWrapper(var1);
         }

         return this.cacheParentW;
      }
   }

   public void layoutContainer(Container var1) {
      synchronized(var1.getTreeLock()) {
         this.checkCache(var1);
         Insets var3 = var1.getInsets();
         int[] var4 = new int[]{var3.left, var3.top, var1.getWidth() - var3.left - var3.right, var1.getHeight() - var3.top - var3.bottom};
         if (this.grid.layout(var4, this.lc.getAlignX(), this.lc.getAlignY(), this.getDebug(), true)) {
            this.grid = null;
            this.checkCache(var1);
            this.grid.layout(var4, this.lc.getAlignX(), this.lc.getAlignY(), this.getDebug(), false);
         }

         long var5 = (long)this.grid.getHeight()[1] + ((long)this.grid.getWidth()[1] << 32);
         if (this.lastSize != var5) {
            this.lastSize = var5;
            final ContainerWrapper var7 = this.checkParent(var1);
            Window var8 = (Window)SwingUtilities.getAncestorOfClass(Window.class, (Component)var7.getComponent());
            if (var8 != null) {
               if (var8.isVisible()) {
                  SwingUtilities.invokeLater(new Runnable() {
                     public void run() {
                        MigLayout.this.adjustWindowSize(var7);
                     }
                  });
               } else {
                  this.adjustWindowSize(var7);
               }
            }
         }

         this.lastInvalidSize = null;
      }
   }

   private void adjustWindowSize(ContainerWrapper var1) {
      BoundSize var2 = this.lc.getPackWidth();
      BoundSize var3 = this.lc.getPackHeight();
      if (var2 != null || var3 != null) {
         Window var4 = (Window)SwingUtilities.getAncestorOfClass(Window.class, (Component)var1.getComponent());
         if (var4 != null) {
            Dimension var5 = var4.getPreferredSize();
            int var6 = this.constrain(this.checkParent(var4), var4.getWidth(), var5.width, var2);
            int var7 = this.constrain(this.checkParent(var4), var4.getHeight(), var5.height, var3);
            int var8 = Math.round((float)var4.getX() - (float)(var6 - var4.getWidth()) * (1.0F - this.lc.getPackWidthAlign()));
            int var9 = Math.round((float)var4.getY() - (float)(var7 - var4.getHeight()) * (1.0F - this.lc.getPackHeightAlign()));
            var4.setBounds(var8, var9, var6, var7);
         }
      }
   }

   private int constrain(ContainerWrapper var1, int var2, int var3, BoundSize var4) {
      if (var4 == null) {
         return var2;
      } else {
         int var5 = var2;
         UnitValue var6 = var4.getPreferred();
         if (var6 != null) {
            var5 = var6.getPixels((float)var3, var1, var1);
         }

         var5 = var4.constrain(var5, (float)var3, var1);
         return var4.getGapPush() ? Math.max(var2, var5) : var5;
      }
   }

   public Dimension minimumLayoutSize(Container var1) {
      synchronized(var1.getTreeLock()) {
         return this.getSizeImpl(var1, 0);
      }
   }

   public Dimension preferredLayoutSize(Container var1) {
      synchronized(var1.getTreeLock()) {
         if (this.lastParentSize == null || !var1.getSize().equals(this.lastParentSize)) {
            label45: {
               Iterator var3 = this.ccMap.keySet().iterator();

               Component var5;
               do {
                  if (!var3.hasNext()) {
                     break label45;
                  }

                  ComponentWrapper var4 = (ComponentWrapper)var3.next();
                  var5 = (Component)var4.getComponent();
               } while(!(var5 instanceof JTextArea) && !(var5 instanceof JEditorPane) && (!(var5 instanceof JComponent) || !Boolean.TRUE.equals(((JComponent)var5).getClientProperty("migLayout.dynamicAspectRatio"))));

               this.layoutContainer(var1);
            }
         }

         this.lastParentSize = var1.getSize();
         return this.getSizeImpl(var1, 1);
      }
   }

   public Dimension maximumLayoutSize(Container var1) {
      return new Dimension(32767, 32767);
   }

   private Dimension getSizeImpl(Container var1, int var2) {
      this.checkCache(var1);
      Insets var3 = var1.getInsets();
      int var4 = LayoutUtil.getSizeSafe(this.grid != null ? this.grid.getWidth() : null, var2) + var3.left + var3.right;
      int var5 = LayoutUtil.getSizeSafe(this.grid != null ? this.grid.getHeight() : null, var2) + var3.top + var3.bottom;
      return new Dimension(var4, var5);
   }

   public float getLayoutAlignmentX(Container var1) {
      return this.lc != null && this.lc.getAlignX() != null ? (float)this.lc.getAlignX().getPixels(1.0F, this.checkParent(var1), (ComponentWrapper)null) : 0.0F;
   }

   public float getLayoutAlignmentY(Container var1) {
      return this.lc != null && this.lc.getAlignY() != null ? (float)this.lc.getAlignY().getPixels(1.0F, this.checkParent(var1), (ComponentWrapper)null) : 0.0F;
   }

   public void addLayoutComponent(String var1, Component var2) {
      this.addLayoutComponent((Component)var2, (Object)var1);
   }

   public void addLayoutComponent(Component var1, Object var2) {
      synchronized(var1.getParent().getTreeLock()) {
         this.setComponentConstraintsImpl(var1, var2, true);
      }
   }

   public void removeLayoutComponent(Component var1) {
      synchronized(var1.getParent().getTreeLock()) {
         this.scrConstrMap.remove(var1);
         this.ccMap.remove(new SwingComponentWrapper(var1));
      }
   }

   public void invalidateLayout(Container var1) {
      this.dirty = true;
   }

   private Object readResolve() throws ObjectStreamException {
      return LayoutUtil.getSerializedObject(this);
   }

   public void readExternal(ObjectInput var1) throws IOException, ClassNotFoundException {
      LayoutUtil.setSerializedObject(this, LayoutUtil.readAsXML(var1));
   }

   public void writeExternal(ObjectOutput var1) throws IOException {
      if (this.getClass() == MigLayout.class) {
         LayoutUtil.writeAsXML(var1, this);
      }

   }

   private class MyDebugRepaintListener implements ActionListener {
      private MyDebugRepaintListener() {
      }

      public void actionPerformed(ActionEvent var1) {
         if (MigLayout.this.grid != null) {
            Component var2 = (Component)MigLayout.this.grid.getContainer().getComponent();
            if (var2.isShowing()) {
               MigLayout.this.grid.paintDebug();
               return;
            }
         }

         MigLayout.this.debugTimer.stop();
         MigLayout.this.debugTimer = null;
      }

      // $FF: synthetic method
      MyDebugRepaintListener(Object var2) {
         this();
      }
   }
}
