//\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
// Magistral layout for SPA (TypeScript class for Blazor-WASM app.) | Author: Sergei Y.Kitaev
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Magistral layout support (static class):
class Magistral
{
   private static _IsInitialized_: boolean = false
   private static _IsInReloading_: boolean = false
   private static _IsInputBlocked_: boolean = false
   private static _IsInBusyState_: boolean = false
   private static _AllowOpCancellation_: boolean = true
   private static _OpCancellationRequested_: boolean = false
   private static _WasOperationAbandoned_: boolean = false
   private static _IsAbandomentHot_: boolean = false
   private static _OperationText_: string|null
   private static _OpErrorMessage_: string|null
   private static _PageContent_: HTMLElement|null
   private static _ModalPopupContent_: HTMLElement|null
   private static _PageContentWidthDiff_: number

   static IsActive(): boolean {
      return Magistral._IsInitialized_ && !Magistral._IsInReloading_
   }

   static HasModalPopup(): boolean {
      return Magistral._ModalPopupContent_ != null
   }

   static SpecifyPageContent(selectionContent: HTMLElement|null) {
      Magistral._PageContent_ = selectionContent
   }
   static SpecifyModalPopup(selectionContent: HTMLElement|null) {
      Magistral._ModalPopupContent_ = selectionContent
      Magistral.UpdateEnable()
   }

   static HasProblemIndication() {
      return Magistral.HasErrorIndication() || Magistral.HasAbandomentIndication()
   }
   static HasErrorIndication() {
      return Magistral._OpErrorMessage_ != null
   }
   static HasAbandomentIndication() {
      return Magistral._WasOperationAbandoned_ && !Magistral.HasErrorIndication()
   }

   static SetOperationFailure(errorMessage: string|null=null): string {
      Magistral._OpErrorMessage_ =
         errorMessage = errorMessage!=null ? errorMessage : "Operation has failed."
      Magistral.UpdateEnable()
      return errorMessage
   }
   static ResetOperationFailure() {
      Magistral._OpErrorMessage_ = null
      Magistral.UpdateEnable()
   }

   static UpdateEnable() {
      let busy = Magistral.IsInBusyState()

      let pageScrollEnabled = Magistral._IsInitialized_ && !Magistral.HasModalPopup() && !busy
      HElement.UseClass(WIN.magistral_ToPageTopA, 'disabledRefA', !pageScrollEnabled)
      HElement.UseClass(WIN.magistral_ToPageBottomA, 'disabledRefA', !pageScrollEnabled)

      HElement.UseClass( WIN.magistral_OperationSPAN,
         'magistral_OperationSPAN_Cancellation',
         Magistral._OpCancellationRequested_ )

      let abandomentEnabled = Magistral.IsAbandomentEnabled()
      if (!abandomentEnabled)
         Magistral.ResetAbandomentHotness()

      let animationDiv = WIN.magistral_BusyAnimationDIV
      let opAbandoned = Magistral._WasOperationAbandoned_
      HElement.UseClass(animationDiv, 'magistral_BusyAnimationDIV', !busy && !opAbandoned)
      HElement.UseClass(animationDiv, 'magistral_BusyAnimationDIV_Busy', busy && !opAbandoned)
      let abandomentUpperDiv = WIN.magistral_AbandomentUpperDIV
      let abandomentLowerDIV = WIN.magistral_AbandomentLowerDIV
      HElement.UseClass(abandomentUpperDiv, 'magistral_AbandomentBackground', abandomentEnabled)
      HElement.UseClass(abandomentLowerDIV, 'magistral_AbandomentBackground', abandomentEnabled)
      HElement.UseClass(abandomentUpperDiv, 'magistral_AbandomentBorder_Active', abandomentEnabled)
      HElement.UseClass(abandomentLowerDIV, 'magistral_AbandomentBorder_Active', abandomentEnabled)
      HElement.UseClass(abandomentUpperDiv, 'magistral_AbandomentBorder_Inactive', !abandomentEnabled)
      HElement.UseClass(abandomentLowerDIV, 'magistral_AbandomentBorder_Inactive', !abandomentEnabled)

      let abandomentTitle = 'Abandon active operation\n(It\'s your choice.)'
      animationDiv.title = abandomentEnabled ? abandomentTitle :
         opAbandoned ? 'Operation has been abandoned.' :
            HOps.NullSubst(Magistral._OpErrorMessage_, 'Operation activity (busy-indicator)')
      WIN.magistral_AbandomentUpperDIV.title =
         WIN.magistral_AbandomentLowerDIV.title = abandomentEnabled ? abandomentTitle :
            'Escape panels (together with animation indicator) are used to abandon active '+
            'operation.\n'+
            '(It is generally available in busy state.)'
      WIN.magistral_PageNameDIV.title = abandomentEnabled ?
         abandomentTitle : 'Current page name (SPA)'

      let escapeUpperSPAN = WIN.magistral_EscapeUpperSPAN
      let escapeLowerSPAN = WIN.magistral_EscapeLowerSPAN
      HElement.UseClass( escapeUpperSPAN, 'magistral_EscapeUpperSPAN_Active', abandomentEnabled)
      HElement.UseClass( escapeLowerSPAN, 'magistral_EscapeLowerSPAN_Active', abandomentEnabled)
      HElement.UseClass( escapeUpperSPAN, 'magistral_EscapeUpperSPAN_Inactive', !abandomentEnabled)
      HElement.UseClass( escapeLowerSPAN, 'magistral_EscapeLowerSPAN_Inactive', !abandomentEnabled)

      let hasProblemIndication = Magistral.HasProblemIndication()
      HElement.UseClass( animationDiv, 'magistral_BusyAnimationDIV_OpAbandoned',
                         hasProblemIndication && Magistral.HasAbandomentIndication() )
      HElement.UseClass( animationDiv, 'magistral_BusyAnimationDIV_OpFailure',
                         hasProblemIndication && Magistral.HasErrorIndication() )
      Magistral.UpdateAnimationImage()
   }

