'use strict';

var utils = require('./utils.js');
var stringResources = require('./stringResources.js');
var command = require('./command.js');
var button = require('./components/button.js');
var toggleButton = require('./components/toggle-button.js');
var RCV = require('@progress/telerik-common-report-viewer');

function _interopNamespaceDefault(e) {
    var n = Object.create(null);
    if (e) {
        Object.keys(e).forEach(function (k) {
            if (k !== 'default') {
                var d = Object.getOwnPropertyDescriptor(e, k);
                Object.defineProperty(n, k, d.get ? d : {
                    enumerable: true,
                    get: function () { return e[k]; }
                });
            }
        });
    }
    n.default = e;
    return Object.freeze(n);
}

var RCV__namespace = /*#__PURE__*/_interopNamespaceDefault(RCV);

var defaultOptions = {};
const componentMap = {
  "button": button.Button,
  "toggle-button": toggleButton.ToggleButton
};
function replaceStringResources($search) {
  if (!$search) {
    return;
  }
  var $searchOptions = $search.find(".trv-search-dialog-search-options");
  var $searchStopButton = $search.find("button[data-command='telerik_ReportViewer_searchDialog_StopSearch']");
  var $searchMatchCaseButton = $search.find("button[data-command='telerik_ReportViewer_searchDialog_MatchCase']");
  var $searchMatchWholeWordButton = $search.find("button[data-command='telerik_ReportViewer_searchDialog_MatchWholeWord']");
  var $searchUseRegexButton = $search.find("button[data-command='telerik_ReportViewer_searchDialog_UseRegex']");
  var $searchNavigateUpButton = $search.find("button[data-command='telerik_ReportViewer_searchDialog_NavigateUp']");
  var $searchNavigateDownButton = $search.find("button[data-command='telerik_ReportViewer_searchDialog_NavigateDown']");
  replaceAttribute($search, "aria-label");
  replaceAttribute($searchOptions, "aria-label");
  replaceTitleAndAriaLabel($searchStopButton);
  replaceTitleAndAriaLabel($searchMatchCaseButton);
  replaceTitleAndAriaLabel($searchMatchWholeWordButton);
  replaceTitleAndAriaLabel($searchUseRegexButton);
  replaceTitleAndAriaLabel($searchNavigateUpButton);
  replaceTitleAndAriaLabel($searchNavigateDownButton);
}
function replaceTitleAndAriaLabel($a) {
  replaceAttribute($a, "title");
  replaceAttribute($a, "aria-label");
}
function replaceAttribute($el, attribute) {
  if ($el) {
    $el.attr(attribute, stringResources.stringResources[$el.attr(attribute)]);
  }
}
class Search {
  constructor(element, options, viewerOptions) {
    this.options = $.extend({}, defaultOptions, options);
    this.viewerOptions = viewerOptions;
    this.element = element;
    this.$element = $(element);
    this.reportViewerWrapper = $(`[data-selector='${this.viewerOptions.viewerSelector}']`);
    this.viewer = this.reportViewerWrapper.data("telerik_ReportViewer");
    this.controller = this.options.controller;
    this.notificationService = this.options.notificationService;
    this.initialized = false;
    this.kendoSearchDialog;
    this.kendoComboBox;
    this.resultsLabel;
    this.kendoListView;
    this.commands;
    this.searchManager;
    this.mruList = [];
    this.inputComboRebinding;
    this.searchMetadataRequested;
    this.searchMetadataLoaded;
    this.windowLocation;
    this.lastSearch = "";
    if (!this.controller) {
      throw "No controller (telerikReporting.ReportViewerController) has been specified.";
    }
    if (!this.notificationService) {
      throw "No notificationService (telerikReporting.NotificationService) has been specified.";
    }
    this.pagesAreaContainer = this.reportViewerWrapper.find('[data-id="trv-pages-area"]');
    this.searchManager = new RCV__namespace.SearchManager(this.pagesAreaContainer[0], this.controller);
    this.searchManager.on("searchComplete", this.updateResultsUI.bind(this));
    this.init();
  }
  init() {
    if (this.initialized) {
      return;
    }
    replaceStringResources(this.$element);
    this._initDialog();
    this._initSearchbox();
    this._initResultsArea();
    this._attachCommands();
    this._attachEvents();
    this.updateResultsUI(null);
    this.initialized = true;
  }
  _attachEvents() {
    this.controller.on("beginLoadReport", this.closeAndClear.bind(this)).on("viewModeChanged", this.closeAndClear.bind(this));
    this.notificationService.setSearchDialogVisible((event, args) => {
      this.toggleSearchDialog(args.visible);
    }).setSendEmailDialogVisible((event, args) => {
      if (args.visible && this.controller.getSearchInitiated()) {
        this.close();
      }
    });
    $(window).on("resize", () => {
      if (this.kendoSearchDialog && this.kendoSearchDialog.options.visible) {
        this.storeDialogPosition();
        this.adjustDialogPosition();
      }
    });
  }
  closeAndClear() {
    if (this.searchMetadataRequested) {
      return;
    }
    this.close();
    this.searchMetadataLoaded = false;
  }
  toggleSearchDialog(show) {
    this.controller.setSearchInitiated(show);
    if (show) {
      var searchMetadataOnDemand = this.viewerOptions.searchMetadataOnDemand;
      if (searchMetadataOnDemand && !this.searchMetadataLoaded) {
        this.searchMetadataRequested = true;
        this.controller.onAsync("reportLoadComplete", async () => {
          if (this.searchMetadataRequested) {
            this.open();
            this.searchMetadataRequested = false;
          }
        });
        this.controller.refreshReport(true);
        return;
      }
    }
    this.toggle(show);
  }
  open() {
    this.toggle(true);
  }
  close() {
    this.toggle(false);
  }
  toggle(show) {
    this.controller.setSearchInitiated(show);
    if (show) {
      this.searchMetadataLoaded = true;
      this.kendoSearchDialog.open();
    } else {
      this.searchManager.closeSearch();
      if (this.kendoSearchDialog && this.kendoSearchDialog.options.visible) {
        this.kendoSearchDialog.close();
      }
    }
  }
  _initSearchbox() {
    this.kendoComboBox = new kendo.ui.ComboBox(this.element.querySelector(".trv-search-dialog-input-box"), {
      placeholder: stringResources.stringResources.searchDialogCaptionText,
      dataTextField: "value",
      dataValueField: "value",
      dataSource: this.mruList,
      contentElement: "",
      change: this.kendoComboBoxSelect.bind(this),
      ignoreCase: false,
      // the actual search-when-typing performs on this event.
      filtering: this.onInputFiltering.bind(this),
      filter: "startswith",
      delay: 1e3,
      open: (event) => {
        if (this.inputComboRebinding) {
          event.preventDefault();
        }
      },
      select: this.processComboBoxEvent.bind(this)
    });
  }
  _initDialog() {
    this.kendoSearchDialog = new kendo.ui.Window(this.element, {
      title: stringResources.stringResources.searchDialogTitle,
      visible: false,
      height: 390,
      width: 310,
      minWidth: 310,
      minHeight: 390,
      maxHeight: 700,
      scrollable: false,
      close: (event) => {
        this.storeDialogPosition();
        this.kendoComboBox.value("");
        this.updateResultsUI(null);
        this.toggleErrorLabel(false, null);
        this.lastSearch = "";
      },
      open: (event) => {
        this.adjustDialogPosition();
      },
      deactivate: (event) => {
        this.notificationService.setSearchDialogVisible({
          visible: false
        });
      },
      activate: (event) => {
        this.kendoComboBox.input.focus();
      }
    });
    this.kendoSearchDialog.element.removeClass("trv-search-dialog k-hidden");
    this.kendoSearchDialog.wrapper.addClass("trv-search-dialog");
  }
  storeDialogPosition() {
    this.windowLocation = this.kendoSearchDialog.wrapper.offset();
  }
  adjustDialogPosition() {
    var windowWidth = $(window).innerWidth();
    var windowHeight = $(window).innerHeight();
    var width = this.kendoSearchDialog.wrapper.outerWidth(true);
    var height = this.kendoSearchDialog.wrapper.outerHeight(true);
    var padding = 10;
    var scrollOverlapOffsetX = 10;
    if (!this.windowLocation) {
      var reportViewerCoords = this.pagesAreaContainer[0].getBoundingClientRect();
      this.kendoSearchDialog.setOptions({
        position: {
          // scrollY ensures that the dialog appears at the correct place even when the viewer is rendered inside a scrollable page
          top: reportViewerCoords.top + padding + window.scrollY,
          left: reportViewerCoords.right - width - padding - scrollOverlapOffsetX
        }
      });
    } else {
      var left = this.windowLocation.left;
      var top = this.windowLocation.top;
      var right = left + width;
      var bottom = top + height;
      if (right > windowWidth - padding) {
        left = Math.max(padding, windowWidth - width - padding);
        this.kendoSearchDialog.setOptions({
          position: {
            left
          }
        });
      }
      if (bottom > windowHeight - padding) {
        top = Math.max(padding, windowHeight - height - padding);
        this.kendoSearchDialog.setOptions({
          position: {
            top
          }
        });
      }
    }
  }
  processComboBoxEvent(event) {
    if (!(window.event || window.event.type)) {
      return;
    }
    var evt = window.event;
    if (evt.type === "keydown") {
      event.preventDefault();
      if (evt.keyCode === 40) {
        this.moveListSelection(1);
      }
      if (evt.keyCode === 38) {
        this.moveListSelection(-1);
      }
    }
  }
  _attachCommands() {
    this.commands = {
      searchDialog_MatchCase: new command.Command(),
      searchDialog_MatchWholeWord: new command.Command(),
      searchDialog_UseRegex: new command.Command(),
      searchDialog_StopSearch: new command.Command(() => {
        this.stopSearch();
      }),
      searchDialog_NavigateUp: new command.Command(() => {
        this.moveListSelection(-1);
      }),
      searchDialog_NavigateDown: new command.Command(() => {
        this.moveListSelection(1);
      })
    };
    Object.keys(this.commands).forEach((key) => {
      const element = this.element.querySelector(`button[data-command='telerik_ReportViewer_${key}']`);
      const factory = componentMap[element?.dataset?.role];
      const command = this.commands[key];
      if (!factory) {
        return;
      }
      return new factory(element, {
        command
      });
    });
    $(this.commands.searchDialog_MatchCase).on("checkedChanged", (event, newState) => {
      this.searchForCurrentToken();
    });
    $(this.commands.searchDialog_MatchWholeWord).on("checkedChanged", (event, newState) => {
      this.searchForCurrentToken();
    });
    $(this.commands.searchDialog_UseRegex).on("checkedChanged", (event, newState) => {
      this.searchForCurrentToken();
    });
  }
  _initResultsArea() {
    this.resultsLabel = this.element.querySelector(".trv-search-dialog-results-label");
    this.resultsLabel.innerText = stringResources.stringResources.searchDialogNoResultsLabel;
    this.kendoListView = new kendo.ui.ListView(this.element.querySelector(".trv-search-dialog-results-area"), {
      selectable: true,
      navigatable: true,
      dataSource: [],
      contentElement: "",
      template: `
                <div class="k-list-item !k-align-items-start">
                    <span class="k-list-item-text">#: description #</span>
                    <span class="k-flex"></span>
                    <span class="k-flex-none">${stringResources.stringResources.searchDialogPageText} #:page#</span>
                </div>
            `.trim(),
      change: (event) => {
        var listView = event.sender;
        var index = listView.select().index();
        var view = listView.dataSource.view();
        var dataItem = view[index];
        this.onSelectedItem(dataItem);
        this.updateUI(index, view.length);
      }
    });
    this.kendoListView.element.addClass("k-list k-list-md");
  }
  stopSearch() {
    this.setStopButtonEnabledState(false);
  }
  setStopButtonEnabledState(enabledState) {
    this.commands.searchDialog_StopSearch.setEnabled(enabledState);
  }
  onInputFiltering(event) {
    event.preventDefault();
    if (event.filter && event.filter.value !== this.lastSearch) {
      this.lastSearch = event.filter.value;
      this.searchForToken(this.lastSearch);
    }
  }
  kendoComboBoxSelect(event) {
    var newValue = event.sender.value();
    if (newValue && this.lastSearch !== newValue) {
      this.lastSearch = newValue;
      this.searchForToken(this.lastSearch);
    }
  }
  searchForCurrentToken() {
    if (this.kendoComboBox) {
      this.searchForToken(this.kendoComboBox.value());
    }
  }
  searchForToken(token) {
    this.onSearchStarted();
    this.addToMRU(token);
    this.searchManager.search({
      searchToken: token,
      matchCase: this.commands.searchDialog_MatchCase.getChecked(),
      matchWholeWord: this.commands.searchDialog_MatchWholeWord.getChecked(),
      useRegularExpressions: this.commands.searchDialog_UseRegex.getChecked()
    });
  }
  onSearchStarted() {
    this.resultsLabel.innerText = stringResources.stringResources.searchDialogSearchInProgress;
    this.setStopButtonEnabledState(true);
    this.toggleErrorLabel(false, null);
  }
  updateResultsUI(results, error) {
    this.setStopButtonEnabledState(false);
    if (error) {
      this.toggleErrorLabel(true, error);
    }
    this.kendoListView.dataSource.data(results || []);
    if (results && results.length > 0) {
      this.kendoListView.select(this.kendoListView.content.children().first());
      this.kendoListView.trigger("change");
    } else {
      this.updateUI(-1, 0);
    }
  }
  addToMRU(token) {
    if (!token || token === "") {
      return;
    }
    var exists = this.mruList.filter((mru) => {
      return mru.value === token;
    });
    if (exists && exists.length > 0) {
      return;
    }
    this.mruList.unshift({ value: token });
    if (this.mruList.length > 10) {
      this.mruList.pop();
    }
    this.inputComboRebinding = true;
    this.kendoComboBox.dataSource.data(this.mruList);
    this.kendoComboBox.select((item) => {
      return item.value === token;
    });
    this.inputComboRebinding = false;
  }
  onSelectedItem(item) {
    this.searchManager.highlightSearchItem(item);
  }
  updateUI(index, count) {
    var str = count === 0 ? stringResources.stringResources.searchDialogNoResultsLabel : utils.stringFormat(stringResources.stringResources.searchDialogResultsFormatLabel, [index + 1, count]);
    this.resultsLabel.innerText = str;
    var allowMoveUp = index > 0;
    var allowMoveDown = index < count - 1;
    this.commands.searchDialog_NavigateUp.setEnabled(allowMoveUp);
    this.commands.searchDialog_NavigateDown.setEnabled(allowMoveDown);
  }
  moveListSelection(offset) {
    var $selected = this.kendoListView.select();
    if (!$selected) {
      $selected = this.kendoListView.element.children().first();
      this.kendoListView.select($selected);
      this.kendoListView.trigger("change");
    } else {
      var index = this.kendoListView.select().trigger("change").index();
      var view = this.kendoListView.dataSource.view();
      var newIndex = Math.min(view.length - 1, Math.max(0, index + offset));
      if (newIndex !== index) {
        var dataItem = view[newIndex];
        var element = this.kendoListView.element.find('[data-uid="' + dataItem.uid + '"]');
        if (element) {
          this.kendoListView.select(element);
          this.kendoListView.trigger("change");
          this.scrollIfNeeded(element[0], this.kendoListView.element[0]);
        }
      }
    }
  }
  scrollIfNeeded(element, container) {
    if (element.offsetTop - element.clientHeight < container.scrollTop) {
      element.scrollIntoView();
    } else {
      var offsetBottom = element.offsetTop + element.offsetHeight;
      var scrollBottom = container.scrollTop + container.offsetHeight;
      if (offsetBottom > scrollBottom) {
        container.scrollTop = offsetBottom - container.offsetHeight;
      }
    }
  }
  toggleErrorLabel(show, message) {
    var $errorIcon = this.$element.find("i[data-role='telerik_ReportViewer_SearchDialog_Error']");
    if (!$errorIcon || $errorIcon.length === 0) {
      console.log(message);
      return;
    }
    if (show) {
      $errorIcon[0].title = message;
      $errorIcon.show();
    } else {
      $errorIcon.hide();
    }
  }
}

exports.Search = Search;
