//\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
// TypeScript helpers (universal micro-lib.) | Author: Sergei Y.Kitaev
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Helpers for HTMLElement-element (static class):
class HElement
{
   static ById(id: string, tagName: string|null=null): HTMLElement {
      return HById.ElementOf<HTMLElement>(id,tagName)
   }
   static GetById(id: string, tagName: string|null=null): HTMLElement|null {
      var element = document.getElementById(id)
      if (!tagName)
         return element
      return element && element.tagName==tagName ? element : null
   }

   static IsDisabled(element: HTMLElement): boolean {
      return (element as HTMLInputElement).disabled===true
   }

   static ContainsPoint(element: HTMLElement, x: number, y: number): boolean {
      let rect = element.getBoundingClientRect()
      return x>=rect.left && x<=rect.right && y>=rect.top && y<=rect.bottom
   }
   static ContainsMousePointer(element: HTMLElement, e: MouseEvent): boolean {
      return HElement.ContainsPoint(element, e.clientX, e.clientY)
   }

   static IsFocused(element: HTMLElement): boolean {
      let activeElement = HDoc.FocusedElement()
      return !!activeElement && element==activeElement
   }
   static ContainsFocus(element: HTMLElement): boolean {
      let activeElement = document.activeElement
      return !!activeElement && element.contains(activeElement)
   }

   static ScriptCurrent(): HTMLElement {
      let scriptTags = document.getElementsByTagName('script')
      if (scriptTags.length == 0)
         throw new Error('ScriptCurrentElement function must be called from <script> tag.')
      let element = scriptTags[scriptTags.length - 1].parentElement
      if (!element)
         throw new Error('Unknown element of <script> tag (ScriptCurrentElement function)')
      return element
   }
   static ScriptCurrent_Get(): HTMLElement|null {
      let scriptTags = document.getElementsByTagName('script')
      return scriptTags.length > 0 ?
         scriptTags[scriptTags.length - 1].parentElement :
         null
   }

   static UseClass(element: HTMLElement, className: string, use: boolean) {
      if (use)
         HElement.IncludeClass(element, className)
      else
         HElement.ExcludeClass(element, className)
   }
   static IncludeClass(element: HTMLElement, className: string): boolean {
      var classList = element.classList
      if (!classList.contains(className)) {
         classList.add(className)
         return true
      }
      return false
   }
   static ExcludeClass(element: HTMLElement, className: string): boolean {
      var classList = element.classList
      if (classList.contains(className)) {
         classList.remove(className)
         return true
      }
      return false
   }

   static Click(element: HTMLElement): boolean {
      if (HElement.IsDisabled(element))
         return false
      element.click()
      return true
   }
   static ClickIfNotNull(element: HTMLElement|null): boolean {
      return element ? HElement.Click(element) : false
   }
   static DeferredClick(element: HTMLElement, milliseconds: number=0): boolean {
      if (HElement.IsDisabled(element))
         return false
      milliseconds = HOps.NullSubst(milliseconds, 0)
      setTimeout(()=>{ element.click() }, milliseconds)
      return true
   }

   static DeferredFocus(element: HTMLElement, milliseconds: number=0) {
      milliseconds = HOps.NullSubst(milliseconds, 0)
      setTimeout(()=>{ element.focus() }, milliseconds)
   }

   static Select(element: HTMLElement): boolean {
      let elem = element as any
      if (!elem.select)
         return false
      elem.select()
      return true
   }
   static DeferredSelect(element: HTMLElement, milliseconds: number=0): boolean {
      milliseconds = HOps.NullSubst(milliseconds, 0)
      let elem = element as any
      if (!elem.select)
         return false
      setTimeout(()=>{ elem.select() }, milliseconds)
      return true
   }

   static FocusSelect(element: HTMLElement) {
      element.focus()
      HElement.Select(element)
   }
   static DeferredFocusSelect(element: HTMLElement, milliseconds: number=0) {
      milliseconds = HOps.NullSubst(milliseconds, 0)
      let elem = element as any
      setTimeout(()=>{
         element.focus()
         if (elem.select)
            elem.select()
      }, milliseconds)
   }

   static SelectAll(container: HTMLElement): boolean {
      if (DOC.selection) { // IE
         var body: any = document.body
         let range = body.createTextRange ? body.createTextRange() : null
         if (range) {
            range.moveToElementText(container)
            range.select()
            return true
         }
         return false
      }
      let selection = window.getSelection ? window.getSelection() : null
      if (!selection)
         return false
      let range = document.createRange()
      range.selectNode(container)
      selection.removeAllRanges()
      selection.addRange(range)
      return true
   }
   static DeferredSelectAll(container: HTMLElement, milliseconds: number=0) {
      milliseconds = HOps.NullSubst(milliseconds, 0)
      setTimeout(()=>{ HElement.SelectAll(container) }, milliseconds)
   }

   static DeferredScrollIntoView(element: HTMLElement, milliseconds: number=0) {
      milliseconds = HOps.NullSubst(milliseconds, 0)
      setTimeout(()=>{ element.scrollIntoView() }, milliseconds)
   }
} // HElement
