main
John Lauer 0.2.0: the bridge is Rust end to end — all 112 verbs dispatch from altium-bridge.exe (spawn.kind exe); Python runtime n… 4fb2c47 1mo ago
//! /health — Altium detection through ab's window enumeration (no Win32 in the bridge).
use crate::{agent, BRIDGE_VERSION};
use serde_json::{json, Value};

/// Parse "<doc> - Altium Designer[ Develop][ (26.9.1)][ - Trial]" (issue #2: edition without parens).
pub fn parse_title(t: &str) -> Option<Value> {
    let i = t.find("Altium Designer")?;
    let rest = &t[i + "Altium Designer".len()..];
    let mut edition = None;
    let mut version = None;
    let mut lic = None;
    let mut s = rest.trim_start();
    for ed in ["Develop", "Viewer", "Standard", "Professional", "Pro", "Enterprise"] {
        if let Some(r) = s.strip_prefix(ed) {
            edition = Some(ed.to_string());
            s = r.trim_start();
            break;
        }
    }
    if let Some(r) = s.strip_prefix('(') {
        if let Some(j) = r.find(')') {
            version = Some(r[..j].to_string());
            s = r[j + 1..].trim_start();
        }
    }
    if let Some(r) = s.strip_prefix("- ") {
        lic = Some(r.trim().to_string());
    }
    if edition.is_none() && version.is_none() && lic.is_none() && rest.trim().is_empty() && i != 0 {
        return None; // bare mid-string "Altium Designer" inside a dialog title
    }
    let doc = if i > 3 && t[..i].ends_with(" - ") { Some(t[..i - 3].to_string()) } else { None };
    Some(json!({"edition": edition, "adVersion": version, "licenceState": lic, "document": doc}))
}

/// Licence/window state — the instance layer's view (instance-aware, Develop absent-tail rule,
/// snapshot-cached). Kept here as the name every verb historically gates on.
pub fn licence_state() -> Value {
    let v = crate::instance::licence_state();
    if v.get("running").and_then(|b| b.as_bool()) == Some(false) && crate::instance::ab_unreachable() {
        return json!({"running": false, "abUnreachable": true});
    }
    v
}

pub fn is_running() -> bool {
    licence_state().get("running").and_then(|b| b.as_bool()).unwrap_or(false)
}

pub fn report() -> Value {
    let lic = licence_state();
    let running = lic.get("running").and_then(|b| b.as_bool()).unwrap_or(false);
    let (led, summary) = if lic.get("abUnreachable").and_then(|b| b.as_bool()).unwrap_or(false) {
        ("yellow", "Adom Bridge unreachable".to_string())
    } else if !running {
        ("yellow", "Altium not running".to_string())
    } else if lic.get("licensed").and_then(|b| b.as_bool()) == Some(false) {
        ("yellow", format!("Altium {}", lic.get("state").and_then(|s| s.as_str()).unwrap_or("No License")))
    } else if agent::is_alive() {
        ("green", "Altium + agent ready".to_string())
    } else {
        ("green", "Altium running (agent idle)".to_string())
    };
    json!({"status": "ok", "led": led, "summary": summary, "tooltip": format!("altium-bridge {BRIDGE_VERSION} - {summary}"),
           "bridgeVersion": BRIDGE_VERSION, "licence": lic, "engine": "rust"})
}