ISOTerminal.addEventListener('init', function(){
  if( typeof Terminal != 'undefined' ) this.xtermInit()
})

ISOTerminal.addEventListener('runISO', function(e){
  let opts = e.detail
  opts.serial_container_xtermjs = opts.screen_container
  delete opts.screen_container
})

ISOTerminal.prototype.xtermInit = function(){
  this.serial_input = 0 // set input to serial line 0
  let isoterm = this
  // monkeypatch Xterm (which V86 initializes) so we can add our own constructor args 
  window._Terminal = window.Terminal 
  window.Terminal = function(opts){
    const term = new window._Terminal({ ...opts,
      cursorBlink:true,
      onSelectionChange: function(e){ console.log("selectchange") },
      letterSpacing: 0
    })

    term.onSelectionChange( () => {
      document.execCommand('copy')
      term.select(0, 0, 0)
      isoterm.emit('status','copied to clipboard')
    })

    term.onRender( () => {
      // xterm relies on requestAnimationFrame (which does not called in immersive mode)
      let _window = term._core._coreBrowserService._window
      if( !_window._XRSH_proxied ){ // patch the planet!

        //_window.requestAnimationFrameAFRAME = function(cb){
        //  if( term.tid != null ) clearTimeout(term.tid)
        //  term.tid = setTimeout( function(){
        //    console.log("render")
        //    cb()
        //    term.tid = null
        //  },100)
        //}
        this.i = 0
        const requestAnimationFrameAFRAME = AFRAME.utils.throttleLeadingAndTrailing(
          function(cb){ cb() }
          ,150 
        )

        // we proxy the _window object of xterm, and reroute 
        // requestAnimationFrame to requestAnimationFrameAFRAME
        _window_new = new Proxy(_window,{
          get(me,k){ 
            if( k == '_XRSH_proxied' ) return true 
            if( k == 'requestAnimationFrame' ){
              return requestAnimationFrameAFRAME.bind(me)
            }
            return typeof me[k] == 'function' ? me[k].bind(me) : me[k]
          },
          set(me,k,v){
            me[k] = v 
            return true
          }
        })
        term._core._coreBrowserService._window = _window_new 
      }

    })

    return term
  }


  this.addEventListener('emulator-started', function(){
    this.emulator.serial_adapter.term.element.querySelector('.xterm-viewport').style.background = 'transparent'
    // toggle immersive with ESCAPE
    //document.body.addEventListener('keydown', (e) => e.key == 'Escape' && this.emulator.serial_adapter.term.blur() )
  })

  const resize = (w,h) => {
    setTimeout( () => {
      if( isoterm?.emulator?.serial_adapter?.term ){
        isoterm.xtermAutoResize(isoterm.emulator.serial_adapter.term, isoterm.instance,-3)
      }
    },800) // wait for resize anim
  }
  isoterm.instance.addEventListener('window.onresize', resize )
  isoterm.instance.addEventListener('window.onmaximize', resize )
}

ISOTerminal.prototype.xtermAutoResize = function(term,instance,rowoffset){
  if( !term.element ) return

  const defaultScrollWidth = 24;
  const MINIMUM_COLS = 2;
  const MINIMUM_ROWS = 2;

  const dims = term._core._renderService.dimensions;
  const scrollbarWidth = (term.options.scrollback === 0
    ? 0
    : (term.options.overviewRuler?.width || defaultScrollWidth ));

  const parentElementStyle = window.getComputedStyle(instance.dom);
  const parentElementHeight = parseInt(parentElementStyle.getPropertyValue('height'));
  const parentElementWidth = Math.max(0, parseInt(parentElementStyle.getPropertyValue('width')));
  const elementStyle = window.getComputedStyle(term.element);
  const elementPadding = {
    top: parseInt(elementStyle.getPropertyValue('padding-top')),
    bottom: parseInt(elementStyle.getPropertyValue('padding-bottom')),
    right: parseInt(elementStyle.getPropertyValue('padding-right')),
    left: parseInt(elementStyle.getPropertyValue('padding-left'))
  };
  const elementPaddingVer = elementPadding.top + elementPadding.bottom;
  const elementPaddingHor = elementPadding.right + elementPadding.left;
  const availableHeight = parentElementHeight - elementPaddingVer;
  const availableWidth = parentElementWidth - elementPaddingHor - scrollbarWidth;
  const geometry = {
    cols: Math.max(MINIMUM_COLS, Math.floor(availableWidth / dims.css.cell.width)),
    rows: Math.max(MINIMUM_ROWS, Math.floor(availableHeight / dims.css.cell.height))
  };
  term.resize(geometry.cols, geometry.rows + (rowoffset||0) );
}