//////////////////////////////////////////////////////////////////////////
//
// pgAdmin 4 - PostgreSQL Tools
//
// Copyright (C) 2013 - 2021, The pgAdmin Development Team
// This software is released under the PostgreSQL Licence
//
//////////////////////////////////////////////////////////////////////////

import $ from 'jquery';
import gettext from 'sources/gettext';
import { getMod } from 'sources/utils';

const PERIOD_KEY = 190,
  FWD_SLASH_KEY = 191,
  ESC_KEY = 27,
  LEFT_KEY = 37,
  UP_KEY = 38,
  RIGHT_KEY = 39,
  DOWN_KEY = 40,
  K_KEY = 75;

function isMac() {
  return window.navigator.platform.search('Mac') != -1;
}

function isKeyCtrlAlt(event) {
  return event.ctrlKey || event.altKey;
}

function isKeyAltShift(event) {
  return event.altKey || event.shiftKey;
}

function isKeyCtrlShift(event) {
  return event.ctrlKey || event.shiftKey;
}

function isKeyCtrlAltShift(event) {
  return event.ctrlKey || event.altKey || event.shiftKey;
}

function isAltShiftBoth(event) {
  return event.altKey && event.shiftKey && !event.ctrlKey;
}

function isCtrlShiftBoth(event) {
  return event.ctrlKey && event.shiftKey && !event.altKey;
}

function isCtrlAltBoth(event) {
  return event.ctrlKey && event.altKey && !event.shiftKey;
}

/* Returns the key of shortcut */
function shortcut_key(shortcut) {
  let key = '';
  if(shortcut['key'] && shortcut['key']['char']) {
    key = shortcut['key']['char'].toUpperCase();
  }
  return key;
}

/* Converts shortcut object to title representation
 * Shortcut object is browser.get_preference().value
 */
function shortcut_title(title, shortcut) {
  let text_representation = '';

  if (typeof shortcut === 'undefined' || shortcut === null) {
    return text_representation;
  }
  if(shortcut['alt']) {
    text_representation = gettext('Alt') + '+';
  }
  if(shortcut['shift']) {
    text_representation += gettext('Shift') + '+';
  }
  if(shortcut['control']) {
    text_representation += gettext('Ctrl') + '+';
  }
  text_representation += shortcut_key(shortcut);

  return `${title} (${text_representation})`;
}

/* Returns the key char of shortcut
 * shortcut object is browser.get_preference().value
 */
function shortcut_accesskey_title(title, shortcut) {
  return `${title} (` + gettext('accesskey') + ` + ${shortcut_key(shortcut)})`;
}


function _stopEventPropagation(event) {
  event.cancelBubble = true;
  event.preventDefault();
  event.stopPropagation();
  event.stopImmediatePropagation();
}

/* Function use to validate shortcut keys */
function validateShortcutKeys(user_defined_shortcut, event) {
  if(!user_defined_shortcut) {
    return false;
  }

  let keyCode = event.which || event.keyCode;
  return user_defined_shortcut.alt == event.altKey &&
    user_defined_shortcut.shift == event.shiftKey &&
    user_defined_shortcut.control == event.ctrlKey &&
    user_defined_shortcut.key.key_code == keyCode;
}

// Finds the desired panel on which user wants to navigate to
function focusDockerPanel(docker, op) {
  if(!docker) {
    return;
  }

  // If no frame in focus, focus the first one
  if(!docker._focusFrame) {
    if(docker._frameList.length == 0 && docker._frameList[0]._panelList.length == 0) {
      return;
    }
    docker._frameList[0]._panelList[docker._frameList[0]._curTab].focus();
  }

  let focus_frame = docker._focusFrame,
    focus_id = 0,
    flash = false;

  // Mod is used to cycle the op
  if (op == 'switch') {
    let i, total_frames = docker._frameList.length;

    for(i = 0; i < total_frames; i++) {
      if(focus_frame === docker._frameList[i]) break;
    }
    focus_frame = docker._frameList[getMod(i+1,total_frames)];
    focus_id = focus_frame._curTab;
    flash = true;
  } else if (op == 'left') {
    focus_id = getMod(focus_frame._curTab-1, focus_frame._panelList.length);
  } else if (op == 'right') {
    focus_id = getMod(focus_frame._curTab+1, focus_frame._panelList.length);
  }

  let focus_panel = focus_frame._panelList[focus_id];

  focus_panel.$container.find('*[tabindex]:not([tabindex="-1"])').trigger('focus');
  focus_panel.focus(flash);
  return focus_panel._type;
}