   static UpdateAnimationImage() {
      WIN.magistral_BusyAnimationIMG.style.visibility =
         Magistral._IsInBusyState_ || Magistral._IsInputBlocked_ || !Magistral.IsActive() ?
            'visible' : 'hidden'
   }

   static SetAbandomentHotness(value=true) {
      let abandomentEnabled = Magistral.IsAbandomentEnabled()
      value = HOps.BoolDefaultTrue( value ) && abandomentEnabled
      if ( value != Magistral._IsAbandomentHot_ ) {
         let abandomentUpperDiv = WIN.magistral_AbandomentUpperDIV
         let abandomentLowerDIV = WIN.magistral_AbandomentLowerDIV
         HElement.UseClass(WIN.magistral_BusyAnimationDIV, 'magistral_AbandomentBackground_Hot', value)
         HElement.UseClass(abandomentUpperDiv, 'magistral_AbandomentBackground', abandomentEnabled)
         HElement.UseClass(abandomentLowerDIV, 'magistral_AbandomentBackground', abandomentEnabled)
         HElement.UseClass(abandomentUpperDiv, 'magistral_AbandomentBackground_Hot', value)
         HElement.UseClass(abandomentLowerDIV, 'magistral_AbandomentBackground_Hot', value)
         HElement.UseClass(abandomentUpperDiv, 'magistral_AbandomentBorder_Active', abandomentEnabled)
         HElement.UseClass(abandomentLowerDIV, 'magistral_AbandomentBorder_Active', abandomentEnabled)
         HElement.UseClass(abandomentUpperDiv, 'magistral_AbandomentBorder_Inactive', !abandomentEnabled)
         HElement.UseClass(abandomentLowerDIV, 'magistral_AbandomentBorder_Inactive', !abandomentEnabled)
         Magistral._IsAbandomentHot_ = value
      }
   }
   static ResetAbandomentHotness() {
      Magistral.SetAbandomentHotness(false)
   }

