//\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
// TypeScript support for Blazor-WASM application | Author: Sergei Y.Kitaev
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Message-box support (instance class):
class MessageBox {
   private static CR: MessageBox|null

   private LayoutDIV: HTMLDivElement
   private HeaderDIV: HTMLDivElement
   private TitleDIV: HTMLDivElement
   private FooterDIV: HTMLDivElement
   private CloseWindowDIV: HTMLDivElement
   private DialogIconIMG: HTMLImageElement

   private LastFocusedElem: HTMLElement|null
   private LastFocusedButton: HTMLButtonElement|null

   constructor() {
      this.LayoutDIV = HById.ElementOf<HTMLDivElement>('messagebox_LayoutDIV','DIV')
      this.HeaderDIV = HById.ElementOf<HTMLDivElement>('messagebox_HeaderDIV','DIV')
      this.TitleDIV = HById.ElementOf<HTMLDivElement>('messagebox_TitleDIV','DIV')
      this.FooterDIV = HById.ElementOf<HTMLDivElement>('messagebox_FooterDIV','DIV')
      this.CloseWindowDIV = HById.ElementOf<HTMLDivElement>('messagebox_CloseWindowDIV','DIV')
      this.DialogIconIMG = HById.ElementOf<HTMLImageElement>('messagebox_DialogIconIMG','IMG')
   }

   Prepare() {
      this.Adjust()
      this.DialogIconIMG.style.visibility = 'visible'
      HDoc.ClearSelection()
   }
   Adjust() {
      let dialogSpaceWidth = ServiceDialogFrame.DialogSpaceWidth()
      let headerDIV = this.HeaderDIV
      let titleDIV = this.TitleDIV
      let dialogIconIMG = this.DialogIconIMG
      var gapWidth =
         parseInt($(headerDIV).css('padding-left')) +
         parseInt($(headerDIV).css('padding-right')) +
         parseInt($(titleDIV).css('margin-right'))
      titleDIV.style.maxWidth = dialogSpaceWidth -
         this.CloseWindowDIV.getBoundingClientRect().width - gapWidth + 'px'
      let dialogIconImageStyle = dialogIconIMG.style
      dialogIconImageStyle.marginTop =
         headerDIV.getBoundingClientRect().height + 10 + 'px'
   }

   Window_OnKeyDown(e: KeyboardEvent) {
      let code = e.keyCode
      if (!( MessageBox.IsActive() && (
             code==13 || code==27 || // Enter, Escape
             code==37 || code==39 || // Left-arrow, Right-arrow
             code==9 ) // Tab
      ))
         return true
      if ( e.ctrlKey || e.altKey || e.shiftKey )
         return true
      let focusedButton = MessageBox.GetFocusedButton()
      let acceptButton = WIN.messagebox_AcceptBUTTON
      let xAcceptButton = WIN.messagebox_XAcceptBUTTON
      let closeButton = WIN.messagebox_CloseBUTTON
      switch (code)
      {
      case 13: // Enter
         if ( ServiceDialogFrame.ContainsFocus() && (
              !focusedButton ||
              focusedButton != acceptButton &&
              focusedButton != xAcceptButton &&
              focusedButton != closeButton ))
            WASM.Invoke('wasm_MessageBox_EnterKeyAutoAttempt')
         break
      case 27: // Escape
         WASM.Invoke('wasm_MessageBox_EscapeCancellationAttempt')
         break
      case 9: // Tab
         if ( focusedButton && acceptButton && ServiceDialogFrame.ContainsFocus() ) {
            let focusTarget =
               focusedButton==acceptButton && !xAcceptButton && closeButton ? closeButton :
               focusedButton==acceptButton && xAcceptButton ? xAcceptButton :
               focusedButton==xAcceptButton && closeButton ? closeButton
               : acceptButton;
            focusTarget.focus()
            return HEvent.Neutralize(e)
         }
         break
      case 37: // Left-arrow
         if (focusedButton==acceptButton)
         {
            if (closeButton) closeButton.focus()
            else if (xAcceptButton) xAcceptButton.focus()
            break
         }
         if (focusedButton==xAcceptButton)
         {
            if (acceptButton) acceptButton.focus()
            break
         }
         if (focusedButton==closeButton)
         {
            if (xAcceptButton) xAcceptButton.focus()
            else if (acceptButton) acceptButton.focus()
            break
         }
         break
      case 39: // Right-arrow
         if (focusedButton==acceptButton)
         {
            if (xAcceptButton) xAcceptButton.focus()
            else if (closeButton) closeButton.focus()
            break
         }
         if (focusedButton==xAcceptButton)
         {
            if (closeButton) closeButton.focus()
            else if (acceptButton) acceptButton.focus()
            break
         }
         if (focusedButton==closeButton)
         {
            if (acceptButton) acceptButton.focus()
            break
         }
         break
      } // switch
      return true
   }

