/**
 * Created by rockyl on 2018/11/7.
 *
 */

import {dirtyFieldTrigger} from "../tools/decorators";

/**
 * 边界类
 */
export default class Bounds {
	@dirtyFieldTrigger
	x: number;
	@dirtyFieldTrigger
	y: number;
	@dirtyFieldTrigger
	width: number;
	@dirtyFieldTrigger
	height: number;

	_onChange: Function;
	
	constructor(x: number = 0, y: number = 0, width: number = 0, height: number = 0, onChange?) {
		this.x = x;
		this.y = y;
		this.width = width;
		this.height = height;

		this._onChange = onChange;
	}

	onModify(value, key, oldValue){
		this._onChange && this._onChange(value, key, oldValue);
	}

	get left(): number {
		return this.x;
	}

	set left(v: number) {
		this.x = v;
	}

	get top(): number {
		return this.y;
	}

	set top(v: number) {
		this.y = v;
	}

	get right(): number {
		return this.x + this.width;
	}

	set right(v: number) {
		this.width = v - this.x;
	}

	get bottom(): number {
		return this.y + this.height;
	}

	set bottom(v: number) {
		this.height = v - this.y;
	}

	/**
	 * 是否包含点
	 * @param x
	 * @param y
	 */
	contains(x: number, y: number): boolean {
		return this.x <= x &&
			this.x + this.width >= x &&
			this.y <= y &&
			this.y + this.height >= y;
	}

	/**
	 * 设置
	 * @param x
	 * @param y
	 * @param width
	 * @param height
	 */
	setTo(x: number, y: number, width: number, height: number) {
		this.x = x;
		this.y = y;
		this.width = width;
		this.height = height;
	}

	/**
	 * 复制一个边界
	 * @param target
	 */
	copyFrom(target: Bounds) {
		this.x = target.x;
		this.y = target.y;
		this.width = target.width;
		this.height = target.height;
	}

	/**
	 * 克隆
	 */
	clone(): Bounds {
		return new Bounds(this.x, this.y, this.width, this.height)
	}

	/**
	 * 扩展
	 * @param dx
	 * @param dy
	 */
	inflate(dx: number, dy: number) {
		this.x -= dx;
		this.width += 2 * dx;
		this.y -= dy;
		this.height += 2 * dy;
	}

	/**
	 * 是否是空边界
	 */
	get isEmpty(): boolean {
		return this.width <= 0 || this.height <= 0;
	}

	/**
	 * 是否是零边界
	 */
	get isZero():boolean{
		return this.x === 0 && this.y === 0 && this.isEmpty;
	}

	/**
	 * 置空
	 */
	setEmpty() {
		this.x = 0;
		this.y = 0;
		this.width = 0;
		this.height = 0;
	}

	/**
	 * 横切
	 * @param toIntersect
	 */
	intersects(toIntersect: Bounds): boolean {
		return Math.max(this.x, toIntersect.x) <= Math.min(this.right, toIntersect.right)
			&& Math.max(this.y, toIntersect.y) <= Math.min(this.bottom, toIntersect.bottom);
	}

	/**
	 * 是否包含另一个边界
	 * @param bounds
	 */
	containsBounds(bounds: Bounds): boolean {
		let r1 = bounds.x + bounds.width;
		let b1 = bounds.y + bounds.height;
		let r2 = this.x + this.width;
		let b2 = this.y + this.height;
		return (bounds.x >= this.x) && (bounds.x < r2) && (bounds.y >= this.y) && (bounds.y < b2) && (r1 > this.x) && (r1 <= r2) && (b1 > this.y) && (b1 <= b2);
	}

	/**
	 * 判断是否相等
	 * @param toCompare
	 */
	equals(toCompare: Bounds): boolean {
		if (this === toCompare) {
			return true;
		}
		return this.x === toCompare.x && this.y === toCompare.y
			&& this.width === toCompare.width && this.height === toCompare.height;
	}

	toString(): string {
		const {x, y, width, height} = this;
		return "(x=" + x + ", y=" + y + ", width=" + width + ", height=" + height + ")";
	}
}
