package nxm.sys.libg;

import java.awt.Component;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Panel;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

import nxm.sys.inc.InternalUseOnly;

/** A class to run a graphical Midas Panel. This class is implemented using
    AWT components while {@link MJPanel} uses swing.

    NOTE: MPanel does NOT currently support Java Serialization, even though it extends classes that support it.

    @see MWindow
    @see MJPanel

    @author Jeff Schoen
 */
public class MPanel extends Panel {
  /** NOTE: this should be changed if the structure/fields of this class changes. */
  private static final long serialVersionUID = 2012021090311L; // for Serializable interface

  /** Message given when user tries to serialize an MPanel object */
  @InternalUseOnly
  public static final String UNSERIALIZABLE_MPANEL_OBJECT_MESSAGE =
      "nxm.sys.libg.MPanel does NOT currently support Java Serialization";

  /** The MWindow associated with this MPanel */
  public transient MWindow MW;

  /** Registry Name   */ private String registryName;
  /** Needs a Refresh */ private boolean needrefresh=false;

  /** Create the panel  */
  public MPanel() {
    super();
    setLayout(null);
  }

  /**
     Create the panel and initialize registryName.
     @param name The string to assign to registryName.
   */
  public MPanel(String name) {
    this();
    registryName = name;
  }

  /**
     Sets the MW.
     @param mw The MWindow associated with this MPanel.
   */
  public void setMWindow (MWindow mw) {
    MW = mw;
    if (needrefresh) MW.process ("REFRESH",0,null);
    needrefresh = false;
  }

  // JWB - methods below were removed as part of BUG 1811, since it did not seem
  //       to be doing anything and was inhibiting some SWING drawing
  /*public void setBounds (Rectangle rect) {
    super.setBounds(rect);
    if ((getComponentCount() == 1) && (getComponent(0) instanceof JComponent)) {
      getComponent(0).setBounds(0, 0, getWidth(), getHeight());
    }
  }

  public void setBounds (int x, int y, int w, int h) {
    super.setBounds(x, y, w, h);
    if ((getComponentCount() == 1) && (getComponent(0) instanceof JComponent)) {
      getComponent(0).setBounds(0, 0, getWidth(), getHeight());
    }
  }*/

  public void update (Graphics g) {
    paint(g);
  }

  /**
     Overrides <CODE>java.awt.Container.paint(Graphics g)</CODE>.
     Calls the paint method in the Container class if there is no Mwindow
     associated with this MPanel, otherwise processes a REFRESH message.
     @param g The Graphics object.
   */
  public void paint (Graphics g) {
/* Fix for Bug 1456
    Rectangle rect=null;
    try { rect = g.getClipBounds(); } catch (Exception e) { }
//System.out.println("Paint "+registryName+" "+MW+" "+rect);
    if (rect==null || rect.width<=1 || rect.height<=1) {
      // do nothing to our panels
    }
    else
END of Bug 1456 fix
*/
    if (MW == null) {
      Dimension d = this.getSize();
      g.setClip(0,0,d.width,d.height);
      g.drawRect(0,0,d.width,d.height);
      if (registryName!=null) g.drawString (registryName,10,20);
      needrefresh = true;
    }
    else {
      MW.process ("PAINT",0,g);
    }
    super.paint(g);	// make sure to paint children
  }

  /**
     Returns whether this MPanel can be focused.
     Overrides <CODE>java.awt.Component.isFocusable()</CODE>
     to return true in order to enable a java.awt.Panel as a KeyListener.
     @return true
  */
  public boolean isFocusable() { return true; }

  /**
     Overrides <CODE>java.awt.Container.add(Component comp)</CODE>.
     Adds the HelpKeyListener to any component added to this MPanel.
     @param comp The Component to be added.
   */
  public Component add (Component comp) {
    comp.addKeyListener(MW.hkl);
    return super.add(comp);
  }

  /**
     Overrides <CODE>java.awt.Container.add(String name, Component comp)</CODE>.
     Adds the HelpKeyListener to any component added to this MPanel.
     NOTE: This method is obsolete as of 1.1. Java recommends using the method
     add(Component, Object) instead.
     @param comp The Component to be added.
   */
  public Component add (String name, Component comp) {
    comp.addKeyListener(MW.hkl);
    return super.add(name, comp);
  }

  /**
     Overrides <CODE>java.awt.Container.add(Component comp, int index)</CODE>.
     Adds the HelpKeyListener to any component added to this MPanel.
     @param comp The Component to be added.
     @param index The position at which to insert the component, or -1 to append the component to the end.
   */
  public Component add (Component comp, int index) {
    comp.addKeyListener(MW.hkl);
    return super.add(comp, index);
  }

  /**
     Overrides <CODE>java.awt.Container.add(Component comp, Object constraints)</CODE>.
     Adds the HelpKeyListener to any component added to this MPanel.
     @param comp The Component to be added.
     @param constraints An object expressing layout constraints for this component.
   */
  public void add (Component comp, Object constraints) {
    comp.addKeyListener(MW.hkl);
    super.add(comp, constraints);
  }

  /**
     Overrides <CODE>java.awt.Container.add(Component comp, Object constraints, int index)</CODE>.
     Adds the HelpKeyListener to any component added to this MPanel.
     @param comp The Component to be added.
     @param constraints An object expressing layout constraints for this component.
     @param index The position at which to insert the component, or -1 to append the component to the end.
   */
  public void add (Component comp, Object constraints, int index) {
    comp.addKeyListener(MW.hkl);
    super.add(comp, constraints, index);
  }

  /**
     Overrides <CODE>java.awt.Container.remove(Component comp)</CODE>.
     Removes the HelpKeyListener from this component before removing
     it from this MPanel.
     @param comp The Component to be removed.
   */
  public void remove (Component comp) {
    if (MW != null) comp.removeKeyListener(MW.hkl);
    super.remove(comp);
  }

  public void removeNotify() {
    super.removeNotify(); // JC4: THIS LINE MUST BE FIRST!!! (see comments to Java Bug 4289940)
    if (false) { // <-- Allows patch to be easily turned on/off
      /* JC4: The AWT focus managers keep pointers to the last window/component to have focus
              until a new one comes along to take the focus. This allows MW to be cleaned up
              while waiting for the pointers to this instance to be broken.
              See MPanel.dispose() for more details.
       */
      removeAll(); // Clean up first - Needs MW to remove the help key listeners.
      //JC4: DO not set MW = null here (causes problem with Push/Pop) set it in MWindow.close()
    }
  }

  /** Overwrite default serialization for WriteObject
   *  to throw an UnsupportedOperationException since Java Serialization is not supported
   *
   *  @param oos Object Output Stream
   *  @throws IOException Exception thrown by writeObject
   */
  private void writeObject (ObjectOutputStream oos) throws IOException {
    throw new UnsupportedOperationException(UNSERIALIZABLE_MPANEL_OBJECT_MESSAGE);
  }

  /** Overwrite default deserialization for ReadObject
   *  to throw an UnsupportedOperationException since Java Serialization is not supported
   *
   *  @param ois Object Input Stream
   *  @throws ClassNotFoundException Exception thrown by readObject
   *  @throws IOException Exception thrown by readObject
   */
  private void readObject (ObjectInputStream ois) throws IOException, ClassNotFoundException {
    throw new UnsupportedOperationException(UNSERIALIZABLE_MPANEL_OBJECT_MESSAGE);
  }
}
