CCCPaste
-- nanomachine_server.lua
-- Designed by fxllenfx for fx-Studios
-- Nanomachine Profile Management Server v2.0

local component = require("component")
local event = require("event")
local serialization = require("serialization")
local filesystem = require("filesystem")

-- Config
local PORT = 2000
local SAVE_FILE = "/home/nanomachine_profiles.cfg"

-- Components
local modem = component.modem

-- Data Storage
local profiles = {}
local discoveredEffects = {}
local clientStats = {}

-- Initialize
local function initialize()
  print("╔═══════════════════════════════════════════════╗")
  print("║   fx-Studios NANOMACHINE SERVER v2.0         ║")
  print("║   Designed by fxllenfx                        ║")
  print("╚═══════════════════════════════════════════════╝")
  print("")

  modem.open(PORT)
  print("✓ Modem listening on port " .. PORT)
  print("✓ Server Address: " .. modem.address)
  print("")

  -- Load saved data
  loadData()

  print("✓ Server bereit")
  print("")

  return true
end

-- Save/Load Functions
local function saveData()
  local data = {
    profiles = profiles,
    discoveredEffects = discoveredEffects,
    version = "2.0",
    lastSaved = os.time()
  }

  local file = io.open(SAVE_FILE, "w")
  if file then
    file:write(serialization.serialize(data))
    file:close()
    print("[SAVE] Daten erfolgreich gespeichert")
    return true
  else
    print("[ERROR] Fehler beim Speichern")
    return false
  end
end

