/*
 * debugger.io: An interactive web scripting sandbox
 *
 * popup.js: template-able popup windows
 */

define([
  'config', 'utils', 'jquery', 'underscore',
  'bus', 'keys', 'templates'
],
function(config, utils, $, _, bus, keys, templates) {
  'use strict';

  var popups = utils.module('popups');
  var popupEl = '#popup';
  var popupKeyHander;

  /**
   *
   */
  popups.Popup = Backbone.Model.extend({
    defaults: { small: false, title: 'Popup' }
  });

  /**
   *
   */
  popups.PopupView = Backbone.View.extend({
    el: popupEl,

    initialize: function(options) {
      var that = this;

      this.render();

      popupKeyHander = keys.register_handler({ key: 'esc' }, function(e) {
        that.destroy();
      });
    },

    events: {
      'click': function(e) {
        // only destroy the popup if the background area is clicked
        if ($(e.target).is(popupEl)) { this.destroy(); }
      }
    },

    destroy: function() {
      var that = this;
      keys.unregister_handler(popupKeyHander);

      popups.hide().always(function() {
        // View.remove would call $el.remove, we want to reuse it
        that.$el.empty();
        that.stopListening();
        that.undelegateEvents();
        // FIXME: need to navigate away now?
      });
    },

    render: function() {
      var that = this;

      var popup_p = templates.get('popup', this);
      var content_p = templates.get(this.template, this);
      var template_fns = $.when(popup_p, content_p);

      template_fns.done(function(popup_fn, content_fn) {
        var that = _.first(utils.ensure_array(this));

        var data = that.model.toJSON();

        var contentHtml = content_fn({ data: data });
        var popupHtml = popup_fn({
          small: !!data.small,
          title: data.title,
          content: contentHtml,
          name: _.sprintf('%s-outer', that.template)
        });

        // remove any existing popups first
        popups.hide().done(function() {
          that.$el.html(popupHtml);
          popups.show().done(function() {
            if (_.isFunction(that.post_render)) { that.post_render(); }
          });
        });

      }).fail(function(err) {
        var that = _.first(utils.ensure_array(this));
        var msg = _.sprintf('Error rendering "%s" - %s', that.template, err);
        console.error(msg);
      });

      return this;
    }
  });

  /**
   *
   */
  popups.LoginPopup = popups.Popup.extend({
    defaults: { small: true, title: 'Login to debugger.io' }
  });

  /**
   *
   */
  popups.LoginPopupView = popups.PopupView.extend({
    template: 'popup-login',

    initialize: function(options) {
      this.events = _.extend({}, this.events, this._events);
      this.constructor.__super__.initialize.apply(this, arguments);
    },

    _events: {
      'submit #login_form': function(e) {
        var that = this;
        e.preventDefault();

        var $form = $(e.target);
        var uri = _.sprintf('%s?%s', $form.attr('action'), $form.serialize());
        var method = $form.attr('method') === 'post' ? 'post' : 'get';

        $[method](uri).done(function(username) {

          // welcome! do something.

          that.destroy();
        }).fail(function() {
          that.show_invalid_login();
        });
      }
    },

    post_render: function() {
      this.$el.find('input[name="username"]').focus();
    },

    show_invalid_login: function() {
      // FIXME
      console.error('INVALID LOGIN');
    }
  });

  /**
   * Build a popup and show it right away
   *
   * @param {String} name - name of the popup template to use
   */
  popups.build = function(name) {
    var modelName = _.sprintf('%sPopup', _.capitalize(_.camelize(name)));
    var viewName = _.sprintf('%sView', modelName);

    var modelConstructor = popups[modelName];
    var viewConstructor = popups[viewName];

    if (!modelConstructor || !viewConstructor) {
      console.error('popups.%s / popups.%s do not exist', modelName, viewName);
      return;
    }

    var model = new modelConstructor();
    var view = new viewConstructor({ model: model });
  };

  /**
   * Show the currently assigned popup
   *
   * @return {Promise} resolves to true after showing, or rejects to false
   */
  popups.show = function() {
    var d = $.Deferred();

    var $popup = $(popupEl);
    if (!$popup.length || $popup.is(':empty')) { d.reject(false); }
    else {
      $popup.show(function() {
        $popup.transition({ 'opacity': 1 }, function() {
          d.resolve(true);
        });
      });
    }

    return d.promise();
  };

  /**
   * Hide the currently visible popup
   *
   * @return {Promise} resolves to true after hiding, or rejects to false
   */
  popups.hide = function() {
    var d = $.Deferred();

    var $popup = $(popupEl);
    if (!$popup.length) { d.reject(false); }
    else {
      // popup is already hidden, don't wait to resolve
      if ($popup.css('opacity') === '0') { d.resolve(true); }
      else {
        $popup.transition({ 'opacity': 0 }, function() {
          $popup.hide();
          d.resolve(true);
        });
      }
    }

    return d.promise();
  };

  return popups;
});

@@ -612,24 +612,148 @@
 .render();%0A%0A
+      // remove popup on popups:destroy or Escape key%0A      bus.on('popups:destroy', function() %7B that.destroy(); %7D, this);%0A
       popupK
@@ -762,16 +762,24 @@
 Hander =
+%0A       
  keys.re
@@ -822,24 +822,16 @@
 ion(e) %7B
-%0A       
  that.de
@@ -838,22 +838,16 @@
 stroy();
-%0A     
  %7D);%0A   
@@ -1323,24 +1323,51 @@
 teEvents();%0A
+        bus.off_for(that);%0A
         // F
@@ -5279,16 +5279,145 @@
 ;%0A  %7D;%0A%0A
+  /**%0A   * Destroy the currently visible popup(s)%0A   */%0A  popups.destroy = function() %7B%0A    bus.trigger('popups:destroy');%0A  %7D;%0A%0A
   return

Add `popups.destroy` for destroying any visible popups