import { Reporter } from '../../reporter/reporter.js';
import { Component } from '../../component/component.js';
import { checkPropTypes, omit } from '../../lib.js';
import { LoadingBase } from '../loader/loading_base.js';
/**
* Component without dependencies that needs
* data be loaded from somewhere
*/
// file has low/med/high quality?
// kan een buildable component altijd de hoogste kwaliteit teruggeven?
class LoadableComponent extends Component {
/**
* @param {Reporter} reporter
* @param {Object} settings
* @param {UUID} [settings.id]
* @param {string} [settings.name]
* @param {QualitySourceMap} settings.source - Either one URL, or three (one for every quality setting)
* @param {number} [settings.sizeBytes]
*/
constructor(reporter, settings) {
super(reporter, settings);
if (!settings.source) {
// console.log(settings)
throw new Error('Missing source property');
}
if (!settings.source.medium) {
throw new Error('Source should always specify a medium quality file');
}
const checkSource = src => {
if ( typeof (src.path) !== 'string' || src.path === '' ) {
return `Property path = ${src.path}, should be a non-empty string.`;
}
if( typeof (src.sizeBytes) !== 'number' ) {
return `Property sizeBytes = ${src.sizeBytes}, should be a number.`;
}
return true;
}
// TODO: dynamisch maken adhv Component.qualities
checkPropTypes(
settings.source,
{
medium: checkSource
},
{
// low: checkSource,
// high: checkSource
}
);
this.source = {
'medium': settings.source.medium
};
this.source.high = settings.source.high || settings.source.medium;
this.source.low = settings.source.low || settings.source.medium;
// this.on( 'status-change', async ({ quality, part, status, previousStatus }) => {
// if any of the other quality sources are equal to this one
// copy the result
// for (let setQuality of Component.qualities) {
// const currStatus = this._status[ part ][ setQuality ].state;
// if ( setQuality !== quality && status !== currStatus && this.source[setQuality].path === this.source[quality].path) {
// this.report({ msg: `Same source updating ${part} ${quality} (${status}) -> ${setQuality} (${currStatus})` });
// if (status === 'ready') {
// await this._setContent('main', setQuality, this._content[ part ][ quality ] );
// }
// else {
// await this._status.main[setQuality].setState(status);
// }
// }
// }
// });
}
/**
* @type {QualitySourceMap}
*/
source = {};
/**
* @protected
* @interface
* @method
* @param {LoadingBase} base
* @param {LoadingQuality} quality
* @returns {Promise<any>}
*/
async _load(base, quality) {
this.report({ level: 'notice', msg: 'Override LoadableComponent _load method!' });
return Promise.reject();
}
/**
* This method is not meant to be called directly.
* Instead it is meant to be called by the ComponentLoader, which will respond to its
* error state changes, in case anything fails.
* @interface
* @method
* @param {LoadingBase} base
* @param {LoadingQuality} [quality = 'medium']
* @returns {Promise<LoadableComponent>}
*/
async load(base, quality = 'medium') {
await this._status.main[quality].setState('loading');
let loadErrorMessage = null;
try {
const content = await this._load(base, quality);
await this._setContent('main', quality, content);
return this;
}
catch (err) {
// await this._status.main[quality].setState('error');
if (err.message) {
loadErrorMessage = `Load errored: ${err.message}`;
}
else {
loadErrorMessage = `Unknown loading error.`;
}
this.report({ msg: loadErrorMessage, level: 'error' });
console.error( `Error loading ${quality} quality ${this.label}`, err);
this._setError('main', quality, new Error( loadErrorMessage ) );
}
}
}
export { LoadableComponent };