   Window_OnMouseUp(e: KeyboardEvent) {
      if (!MessageBox.IsActive())
         return
      let activeElement = HDoc.FocusedElement()
      if ( activeElement!=WIN.messagebox_AcceptBUTTON &&
           activeElement!=WIN.messagebox_XAcceptBUTTON &&
           activeElement!=WIN.messagebox_CloseBUTTON ) {
         var lfb = this.LastFocusedButton
         if (lfb) lfb.focus()
      }
   }

   Handle_Window_OnFocus() {
      let activeElement = HDoc.FocusedElement()
      if ( activeElement &&
           activeElement==WIN.messagebox_AcceptBUTTON ||
           activeElement==WIN.messagebox_XAcceptBUTTON ||
           activeElement==WIN.messagebox_CloseBUTTON ||
           activeElement==this.LayoutDIV ) {
         this.LastFocusedElem = activeElement
         let focusedButton = MessageBox.GetFocusedButton()
         if (focusedButton && focusedButton.tagName=='BUTTON')
            this.LastFocusedButton = focusedButton
         return
      }
      this.RecoverFocus(true)
   }
   RecoverFocus(deferred: boolean=false) {
      var lastFocused = this.LastFocusedElem
      var focusTarget: HTMLElement = lastFocused ? lastFocused : this.LayoutDIV
      if (deferred)
         HElement.DeferredFocus(focusTarget)
      else
         focusTarget.focus()
   }

   static GetFocusedButton(): HTMLButtonElement|null {
      let focusedElement = HDoc.FocusedElement()
      return focusedElement instanceof HTMLButtonElement ?
         focusedElement as HTMLButtonElement : null
   }

   static IsActive(): boolean {
      return MessageBox.CR!=null && ServiceDialogFrame.IsOpen()
   }
   static Current(): MessageBox {
      var curr = MessageBox.CR
      if (!curr)
         throw new Error('Message box is not open (\"MessageBox\").')
      return curr
   }

   static Prepare() {
      MessageBox.Reset()
      let inst = new MessageBox()
      inst.Prepare()
      MessageBox.CR = inst
   }
   static Reset() {
      MessageBox.CR = null
   }

   static Window_OnKeyDown(e: KeyboardEvent) {
      var curr = MessageBox.CR
      if (curr) curr.Window_OnKeyDown(e)
   }
   static Window_OnMouseUp(e: KeyboardEvent) {
      var curr = MessageBox.CR
      if (curr) curr.Window_OnMouseUp(e)
   }
   static Handle_Window_OnResize() {
      var curr = MessageBox.CR
      if (curr) curr.Adjust()
   }
   static Handle_Window_OnFocus() {
      var curr = MessageBox.CR
      if (curr) curr.Handle_Window_OnFocus()
   }
   static RecoverFocus() {
      var curr = MessageBox.CR
      if (curr) curr.RecoverFocus()
   }
}

//==================================================================================================
// MESSAGE-BOX SUPPORT — INITIALIZATION:
//--------------------------------------------------------------------------------------------------

window.addEventListener('keydown', MessageBox.Window_OnKeyDown, true)
window.addEventListener('mouseup', MessageBox.Window_OnMouseUp, true)
var LastFocused: HTMLElement|null

//==================================================================================================
// MESSAGE-BOX SUPPORT — FUNCTIONS:
//--------------------------------------------------------------------------------------------------

function MessageBox_Prepare() {
   MessageBox.Prepare()
}

//==================================================================================================
