/*                     __                                               *\
**     ________ ___   / /  ___     Scala API                            **
**    / __/ __// _ | / /  / _ |    (c) 2007-2010, LAMP/EPFL             **
**  __\ \/ /__/ __ |/ /__/ __ |    http://scala-lang.org/               **
** /____/\___/_/ |_/____/_/ | |                                         **
**                          |/                                          **
\*                                                                      */



package scala.swing

import java.awt.{Window => AWTWindow, Frame => AWTFrame}
import javax.swing._
import Swing._

object RichWindow {
  /**
   * Mixin this trait if you want an undecorated window.
   */
  trait Undecorated extends RichWindow {
    // we do a mixin here, since setUndecorated is only allowed to be called
    // when the component is not displayable.
    peer.setUndecorated(true) 
  }
}

/**
 * A window that adds some functionality to the plain Window class and serves as 
 * the common base class for frames and dialogs.
 * 
 * Implementation note: this class is sealed since we need to know that a rich
 * window is either a dialog or a frame at some point.
 */
sealed trait RichWindow extends Window {
  def peer: AWTWindow with InterfaceMixin
  
  trait InterfaceMixin extends super.InterfaceMixin {
    def getJMenuBar: JMenuBar
    def setJMenuBar(b: JMenuBar)
    def setUndecorated(b: Boolean)
    def setTitle(s: String)
    def getTitle: String
    def setResizable(b: Boolean)
    def isResizable: Boolean
  }
  
  def title: String = peer.getTitle
  def title_=(s: String) = peer.setTitle(s)
  
  /**
   * The menu bar of this frame or `NoMenuBar` if no menu bar is set.
   */
  def menuBar: MenuBar = {
      val m = UIElement.cachedWrapper[MenuBar](peer.getJMenuBar)
      if (m != null) m else MenuBar.NoMenuBar 
  }
  /**
   * Set the current menu bar of this frame. Pass `NoMenuBar` if this frame 
   * should not show a menu bar.
   */
  def menuBar_=(m: MenuBar) = 
    peer.setJMenuBar(if(m == MenuBar.NoMenuBar) null else m.peer)
  
  def resizable_=(b: Boolean) { peer.setResizable(b) }
  def resizable = peer.isResizable
}

/**
 * A window with decoration such as a title, border, and action buttons.
 * 
 * An AWT window cannot be wrapped dynamically with this class, i.e., you cannot 
 * write something like new Window { def peer = myAWTWindow }
 * 
 * @see javax.swing.JFrame
 */
class Frame extends RichWindow {
  override lazy val peer: JFrame with InterfaceMixin = new JFrame with InterfaceMixin with SuperMixin
  
  protected trait SuperMixin extends JFrame {
    override protected def processWindowEvent(e: java.awt.event.WindowEvent) {
      super.processWindowEvent(e)
      if (e.getID() == java.awt.event.WindowEvent.WINDOW_CLOSING)
        closeOperation()
    }
  }

  def iconify() { peer.setExtendedState(peer.getExtendedState | AWTFrame.ICONIFIED) }
  def uniconify() { peer.setExtendedState(peer.getExtendedState & ~AWTFrame.ICONIFIED) }
  def iconified() { (peer.getExtendedState & AWTFrame.ICONIFIED) != 0 }
  def maximize() { peer.setExtendedState(peer.getExtendedState | AWTFrame.MAXIMIZED_BOTH) }
  def unmaximize() { peer.setExtendedState(peer.getExtendedState & ~AWTFrame.MAXIMIZED_BOTH) }
  def maximized() { (peer.getExtendedState & AWTFrame.MAXIMIZED_BOTH) != 0 }
  
  def iconImage: Image = peer.getIconImage
  def iconImage_=(i: Image) { peer.setIconImage(i) }
}

/**
 * Simple predefined dialogs.
 * 
 * @see javax.swing.JOptionPane
 */
