Source: resources/CubeTexture.js

import { Utils } from '../common/Utils'
import { ImageWrapType, ImageMappingType } from '../const';
import { BaseImageTexture } from './BaseImageTexture';

/**
 * @class CubeTexture
 * The cube texture resource.
 * @memberof THING
 * @extends THING.BaseImageTexture
 * @public
 */
class CubeTexture extends BaseImageTexture {

	/**
	 * The cube texture that load image resource and use by style.
	 * @param {Object} param The initial parameters.
	 * @example
	 * // Create cube texture from cube map images
	 * let cubeTexture = new THING.CubeTexture([
	 * 	'./skyboxes/bluesky/posx.jpg', './skyboxes/bluesky/negx.jpg',
	 * 	'./skyboxes/bluesky/posy.jpg', './skyboxes/bluesky/negy.jpg',
	 * 	'./skyboxes/bluesky/posz.jpg', './skyboxes/bluesky/negz.jpg'
	 * ]);
	 *
	 * // Create cube texture
	 * let cubeTexture = new THING.CubeTexture({
	 * 	url:{
	 * 		negx: './images/Night/negx.jpg', // 左
	 * 		negy: './images/Night/negy.jpg', // 下
	 * 		negz: './images/Night/negz.jpg', // 前
	 * 		posx: './images/Night/posx.jpg', // 右
	 * 		posy: './images/Night/posy.jpg', // 上
	 * 		posz: './images/Night/posz.jpg'  // 后
	 *	}
	 * });
	 *
	 * // Create cube texture from folder path
	 * let cubeTexture = new THING.CubeTexture({
	 *	url: './images/Night/?png'
	 * }};
	 */
	constructor(param = {}) {
		super(param);
	}

	onLoad(param) {
		// Parse arguments

		let onLoad = Utils.parseValue(param['onLoad'], null);

		this._updateUrl();

		// Some features do not support in compressed texture
		this.flipY = Utils.parseValue(param['flipY'], false);
		this.wrapType = Utils.parseValue(param['wrapType'], ImageWrapType.ClampToEdge);
		this.mappingType = Utils.parseValue(param['mappingType'], ImageMappingType.CubeReflection);

		const data = Utils.parseValue(param['data'], null);

		if (data) {
			this._loadImages(data, onLoad);
		}
		else {
			this._parseUrl(param);
		}
	}

	_parseUrl(param) {
		if (Utils.isString(param)) {
			param = { url: param };
		}

		const _url = param['url'];
		const onLoad = Utils.parseValue(param['onLoad'], null);

		if (Utils.isObject(_url)) {
			// convert object to array with a fixed order
			if (_url['negx'] && _url['negy'] && _url['negz'] && _url['posx'] && _url['posy'] && _url['posz']) {
				param['url'] = [_url['posx'], _url['negx'], _url['posy'], _url['negy'], _url['posz'], _url['negz']]
			}
		}
		// Parse folder url path
		else if (Utils.isString(_url)) {
			if (!Utils.isImagePath(_url)) {
				let suffix = '.jpg';
				let preffix = _url;
				if (_url.indexOf('?') > -1) {
					let arr = _url.split('?');
					suffix = '.' + arr.pop();
					preffix = arr.join('');
				}

				let baseUrl = preffix + '/';
				if (preffix.charAt(preffix.length - 1) === '/' || preffix.slice(preffix.length - 1, preffix.length - 2) === '\\') {
					baseUrl = preffix;
				}

				let fileNames = ['posx', 'negx', 'posy', 'negy', 'posz', 'negz'];
				param = {
					url: fileNames.map(name => baseUrl + name + suffix),
					// url: [
					// 	baseUrl + 'posx.jpg', baseUrl + 'negx.jpg',
					// 	baseUrl + 'posy.jpg', baseUrl + 'negy.jpg' ,
					// 	baseUrl + 'posz.jpg' , baseUrl + 'negz.jpg'
					// ]
				};
			}
		}

		if (Utils.isArray(param) || Utils.isString(param)) {
			param = { url: param };
		}

		this._url = param['url'];

		if (!this._url) {
			this.onNotifyComplete();
		}

		// load image url
		if (Utils.isArray(this._url)) {
			let promises = [];
			this._url.forEach(url => {
				promises.push(this._loadImageFileAsync(url, param));
			});

			Promise.all(promises).then(
				(images) => {
					this._loadImages(images, onLoad);
				},
				(ev) => {
					this.onTriggerErrorEvent(ev);
				}
			);
		}
		else if (Utils.isString(this._url)) {
			this._loadImageFile();
		}
	}

	_loadImages(image, onLoad) {
		this._image = image;

		// Check whether set the image format
		if (this._image.length > 0) {
			this._image.forEach((image) => {
				if (image.format) {
					this.colorFormat = image.format;
				}
			})
		}

		if (onLoad) {
			onLoad({ images: this });
		}

		this.onNotifyComplete();
	}

	_loadImageFileAsync(url, options) {
		const defaultOptions = {
			flipY: this.flipY,
			premultiplyAlpha: this.premultiplyAlpha,
			generateMipmaps: this.generateMipmaps,
			extensions: Utils.getCurrentApp().view.getExtensions()
		};

		const param = Object.assign({}, defaultOptions, options);

		return Utils.loadImageFile(
			url,
			null,
			null,
			null,
			param
		);
	}

	_loadImageFile() {
		Utils.loadImageFile(this._url,
			// Load
			(image) => {
				this._image = image;

				this.onFixupFromImage(image);

				if (onLoad) {
					onLoad({ images: this });
				}

				this.onNotifyComplete();
			},
			// Progress
			(ev) => {

			},
			// Error
			(ev) => {
				this.onTriggerErrorEvent(ev);
			},
			{
				flipY: this.flipY,
				premultiplyAlpha: this.premultiplyAlpha,
				generateMipmaps: this.generateMipmaps,
				extensions: Utils.getCurrentApp().view.getExtensions()
			}
		);
	}

	onCreateTextureResource() {
		let images = this._image;
		if (images) {
			// Image had been loaded
			return Utils.createObject('CubeTextureResource', { data: images });
		}
		else {
			let textureType = Utils.isString(this._url) ? "CompressedImage" : "ArrayImage";

			// Image is still loading, should replace it when it finished
			let textureResource = Utils.createObject('CubeTextureResource', { textureType });

			this.waitForComplete().then((images) => {
				if (images.resource) {
					// Replace texture image
					textureResource.setImages(images.resource);
				}
			});

			return textureResource;
		}
	}

	/**
	 * Get the image of the index.
	 * @param {Number} index The image index.
	 * @returns {Object}
	 * @private
	 */
	getImageByIndex() {
		return this.textureResource.getImageByIndex(index);
	}

	// #region Accessors

	/**
	 * Get/Set resource.
	 * @type {*}
	 * @private
	 */
	get resource() {
		return this._image;
	}
	set resource(value) {
		this._image = value;

		if (this.textureResource) {
			this.textureResource.setImages(value);
		}
	}

	/**
	 * Get/Set images
	 * @type {Array<String>}
	 * @private
	 */
	get urls() {
		return this._url;
	}
	set urls(value) {
		this._setUrl(value);
	}

	// #endregion

	/**
	 * Check class type.
	 * @type {Boolean}
	 * @example
	 * 	if (texture.isCubeTexture) {
	 * 		console.log(`It's cube texture`);
	 * 	}
	 * @public
	 */
	get isCubeTexture() {
		return true;
	}

}

export { CubeTexture }