import { Utils } from '../common/Utils'
import { GeometryResource } from '../resources/GeometryResource';
import { MaterialResource } from '../resources/MaterialResource';
import { Object3D } from './Object3D';

/**
 * Mesh - 三维网格物体
 *
 * 用于创建自定义三维网格物体(带材质),支持传入顶点数据和材质属性。
 * @class Mesh
 * @memberof THING
 * @extends THING.Object3D
 * @public
 * @example
 const mesh = new THING.Mesh({
   data: {
     position: [0, 0, 0, 1, 0, 0, 0, 1, 0],
     index: [0, 1, 2],
   },
   material: {
	color:[1,0,0],
	transparent:true,
     opacity:0.5,
   }
 });
 */
class Mesh extends Object3D {

	static defaultTagArray = ['Geometry'];

	/**
	 三维网格物体(带材质)
	 * @param {object} param 初始化参数列表
	 * @param {object} param.data 存放模型的顶点信息,包括顶点位置(position)、法向量(normal)、贴图坐标(uv)、索引(index)等
	 * @param {object} param.material 材质属性
	 * @constructor
	 * @public
	 */

	constructor(param = {}) {
		super(param);
	}



	// #region Private



	_createCustomNode() {
		let geometryResource = this._geometry.resource;

		let materialResource = this._material.resource;



		return Utils.createObject('CustomNode', { app: this.app, geometryResource, materialResource });
	}



	_loadGeometryResource(param) {
		let data = param['data'];

		if (data) {
			this._geometry = new GeometryResource(data);
		}

		else if (param['geometry']) {
			this._geometry = param['geometry'];

			this._geometry.addRef();
		}
	}



	_loadMaterialResource(param) {
		let material = param['material'];

		if (material) {
			if (material.isMaterialResource) {
				this._material = material;

				this._material.addRef();
			}

			else {
				this._material = new MaterialResource(material);
			}
		}

		else {
			this._material = new MaterialResource();
		}
	}



	// #endregion



	// #region Overrides



	onDestroy() {
		if (this._geometry) {
			this._geometry.release();

			this._geometry = null;
		}



		if (this._material) {
			this._material.release();

			this._material = null;
		}



		super.onDestroy();
	}



	onTaskExecutorComplete(callback, error) {
		if (this.taskExecutor.length) {
			this.taskExecutor.then(callback, error);
		}

		else {
			callback();
		}
	}



	onLoadResource(options, resolve, reject) {
		// 如果动态加载直接返回

		const dynamic = Utils.parseValue(options['dynamic'], false);

		if (dynamic) {
			resolve();

			return;
		}



		if (this.destroyed) {
			return;
		}



		this._resourceState = Object3D.ResourceState.Loading;



		this._loadGeometryResource(this.options);

		this._loadMaterialResource(this.options);



		// 再加载unode

		if (this._geometry) {
			let node = this._createCustomNode();

			this.body.setNode(node);
		}



		// 最后加载图片资源

		if (this._material.loaded) {
			resolve();
		}

		else {
			this._material.waitForComplete().then(() => {
				resolve();
			});
		}
	}



	onCopy(object) {
		super.onCopy(object);



		let resource = object.geometry.resource;

		if (!this.geometry) {
			this.geometry = new GeometryResource({ array: resource._vertexData });
		}

		else {
			this.setNormal(resource.getAttribute('a_Normal'));

			this.setPosition(resource.getAttribute('a_Position'));

			this.setUv(resource.getAttribute('a_Uv'));

			this.setUv2(resource.getAttribute('a_Uv2'));
		}
	}



	/**
	 设置顶点位置信息 当 geometry 仅被当前 Mesh 引用时,使用此接口设置 Mesh 顶点。
	 * @param {Array<number>|Float32Array} array 顶点位置信息。
	 * @public
	 */

	setPosition(array) {
		if (this.geometry.refCount == 1) {
			if (array instanceof Array) {
				array = new Float32Array(array);
			}

			this.geometry.resource.setAttribute('a_Position', array);
		}
	}



	/**
	 * 获取顶点位置信息
	 * @returns {Float32Array} 顶点位置信息。
	 * @public
	 */

	getPosition() {
		return this.geometry.resource.getAttribute('a_Position');
	}



	/**
	 * 设置顶点贴图坐标信息 当 geometry 仅被当前 Mesh 引用时,使用此接口设置 UV。
	 * @param {Array<number>|Float32Array} array 顶点贴图坐标信息。
	 * @public
	 */

	setUv(array) {
		if (this.geometry.refCount == 1) {
			if (array instanceof Array) {
				array = new Float32Array(array);
			}

			this.geometry.resource.setAttribute('a_Uv', array);
		}
	}



	/**
	 获取顶点贴图坐标信息
	 * @returns {Float32Array} 顶点贴图坐标信息。
	 * @public
	 */

	getUv() {
		return this.geometry.resource.getAttribute('a_Uv');
	}



	/**
	 设置顶点第二套贴图坐标信息
	 * @param {Array<number>|Float32Array} array 顶点第二套贴图坐标信息。
	 * @private
	 */

	setUv2(array) {
		if (this.geometry.refCount == 1) {
			if (array instanceof Array) {
				array = new Float32Array(array);
			}

			this.geometry.resource.setAttribute('a_Uv2', array);
		}
	}



	/**
	 设置顶点法线信息 当 geometry 仅被当前 Mesh 引用时,使用此接口设置法线。
	 * @param {Array<number>|Float32Array} array 顶点法线信息。
	 * @public
	 */

	setNormal(array) {
		if (this.geometry.refCount == 1) {
			if (array instanceof Array) {
				array = new Float32Array(array);
			}

			this.geometry.resource.setAttribute('a_Normal', array);
		}
	}



	/**
	 获取顶点法线信息
	 * @returns {Float32Array} 顶点法线信息。
	 * @public
	 */

	getNormal() {
		return this.geometry.resource.getAttribute('a_Normal');
	}



	setIndices(array) {
		if (this.geometry.refCount == 1) {
			if (array instanceof Array) {
				array = new Float32Array(array);
			}

			this.geometry.resource.setIndices(array);
		}
	}

	getIndices() {
		return this.geometry.resource.getIndices();
	}



	// #endregion



	// #region Accessor



	/**

	 获取Mesh的数据
	 * @type {object}
	 * @public
	 */

	get data() {
		return {

			geometryData: this._geometry ? this._geometry.vertexData : null,

			materialData: this._material ? this._material.data : null,

		}
	}



	/**

	 Get geometry. 获取Mesh的几何数据
	 * @type {GeometryResource}
	 * @private
	 */

	get geometry() {
		return this._geometry;
	}

	set geometry(value) {
		this._geometry = value;
	}



	// #endregion



	/**

	 检查是否为Mesh类型或继承自Mesh。
	 * @type {boolean}
	 * @public
	 */

	get isMesh() {
		return true;
	}



}



export { Mesh }