// +build windows

package winterm

// effectiveSr gets the current effective scroll region in buffer coordinates
func (h *windowsAnsiEventHandler) effectiveSr(window SMALL_RECT) scrollRegion {
	top := addInRange(window.Top, h.sr.top, window.Top, window.Bottom)
	bottom := addInRange(window.Top, h.sr.bottom, window.Top, window.Bottom)
	if top >= bottom {
		top = window.Top
		bottom = window.Bottom
	}
	return scrollRegion{top: top, bottom: bottom}
}

func (h *windowsAnsiEventHandler) scrollUp(param int) error {
	info, err := GetConsoleScreenBufferInfo(h.fd)
	if err != nil {
		return err
	}

	sr := h.effectiveSr(info.Window)
	return h.scroll(param, sr, info)
}

func (h *windowsAnsiEventHandler) scrollDown(param int) error {
	return h.scrollUp(-param)
}

func (h *windowsAnsiEventHandler) deleteLines(param int) error {
	info, err := GetConsoleScreenBufferInfo(h.fd)
	if err != nil {
		return err
	}

	start := info.CursorPosition.Y
	sr := h.effectiveSr(info.Window)
	// Lines cannot be inserted or deleted outside the scrolling region.
	if start >= sr.top && start <= sr.bottom {
		sr.top = start
		return h.scroll(param, sr, info)
	} else {
		return nil
	}
}

func (h *windowsAnsiEventHandler) insertLines(param int) error {
	return h.deleteLines(-param)
}

// scroll scrolls the provided scroll region by param lines. The scroll region is in buffer coordinates.
func (h *windowsAnsiEventHandler) scroll(param int, sr scrollRegion, info *CONSOLE_SCREEN_BUFFER_INFO) error {
	h.logf("scroll: scrollTop: %d, scrollBottom: %d", sr.top, sr.bottom)
	h.logf("scroll: windowTop: %d, windowBottom: %d", info.Window.Top, info.Window.Bottom)

	// Copy from and clip to the scroll region (full buffer width)
	scrollRect := SMALL_RECT{
		Top:    sr.top,
		Bottom: sr.bottom,
		Left:   0,
		Right:  info.Size.X - 1,
	}

	// Origin to which area should be copied
	destOrigin := COORD{
		X: 0,
		Y: sr.top - int16(param),
	}

	char := CHAR_INFO{
		UnicodeChar: ' ',
		Attributes:  h.attributes,
	}

	if err := ScrollConsoleScreenBuffer(h.fd, scrollRect, scrollRect, destOrigin, char); err != nil {
		return err
	}
	return nil
}

func (h *windowsAnsiEventHandler) deleteCharacters(param int) error {
	info, err := GetConsoleScreenBufferInfo(h.fd)
	if err != nil {
		return err
	}
	return h.scrollLine(param, info.CursorPosition, info)
}

func (h *windowsAnsiEventHandler) insertCharacters(param int) error {
	return h.deleteCharacters(-param)
}

// scrollLine scrolls a line horizontally starting at the provided position by a number of columns.
func (h *windowsAnsiEventHandler) scrollLine(columns int, position COORD, info *CONSOLE_SCREEN_BUFFER_INFO) error {
	// Copy from and clip to the scroll region (full buffer width)
	scrollRect := SMALL_RECT{
		Top:    position.Y,
		Bottom: position.Y,
		Left:   position.X,
		Right:  info.Size.X - 1,
	}

	// Origin to which area should be copied
	destOrigin := COORD{
		X: position.X - int16(columns),
		Y: position.Y,
	}

	char := CHAR_INFO{
		UnicodeChar: ' ',
		Attributes:  h.attributes,
	}

	if err := ScrollConsoleScreenBuffer(h.fd, scrollRect, scrollRect, destOrigin, char); err != nil {
		return err
	}
	return nil
}
