text: /*  Copyright 2015 igallyamov <https://github.com/igallyamov>
      Copyright 2016 ufaks <https://github.com/ufaks>
      Copyright 2016 Ivan Yelizariev <https://it-projects.info/team/yelizariev>
      Copyright 2019 Kolushov Alexandr <https://it-projects.info/team/kolushovalexandr>
      Copyright 2019 ssaid <https://github.com/ssaid>
      Copyright 2019 raulovallet <https://github.com/raulovallet>
      License MIT (https://opensource.org/licenses/MIT). */
  /* eslint-disable complexity */
  odoo.define("pos_keyboard.pos", function(require) {
      "use strict";
  
      var core = require("web.core");
      var gui = require("point_of_sale.gui");
      var models = require("point_of_sale.models");
      var screens = require("point_of_sale.screens");
      var PopupWidget = require("point_of_sale.popups");
  
      gui.Gui.prototype.popup_classes
          .filter(function(c) {
              return c.name === "password";
          })[0]
          .widget.include({
              init: function(parent, args) {
                  this._super(parent, args);
                  this.popup_type = "password";
              },
          });
  
      PopupWidget.include({
          keypad_action: function(data) {
              var type = this.pos.keypad.type;
              if (data.type === type.numchar) {
                  this.click_keyboard(data.val);
              } else if (data.type === type.backspace) {
                  this.click_keyboard("BACKSPACE");
              } else if (data.type === type.enter) {
                  // Some pop-ups might throw an error due to lack of some income data
                  try {
                      return this.click_confirm();
                  } catch (error) {
                      return;
                  }
              } else if (data.type === type.escape) {
                  this.click_cancel();
              }
          },
          click_keyboard: function(value) {
              if (typeof this.inputbuffer === "undefined") {
                  return;
              }
              var newbuf = this.gui.numpad_input(this.inputbuffer, value, {
                  firstinput: this.firstinput,
              });
  
              this.firstinput = newbuf.length === 0;
  
              var $value = this.$(".value");
              if (newbuf !== this.inputbuffer) {
                  this.inputbuffer = newbuf;
                  $value.text(this.inputbuffer);
              }
              if (this.popup_type === "password" && newbuf) {
                  $value.text($value.text().replace(/./g, "•"));
              }
          },
          show: function(options) {
              this._super(options);
              this.$("input,textarea").focus();
          },
      });
  
      screens.NumpadWidget.include({
          keypad_action: function(data) {
              var type = this.pos.keypad.type;
              if (data.type === type.numchar) {
                  this.state.appendNewChar(data.val);
              } else if (data.type === type.bmode) {
                  this.state.changeMode(data.val);
              } else if (data.type === type.sign) {
                  this.clickSwitchSign();
              } else if (data.type === type.backspace) {
                  this.clickDeleteLastChar();
              }
          },
      });
  
      screens.PaymentScreenWidget.include({
          show: function() {
              this._super();
              this.pos.keypad.disconnect();
          },
          hide: function() {
              this._super();
              this.pos.keypad.connect();
          },
      });
  
      // This module mimics a keypad-only cash register. Use connect() and
      // disconnect() to activate and deactivate it.
      var Keypad = core.Class.extend({
          init: function(attributes) {
              this.pos = attributes.pos;
              /* This.pos_widget = this.pos.pos_widget;*/
              this.type = {
                  numchar: "number, dot",
                  bmode: "quantity, discount, price",
                  sign: "+, -",
                  backspace: "backspace",
                  enter: "enter",
                  escape: "escape",
              };
              this.data = {
                  // Type: undefined,
                  // val: undefined
              };
              delete this.action_callback;
              this.active = false;
          },
  
          save_callback: function() {
              this.saved_callback_stack.push(this.action_callback);
          },
  
          restore_callback: function() {
              if (this.saved_callback_stack.length > 0) {
                  this.action_callback = this.saved_callback_stack.pop();
              }
          },
  
          set_action_callback: function(callback) {
              this.action_callback = callback;
          },
  
          // Remove action callback
          reset_action_callback: function() {
              delete this.action_callback;
          },
  
          // Starts catching keyboard events and tries to interpret keystrokes,
          // calling the callback when needed.
          connect: function() {
              var self = this;
              if (self.active) {
                  return;
              }
              // --- additional keyboard ---//
              // KeyCode: + or - (Keypad '+')
              var KC_PLU = 107;
              // KeyCode: Quantity (Keypad '/')
              var KC_QTY = 111;
              // KeyCode: Price (Keypad '*')
              var KC_AMT = 106;
              // KeyCode: Discount Percentage [0..100] (Keypad '-')
              var KC_DISC = 109;
              // --- basic keyboard --- //
              // KeyCode: sign + or - (Keypad 's')
              var KC_PLU_1 = 83;
              // KeyCode: Quantity (Keypad 'q')
              var KC_QTY_1 = 81;
              // KeyCode: Price (Keypad 'p')
              var KC_AMT_1 = 80;
              // KeyCode: Discount Percentage [0..100] (Keypad 'd')
              var KC_DISC_1 = 68;
  
              // KeyCode: Backspace (Keypad 'backspace')
              var KC_BACKSPACE = 8;
              // KeyCode: Enter (Keypad 'enter')
              var KC_ENTER = 13;
              // KeyCode: Escape (Keypad 'esc')
              var KC_ESCAPE = 27;
              var kc_lookup = {
                  48: "0",
                  49: "1",
                  50: "2",
                  51: "3",
                  52: "4",
                  53: "5",
                  54: "6",
                  55: "7",
                  56: "8",
                  57: "9",
                  80: "p",
                  83: "s",
                  68: "d",
                  190: ".",
                  81: "q",
                  96: "0",
                  97: "1",
                  98: "2",
                  99: "3",
                  100: "4",
                  101: "5",
                  102: "6",
                  103: "7",
                  104: "8",
                  105: "9",
                  106: "*",
                  107: "+",
                  109: "-",
                  110: ".",
                  111: "/",
              };
  
              // Usb keyboard keyup event
              var rx = /INPUT|SELECT|TEXTAREA/i;
              var ok = false;
              var timeStamp = 0;
              $("body").on("keyup", "", function(e) {
                  var statusHandler =
                      !rx.test(e.target.tagName) ||
                      e.target.disabled ||
                      e.target.readOnly;
                  if (statusHandler) {
                      var is_number = false;
                      var type = self.type;
                      var buttonMode = {
                          qty: "quantity",
                          disc: "discount",
                          price: "price",
                      };
                      var token = e.keyCode;
                      if (
                          (token >= 96 && token <= 105) ||
                          token === 110 ||
                          (token >= 48 && token <= 57) ||
                          token === 190
                      ) {
                          self.data.type = type.numchar;
                          self.data.val = kc_lookup[token];
                          is_number = true;
                          ok = true;
                      } else if (token === KC_PLU || token === KC_PLU_1) {
                          self.data.type = type.sign;
                          ok = true;
                      } else if (token === KC_QTY || token === KC_QTY_1) {
                          self.data.type = type.bmode;
                          self.data.val = buttonMode.qty;
                          ok = true;
                      } else if (token === KC_AMT || token === KC_AMT_1) {
                          self.data.type = type.bmode;
                          self.data.val = buttonMode.price;
                          ok = true;
                      } else if (token === KC_DISC || token === KC_DISC_1) {
                          self.data.type = type.bmode;
                          self.data.val = buttonMode.disc;
                          ok = true;
                      } else if (token === KC_BACKSPACE) {
                          self.data.type = type.backspace;
                          ok = true;
                      } else if (token === KC_ENTER) {
                          self.data.type = type.enter;
                          ok = true;
                      } else if (token === KC_ESCAPE) {
                          self.data.type = type.escape;
                          ok = true;
                      } else {
                          delete self.data.type;
                          delete self.data.val;
                          ok = false;
                      }
  
                      if (is_number) {
                          if (timeStamp + 50 > new Date().getTime()) {
                              ok = false;
                          }
                      }
  
                      timeStamp = new Date().getTime();
  
                      setTimeout(function() {
                          if (ok) {
                              self.action_callback(self.data);
                          }
                      }, 50);
                  }
              });
              self.active = true;
          },
  
          // Stops catching keyboard events
          disconnect: function() {
              $("body").off("keyup", "");
              this.active = false;
          },
      });
  
      var _super_posmodel = models.PosModel.prototype;
      models.PosModel = models.PosModel.extend({
          initialize: function(session, attributes) {
              var self = this;
              this.keypad = new Keypad({pos: this});
              _super_posmodel.initialize.call(this, session, attributes);
              this.ready.then(function() {
                  self.keypad.set_action_callback(function(data) {
                      var current_screen = self.gui.current_screen;
                      var current_popup = self.gui.current_popup;
  
                      if (current_popup) {
                          current_popup.keypad_action(data);
                      } else if (
                          current_screen.numpad &&
                          current_screen.numpad.keypad_action
                      ) {
                          current_screen.numpad.keypad_action(data);
                      }
                  });
              });
          },
      });
  
      return {
          Keypad: Keypad,
      };
  });
  