   static AbandomentDiv_OnMouseEnter(e) {
      if (Magistral.IsActive() && Magistral.IsAbandomentEnabled())
         Magistral.SetAbandomentHotness()
   }
   static AbandomentDiv_OnMouseMove(e) {
      if (Magistral.IsActive() && Magistral.IsAbandomentEnabled())
         Magistral.SetAbandomentHotness()
   }
   static AbandomentDiv_OnMouseLeave(e) {
      if (Magistral.IsActive() && Magistral.IsAbandomentEnabled())
         Magistral.ResetAbandomentHotness()
   }

   static IsAbandomentEnabled(): boolean {
      return Magistral.IsInBusyState() &&
         Magistral._AllowOpCancellation_ &&
         !Magistral._OpCancellationRequested_
   }

   static AbandomentDiv_OnClick() {
      if (Magistral.IsActive() && Magistral.IsAbandomentEnabled()) {
         Magistral._OpCancellationRequested_ = true
         Magistral.UpdateEnable()
         WASM.Invoke('wasm_Magistral_CancelPendingOperation')
      }
   }

   static IsInputBlocked(): boolean {
      return Magistral._IsInputBlocked_
   }
   static BlockInput(value: boolean=true, useWaitingCursor: boolean=false) {
      value = HOps.BoolDefaultTrue(value)
      WIN.magistral_InputBlockingDIV.style.pointerEvents = value ? 'none' : 'all'
      Magistral._IsInputBlocked_ = value
      Magistral.UpdateAnimationImage()
      if (useWaitingCursor===true)
         Magistral.SetWaitingCursor(value)
   }
   static UnblockInput(useWaitingCursor: boolean=true) {
      Magistral.BlockInput(false, useWaitingCursor)
   }

   static SetWaitingCursor(value: boolean=true) {
      let waiting = value===true || value==null
      WIN.magistral_WaitingFullDIV.style.cursor = waiting ? 'wait' : 'default'
   }

   static IsInBusyState(): boolean {
      return Magistral._IsInBusyState_
   }
   static OperationText(): string|null {
      return Magistral._OperationText_
   }
   static SetBusyState( operationText: string|null,
                        allowOpCancellation: boolean=true ) {
      Magistral.DoSetBusyState(true, operationText, allowOpCancellation)
   }
   static ResetBusyState() {
      Magistral.DoSetBusyState(false, null)
   }
   private static DoSetBusyState( value: boolean,
                                  operationText: string|null,
                                  allowOpCancellation: boolean=true ) {
      value = HOps.BoolDefaultTrue(value)
      allowOpCancellation = value && HOps.BoolDefaultTrue(allowOpCancellation)
      Magistral._OperationText_ = value ? operationText : null
      Magistral._AllowOpCancellation_ = allowOpCancellation
      Magistral._OpCancellationRequested_ = false
      WIN.magistral_BlockingOverlayDIV.style.visibility =
         WIN.magistral_OperationSPAN.style.visibility = value ? 'visible' : 'hidden'
      Magistral._IsInBusyState_ = value
      Magistral.UpdateAnimationImage()
      if (value)
      {
         Magistral._OpErrorMessage_ = null
         Magistral._WasOperationAbandoned_ = false
      }
      Magistral.SetOperationText(Magistral._OperationText_, Magistral._AllowOpCancellation_)
   }
   static SetOperationText( operationText: string|null,
                            allowOpCancellation: boolean=true ) {
      let isBusy = Magistral._IsInBusyState_
      let text = isBusy ? operationText : null
      Magistral._OperationText_ = text
      Magistral._AllowOpCancellation_ = allowOpCancellation
      WIN.magistral_OperationSPAN.innerHTML = isBusy ? HOps.NullSubst(text,'???') : ''
      Magistral.UpdateEnable()
   }
   static NotifyOpAbandoned(resetBusyState: boolean) {
      Magistral._WasOperationAbandoned_ = Magistral._IsInBusyState_ ? true : false
      Magistral._OpErrorMessage_ = null
      if (resetBusyState===true || resetBusyState==null)
         Magistral.ResetBusyState()
      else
         Magistral.UpdateEnable()
   }

