declare namespace cc {

	export interface Node {
		/**
		 * 設定世界座標
		 * @param worldPoint
		 */
		SetWorldPosition(worldPoint: cc.Vec2 | cc.Vec3): void;
		/**
		 * 取得世界座標
		 */
		GetWorldPosition(): cc.Vec2;
		/**
		 * 取得目標在自己區域的相對座標
		 * @param target
		 */
		GetTargetInMyLocalPosition(target: cc.Node): cc.Vec2;
		/**
		 * 取得目標距離
		 * @param target
		 */
		GetTargetDistance(target: cc.Node): number;
		/**
		 * 設定長寬
		 * @param size
		 */
		SetSizeDelta(size: cc.Vec2);
		/**
		 * 取得長寬
		 */
		GetSizeDelta(): cc.Vec2;
		/**
		 * 增加一個子物件
		 * @param childObj
		 */
		ExAddChild(childObj: cc.Prefab | cc.Node, childActive?: boolean): cc.Node;

		/**設定層級為最低層 */
		ExSetLowestOrder(): void;

		/**設定層級為最高層 */
		ExSetHighestOrder(): void;

		/**設定層級,比目標OBJ再低一層 */
		ExSetOrderUnderTheObj(obj: cc.Node, isNew?: boolean): number;

		/**設定層級,比目標OBJ再高一層 */
		ExSetOrderOverTheObj(obj: cc.Node, isNew?: boolean): number;
		/**位置維持在原位 */
		ExSetParent(parentObj: cc.Node): void;
		ExSetGray(showGray: boolean): void;

		/** 通過觀察目標來設置 rotation */
		ExLookAt(targetPos: cc.Vec3): void;

		/**
		 * !#zh
		 * 当前节点的自身激活状态。<br/>
		 * 值得注意的是,一个节点的父节点如果不被激活,那么即使它自身设为激活,它仍然无法激活。<br/>
		 * 如果你想检查节点在场景中实际的激活状态可以使用 {{#crossLink "Node/activeInHierarchy:property"}}{{/crossLink}}。
		 * @param value 当前节点的自身激活状态
		 */
		SetActive(value: boolean): void;
	}

	// export interface ActionInterval {
	//     step(dt: number): void;
	// }

	export interface Tween {
		/**
		 * 獲取持續時間
		 * @example let duration = tween.duration();
		 */
		duration(): number;
		/**
		 * 獲取已經進行的時間
		 * @example let elapsed = tween.elapsed();
		 */
		elapsed(): number;
		/**
		 * 跳轉到指定時間
		 * @param time 時間(秒)
		 * @example tween.goto(2);
		 */
		goto(time: number): void;
	}
}

