import { Buffer } from 'buffer'; // Import Buffer type
import get_convert from '../lib/packet/converters.js';
/* packet.ts
 *
 * author: Piero Proietti <piero.proietti@gmail.com>
 * refactored for modern TypeScript
 */
import { readIp, readMacAddress } from '../lib/utils.js';
// Mettiamo 'export' direttamente davanti alla classe
export class Packet {
    chaddr;
    ciaddr;
    flags;
    fname;
    giaddr;
    hlen;
    hops;
    htype;
    // Aggiunto '!' per il "Definite Assignment Assertion"
    op;
    options;
    secs;
    siaddr;
    sname;
    xid;
    yiaddr;
    constructor(init) {
        // Usiamo Partial<Packet> per l'inizializzazione
        Object.assign(this, init);
    }
    // --- METODI STATICI (prima erano funzioni esterne) ---
    /**
     * Crea un oggetto Packet da un Buffer
     * @param b Il Buffer da cui leggere
     * @returns Un'istanza di Packet
     */
    static fromBuffer(b) {
        const ret = {
            chaddr: readMacAddress(b.slice(28, 28 + b.readUInt8(2))),
            ciaddr: readIp(b, 12),
            flags: b.readUInt16BE(10),
            fname: stripBinNull(b.toString('ascii', 108, 236)),
            giaddr: readIp(b, 24),
            hlen: b.readUInt8(2),
            hops: b.readUInt8(3),
            htype: b[1],
            op: b[0],
            options: {},
            secs: b.readUInt16BE(8),
            siaddr: readIp(b, 20),
            sname: stripBinNull(b.toString('ascii', 44, 108)),
            xid: b.readUInt32BE(4),
            yiaddr: readIp(b, 16)
        };
        let i = 240;
        while (i < b.length && b[i] !== 255) {
            const optNum = b[i++];
            const optLen = b[i++];
            if (i + optLen > b.length)
                break; // Evita errori di out-of-bounds
            const converter = get_convert(optNum);
            const optVal = converter.decode(b.slice(i, i + optLen), optNum);
            ret.options[optNum] = optVal;
            i += optLen;
        }
        return new Packet(ret);
    }
    // --- METODI DI ISTANZA (quelli che restituiscono 'this' e toBuffer) ---
    getRequestedIPAddress() {
        return this.options[50];
    }
    // ... tutti i tuoi metodi "builder" che restituiscono 'this' vanno qui
    // Esempio:
    op_set(op) {
        this.op = op;
        return this;
    }
    // ...e così via per htype, hlen, xid, etc.
    /**
     * Converte l'oggetto Packet in un Buffer
     * @returns Il Buffer DHCP
     */
    toBuffer() {
        const buffer = Buffer.alloc(512); // Usare Buffer.alloc è più sicuro
        buffer.fill(0);
        buffer[0] = this.op;
        buffer[1] = this.htype;
        buffer.writeUInt8(this.hlen, 2);
        buffer.writeUInt8(this.hops, 3);
        buffer.writeUInt32BE(this.xid, 4);
        buffer.writeUInt16BE(this.secs, 8);
        buffer.writeUInt16BE(this.flags, 10);
        let pos = 12;
        for (const addr of [this.ciaddr, this.yiaddr, this.siaddr, this.giaddr]) {
            for (const octet of (addr || '0.0.0.0').split('.')) {
                buffer.writeUInt8(Number.parseInt(octet, 10), pos++);
            }
        }
        for (const hex of this.chaddr.split(':')) {
            buffer[pos++] = Number.parseInt(hex, 16);
        }
        buffer.fill(0, pos, 236); // Pulisce il resto dell'header
        buffer.write(this.sname || '', 44, 64, 'ascii');
        buffer.write(this.fname || '', 108, 128, 'ascii');
        pos = 236;
        for (const magicCookieByte of [99, 130, 83, 99]) {
            buffer[pos++] = magicCookieByte;
        }
        pos = 240;
        for (const opt in this.options) {
            if (this.options.hasOwnProperty(opt)) {
                const value = this.options[opt];
                const converter = get_convert(Number.parseInt(opt));
                pos = converter.encode(buffer, Number.parseInt(opt), value, pos);
            }
        }
        buffer[pos++] = 255; // End Option
        return buffer.slice(0, pos);
    }
}
// Funzione helper, può rimanere qui o essere spostata in un file di utility
function stripBinNull(str) {
    const pos = str.indexOf('\u0000');
    return pos === -1 ? str : str.slice(0, Math.max(0, pos));
}