   static AdjustLayout() {
      let winInnerWidth = window.innerWidth
      let scrollbarWidth = WIN.magistral_PageScrollableDIV.offsetWidth -
                           WIN.magistral_PageScrollableDIV.clientWidth
      let toolpanelWidth = WIN.magistral_ToolPanelDIV.offsetWidth
      let pageContentWidth = winInnerWidth - toolpanelWidth - scrollbarWidth
      Magistral._PageContentWidthDiff_ = winInnerWidth - pageContentWidth
      WIN.magistral_ToolPanelDIV.style.left = winInnerWidth - toolpanelWidth - scrollbarWidth + 'px'
      WIN.magistral_ToolPanelDIV.style.right = 0
      WIN.magistral_BlockingOverlayDIV.style.width = WIN.magistral_PageScrollableDIV.offsetWidth -
                                                     scrollbarWidth + 'px'
      WIN.magistral_OperationSPAN.style.right = toolpanelWidth + scrollbarWidth + 5 + 'px'
      let unselectionDivBottom = WIN.magistral_UnselectionDIV.getBoundingClientRect().bottom
      let escapeHeight = WIN.magistral_EscapeUpperSPAN.getBoundingClientRect().height
      WIN.magistral_TopBottomUpperDIV.style.minHeight = unselectionDivBottom + escapeHeight + 'px'
      let toPageBottomHRefBottom = WIN.magistral_ToPageBottomA.getBoundingClientRect().bottom
      let abandomentUpperDIV = WIN.magistral_AbandomentUpperDIV
      abandomentUpperDIV.style.height =
         abandomentUpperDIV.style.minHeight = Math.max(
            WIN.magistral_ToPageTopA.getBoundingClientRect().top - unselectionDivBottom - 1,
            escapeHeight ) + 'px'
      let abandomentLowerDIV = WIN.magistral_AbandomentLowerDIV
      abandomentLowerDIV.style.top = toPageBottomHRefBottom + 'px'
      abandomentLowerDIV.style.height =
         abandomentLowerDIV.style.minHeight =
            WIN.magistral_ToolPanelDIV.getBoundingClientRect().height -
            toPageBottomHRefBottom + 'px'
   }

   static SetPageName(verticalName: string|null) {
      let html = ''
      if (verticalName)
         for (let i=0; i<verticalName.length; i++)
            html += (html.length ? '<br>' : '') + verticalName[i]
      Magistral.SetPageNameHTML(html)
   }
   static SetPageNameHTML(verticalNameHTML: string|null) {
      WIN.magistral_PageNameDIV.innerHTML = verticalNameHTML
   }

   static SetDropdownIcon( iconClassName: string|null,
                           iconPath: string|null ) {
      if (iconClassName)
         Magistral.SetDropdownIconClass(iconClassName)
      else
         Magistral.SetDropdownIconPath(iconPath)
   }
   static SetDropdownIconClass(className: string|null) {
      Magistral.SetDropdownIconHtml( className ?
         '<span class="'+className+'"></span>' : null )
   }
   static SetDropdownIconPath(iconPath: string|null) {
      Magistral.SetDropdownIconHtml( iconPath ?
         '<img src="'+iconPath+'" />' : null )
   }
   static SetDropdownIconHtml(html: string|null) {
      WIN.magistral_DropdownIconBUTTON.innerHTML = HStr.NullAsEmpty(html)
   }

   static SetPageNameDropdownIcon( verticalName: string|null,
                                   iconClassName: string|null,
                                   iconPath: string|null ) {
      Magistral.SetPageName(verticalName)
      Magistral.SetDropdownIcon(iconClassName, iconPath)
   }
   static SetPageNameIconClass( verticalName: string|null,
                                iconClassName: string|null ) {
      Magistral.SetPageName(verticalName)
      Magistral.SetDropdownIconClass(iconClassName)
   }
   static SetPageNameIconPath( verticalName: string|null,
                               iconPath: string|null ) {
      Magistral.SetPageName(verticalName)
      Magistral.SetDropdownIconPath(iconPath)
   }
   static SetPageNameAndIcon( verticalName: string|null,
                              iconClassName: string|null,
                              iconPath: string|null ) {
      Magistral.SetPageName(verticalName)
      if (iconClassName)
         Magistral.SetDropdownIconClass(iconClassName)
      else
         Magistral.SetDropdownIconPath(iconPath)
   }

