// Copyright (c) Jupyter Development Team.
// Distributed under the terms of the Modified BSD License.

define(function(require){
    "use strict";

    var QH = require("notebook/js/quickhelp");
    var $ = require("jquery");

    /**
     * Humanize the action name to be consumed by user.
     * internaly the actions anem are of the form
     * <namespace>:<description-with-dashes>
     * we drop <namesapce> and replace dashes for space.
     */
    var humanize_action_id = function(str) {
      return str.split(':')[1].replace(/-/g, ' ').replace(/_/g, '-');
    };

    /**
     * given an action id return 'command-shortcut', 'edit-shortcut' or 'no-shortcut'
     * for the action. This allows us to tag UI in order to visually distinguish
     * wether an action have a keybinding or not.
     **/
    var get_mode_for_action_id = function(name, notebook) {
      var shortcut = notebook.keyboard_manager.command_shortcuts.get_action_shortcut(name);
      if (shortcut) {
        return 'command-shortcut';
      }
      shortcut = notebook.keyboard_manager.edit_shortcuts.get_action_shortcut(name);
      if (shortcut) {
        return 'edit-shortcut';
      }
      return 'no-shortcut';
    };

    var CommandPalette = function(notebook) {
        if(!notebook){
          throw new Error("CommandPalette takes a notebook non-null mandatory arguement");
        }

        // typeahead lib need a specific layout with specific class names.
        // the following just does that
        var form = $('<form/>');
        var container = $('<div/>').addClass('typeahead-container');
        var field = $('<div/>').addClass('typeahead-field');
        var input = $('<input/>').attr('type', 'search');

        field
          .append(
            $('<span>').addClass('typeahead-query').append(
              input
            )
          )
          .append(
            $('<span/>').addClass('typeahead-button').append(
              $('<button/>').attr('type', 'submit').append(
                $('<span/>').addClass('typeahead-search-icon')
              )
            )
          );

        container.append(field);
        form.append(container);


        var mod = $('<div/>').addClass('modal cmd-palette').append(
          $('<div/>').addClass('modal-dialog')
          .append(
            $('<div/>').addClass('modal-content').append(
              $('<div/>').addClass('modal-body')
              .append(
                form
              )
            )
          )
        )
        // end setting up right layout
        .modal({show: false, backdrop:true})
        .on('shown.bs.modal', function () {
              // click on button trigger de-focus on mouse up.
              // or somethign like that.
              setTimeout(function(){input.focus();}, 100);
        });

        notebook.keyboard_manager.disable();

        var before_close = function() {
          // little trick to trigger early in onsubmit
          // when the action called pop-up a dialog
          // insure this function is only called once
          if (before_close.ok) {
            return;
          }
          var cell = notebook.get_selected_cell();
          if (cell) {
            cell.select();
          }
          if (notebook.keyboard_manager) {
            notebook.keyboard_manager.enable();
            notebook.keyboard_manager.command_mode();
          }
          before_close.ok = true; // avoid double call.
        };
        
        mod.on("hide.bs.modal", before_close);
        

        // will be trigger when user select action
        var onSubmit = function(node, query, result, resultCount) {
          if (actions.indexOf(result.key) >= 0) {
            before_close();
            notebook.keyboard_manager.actions.call(result.key);
          } else {
            console.warning("No command " + result.key);
          }
          mod.modal('hide');
        };

        /* Whenever a result is rendered, if there is only one resulting
         * element then automatically select that element.
         */
        var onResult = function(node, query, result, resultCount) {
            if (resultCount == 1) {
                requestAnimationFrame(function() {
                    $('.typeahead-list > li:nth-child(2)').addClass('active');
                });
            }
        };

        // generate structure needed for typeahead layout and ability to search
        var src = {};

        var actions = Object.keys(notebook.keyboard_manager.actions._actions);

        for (var i = 0; i < actions.length; i++) {
          var action_id = actions[i];
          var action = notebook.keyboard_manager.actions.get(action_id);
          var group = action_id.split(':')[0];

          src[group] = src[group] || {
            data: [],
            display: 'display'
          };

          var short = notebook.keyboard_manager.command_shortcuts.get_action_shortcut(action_id) ||
            notebook.keyboard_manager.edit_shortcuts.get_action_shortcut(action_id);
          if (short) {
            short = QH.humanize_sequence(short);
          }

          src[group].data.push({
            display: humanize_action_id(action_id),
            shortcut: short,
            mode_shortcut: get_mode_for_action_id(action_id, notebook),
            group: group,
            icon: action.icon,
            help: action.help,
            key: action_id,
          });
        }

        // now src is the right structure for typeahead

        input.typeahead({
          emptyTemplate: "No results found for <pre>{{query}}</pre>",
          maxItem: 1e3,
          minLength: 0,
          hint: true,
          group: ["group", "{{group}} command group"],
          searchOnFocus: true,
          mustSelectItem: true,
          template: '<i class="fa fa-icon {{icon}}"></i>{{display}}  <div class="pull-right {{mode_shortcut}}">{{shortcut}}</div>',
          order: "asc",
          source: src,
          callback: {
            onSubmit: onSubmit,
            onClickAfter: onSubmit,
            onResult: onResult
          },
          debug: false,
        });

        mod.modal('show');
    };
    return {'CommandPalette': CommandPalette};
});
