Source: sources/workers/AbstractWorker.js

/**
 * @author [Tristan Valcke]{@link https://github.com/Itee}
 */

import {
    isArray,
    isArrayBuffer,
    isEmptyString,
    isNotArray,
    isNotDefined,
    isNotString
}                                from 'itee-validators'
import { WorkerMessageData }     from './messages/WorkerMessageData'
import { WorkerMessageError }    from './messages/WorkerMessageError'
import { WorkerMessageProgress } from './messages/WorkerMessageProgress'

/**
 * @class
 * @classdesc Base worker interface that allow messaging between callee and caller
 */
class AbstractWorker {

    /**
     *
     * @param progress
     */
    postProgress ( progress ) {

        if ( progress.isWorkerMessageProgress ) {
            postMessage( progress.toJSON() )
        } else {
            postMessage( new WorkerMessageProgress( progress.loaded, progress.total ).toJSON() )
        }

    }

    /**
     *
     * @param error
     */
    postError ( error ) {

        if ( error.isWorkerMessageError ) {
            postMessage( error.toJSON() )
        } else {
            postMessage( new WorkerMessageError( error ).toJSON() )
        }

    }

    /**
     *
     * @param type
     * @param arrayBuffer
     */
    postData ( type, arrayBuffer ) {

        if ( isArray( arrayBuffer ) ) {
            postMessage( new WorkerMessageData( type, arrayBuffer ).toJSON(), [ ...arrayBuffer ] )
        } else if ( isArrayBuffer( arrayBuffer ) ) {
            postMessage( new WorkerMessageData( type, arrayBuffer ).toJSON(), [ arrayBuffer ] )
        } else {
            throw new TypeError( `AbstractWorker.postData: Unable to post data of type [${ type }].` )
        }

    }

    /**
     *
     * @param message
     * @returns {boolean}
     */
    onMessage ( message ) {

        if ( isNotDefined( message ) ) {
            this.postError( new Error( 'Message event cannot be null or undefined !' ) )
            return true
        }

        const data = message.data
        if ( isNotDefined( data ) ) {
            this.postError( new Error( 'Message data cannot be null or undefined !' ) )
            return true
        }

        const dataType = data.type
        if ( isNotDefined( dataType ) ) {
            this.postError( new Error( 'Message data type cannot be null or undefined !' ) )
            return true
        }

        if ( data.type === 'methodCall' ) {

            const methodName = data.method
            if ( isNotDefined( methodName ) ) {
                this.postError( new Error( 'Message of type "methodCall" cannot have null, undefined or empty name !' ) )
                return true
            }

            if ( isNotString( methodName ) ) {
                this.postError( new Error( 'Message of type "methodCall" expect name to be a string !' ) )
                return true
            }

            if ( isEmptyString( methodName ) ) {
                this.postError( new Error( 'Message of type "methodCall" expect name to be a non empty string !' ) )
                return true
            }

            const methodParameters = data.parameters || []
            if ( isNotArray( methodParameters ) ) {
                this.postError( new Error( 'Message of type "methodCall" expect parameters to be an array !' ) )
                return true
            }

            this._invoke( methodName, methodParameters )
            return true

        }

    }

    /**
     *
     * @param name
     * @param parameters
     * @private
     */
    _invoke ( name, parameters = [] ) {

        try {

            const result = this[ name ]( ...parameters )
            if ( result ) {
                postMessage( {
                    type:   name,
                    result: result
                } )
            }

        } catch ( error ) {
            this.postError( error )
        }

    }

}

export { AbstractWorker }