   static ResetPageNameDropdownIcon() {
      Magistral.SetPageNameDropdownIcon(null, null, null)
   }

   static EscapeToolPanelFocus() {
      if ( Magistral.IsActive() && !Magistral.HasModalPopup() &&
           !HElement.ContainsFocus( WIN.magistral_PageScrollableDIV ) )
         WIN.magistral_PageScrollableDIV.focus()
   }

   static FocusPageBackground(): boolean {
      if (Magistral.HasModalPopup())
         return false
      WIN.magistral_PageScrollableDIV.focus()
      return true
   }
   static DeferredFocusPageBackground(milliseconds: number=0): boolean {
      if (Magistral.HasModalPopup())
         return false
      milliseconds = HOps.NullSubst(milliseconds, 0)
      setTimeout(()=>{ WIN.magistral_PageScrollableDIV.focus() }, milliseconds)
      return true
   }

   static IsDropdownMenuOpen(): boolean {
      return !$('#magistral_DropdownMenuDIV').is(':hidden')
   }
   static CloseDropdownMenu(): boolean {
      let jDDMenuDIV = $('#magistral_DropdownMenuDIV')
      if (jDDMenuDIV.is(':hidden'))
         return false
      jDDMenuDIV.dropdown('toggle')
      return true
   }

   static GetScrollLeft(): number {
      return WIN.magistral_PageScrollableDIV.scrollLeft
   }
   static GetScrollTop(): number {
      return WIN.magistral_PageScrollableDIV.scrollTop
   }

   static ScrollTo(scrollLeft: number|null, scrollTop: number|null): boolean {
      if (scrollLeft==null && scrollTop==null)
         return false
      if (scrollLeft!=null)
         WIN.magistral_PageScrollableDIV.scrollLeft = scrollLeft
      if (scrollTop!=null)
         WIN.magistral_PageScrollableDIV.scrollTop = scrollTop
      return true
   }
   static DeferredScrollTo( scrollLeft: number|null,
                            scrollTop: number|null,
                            milliseconds: number=0 ): boolean {
      if (scrollLeft==null && scrollTop==null)
         return false
      milliseconds = HOps.NullSubst(milliseconds, 0)
      setTimeout(()=>{ Magistral.ScrollTo(scrollLeft, scrollTop) }, milliseconds)
      return true
   }

   static ScrollToPageTop(): boolean {
      if (!Magistral.IsActive())
         return false
      WIN.magistral_PageScrollableDIV.scrollTop = 0
      return true
   }
   static DeferredScrollToPageTop(milliseconds: number=0): boolean {
      if (!Magistral.IsActive())
         return false
      milliseconds = HOps.NullSubst(milliseconds, 0)
      setTimeout(()=>{ Magistral.ScrollToPageTop() }, milliseconds)
      return true
   }
   static ScrollToPageBottom(): boolean {
      if (!Magistral.IsActive())
         return false
      let div = WIN.magistral_PageScrollableDIV
      div.scrollTop = div.scrollHeight - div.clientHeight + 1
      return true
   }
   static DeferredScrollToPageBottom(milliseconds: number=0): boolean {
      if (!Magistral.IsActive())
         return false
      milliseconds = HOps.NullSubst(milliseconds, 0)
      setTimeout(()=>{ Magistral.ScrollToPageBottom() }, milliseconds)
      return true
   }

   static ClearSelectionUnscrollEtc() {
      Page.ClearSelectionUnscroll()
   }
   static ClearSelectionDeferredUnscrollEtc(milliseconds: number=0) {
      Page.ClearSelectionDeferredUnscroll(milliseconds)
   }