cc.Node.prototype.SetWorldPosition || Object.defineProperty(cc.Node.prototype, 'SetWorldPosition', {
	enumerable: false,
	value: function (cocosWorldPos: cc.Vec2 | cc.Vec3) {
		// let cocosWorldPos = new cc.Vec2(unityWorldPos.x + 711, unityWorldPos.y + 400);
		this.setPosition(this.parent.convertToNodeSpaceAR(cocosWorldPos));
	}
})
cc.Node.prototype.GetWorldPosition || Object.defineProperty(cc.Node.prototype, 'GetWorldPosition', {
	enumerable: false,
	value: function () {
		let cocosWorldPos = this.parent.convertToWorldSpaceAR(this.position);
		// let unityWorldPos = new cc.Vec2(cocosWorldPos.x - 711, cocosWorldPos.y - 400);
		return cocosWorldPos;
	}
})
cc.Node.prototype.GetTargetInMyLocalPosition || Object.defineProperty(cc.Node.prototype, 'GetTargetInMyLocalPosition', {
	enumerable: false,
	value: function (target: cc.Node): cc.Vec2 {
		let selfPos: cc.Vec2 = this.GetWorldPosition();
		let targetPos: cc.Vec2 = target.GetWorldPosition();
		let diff: cc.Vec2 = targetPos.sub(selfPos);
		let newPos: cc.Vec2 = this.getPosition().add(diff);
		return newPos;
	}
});
cc.Node.prototype.GetTargetDistance || Object.defineProperty(cc.Node.prototype, 'GetTargetDistance', {
	enumerable: false,
	value: function (target: cc.Node): number {
		let vector: cc.Vec2 = target.GetWorldPosition().sub(this.GetWorldPosition());
		let distance: number = vector.mag();
		return distance;
	}
});
cc.Node.prototype.SetSizeDelta || Object.defineProperty(cc.Node.prototype, 'SetSizeDelta', {
	enumerable: false,
	value: function (size: cc.Vec2) {
		this.setContentSize(size.x, size.y);
	}
})
cc.Node.prototype.GetSizeDelta || Object.defineProperty(cc.Node.prototype, 'GetSizeDelta', {
	enumerable: false,
	value: function () {
		let size: cc.Size = this.GetSizeDelta();
		return new cc.Vec2(size.width, size.width);
	}
})
cc.Node.prototype.ExAddChild || Object.defineProperty(cc.Node.prototype, 'ExAddChild', {
	enumerable: false,
	value: function (childObj: cc.Prefab | cc.Node, childActive: boolean = true) {
		let gameObj = null;
		if (childObj instanceof cc.Prefab) {
			gameObj = cc.instantiate(childObj);
		}
		else {
			gameObj = cc.instantiate(childObj);
		}
		gameObj.active = childActive ? true : childActive;
		gameObj.parent = this;
		return gameObj;
	}
})
cc.Node.prototype.ExSetLowestOrder || Object.defineProperty(cc.Node.prototype, 'ExSetLowestOrder', {
	enumerable: false,
	value: function () {
		this.setSiblingIndex(0);
	}
})
cc.Node.prototype.ExSetHighestOrder || Object.defineProperty(cc.Node.prototype, 'ExSetHighestOrder', {
	enumerable: false,
	value: function () {
		this.setSiblingIndex(Number.MAX_VALUE);
	}
})
cc.Node.prototype.ExSetOrderUnderTheObj || Object.defineProperty(cc.Node.prototype, 'ExSetOrderUnderTheObj', {
	enumerable: false,
	value: function (obj: cc.Node, isNew?: boolean) {

		let newIndex: number;
		let objIndex = obj.getSiblingIndex();

		// 如果是新創的元件
		if (isNew) {
			newIndex = objIndex;
		}
		// 如果是已經在場景上的元件
		else {
			let myIndex = this.getSiblingIndex();

			// 如果一開始就在它下面
			if (myIndex < objIndex) {
				newIndex = objIndex - 1;
			}
			else {
				newIndex = objIndex;
			}
		}
		this.setSiblingIndex(newIndex);
		return newIndex;
	}
})
cc.Node.prototype.ExSetOrderOverTheObj || Object.defineProperty(cc.Node.prototype, 'ExSetOrderOverTheObj', {
	enumerable: false,
	value: function (obj: cc.Node, isNew?: boolean) {
		let newIndex: number;
		let objIndex = obj.getSiblingIndex();

		// 如果是新創的元件
		if (isNew) {
			newIndex = objIndex + 1;
		}
		// 如果是已經在場景上的元件
		else {
			let myIndex = this.getSiblingIndex();

			// 如果一開始就在它下面
			if (myIndex < objIndex) {
				newIndex = objIndex;
			}
			else {
				newIndex = objIndex + 1;
			}
		}
		this.setSiblingIndex(newIndex);
		return newIndex;
	}
})
cc.Node.prototype.ExSetParent || Object.defineProperty(cc.Node.prototype, 'ExSetParent', {
	enumerable: false,
	value: function (parentObj: cc.Node) {
		let oriPos = this.GetWorldPosition();
		this.setParent(parentObj);
		this.SetWorldPosition(oriPos);
	}
})
cc.Node.prototype.ExSetGray || Object.defineProperty(cc.Node.prototype, 'ExSetGray', {
	enumerable: false,
	value: function (showGray: boolean): void {
		let btn: cc.Button = this.getComponent(cc.Button);
		if (btn) {
			btn.interactable = !showGray;
		}
		let material: cc.Material = cc.Material.createWithBuiltin(showGray ? cc.Material.BUILTIN_NAME.GRAY_SPRITE.toString() : cc.Material.BUILTIN_NAME.SPRITE.toString(), 0);
		!showGray && material.define("USE_TEXTURE", true, 0);
		let spriteComs: any[] = this.getComponentsInChildren(cc.Sprite).concat(this.getComponentsInChildren(cc.Label));
		for (let sprite of spriteComs) {
			sprite.setMaterial(0, material);
		}

		// 先使用createWithBuiltin,如果材質球一直Create沒被刪除,會在修改。
		// let material: cc.Material = cc.Material.getBuiltinMaterial(showGray ? cc.Material.BUILTIN_NAME.GRAY_SPRITE.toString() : cc.Material.BUILTIN_NAME.SPRITE.toString());
		// for (let sprite of spriteComs) {
		//     if (showGray) {
		//         sprite.setMaterial(0, cc.Material.getBuiltinMaterial('2d-gray-sprite'));
		//     }
		//     else {
		//         sprite.setMaterial(0, cc.Material.getBuiltinMaterial('2d-sprite'));
		//     }
		// }
	},
});
cc.Node.prototype.ExLookAt || Object.defineProperty(cc.Node.prototype, "ExLookAt", {
	enumerable: false,
	value: function (targetPos: cc.Vec3): void {
		let TargetX: number = targetPos.x;
		let TargetY: number = targetPos.y;
		let SelfX: number = this.x;
		let SelfY: number = this.y;
		let r1: number = Math.atan2(TargetX - SelfX, TargetY - SelfY);
		let angle: number = (180 * r1 / Math.PI);
		this.angle = -angle;
	},
});
cc.Node.prototype.SetActive || Object.defineProperty(cc.Node.prototype, "SetActive", {
	enumerable: false,
	value: function (value: boolean): void {
		this.active = value;
	},
});
// cc.Node.prototype.SetWorldPosition = function (cocosWorldPos: cc.Vec2): void {
//     // let cocosWorldPos = new cc.Vec2(unityWorldPos.x + 711, unityWorldPos.y + 400);
//     this.setPosition(this.parent.convertToNodeSpaceAR(cocosWorldPos));
// }
// cc.Node.prototype.GetWorldPosition = function (): cc.Vec2 {
//     let cocosWorldPos = this.parent.convertToWorldSpaceAR(this.position);
//     // let unityWorldPos = new cc.Vec2(cocosWorldPos.x - 711, cocosWorldPos.y - 400);
//     return cocosWorldPos;
// }

