npm package: @nanomatic/fsm
Description: Implementation of the Finite State Machine
Author: NANOmatic
Latest version: 1.6.1

<p align="center">
  <a href="" rel="noopener">
  <img src="https://o.quizlet.com/d50UKgZJNItlLVhnKrsIaQ.png" alt="FSM"></a>
</p>
<h3 align="center">@nanomatic/fsm</h3>

<div align="center">

[![Status](https://img.shields.io/badge/status-active-success.svg)]()
[![License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE.md)

</div>

---

<p align="center">
    Implementation of the Finite State Machine.
    <br />
</p>

## 📝 Table of Contents

- [📝 Table of Contents](#-table-of-contents)
- [🏁 Getting Started <a name = "getting_started"></a>](#-getting-started-)
  - [Installing](#installing)
  - [Using](#using)
- [⛏️ Built With <a name = "tech_stack"></a>](#️-built-with-)
- [📦 Dependencies <a name = "dependencies"></a>](#-dependencies-)
- [✍️ Authors <a name = "authors"></a>](#️-authors-)
- [🎉 Acknowledgments <a name = "acknowledgments"></a>](#-acknowledgments-)

## 🏁 Getting Started <a name = "getting_started"></a>

### Installing

```
npm i @nanomatic/fsm
```

### Using

Example code below:

```js
import { State, StateMachine } from '@nanomatic/fsm';

/*
    Three states. Steps:
    1. All devices turned off.
    2. Lamp turned on after three seconds (simulated user operation).
    3. Motor turned on after another three seconds.
    4. Go to the step 1 after ten seconds from beginig.

    FSM will be paused after 4 seconds from the start.
    Another 4 seconds to resume.
*/

// Time in s
const hundredMiliseconds = .1;
const threeSeconds = 3;
const fourSeconds = 4;
const eightSeconds = 8;
const fiveteenSeconds = 15;

// Types
interface Data {
    lamp: boolean;
    motor: boolean;
    start: boolean;
}

// Variables
let showLogs = true;
const data: Data = {
    lamp: false,
    motor: false,
    start: false
};

// Helper function
const allSwitchOff = () => {
    data.lamp = false;
    data.motor = false;
    showLogs = false;
};

// States
const allOff = new State;
const lampOn = new State(() => data.lamp = true);
const motorOn = new State({ entry: () => data.motor = true, exit: allSwitchOff });

console.log(`Total number of states: ${State.states}`);

// State machine
// const fsm = new StateMachine(allOff);                        // Step 1 (immediately)
const fsm = new StateMachine<Data>(allOff);                     // Step 1 (immediately)

// Transitions
allOff.addTransition(lampOn, ({ start }: Data) => start);       // Step 2 (after three seconds)
lampOn.addTransition(motorOn);                                  // Step 3 (automatic flow after another three seconds)
lampOn.time = threeSeconds;                                     // When time is equal to zero then transition fire imiditly
// lampOn.time = () => threeSeconds;
fsm.addCommonState(allOff, [], ({ start }: Data) => !start);    // Step 4 (after ten seconds from beginig)

// Program cycle (100 ms)
setInterval(() => fsm.step(data), hundredMiliseconds);

// Only for data simulation
setTimeout(() => data.start = true, threeSeconds * 1000);       // Step 2 (after three seconds)
setTimeout(() => data.start = false, fiveteenSeconds * 1000);   // Step 4 (after ten seconds from beginig)
const programInterval = setInterval(() => {
    // tslint:disable-next-line: no-console
    console.log(`Lamp: ${data.lamp}\tMotor: ${data.motor}\tStart: ${data.start}\tRemaining time: ${fsm.state.timer.remainingTime.toFixed(3)}s`);
    if (!showLogs)
        clearInterval(programInterval);
}, hundredMiliseconds * 1000);

setTimeout(() => fsm.pause(), fourSeconds * 1000);              // Pause after 4 seconds
setTimeout(() => fsm.resume(), eightSeconds * 1000);            // Resume after next 4 seconds
```

## ⛏️ Built With <a name = "tech_stack"></a>

- [ts-node-dev](https://www.npmjs.com/package/ts-node-dev) - TypeScript Node Dev
- [tsc-watch](https://www.npmjs.com/package/tsc-watch) - The nodemon for TypeScript
- [TSLint](https://www.npmjs.com/package/tslint) - TypeScript linter
- [NodeJs](https://nodejs.org/en/) - Test Environment

## 📦 Dependencies <a name = "dependencies"></a>

- [@nanomatic/timer](https://www.npmjs.com/package/@nanomatic/timer) - Implementation of the reuseable timer

## ✍️ Authors <a name = "authors"></a>

- [@NANOmatic](https://github.com/NANOmatic) - Idea & Initial work

## 🎉 Acknowledgments <a name = "acknowledgments"></a>

- Special thanks for Sebastian for working together and giving ideas 😉