   static NavigationClicked( href: string,
                             pageName: string|null=null,
                             iconClassName: string|null=null,
                             iconPath: string|null=null ) {
      if (!Magistral.IsActive())
         return false
      Magistral.ClearSelectionUnscrollEtc()
      Magistral.SetDropdownIcon(iconClassName, iconPath)
      let loc = window.location.href
      let address = HAddress.ToAbsolute(href)
      let withNavigation = address.toLowerCase() != HAddress.NormalizeSlashes(loc).toLowerCase()
      Magistral.SetPageName(withNavigation ? null : pageName)
      if (withNavigation)
         WASM.Invoke_1('wasm_Magistral_PerformNavigation', href)
      return false
   }

   static LocationChanged() {
      setTimeout(()=>{ Magistral.CloseDropdownMenu() })
      Magistral.ClearSelectionUnscrollEtc()
      Magistral._OpErrorMessage_ = null
      Magistral._WasOperationAbandoned_ = false
      Magistral.UpdateEnable()
      AFXUI.Invoke('wasm_Breakdown_ResetIgnorePopupDialog')
   }

   static InitiateReloadPage(): boolean {
      if (!Magistral.IsActive())
         return false
      Magistral._IsInReloading_ = true
      Magistral.UpdateAnimationImage()
      Magistral.ClearSelectionUnscrollEtc()
      WASM.AsyncInvoke('wasm_Magistral_ReloadPage_A').then(r => {
         Magistral._IsInReloading_ = false
         Magistral.UpdateEnable()
         Magistral.EscapeToolPanelFocus()
         AFXUI.Invoke('wasm_Breakdown_ResetIgnorePopupDialog')
      })
      return true
   }
   static DeferredInitiateReloadPage(milliseconds: number=0) {
      if (!Magistral.IsActive())
         return false
      milliseconds = HOps.NullSubst(milliseconds, 0)
      setTimeout(Magistral.InitiateReloadPage, milliseconds)
      return true
   }

   static Window_OnResize(e) {
      Magistral.AdjustLayout()
   }

   static SuppressBlockedInput(e: KeyboardEvent): boolean {
      return Magistral.IsInputBlocked() ? HEvent.Neutralize(e) : true
   }
   static ScrollOnMouseWheel(e): boolean {
      if (Magistral.IsInputBlocked())
         return HEvent.Neutralize(e)
      let scrollTop = WIN.magistral_PageScrollableDIV.scrollTop
      if (e.deltaY)
         WIN.magistral_PageScrollableDIV.scrollTop += e.deltaY
      return true
   }
/*
   static OpAbandomentBUTTON_OnClick() {
      if (!Magistral.IsActive())
         return
      Magistral._OpCancellationRequested_ = true
      Magistral.UpdateEnable()
      WASM.Invoke('wasm_Magistral_CancelPendingOperation')
   }
*/
   static DropdownItemA_OnClick( href: string,
                                 pageName: string|null,
                                 iconClassName: string|null,
                                 iconPath: string|null ): boolean {
      return Magistral.NavigationClicked(href, pageName, iconClassName, iconPath)
   }

   static HomeA_OnClick( href: string,
                         pageName: string|null,
                         iconClassName: string|null,
                         iconPath: string|null ): boolean {
      return Magistral.NavigationClicked(href, pageName, iconClassName, iconPath)
   }
   static ReloadPageA_OnClick(): boolean {
      Magistral.InitiateReloadPage()
      return false
   }
   static SelectAllContentA_OnClick(): boolean {
      if (Magistral.IsActive())
         HElement.SelectAll(HOps.NullSubst(
            HOps.NullSubst(Magistral._ModalPopupContent_, Magistral._PageContent_),
            WIN.magistral_PageContentDIV ))
      return false
   }

   static ToPageTopA_OnClick(): boolean {
      Magistral.ScrollToPageTop()
      return false
   }
   static ToPageBottomA_OnClick(): boolean {
      Magistral.ScrollToPageBottom()
      return false
   }

   static IsBrowserImportantKey(e: KeyboardEvent): boolean {
      return e.keyCode==116 && !e.ctrlKey && !e.altKey && !e.shiftKey || ( // F5
         (App.IsDebugConfiguration() || !Magistral._IsInitialized_) &&
         e.keyCode==73 && e.ctrlKey && !e.altKey && e.shiftKey ) // Ctrl+Shift+I
   }

