import {Viewport, Point} from './Viewport';

export interface CenteredPanZoomOptions {
	screenWidth: number;
	screenHeight: number;
	scale?: number;
	contentSize: {
		width: number;
		height: number;
	}
}

export class CenteredPanZoom {
	screen: Viewport;
	viewport: Viewport;
	scale: number;
	contentSize: {
		width: number;
		height: number;
	};

	constructor(options: CenteredPanZoomOptions) {
		const scale = options.scale || (options.screenWidth / options.contentSize.width);
		this.screen = new Viewport({
			x: 0,
			y: 0,
			width: options.screenWidth,
			height: options.screenHeight
		});
		this.viewport = new Viewport({
			x: (options.screenWidth - (options.contentSize.width * scale)) / 2,
			y: ( options.screenHeight - (options.contentSize.height * scale)) / 2,
			width: options.screenWidth,
			height: options.screenHeight
		});
		this.scale = scale;
		this.contentSize = options.contentSize;
	}

	setSize(width, height) {
		this.screen.width = width;
		this.screen.height = height;
		this.viewport.width = width * this.scale;
		this.viewport.height = height * this.scale;
		this.constrainPan(true);
	}

	setContentSize(width, height) {
		this.contentSize = {width, height};
		this.constrainPan(true);
	}

	pan(screenX, screenY) {
		this.viewport.x = this.viewport.x + screenX;
		this.viewport.y = this.viewport.y + screenY;
		this.constrainPan();
	}

	constrainPan(strict = false) {
		const minX = (strict) ? 0 : this.screen.width * 0.5;
		const minY = (strict) ? 0 : this.screen.height * 0.5;
		this.viewport.x = Math.min(minX, this.viewport.x);
		this.viewport.y = Math.min(minY * 0.5, this.viewport.y);
		const maxY = (this.screen.height - (this.contentSize.height * this.scale)) - (strict ? 0 : this.screen.height * 0.5);
		const maxX = (this.screen.width - (this.contentSize.width * this.scale)) - (strict ? 0 : this.screen.width * 0.5);
		this.viewport.y = Math.max(maxY, this.viewport.y);
		this.viewport.x = Math.max(maxX, this.viewport.x);
		if (maxY > ((strict) ? 0 : this.screen.height * 0.5)) {
			this.viewport.y = Math.floor(maxY / 2);
		}
		if (maxX > ((strict) ? 0 : this.screen.width * 0.5)) {
			this.viewport.x = Math.floor(maxX / 2);
		}
	}

	panFrom(screenStart: Point, screenEnd: Point) {
		this.pan(screenEnd.x - screenStart.x, screenEnd.y - screenStart.y);
	}

	//find zoom point in pre-zoom viewport
	//make that point the same in the post-zoom viewport
	zoom(scale: number, screenCenter: Point) {
		const v1 = Viewport.convert(screenCenter, {
			from: this.screen,
			to: this.viewport
		});
		this.viewport.x = this.viewport.x * (scale / this.scale);
		this.viewport.y = this.viewport.y * (scale / this.scale);
		this.viewport.width = this.screen.width * scale;
		this.viewport.height = this.screen.height * scale;
		const minScale = Math.min(this.screen.width / this.contentSize.width, this.screen.height / this.contentSize.height);
		scale = Math.max(minScale, scale);
		this.scale = scale;

		const v2 = Viewport.convert(screenCenter, {
			from: this.screen,
			to: this.viewport
		});
		const deltaX = v2.x - v1.x;
		const deltaY = v2.y - v1.y;
		this.pan(deltaX * scale, deltaY * scale);
	}
}
