'use strict';
// ESU ECoS / ECoS 2 adapter — TCP (poort 15471), tekst-protocol ("ECoSnet").
// Commando's hebben de vorm:  request(<id>, <action>[, options])
//   set(1, go)                 // power on  (1 = command station object)
//   set(1, stop)               // power off
//   set(<locoOID>, speed[N])   // snelheid 0..127
//   set(<locoOID>, dir[0|1])   // richting
//   set(<locoOID>, func[F,1])  // functie aan/uit
//   set(<turnoutOID>, state[0|1])
// Loc's/wissels zijn "objecten" met een OID; die haal je op via queryObjects(10|11).
//
// ⚠️ SCAFFOLD: de OID-koppeling (adres → object-id) en het antwoord-parsen moeten tegen een
//    echte ECoS worden afgemaakt. De adapter houdt de toestand bij en logt wat hij zou sturen.
const net = require('net');
const EventEmitter = require('events');

class Ecos extends EventEmitter {
  constructor(opts = {}) {
    super();
    this.mode = 'ecos';
    this.host = opts.host || '192.168.0.5';
    this.port = opts.port || 15471;
    this.connected = false;
    this.sock = null;
    this.state = { power: false, locos: {}, turnouts: {}, sensors: {} };
    this._oid = {};   // addr -> ECoS object-id (te vullen via queryObjects)
  }

  connect() {
    const s = new net.Socket(); this.sock = s; s.setEncoding('utf8');
    s.on('connect', () => {
      this.connected = true; this.emit('open');
      this.emit('log', '[ecos] TCP ' + this.host + ':' + this.port);
      this._tx('queryObjects(10, addr, name)');   // locs
      this._tx('queryObjects(11, addr, name)');   // wissels
    });
    s.on('data', (d) => this.emit('log', '↩ ' + d.trim()));
    s.on('error', (e) => this.emit('log', '[ecos] fout: ' + e.message));
    s.on('close', () => { this.connected = false; this.emit('close'); setTimeout(() => this.connect(), 3000); });
    s.connect(this.port, this.host);
  }

  _tx(cmd) {
    this.emit('log', '→ ' + cmd);
    if (this.connected && this.sock) { try { this.sock.write(cmd + '\n'); } catch (e) { this.emit('log', '[tx-fout] ' + e.message); } }
  }
  _loco(addr) { if (!this.state.locos[addr]) this.state.locos[addr] = { speed: 0, dir: 1, fns: {} }; return this.state.locos[addr]; }
  _oidFor(addr) { return this._oid[addr] || ('addr:' + addr); }  // val terug op adres tot OID bekend is

  power(on) { this.state.power = !!on; this._tx('set(1, ' + (on ? 'go' : 'stop') + ')'); this.emit('state'); }
  throttle(addr, speed, dir) {
    addr = parseInt(addr, 10); const ui = Math.max(0, Math.min(126, parseInt(speed, 10)));
    const l = this._loco(addr); l.speed = ui; l.dir = dir ? 1 : 0;
    this._tx('set(' + this._oidFor(addr) + ', speed[' + ui + '])');
    this._tx('set(' + this._oidFor(addr) + ', dir[' + (dir ? 0 : 1) + '])');
    this.emit('state');
  }
  func(addr, fn, on) {
    addr = parseInt(addr, 10); fn = parseInt(fn, 10); this._loco(addr).fns[fn] = !!on;
    this._tx('set(' + this._oidFor(addr) + ', func[' + fn + ',' + (on ? 1 : 0) + '])');
    this.emit('state');
  }
  estop() {
    for (const a of Object.keys(this.state.locos)) this.state.locos[a].speed = 0;
    this._tx('set(1, stop)'); this.emit('log', '⛔ NOODSTOP'); this.emit('state');
  }
  turnout(id, thrown) {
    id = parseInt(id, 10); this.state.turnouts[id] = !!thrown;
    this._tx('set(' + ('addr:' + id) + ', state[' + (thrown ? 1 : 0) + '])');
    this.emit('state');
  }
}

module.exports = { Ecos };