   static Window_OnKeyDown(e: KeyboardEvent): boolean {
      if (Magistral.IsBrowserImportantKey(e))
         return false;
      if (!Magistral.IsActive())
         return HEvent.Neutralize(e)
/*
      if (e.keyCode==27) { // Escape
         let opAbandomentButton = WIN.magistral_OpAbandomentBUTTON
         if (opAbandomentButton.disabled===false && !Magistral.HasModalPopup()) {
            opAbandomentButton.click()
            return HEvent.Neutralize(e)
         }
      }
*/
      if (e.keyCode==27) // Escape
      {
         if (Magistral.CloseDropdownMenu())
            return HEvent.Neutralize(e)
         if (Magistral.IsAbandomentEnabled()) {
            Magistral.AbandomentDiv_OnClick()
            return HEvent.Neutralize(e)
         }
      }
      if (Magistral.IsInputBlocked() || Magistral.IsInBusyState())
         return HEvent.Neutralize(e)
      return true
   }
   static Window_OnKeyUp(e: KeyboardEvent): boolean {
      if (!Magistral.IsActive())
         return HEvent.Neutralize(e)
      return Magistral.IsInputBlocked() || Magistral.IsInBusyState() ?
         HEvent.Neutralize(e) : true;
   }

   static PageScrollableDIV_OnMouseWheel(e: MouseEvent): boolean {
      return !Magistral.IsActive() || Magistral.IsInputBlocked() ? HEvent.Neutralize(e) : true
   }

   static Visualize() {
      Magistral.UpdateEnable()
      WIN.magistral_ToolPanelDIV.style.visibility = 'visible'
      Magistral.EscapeToolPanelFocus()
   }
   static Initialize() {
      if (Magistral._IsInitialized_)
         return

      window.addEventListener('keydown', Magistral.Window_OnKeyDown, true)
      window.addEventListener('keyup', Magistral.Window_OnKeyUp, true)

      Magistral.AddSuppressionListener('mousedown')
      Magistral.AddSuppressionListener('mouseup')
      Magistral.AddSuppressionListener('mousemove')
      Magistral.AddSuppressionListener('mouseout')
      Magistral.AddSuppressionListener('mouseover')
      Magistral.AddSuppressionListener('click')
      Magistral.AddSuppressionListener('dblclick')

      WIN.magistral_PageScrollableDIV.addEventListener(
         'wheel', Magistral.PageScrollableDIV_OnMouseWheel, true)
      WIN.magistral_ToolPanelDIV.addEventListener(
         'wheel', Magistral.ScrollOnMouseWheel, true)
      WIN.magistral_BlockingOverlayDIV.addEventListener(
         'wheel', Magistral.ScrollOnMouseWheel, true)
      WIN.magistral_OperationSPAN.addEventListener(
         'wheel', Magistral.ScrollOnMouseWheel, true)

      WIN.magistral_DropdownIconBUTTON.disabled = null
      HElement.ExcludeClass(WIN.magistral_DropdownIconBUTTON, 'cursor_default')

      Magistral.UnblockHRef(WIN.magistral_HomeA)
      Magistral.UnblockHRef(WIN.magistral_ReloadPageA)
      Magistral.UnblockHRef(WIN.magistral_SelectAllContentA)

      Magistral._IsInitialized_ = true
      Magistral.Visualize()
      Magistral.UpdateAnimationImage()
   }
   static AddSuppressionListener(eventType: string) {
      document.body.addEventListener(eventType, Magistral.SuppressBlockedInput, true)
   }
   static UnblockHRef(element: HTMLInputElement) {
      HElement.ExcludeClass(element, 'disabledRefA')
   }

   static GetPageContentWidthDiff(): number {
      let value = Magistral._PageContentWidthDiff_
      if ( value == null )
         throw new Error(
            '\"PageContentWidthDiff\"-property has not been initialized (\"Magistral\").' )
      return value
   }
} // Magistral
