import * as i0 from '@angular/core';
import { NgModule, Injectable } from '@angular/core';
import { CommonModule } from '@angular/common';
import '@iotize/tap-scripts/ext';
import { bufferToHexString, bufferToAsciiString } from '@iotize/common/byte-converter';
import * as i1 from '@iotize/ionic';
import { GrammarHelper, ScriptRunner } from '@iotize/tap-scripts';
import { Subject } from 'rxjs';
import { share } from 'rxjs/operators';

class TapScriptModule {
}
/** @nocollapse */ /** @nocollapse */ TapScriptModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.0", ngImport: i0, type: TapScriptModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
/** @nocollapse */ /** @nocollapse */ TapScriptModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "13.3.0", ngImport: i0, type: TapScriptModule, imports: [CommonModule] });
/** @nocollapse */ /** @nocollapse */ TapScriptModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "13.3.0", ngImport: i0, type: TapScriptModule, imports: [[CommonModule]] });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.0", ngImport: i0, type: TapScriptModule, decorators: [{
            type: NgModule,
            args: [{
                    declarations: [],
                    imports: [CommonModule],
                }]
        }] });

class TapScriptRunnerService {
    constructor(events) {
        this.events = events;
        this.scriptTypes = {
            NORMAL: 1,
            CONFIGURATION: 2,
        };
        this._outputMessages = [];
        this._errors = new Subject();
        this.output = new Subject();
        /** The ScriptRunner object is given options with what is done with values retrieved by the script
         * The output property defines the actions to perform on data retrieving.
         * The display property defines how to log informations given back by the scriptRunner.
         * @see {ScriptRunner}
         */
        this.scriptRunnerOptions = {
            output: (response) => {
                /**
                 * Waiting for ScriptRunner update, display tweak
                 * If response is 1 or 2 bytes or contains 0, displays it as an hex string
                 * else displays it as an ASCII string
                 */
                if (response) {
                    let responseDisplayed;
                    const responseBody = response.body();
                    if (responseBody.length <= 2 || responseBody.includes(0)) {
                        responseDisplayed = bufferToHexString(responseBody);
                    }
                    else {
                        responseDisplayed = bufferToAsciiString(responseBody);
                    }
                    this.addOutput('info', `${responseDisplayed}`);
                }
            },
            display: (level, content) => {
                console.log(`[${level}] : ${content}`);
                if (level == 'message') {
                    this.addOutput('info', `${content}`);
                    return;
                }
                this.addOutput(level, content);
            },
        };
        this.scriptFile = {
            name: '',
            scriptString: '',
        };
        this.scriptType = this.scriptTypes.NORMAL;
    }
    get isRunning() {
        return this.scriptRunner !== undefined && this.scriptRunner.isRunning();
    }
    get hasScript() {
        return this.scriptFile.scriptString !== '';
    }
    /**
     * Converts script content, read as a string, into a list of instructions
     * @param scriptString content of the loaded script file
     * @returns
     */
    getProgInstructions(scriptString) {
        return GrammarHelper.toProgInstructions(scriptString);
    }
    runScript(instructions, tap) {
        this._outputMessages = [];
        return this.executeScriptFromInstructions(tap, instructions);
    }
    stopScript() {
        // TODO
    }
    get errors() {
        return this._errors;
    }
    /**
     * Reads and executes the given instruction list.
     * @param instructions
     */
    executeScriptFromInstructions(tap, instructions) {
        this._outputMessages = [];
        let checkErrorCount = 0;
        const scriptRunner = (this.scriptRunner = new ScriptRunner(this.scriptRunnerOptions));
        scriptRunner.errorHandler = (error) => {
            // this.addOutput('error', error.message);
            this._errors.next(error);
            // console.error(error);
            if (/Check instruction/.test(error.message)) {
                checkErrorCount++;
            }
        };
        return scriptRunner.run(instructions, tap).pipe(
        // rxTap({
        //   next: (event: ScriptRunnerEvent) => {
        //     console.warn(event);
        //     if (event.type == 'after') {
        //       if ('cmd' in event.instruction) {
        //         // this.addOutput('verbose', `Command ${event.instruction['cmd'].toString()}`);
        //       }
        //     }
        //   },
        //   complete: () => {
        //     console.log("Script execution: DONE");
        //     // this.addOutput('info', '\n');
        //     // this.addOutput('info', '--------Script execution: DONE--------');
        //     if (checkErrorCount > 0) {
        //       // this.addOutput('error', `Failed Check instructions: ${checkErrorCount}`);
        //     }
        //     // this.isRunning = false;
        //   },
        //   error: (error) => {
        //     console.error(error);
        //     // this.isRunning = false;
        //   }
        // }),
        share());
    }
    stop() {
        if (this.scriptRunner) {
            this.scriptRunner.stop();
        }
    }
    addOutput(level, message) {
        console.info('SCRIPT', level, message);
        this._outputMessages.push({
            level: level,
            message: message,
        });
        this.output.next(this._outputMessages);
    }
    /**
     * Converts, reads and executes instructions from the raw content of a script file.
     * In the configuration routine, script execution is preceded by:
     * - Log as admin
     * - Factory reset
     * - Wait time
     * And succeeded with
     * - Wait time
     * - Configuration reload
     * - Wait time
     *
     * The configuration routine has succeeded if all these steps did.
     *
     * TODO remove as it's in library
     *
     * @param scriptString
     */
    async executeConfigurationScriptRoutine(scriptString, tap) {
        const waitingTime = 400;
        const instructions = this.getProgInstructions(scriptString);
        try {
            console.log('@@@@@@@@@ Logging as admin @@@@@@@@@');
            // TODO only if not already logged in as an admin
            await tap.auth.login({
                username: 'admin',
                password: 'admin',
            });
            console.log('@@@@@@@@@  factory reset @@@@@@@@@');
            this.events.publish('configuration', 'factory reset');
            const factoryResetResponse = tap.service.device.factoryReset();
            const result = (await factoryResetResponse).body();
            console.log(`factoryReset : ${result}`);
        }
        catch (error) {
            console.error(error);
            throw new Error('factory reset failed');
        }
        this.events.publish('configuration', 'executing script');
        console.log('@@@@@@@@@  Wait after factory reset, before script execution @@@@@@@@@');
        await this.sleep(waitingTime);
        try {
            await this.executeScriptFromInstructions(tap, instructions);
        }
        catch (error) {
            console.error(error);
            throw new Error('Script execution failed');
        }
        try {
            console.log('@@@@@@@@@  Wait after script execution, before reloading config @@@@@@@@@');
            //  5. wait 400ms
            await this.sleep(waitingTime);
            //  6. reload config. Custom call to post /1024//10 while reloadConfig method is not implemented
            const reloadResponse = tap.service.interface.reloadConfig();
            console.log('Waiting for reloadResponse');
            await reloadResponse;
        }
        catch (error) {
            console.error(error);
            throw new Error('Reloading config failed');
        }
        //  7. wait 400ms
        await this.sleep(waitingTime);
        console.log('@@@@@@@@@ configuration complete @@@@@@@@@');
        this.events.publish('configuration', 'configuration completed');
    }
    /**
     * Executes currently loaded script, if no script is running, using the routine defined by the scriptType property
     */
    executeLoadedScript(tap) {
        if (this.isRunning) {
            console.error('Another script is running');
            return;
        }
        if (this.scriptType === this.scriptTypes.CONFIGURATION) {
            return this.executeConfigurationScriptRoutine(this.scriptFile.scriptString, tap);
        }
        if (this.scriptType === this.scriptTypes.NORMAL) {
            return this.executeScriptFromInstructions(tap, this.getProgInstructions(this.scriptFile.scriptString));
        }
    }
    /**
     * Returns a promise that resolve after given time in milliseconds
     * @param milliseconds
     * @returns
     */
    sleep(milliseconds) {
        return new Promise((resolve) => {
            setTimeout(() => resolve(), milliseconds);
        });
    }
}
/** @nocollapse */ /** @nocollapse */ TapScriptRunnerService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.0", ngImport: i0, type: TapScriptRunnerService, deps: [{ token: i1.GlobalEventsService }], target: i0.ɵɵFactoryTarget.Injectable });
/** @nocollapse */ /** @nocollapse */ TapScriptRunnerService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "13.3.0", ngImport: i0, type: TapScriptRunnerService, providedIn: 'root' });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.0", ngImport: i0, type: TapScriptRunnerService, decorators: [{
            type: Injectable,
            args: [{
                    providedIn: 'root',
                }]
        }], ctorParameters: function () { return [{ type: i1.GlobalEventsService }]; } });

/**
 * Generated bundle index. Do not edit.
 */

export { TapScriptModule, TapScriptRunnerService };
//# sourceMappingURL=iotize-ionic-scripts.mjs.map