object Dialog {
  /**
   * The message type of a dialog.
   */
  object Message extends Enumeration {
    val Error = Value(JOptionPane.ERROR_MESSAGE)
    val Info = Value(JOptionPane.INFORMATION_MESSAGE)
    val Warning = Value(JOptionPane.WARNING_MESSAGE)
    val Question = Value(JOptionPane.QUESTION_MESSAGE)
    val Plain = Value(JOptionPane.PLAIN_MESSAGE)
  }
  
  /**
   * The possible answers a user can select.
   */
  object Options extends Enumeration {
    val Default = Value(JOptionPane.DEFAULT_OPTION)
    val YesNo = Value(JOptionPane.YES_NO_OPTION)
    val YesNoCancel = Value(JOptionPane.YES_NO_CANCEL_OPTION)
    val OkCancel = Value(JOptionPane.OK_CANCEL_OPTION)
  }
  
  /**
   * The selected result of dialog.
   */
  object Result extends Enumeration {
    val Yes = Value(JOptionPane.YES_OPTION)
    val Ok = Yes
    val No = Value(JOptionPane.NO_OPTION)
    val Cancel = Value(JOptionPane.CANCEL_OPTION)
    val Closed = Value(JOptionPane.CLOSED_OPTION)
  }
  
  private def uiString(txt: String) = UIManager.getString(txt)
  
  def showConfirmation(parent: Component = null,
                       message: Any, 
                       title: String = uiString("OptionPane.titleText"), 
                       optionType: Options.Value = Options.YesNo, 
                       messageType: Message.Value = Message.Question, 
                       icon: Icon = EmptyIcon): Result.Value =
     Result(JOptionPane.showConfirmDialog(nullPeer(parent), message, title, 
                                   optionType.id, messageType.id, Swing.wrapIcon(icon)))
  
  def showOptions(parent: Component = null, 
                  message: Any, 
                  title: String = uiString("OptionPane.titleText"),  
                  optionType: Options.Value = Options.YesNo, 
                  messageType: Message.Value = Message.Question, 
                  icon: Icon = EmptyIcon, 
                  entries: Seq[Any], 
                  initial: Int): Result.Value = {
    val r = JOptionPane.showOptionDialog(nullPeer(parent), message, title, 
                                   optionType.id, messageType.id, Swing.wrapIcon(icon), 
                                   entries map toAnyRef toArray, entries(initial))
    Result(r)
  }

  def showInput[A](parent: Component = null, 
                   message: Any, 
                   title: String = uiString("OptionPane.inputDialogTitle"),
                   messageType: Message.Value = Message.Question, 
                   icon: Icon = EmptyIcon, 
                   entries: Seq[A] = Nil, 
                   initial: A): Option[A] = {
    val e = if (entries.isEmpty) null
            else entries map toAnyRef toArray
    val r = JOptionPane.showInputDialog(nullPeer(parent), message, title,
        messageType.id, Swing.wrapIcon(icon), 
        e, initial)
        
    toOption[A](r)
  }
  def showMessage(parent: Component = null, 
                  message: Any, 
                  title: String = uiString("OptionPane.messageDialogTitle"), 
                  messageType: Message.Value = Message.Info, 
                  icon: Icon = EmptyIcon) {
     JOptionPane.showMessageDialog(nullPeer(parent), message, title, 
                                   messageType.id, Swing.wrapIcon(icon))
  }
}

/**
 * A dialog window.
 * 
 * @see javax.swing.JDialog
 */
class Dialog(owner: Window) extends RichWindow {
  override lazy val peer: JDialog with InterfaceMixin = 
    if (owner == null) new JDialog with InterfaceMixin
    else owner match {
      case f: Frame => new JDialog(f.peer) with InterfaceMixin
      case d: Dialog => new JDialog(d.peer) with InterfaceMixin
    }
  
  def this() = this(null)
  
  def modal_=(b: Boolean) { peer.setModal(b) }
  def modal = peer.isModal
}