/* Debugger: Keyboard Shortcuts handling */
function keyboardShortcutsDebugger($el, event, preferences, docker) {
  let panel_type = '', panel_content, $input;

  if(this.validateShortcutKeys(preferences.edit_grid_values, event)) {
    this._stopEventPropagation(event);
    panel_content = $el.find(
      'div.wcPanelTabContent:not(".wcPanelTabContentHidden")'
    );
    if(panel_content.length) {
      $input = $(panel_content).find('td.editable:first');
      if($input.length)
        $input.trigger('click');
    }
  } else if(this.validateShortcutKeys(preferences.move_next, event)) {
    this._stopEventPropagation(event);
    panel_type = focusDockerPanel(docker, 'right');
  } else if(this.validateShortcutKeys(preferences.move_previous, event)) {
    this._stopEventPropagation(event);
    panel_type = focusDockerPanel(docker, 'left');
  } else if(this.validateShortcutKeys(preferences.switch_panel, event)) {
    this._stopEventPropagation(event);
    panel_type = focusDockerPanel(docker, 'switch');
  }
  return panel_type;
}

/* Query tool: Keyboard Shortcuts handling */
function keyboardShortcutsQueryTool(
  sqlEditorController, queryToolActions, event, docker
) {
  if (sqlEditorController.isQueryRunning()) {
    return;
  }
  let keyCode = event.which || event.keyCode, panel_type = '';
  let executeKeys = sqlEditorController.preferences.execute_query;
  let explainKeys = sqlEditorController.preferences.explain_query;
  let explainAnalyzeKeys = sqlEditorController.preferences.explain_analyze_query;
  let downloadCsvKeys = sqlEditorController.preferences.download_results;
  let nextTabKeys = sqlEditorController.preferences.move_next;
  let previousTabKeys = sqlEditorController.preferences.move_previous;
  let switchPanelKeys = sqlEditorController.preferences.switch_panel;
  let toggleCaseKeys = sqlEditorController.preferences.toggle_case;
  let commitKeys = sqlEditorController.preferences.commit_transaction;
  let rollbackKeys = sqlEditorController.preferences.rollback_transaction;
  let saveDataKeys = sqlEditorController.preferences.save_data;
  let queryToolKeys = sqlEditorController.preferences.show_query_tool;

  if (this.validateShortcutKeys(executeKeys, event)) {
    this._stopEventPropagation(event);
    queryToolActions.executeQuery(sqlEditorController);
  } else if (this.validateShortcutKeys(explainKeys, event)) {
    this._stopEventPropagation(event);
    queryToolActions.explain(sqlEditorController);
  } else if (this.validateShortcutKeys(explainAnalyzeKeys, event)) {
    this._stopEventPropagation(event);
    queryToolActions.explainAnalyze(sqlEditorController);
  } else if (this.validateShortcutKeys(downloadCsvKeys, event)) {
    if(!sqlEditorController.is_save_results_to_file_disabled) {
      this._stopEventPropagation(event);
      queryToolActions.download(sqlEditorController);
    }
  } else if (this.validateShortcutKeys(toggleCaseKeys, event)) {
    this._stopEventPropagation(event);
    queryToolActions.toggleCaseOfSelectedText(sqlEditorController);
  } else if (this.validateShortcutKeys(commitKeys, event)) {
    // If transaction buttons are disabled then no need to execute commit.
    if (!sqlEditorController.is_transaction_buttons_disabled) {
      this._stopEventPropagation(event);
      queryToolActions.executeCommit(sqlEditorController);
    }
  } else if (this.validateShortcutKeys(rollbackKeys, event)) {
    // If transaction buttons are disabled then no need to execute rollback.
    if (!sqlEditorController.is_transaction_buttons_disabled) {
      this._stopEventPropagation(event);
      queryToolActions.executeRollback(sqlEditorController);
    }
  } else if (this.validateShortcutKeys(saveDataKeys, event)) {
    this._stopEventPropagation(event);
    queryToolActions.saveDataChanges(sqlEditorController);
  } else if (this.validateShortcutKeys(queryToolKeys, event)) {
    this._stopEventPropagation(event);
    queryToolActions.openQueryTool(sqlEditorController);
  } else if ((
    (this.isMac() && event.metaKey) ||
     (!this.isMac() && event.ctrlKey)
  ) && !event.altKey && event.shiftKey && keyCode === FWD_SLASH_KEY) {
    this._stopEventPropagation(event);
    queryToolActions.commentBlockCode(sqlEditorController);
  } else if ((
    (this.isMac() && !this.isKeyCtrlAltShift(event) && event.metaKey) ||
     (!this.isMac() && !this.isKeyAltShift(event) && event.ctrlKey)
  ) && keyCode === FWD_SLASH_KEY) {
    this._stopEventPropagation(event);
    queryToolActions.commentLineCode(sqlEditorController);
  } else if ((
    (this.isMac() && !this.isKeyCtrlAltShift(event) && event.metaKey) ||
     (!this.isMac() && !this.isKeyAltShift(event) && event.ctrlKey)
  ) && keyCode === PERIOD_KEY) {
    this._stopEventPropagation(event);
    queryToolActions.uncommentLineCode(sqlEditorController);
  } else if ((
    (this.isMac() && event.metaKey) ||
     (!this.isMac() && event.ctrlKey)
  ) && !event.altKey && event.shiftKey && keyCode === K_KEY) {
    this._stopEventPropagation(event);
    queryToolActions.formatSql(sqlEditorController);
  }  else if (keyCode == ESC_KEY) {
    queryToolActions.focusOut(sqlEditorController);
    /*Apply only for sub-dropdown*/
    if($(event.target).hasClass('dropdown-item')
        && $(event.target).closest('.dropdown-submenu').length > 0) {
      $(event.target).closest('.dropdown-submenu').find('.dropdown-menu').removeClass('show');
    }
  } else if(this.validateShortcutKeys(nextTabKeys, event)) {
    this._stopEventPropagation(event);
    panel_type = focusDockerPanel(docker, 'right');
  } else if(this.validateShortcutKeys(previousTabKeys, event)) {
    this._stopEventPropagation(event);
    panel_type = focusDockerPanel(docker, 'left');
  } else if(this.validateShortcutKeys(switchPanelKeys, event)) {
    this._stopEventPropagation(event);
    panel_type = focusDockerPanel(docker, 'switch');
  } else if(keyCode === UP_KEY || keyCode === DOWN_KEY) {
    /*Apply only for dropdown*/
    if($(event.target).closest('.dropdown-menu').length > 0) {
      this._stopEventPropagation(event);
      let currLi = $(event.target).closest('li');
      /*close all the submenus on movement*/
      $(event.target).closest('.dropdown-menu').find('.show').removeClass('show');

      if(keyCode === UP_KEY) {
        currLi = currLi.prev();
      }
      else if(keyCode === DOWN_KEY){
        currLi = currLi.next();
      }

      /*do not focus on divider, disabled and d-none */
      while(currLi.hasClass('dropdown-divider')
        || currLi.hasClass('d-none')
        || currLi.find('.dropdown-item').first().hasClass('disabled')) {
        if(keyCode === UP_KEY) {
          currLi = currLi.prev();
        }
        else if(keyCode === DOWN_KEY){
          currLi = currLi.next();
        }
      }
      currLi.find('.dropdown-item').trigger('focus');
    }
  } else if(keyCode === LEFT_KEY || keyCode === RIGHT_KEY) {
    /*Apply only for dropdown*/
    if($(event.target).closest('.dropdown-menu').length > 0) {
      this._stopEventPropagation(event);
      let currLi = $(event.target).closest('li');

      if(keyCode === RIGHT_KEY) {
        /*open submenu if any*/
        if(currLi.hasClass('dropdown-submenu')){
          currLi.find('.dropdown-menu').addClass('show');
          currLi.find('.dropdown-menu .dropdown-item').first().trigger('focus');
        }
      } else if(keyCode === LEFT_KEY) {
        /*close submenu*/
        let currMenu = currLi.closest('.dropdown-menu');
        if(currMenu.closest('.dropdown-submenu').length > 0) {
          currMenu.removeClass('show');
          currLi = currMenu.closest('.dropdown-submenu');
          currLi.find('.dropdown-item').trigger('focus');
        }
      }
    }
  } else {
    // Macros
    let macroId = this.validateMacros(sqlEditorController, event);

    if  (macroId !== false) {
      this._stopEventPropagation(event);
      queryToolActions.executeMacro(sqlEditorController, macroId);
    }
  }

  return panel_type;
}

function validateMacros(sqlEditorController, event) {
  let keyCode = event.which || event.keyCode;

  let macro = sqlEditorController.macros.filter(mc =>
    mc.alt == event.altKey &&
    mc.control  == event.ctrlKey &&
    mc.key_code == keyCode);

  if (macro.length == 1) {
    return macro[0].id;
  }

  return false;
}

export {
  keyboardShortcutsDebugger as processEventDebugger,
  keyboardShortcutsQueryTool as processEventQueryTool,
  focusDockerPanel, validateShortcutKeys, validateMacros,
  _stopEventPropagation, isMac, isKeyCtrlAlt, isKeyAltShift, isKeyCtrlShift,
  isKeyCtrlAltShift, isAltShiftBoth, isCtrlShiftBoth, isCtrlAltBoth,
  shortcut_key, shortcut_title, shortcut_accesskey_title,
};
