// Make sure the XWiki 'namespace' exists.
if(typeof(XWiki) == 'undefined') {
  XWiki = new Object();
}

// Make sure the widgets 'namespace' exists.
if(typeof(XWiki.widgets) == 'undefined') {
  XWiki.widgets = new Object();
}

XWiki.widgets.ModalPopup = Class.create({
  /** Configuration. */
  options : {
    title : "",
    displayCloseButton : true,
    screenColor : "#000",
    borderColor : "#333",
    titleColor : "#333",
    backgroundColor : "#EEE",
    screenOpacity : "0.5",
    verticalPosition : "center",
    horizontalPosition : "center"
  },
  /** Constructor. Registers the key listener that pops up the dialog. */
  initialize : function(content, shortcuts, options) {
    /** Shortcut configuration. Action name -&gt; {method: function(evt), keys: string[]}. */
    this.shortcuts = {
      "show" : { method : this.showDialog, keys : ['Ctrl+G', 'Meta+G']},
      "close" : { method : this.closeDialog, keys : ['Esc']}
    },

    this.content = content || "Hello world!";
    // Add the new shortcuts
    this.shortcuts = Object.extend(Object.clone(this.shortcuts), shortcuts || { });
    // Add the custom options
    this.options = Object.extend(Object.clone(this.options), options || { });
    // Register a shortcut for showing the dialog.
    this.registerShortcuts("show");
  },
  /** Create the dialog, if it is not already loaded. Otherwise, just make it visible again. */
  createDialog : function(event) {
    this.dialog = new Element('div', {'class': 'xdialog-modal-container'});
    // A full-screen semi-transparent screen covering the main document
    var screen = new Element('div', {'class': 'xdialog-screen'}).setStyle({
      opacity : this.options.screenOpacity,
      backgroundColor : this.options.screenColor
    });
    this.dialog.update(screen);
    // The dialog chrome
    this.dialogBox = new Element('div', {'class': 'xdialog-box'});
    // Insert the content
    this.dialogBox._x_contentPlug = new Element('div');
    this.dialogBox.update(this.dialogBox._x_contentPlug);
    this.dialogBox._x_contentPlug.update(this.content);
    // Add the dialog title
    if (this.options.title) {
      var title = new Element('div', {'class': 'xdialog-title'}).update(this.options.title);
      title.setStyle({"color" : this.options.titleColor});
      this.dialogBox.insertBefore(title, this.dialogBox.firstChild);
    }
    // Add the close button
    if (this.options.displayCloseButton) {
      var closeButton = new Element('div', {'class': 'xdialog-close', 'title': 'Close'}).update("X");
      closeButton.setStyle({"color": this.options.titleColor});
      closeButton.observe("click", this.closeDialog.bindAsEventListener(this));
      this.dialogBox.insertBefore(closeButton, this.dialogBox.firstChild);
    }
    this.dialog.appendChild(this.dialogBox);
    this.dialogBox.setStyle({
      "textAlign": "left",
      "borderColor": this.options.borderColor,
      "backgroundColor" : this.options.backgroundColor
    });
    switch(this.options.verticalPosition) {
      case "top":
        this.dialogBox.setStyle({"top": "0"});
        break;
      case "bottom":
        this.dialogBox.setStyle({"bottom": "0"});
        break;
      default:
        // TODO: smart alignment according to the actual height
        this.dialogBox.setStyle({"top": "35%"});
        break;
    }
    switch(this.options.horizontalPosition) {
      case "left":
        this.dialog.setStyle({"textAlign": "left"});
        break;
      case "right":
        this.dialog.setStyle({"textAlign": "right"});
        break;
      default:
        this.dialog.setStyle({"textAlign": "center"});
        this.dialogBox.setStyle({"margin": "auto"});
      break;
    }
    // Append to the end of the document body.
    document.body.appendChild(this.dialog);
    this.dialog.hide();
  },
  /** Set a class name to the dialog box */
  setClass : function(className) {
    this.dialogBox.addClassName('xdialog-box-' + className);
  },
  /** Remove a class name from the dialog box */
  removeClass : function(className) {
    this.dialogBox.removeClassName('xdialog-box-' + className);
  },
  /** Set the content of the dialog box */
  setContent : function(content) {
     this.content = content;
     this.dialogBox._x_contentPlug.update(this.content);
  },
  /** Called when the dialog is displayed. Enables the key listeners and gives focus to the (cleared) input. */
  showDialog : function(event) {
    if (event) {
      Event.stop(event);
    }
    // Only do this if the dialog is not already active.
    if (!XWiki.widgets.ModalPopup.active) {
      XWiki.widgets.ModalPopup.active = true;
      if (!this.dialog) {
        // The dialog wasn't loaded, create it.
        this.createDialog();
      }
      // Start listening to keyboard events
      this.attachKeyListeners();
      // In IE, position: fixed does not work.
      if (Prototype.Browser.IE) {
        this.dialog.setStyle({top : document.viewport.getScrollOffsets().top + "px"});
        this.dialog._x_scrollListener = this.onScroll.bindAsEventListener(this);
        Event.observe(window, "scroll", this.dialog._x_scrollListener);
        $$("select").each(function(item) {
          item._x_initiallyVisible = item.style.visibility;
          item.style.visibility = 'hidden';
        });
      }
      // Display the dialog
      this.dialog.show();
    }
  },
  onScroll : function(event) {
    this.dialog.setStyle({top : document.viewport.getScrollOffsets().top + "px"});
  },
  /** Called when the dialog is closed. Disables the key listeners, hides the UI and re-enables the 'Show' behavior. */
  closeDialog : function(event) {
    if (event) {
      Event.stop(event);
    }
    if (Prototype.Browser.IE) {
      Event.stopObserving(window, "scroll", this.dialog._x_scrollListener);
      $$("select").each(function(item) {
        item.style.visibility = item._x_initiallyVisible;
      });
    }
    // Hide the dialog, without removing it from the DOM.
    this.dialog.hide();
    // Stop the UI shortcuts (except the initial Show Dialog one).
    this.detachKeyListeners();
    // Re-enable the 'show' behavior.
    XWiki.widgets.ModalPopup.active = false;
  },
  /** Enables all the keyboard shortcuts, except the one that opens the dialog, which is already enabled. */
  attachKeyListeners : function() {
    for (var action in this.shortcuts) {
      if (action != "show") {
        this.registerShortcuts(action);
      }
    }
  },
  /** Disables all the keyboard shortcuts, except the one that opens the dialog. */
  detachKeyListeners : function() {
    for (var action in this.shortcuts) {
      if (action != "show") {
        this.unregisterShortcuts(action);
      }
    }
  },
  /**
   * Enables the keyboard shortcuts for a specific action.
   *
   * @param {String} action The action to register
   * {@see #shortcuts}
   */
  registerShortcuts : function(action) {
    var shortcuts = this.shortcuts[action].keys;
    var method = this.shortcuts[action].method;
    for (var i = 0; i < shortcuts.size(); ++i) {
      if (Prototype.Browser.IE || Prototype.Browser.WebKit) {
        shortcut.add(shortcuts[i], method.bindAsEventListener(this, action), {type: 'keyup'});
      } else {
        shortcut.add(shortcuts[i], method.bindAsEventListener(this, action), {type: 'keypress'});
      }
    }
  },
  /**
   * Disables the keyboard shortcuts for a specific action.
   * 
   * @param {String} action The action to unregister {@see #shortcuts}
   */
  unregisterShortcuts : function(action) {
    for (var i = 0; i < this.shortcuts[action].keys.size(); ++i) {
      shortcut.remove(this.shortcuts[action].keys[i]);
    }
  },
  createButton : function(type, text, title, id) {
    var wrapper = new Element("span", {"class" : "buttonwrapper"});
    var button = new Element("input", {
      "type" : type,
      "class" : "button",
      "value" : text,
      "title" : title,
      "id" : id
    });
    wrapper.update(button);
    return wrapper;
  }
});
/** Whether or not the dialog is already active (or activating). */
XWiki.widgets.ModalPopup.active = false;

// When the document is loaded, enable the keyboard listener that triggers the dialog.
// document.observe("xwiki:dom:loaded", function() {
//   new XWiki.widgets.ModalPopup("An example dialog",
//     { "show" : { method : "this.createDialog", keys : ['Ctrl+Y', 'Meta+Y']} },
//     { title: "Example", titleColor: "#369", borderColor: "#369", screenColor: "#FFF" }
//   );
// });