/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the Source EULA. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/

import { Directive, Inject, forwardRef, ElementRef, Input } from '@angular/core';

import { ScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableElement';
import { ScrollbarVisibility } from 'vs/base/common/scrollable';
import { getContentHeight, addDisposableListener, EventType, getContentWidth } from 'vs/base/browser/dom';
import { AngularDisposable } from 'sql/base/browser/lifecycle';

@Directive({
	selector: '[scrollable]'
})
export class ScrollableDirective extends AngularDisposable {
	private scrollableElement!: ScrollableElement;
	private parent!: HTMLElement;
	private scrolled!: HTMLElement;
	@Input() horizontalScroll?: ScrollbarVisibility;
	@Input() verticalScroll?: ScrollbarVisibility;
	@Input() useShadow = false;
	@Input() scrollYToX = false;

	constructor(
		@Inject(forwardRef(() => ElementRef)) private _el: ElementRef
	) {
		super();
	}

	ngOnInit() {
		this.scrolled = this._el.nativeElement as HTMLElement;
		this.parent = this.scrolled.parentElement!;
		const next = this.scrolled.nextSibling;
		this.parent.removeChild(this.scrolled);

		this.scrolled.style.position = 'relative';

		this.scrollableElement = new ScrollableElement(this.scrolled, {
			horizontal: this.horizontalScroll,
			vertical: this.verticalScroll,
			useShadows: this.useShadow,
			scrollYToX: this.scrollYToX,
			horizontalScrollbarSize: 3
		});

		this.scrollableElement.onScroll(e => {
			if (this.verticalScroll === ScrollbarVisibility.Auto) {
				this.scrolled.style.bottom = e.scrollTop + 'px';
			} else if (this.horizontalScroll === ScrollbarVisibility.Auto) {
				this.scrolled.scrollLeft = e.scrollLeft;
			}
		});

		this.parent.insertBefore(this.scrollableElement.getDomNode(), next);
		const initialHeight = getContentHeight(this.scrolled);
		const initalWidth = getContentWidth(this.scrolled);
		this.resetScrollDimensions();

		this._register(addDisposableListener(window, EventType.RESIZE, () => {
			this.resetScrollDimensions();
		}));

		// unforunately because of angular rendering behavior we need to do a double check to make sure nothing changed after this point
		setTimeout(() => {
			let currentheight = getContentHeight(this.scrolled);
			let currentWidth = getContentWidth(this.scrolled);
			if (initialHeight !== currentheight || initalWidth !== currentWidth) {
				this.resetScrollDimensions();
			}
		}, 200);
	}

	private resetScrollDimensions() {
		this.scrollableElement.setScrollDimensions({
			scrollHeight: this.verticalScroll === ScrollbarVisibility.Auto ? getContentHeight(this.scrolled) : undefined,
			height: this.verticalScroll === ScrollbarVisibility.Auto ? getContentHeight(this.parent) : undefined,
			scrollWidth: this.horizontalScroll === ScrollbarVisibility.Auto ? this.scrolled.scrollWidth : undefined,
			width: this.horizontalScroll === ScrollbarVisibility.Auto ? this.scrolled.offsetWidth : undefined
		});
	}

	public layout() {
		this.resetScrollDimensions();
	}
}
