import { Matrix4 } from '../math/Matrix4';
import { Bone3D } from './Bone3D';
import { HashObject } from '../../2d/HashObject';
import { BaseTexture } from '../../2d/texture';

const offsetMatrix = new Matrix4();
const identityMatrix = new Matrix4();

export class Skeleton3D extends HashObject {
	bones: Bone3D[];
	boneMatrices: Float32Array;
	boneInverses: Matrix4[];
	boneTexture: BaseTexture;
	boneTextureSize:number
	constructor(bones: Bone3D[] = [], boneInverses?: Matrix4[]) {
		super();
		this._instanceType = "Skeleton3D";
		this.bones = bones.slice(0);
		this.boneMatrices = new Float32Array(this.bones.length * 16);

		if (!boneInverses) {

			this.calculateInverses();

		} else {

			if (this.bones.length === boneInverses.length) {

				this.boneInverses = boneInverses.slice(0);

			} else {

				console.warn('boneInverses长度有误');

				this.boneInverses = [];

				for (var i = 0, il = this.bones.length; i < il; i++) {

					this.boneInverses.push(new Matrix4());

				}

			}

		}
	}
	calculateInverses() {
		this.boneInverses = [];
		for (var i = 0, il = this.bones.length; i < il; i++) {
			var inverse = new Matrix4();
			if (this.bones[i]) {
				inverse.setInverseOf(this.bones[i]._worldMatrix);
			}
			this.boneInverses.push(inverse);
		}
	}

	pose() {

		var bone: Bone3D, i, il;

		// recover the bind-time world matrices

		for (i = 0, il = this.bones.length; i < il; i++) {

			bone = this.bones[i];

			if (bone) {

				bone._worldMatrix.setInverseOf(this.boneInverses[i]);

			}

		}

		// compute the local matrices, positions, rotations and scales

		for (i = 0, il = this.bones.length; i < il; i++) {

			bone = this.bones[i];

			if (bone) {

				if (bone.parent && bone.parent.instanceType == "Bone3D") {
					bone._localMatrix.setInverseOf(bone.parent._worldMatrix);
					bone._localMatrix.multiply(bone._worldMatrix);
				} else {

					bone._localMatrix.copy(bone._worldMatrix);

				}

				bone._localMatrix.decompose(bone.position, bone.quaternion, bone.scale);

			}

		}

	}

	/**
	 * skinnedMesh3D里面调用
	 */
	update() {
		// this.calculateInverses();
		var bones = this.bones;
		var boneInverses = this.boneInverses;
		var boneMatrices = this.boneMatrices;
		var boneTexture = this.boneTexture;

		// flatten bone matrices to array

		for (var i = 0, il = bones.length; i < il; i++) {

			// compute the offset between the current and the original transform

			var matrix = bones[i] ? bones[i]._worldMatrix : identityMatrix;

			offsetMatrix.multiplyMatrices(matrix, boneInverses[i]);
			//@ts-ignore
			offsetMatrix.toArray(boneMatrices, i * 16);

		}
		// if(this.instanceId==310)console.log(this.bones[0]._worldMatrix.elements[2])
		if (boneTexture) boneTexture.update();
	};



	clone() {
		return new Skeleton3D(this.bones, this.boneInverses);
	}

	getBoneByName(name: string) {
		for (var i = 0, il = this.bones.length; i < il; i++) {
			var bone = this.bones[i];
			if (bone.name === name) return bone;
		}
		return null;
	}
	destroy() {
		//TODO
	}
}




