package jnet.lib.snmp;

import java.io.IOException;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import org.snmp4j.CommunityTarget;
import org.snmp4j.PDU;
import org.snmp4j.Snmp;
import org.snmp4j.TransportMapping;
import org.snmp4j.event.ResponseEvent;
import org.snmp4j.smi.OID;
import org.snmp4j.smi.OctetString;
import org.snmp4j.smi.UdpAddress;
import org.snmp4j.smi.Variable;
import org.snmp4j.smi.VariableBinding;
import org.snmp4j.transport.DefaultUdpTransportMapping;


public class SNMPTrafficMonitor {
    
    private Snmp snmp;
    private String address;
    private String community;
    private int version;
    private ScheduledExecutorService scheduler;
    
    private long previousInOctets = 0;
    private long previousOutOctets = 0;
    private long previousTimestamp = System.currentTimeMillis();
    
    public SNMPTrafficMonitor(String ip, String port, String community, int version) throws IOException {
        this.address = ip + "/" + port; 
        this.community = community;
        this.version = version;
        
        TransportMapping<UdpAddress> transport = new DefaultUdpTransportMapping();
        snmp = new Snmp(transport);
        transport.listen();
    }
    
    /**
     * Vytvoření SNMP cíle (target).
     */
    private CommunityTarget createTarget() {
        CommunityTarget target = new CommunityTarget();
        target.setCommunity(new OctetString(this.community));
        target.setAddress(new UdpAddress(this.address));
        target.setVersion(this.version);
        target.setRetries(2);
        target.setTimeout(1500);
        return target;
    }
    
    public void getTraffic(int interfaceIndex) throws Exception {
        // OID pro přijaté a odeslané bajty specifického rozhraní
        OID oidInOctets = new OID("1.3.6.1.2.1.2.2.1.10." + interfaceIndex);  // ifInOctets pro daný interface
        OID oidOutOctets = new OID("1.3.6.1.2.1.2.2.1.16." + interfaceIndex); // ifOutOctets pro daný interface

        // Vytvoření SNMP požadavku pro získání hodnot
        PDU pdu = new PDU();
        pdu.add(new VariableBinding(oidInOctets));  // Přidaní OID pro příchozí traffic
        pdu.add(new VariableBinding(oidOutOctets)); // Přidaní OID pro odchozí traffic
        pdu.setType(PDU.GET);

        // Definování cíle SNMP zařízení
        CommunityTarget target = createTarget();

        // Odeslání požadavku a zpracování odpovědi
        ResponseEvent response = snmp.get(pdu, target);

        if (response != null && response.getResponse() != null) {
            PDU responsePDU = response.getResponse();
            Variable inOctets = responsePDU.getVariableBindings().get(0).getVariable();
            Variable outOctets = responsePDU.getVariableBindings().get(1).getVariable();

            long currentInOctets = inOctets.toLong();
            long currentOutOctets = outOctets.toLong();
            long currentTimestamp = System.currentTimeMillis();

            // Vypočítání traffiku za sekundu
            long deltaInOctets = currentInOctets - previousInOctets;
            long deltaOutOctets = currentOutOctets - previousOutOctets;
            long deltaTime = currentTimestamp - previousTimestamp;

            // Vypočítání traffiku za sekundu
            double inTrafficPerSecond = (deltaInOctets * 1000.0) / deltaTime;  // Počet bajtů za sekundu
            double outTrafficPerSecond = (deltaOutOctets * 1000.0) / deltaTime;

            System.out.println("Traffic na rozhrani " + interfaceIndex + ":");
            System.out.println("Prijaty traffic (In Octets): " + formatBytes(currentInOctets) + " | Za sekundu: " + formatBytesPerSecond(inTrafficPerSecond));
            System.out.println("Odeslany traffic (Out Octets): " + formatBytes(currentOutOctets) + " | Za sekundu: " + formatBytesPerSecond(outTrafficPerSecond));

            // Uložení aktuálních hodnot pro další výpočet
            previousInOctets = currentInOctets;
            previousOutOctets = currentOutOctets;
            previousTimestamp = currentTimestamp;
        } else {
            System.out.println("Chyba při získávání dat z cílového zařízení.");
        }
    }
    
    public void startMonitoring(int interfaceIndex) {
        // Vytvoření plánovače pro spuštění každých 5 sekund
        scheduler = Executors.newScheduledThreadPool(1);
        scheduler.scheduleAtFixedRate(() -> {
            try {
                getTraffic(interfaceIndex);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }, 0, 3, TimeUnit.SECONDS); // Start okamžitě a potom každých 5 sekund
    }

    public void stopMonitoring() {
        if (scheduler != null) {
            scheduler.shutdown();  // Umožní ukončení plánování
        }
    }
    
    // Metoda pro přepočet traffiku za sekundu na čitelnou podobu
    private String formatBytesPerSecond(double bytesPerSecond) {
        if (bytesPerSecond < 1024) {
            return String.format("%.2f B/s", bytesPerSecond);
        } else if (bytesPerSecond < 1048576) {  // 1024 * 1024
            return String.format("%.2f KB/s", bytesPerSecond / 1024.0);
        } else if (bytesPerSecond < 1073741824) {  // 1024 * 1024 * 1024
            return String.format("%.2f MB/s", bytesPerSecond / 1048576.0);
        } else {
            return String.format("%.2f GB/s", bytesPerSecond / 1073741824.0);
        }
    }

    public void stop() throws Exception {
        if (snmp != null) {
            snmp.close();
        }
    }

    
    // Metoda pro přepočet bajtů na čitelnou podobu
    private String formatBytes(long bytes) {
        if (bytes < 1024) {
            return bytes + " B";
        } else if (bytes < 1048576) {  // 1024 * 1024
            return String.format("%.2f KB", bytes / 1024.0);
        } else if (bytes < 1073741824) {  // 1024 * 1024 * 1024
            return String.format("%.2f MB", bytes / 1048576.0);
        } else {
            return String.format("%.2f GB", bytes / 1073741824.0);
        }
    }

}