// cc.Node.prototype.SetSizeDelta = function (size: cc.Vec2) {
//     this.setContentSize(size.x, size.y);
// }
// cc.Node.prototype.GetSizeDelta = function (): cc.Vec2 {
//     let size: cc.Size = this.GetSizeDelta();
//     return new cc.Vec2(size.width, size.width);
// }

// cc.Node.prototype.ExAddChild = function (childObj: cc.Prefab | cc.Node): cc.Node {

//     let gameObj = null;
//     if (childObj instanceof cc.Prefab) {
//         gameObj = cc.instantiate(childObj);
//     }
//     else {
//         gameObj = cc.instantiate(childObj);
//     }
//     gameObj.parent = this;
//     return gameObj;
// }

// cc.Node.prototype.ExSetLowestOrder = function (): void {
//     this.setSiblingIndex(0);
// }
// cc.Node.prototype.ExSetHighestOrder = function (): void {
//     this.setSiblingIndex(Number.MAX_VALUE);
// }


// cc.ActionInterval.prototype.step || Object.defineProperty(cc.ActionInterval.prototype, "step", {
//     enumerable: false,
//     value: function (dt: number): void {
//         if (this.paused) {
//             return;
//         }

//         if (this._firstTick && !this._goto) {
//             this._firstTick = false;
//             this._elapsed = 0;
//         } else {
//             this._elapsed += dt;
//         }

//         let t: number = this._elapsed / (this._duration > 0.0000001192092896 ? this._duration : 0.0000001192092896);
//         t = (1 > t ? t : 1);
//         this.update(t > 0 ? t : 0);

//         // Compatible with repeat class, Discard after can be deleted (this._repeatMethod)
//         if (this._repeatMethod && this._timesForRepeat > 1 && this.isDone()) {
//             if (!this._repeatForever) {
//                 this._timesForRepeat--;
//             }
//             this.startWithTarget(this.target);
//             this.step(this._elapsed - this._duration);
//         }
//     }
// });

// /**
//  * 暂停
//  * @example tween.pause();
//  */
// cc.Tween.prototype.pause = function () {
//     this._finalAction.paused = true;
// };

// /**
//  * 恢复
//  * @example tween.resume();
//  */
// cc.Tween.prototype.resume = function () {
//     this._finalAction.paused = false;
// };

// /**
//  * 倍速播放
//  * @param speed 倍速
//  * @example tween.speed(2);
//  */
// cc.Tween.prototype.speed = function (speed) {
//     this._finalAction._speedMethod = true;
//     this._finalAction._speed = speed;
// }

cc.Tween.prototype.duration || Object.defineProperty(cc.Tween.prototype, "duration", {
	enumerable: false,
	value: function (): number {
		// let duration: number = this._finalAction._duration;
		let duration: number = 0;
		for (let i: number = 0; i < this["_actions"].length - 1; i++) {
			const action: any = this["_actions"][i];
			duration += action._duration;
		}
		// duration += ((cc.game.getFrameRate() / 3) / cc.game.getFrameRate());
		duration *= 1.3;
		return duration;
	}
});

cc.Tween.prototype.elapsed || Object.defineProperty(cc.Tween.prototype, "elapsed", {
	enumerable: false,
	value: function (): number {
		return this._finalAction._elapsed;
	}
});

cc.Tween.prototype.goto || Object.defineProperty(cc.Tween.prototype, "goto", {
	enumerable: false,
	/**
	 * @param time 時間(秒)
	 */
	value: function (time: number): void {
		this._finalAction._goto = true;
		this._finalAction._elapsed = time;
	}
});

// cc.ActionManager.prototype.pauseByTag = function (tag, pause) {
//     if (tag === cc.Action.TAG_INVALID) {
//         cc.logID(1002);
//     }

//     let hashTargets = this._hashTargets;
//     for (let name in hashTargets) {
//         let element = hashTargets[name];
//         for (let i = 0, l = element.actions.length; i < l; ++i) {
//             let action = element.actions[i];
//             if (action && action.getTag() === tag) {
//                 action.paused = pause;
//                 break;
//             }
//         }
//     }
// }

// /**
//  * 根据标签暂停动作
//  * @param tag tween的标签
//  * @example cc.Tween.pauseByTag(100);
//  */
// cc.Tween.pauseByTag = function (tag) {
//     cc.director.getActionManager().pauseByTag(tag, true);
// }

// /**
//  * 根据标签恢复动作
//  * @param tag tween的标签
//  * @example cc.Tween.resumeByTag(100);
//  */
// cc.Tween.resumeByTag = function (tag) {
//     cc.director.getActionManager().pauseByTag(tag, false);
// }