local function loadData()
  if not filesystem.exists(SAVE_FILE) then
    print("[LOAD] Keine gespeicherten Daten gefunden")

    -- Create default profiles
    profiles = {
      {
        name = "Safe",
        description = "Nur Regeneration",
        inputs = {},
        created = os.time(),
        creator = "system"
      },
      {
        name = "Combat",
        description = "Kampf-Modus mit Staerke und Geschwindigkeit",
        inputs = {},
        created = os.time(),
        creator = "system"
      },
      {
        name = "Mining",
        description = "Bergbau mit Haste und Nachtsicht",
        inputs = {},
        created = os.time(),
        creator = "system"
      }
    }

    saveData()
    return
  end

  local file = io.open(SAVE_FILE, "r")
  if file then
    local content = file:read("*a")
    file:close()

    local success, data = pcall(serialization.unserialize, content)
    if success and data then
      profiles = data.profiles or {}
      discoveredEffects = data.discoveredEffects or {}

      print("[LOAD] Daten geladen")
      print("       Profile: " .. #profiles)
      print("       Entdeckte Effekte: " .. #discoveredEffects)
    else
      print("[ERROR] Fehler beim Parsen der Daten")
    end
  end
end

-- Profile Management
local function addProfile(profile)
  -- Check if profile name already exists
  for i, p in ipairs(profiles) do
    if p.name == profile.name then
      -- Update existing profile
      profiles[i] = profile
      print("[PROFILE] Profil aktualisiert: " .. profile.name)
      saveData()
      return true
    end
  end

  -- Add new profile
  table.insert(profiles, profile)
  print("[PROFILE] Neues Profil gespeichert: " .. profile.name)
  saveData()
  return true
end

local function deleteProfile(profileName)
  for i, profile in ipairs(profiles) do
    if profile.name == profileName then
      table.remove(profiles, i)
      print("[PROFILE] Profil geloescht: " .. profileName)
      saveData()
      return true
    end
  end

  print("[ERROR] Profil nicht gefunden: " .. profileName)
  return false
end

local function getProfile(profileName)
  for _, profile in ipairs(profiles) do
    if profile.name == profileName then
      return profile
    end
  end
  return nil
end

-- Discovery Management
local function addDiscoveredEffect(effectData)
  -- Check if combination already exists
  local comboStr = table.concat(effectData.combination, ",")

  for _, existing in ipairs(discoveredEffects) do
    local existingStr = table.concat(existing.combination, ",")
    if existingStr == comboStr then
      -- Update existing
      existing.effects = effectData.effects
      existing.lastSeen = os.time()
      return true
    end
  end

  -- Add new discovery
  table.insert(discoveredEffects, effectData)
  print("[DISCOVERY] Neuer Effekt entdeckt: " .. table.concat(effectData.effects, ", "))
  saveData()
  return true
end

-- Client Statistics
local function updateClientStats(clientAddr, action)
  if not clientStats[clientAddr] then
    clientStats[clientAddr] = {
      address = clientAddr,
      firstSeen = os.time(),
      lastSeen = os.time(),
      requests = 0
    }
  end

  clientStats[clientAddr].lastSeen = os.time()
  clientStats[clientAddr].requests = clientStats[clientAddr].requests + 1
  clientStats[clientAddr].lastAction = action
end

-- Message Handler
local function handleMessage(sender, port, distance, command, serializedData)
  updateClientStats(sender, command)

  print("[REQUEST] " .. command .. " von " .. sender:sub(1, 8) .. "...")

  if command == "GET_PROFILES" then
    local serialized = serialization.serialize(profiles)
    modem.send(sender, PORT, "GET_PROFILES_RESPONSE", serialized)

  elseif command == "SAVE_PROFILE" then
    if serializedData then
      local success, profile = pcall(serialization.unserialize, serializedData)
      if success and profile then
        profile.lastModified = os.time()
        profile.modifiedBy = sender:sub(1, 8)
        addProfile(profile)
        modem.send(sender, PORT, "ACK")
      else
        modem.send(sender, PORT, "ERROR")
      end
    end

  elseif command == "DELETE_PROFILE" then
    if serializedData then
      local success, profileName = pcall(serialization.unserialize, serializedData)
      if success and profileName then
        deleteProfile(profileName)
        modem.send(sender, PORT, "ACK")
      else
        modem.send(sender, PORT, "ERROR")
      end
    end

  elseif command == "GET_PROFILE" then
    if serializedData then
      local success, profileName = pcall(serialization.unserialize, serializedData)
      if success and profileName then
        local profile = getProfile(profileName)
        if profile then
          local serialized = serialization.serialize(profile)
          modem.send(sender, PORT, "GET_PROFILE_RESPONSE", serialized)
        else
          modem.send(sender, PORT, "ERROR")
        end
      end
    end

  elseif command == "SAVE_DISCOVERY" then
    if serializedData then
      local success, effectData = pcall(serialization.unserialize, serializedData)
      if success and effectData then
        addDiscoveredEffect(effectData)
        modem.send(sender, PORT, "ACK")
      else
        modem.send(sender, PORT, "ERROR")
      end
    end

  elseif command == "GET_DISCOVERIES" then
    local serialized = serialization.serialize(discoveredEffects)
    modem.send(sender, PORT, "GET_DISCOVERIES_RESPONSE", serialized)

  elseif command == "PING" then
    modem.send(sender, PORT, "PONG")

  elseif command == "GET_STATS" then
    local serialized = serialization.serialize(clientStats)
    modem.send(sender, PORT, "GET_STATS_RESPONSE", serialized)

  else
    print("[WARNING] Unbekannter Command: " .. command)
    modem.send(sender, PORT, "ERROR")
  end
end

-- Status Display
local function displayStatus()
  print("╔═══════════════════════════════════════════════╗")
  print("║   fx-Studios NANOMACHINE SERVER STATUS       ║")
  print("╚═══════════════════════════════════════════════╝")
  print("")
  print("Server: " .. modem.address:sub(1, 8) .. "...")
  print("Port: " .. PORT)
  print("")
  print("Gespeicherte Profile: " .. #profiles)
  print("Entdeckte Effekte: " .. #discoveredEffects)
  print("Verbundene Clients: " .. (function()
    local count = 0
    for _ in pairs(clientStats) do count = count + 1 end
    return count
  end)())
  print("")

  -- Show recent profiles
  if #profiles > 0 then
    print("═══ LETZTE PROFILE ═══")
    for i = math.max(1, #profiles - 4), #profiles do
      local p = profiles[i]
      print(string.format("  [%d] %s (%d inputs)", i, p.name, #p.inputs))
    end
    print("")
  end

  -- Show active clients
  local activeClients = 0
  local cutoff = os.time() - 60  -- Active in last 60 seconds

  for addr, stats in pairs(clientStats) do
    if stats.lastSeen > cutoff then
      activeClients = activeClients + 1
    end
  end

  if activeClients > 0 then
    print("Aktive Clients (letzte 60s): " .. activeClients)
    print("")
  end

  print("Druecke Ctrl+C zum Beenden")
  print("───────────────────────────────────────────────")
end

-- Cleanup old client stats
local function cleanupClientStats()
  local cutoff = os.time() - 3600  -- Remove clients inactive for 1 hour
  local removed = 0

  for addr, stats in pairs(clientStats) do
    if stats.lastSeen < cutoff then
      clientStats[addr] = nil
      removed = removed + 1
    end
  end

  if removed > 0 then
    print("[CLEANUP] " .. removed .. " inaktive Clients entfernt")
  end
end

-- Main Loop
local function main()
  if not initialize() then
    print("Server-Initialisierung fehlgeschlagen")
    return
  end

  local lastStatusDisplay = 0
  local lastCleanup = 0

  while true do
    local currentTime = os.time()

    -- Display status every 30 seconds
    if currentTime - lastStatusDisplay >= 30 then
      displayStatus()
      lastStatusDisplay = currentTime
    end

    -- Cleanup every 10 minutes
    if currentTime - lastCleanup >= 600 then
      cleanupClientStats()
      lastCleanup = currentTime
    end

    -- Handle messages
    local _, _, sender, port, distance, command, data = event.pull(0.5, "modem_message")

    if command then
      handleMessage(sender, port, distance, command, data)
    end
  end
end

-- Cleanup
local function cleanup()
  print("")
  print("╔═══════════════════════════════════════════════╗")
  print("║   SERVER HERUNTERFAHREN                       ║")
  print("╚═══════════════════════════════════════════════╝")
  print("")

  -- Save data one last time
  saveData()

  -- Close modem
  modem.close(PORT)

  print("✓ Server gestoppt")
  print("")
  print("fx-Studios - Designed by fxllenfx")
end

-- Error handling
local success, err = xpcall(main, debug.traceback)

if not success then
  print("")
  print("╔═══════════════════════════════════════════════╗")
  print("║   FATAL ERROR                                 ║")
  print("╚═══════════════════════════════════════════════╝")
  print("")
  print(tostring(err))
  print("")
end

cleanup()