mod check;
mod mlir;
use super::*;
use std::collections::BTreeSet;
use std::sync::Arc;
#[derive(Debug, Clone)]
pub struct Circuit(pub(crate) Package, pub(crate) Arc<Component>);
impl Circuit {
    pub fn package(&self) -> &Package {
        &self.0
    }
    pub fn top(&self) -> Arc<Component> {
        self.1.clone()
    }
    pub fn component(&self, path: Path) -> Option<Arc<Component>> {
        if path == "top".into() {
            return Some(self.top());
        }
        let root_prefix = format!("top.");
        if !path.starts_with(&root_prefix) {
            return None;
        }
        let path: Path = path[root_prefix.len()..].into();
        self.component_from(self.top(), path)
    }
    fn component_from(&self, component: Arc<Component>, path: Path) -> Option<Arc<Component>> {
        let mut result: Arc<Component> = component;
        for part in path.split(".") {
            if let Some(child) = result.child(part) {
                if let Component::ModInst(_loc, _name, moddef) = &*child {
                    result = moddef.clone();
                } else {
                    result = child.clone();
                }
            } else if part == "set" {
                if let Component::Reg(_loc, _name, _typ, _reset) = &*result {
                    } else {
                    return None;
                }
            }else {
                return None;
            }
        }
        Some(result)
    }
    pub fn wires(&self) -> Vec<(Path, Wire)> {
        let mut results = vec![];
        for (path, component) in self.walk_instances() {
            for wire in component.wires() {
                results.push((path.clone(), wire));
            }
        }
        results
    }
    pub fn exts(&self) -> Vec<(Path, Arc<Component>)> {
        let mut results = vec![];
        for (path, component) in self.walk_instances() {
            if let Component::Ext(_loc, _name, _children) = &*component {
                results.push((path, component.clone()));
            }
        }
        results
    }
    pub fn regs(&self) -> Vec<Path> {
        let mut results = vec![];
        for (path, component) in self.walk_instances() {
            if let Component::Reg(_loc, _name, _typ, _reset) = &*component {
                results.push(path);
            }
        }
        results
    }
    pub fn paths(&self) -> Vec<Path> {
        self.top().paths_rec("top".into())
    }
    pub fn reset_for_reg(&self, path: Path) -> Option<Arc<Expr>> {
        if let Component::Reg(_loc, _name, _typ, reset) = &*self.component(path)? {
            reset.clone()
        } else {
            None
        }
    }
    fn walk_instances(&self) -> Vec<(Path, Arc<Component>)> {
        self.walk_instances_rec(self.top(), "top".into())
    }
    fn walk_instances_rec(
        &self,
        component: Arc<Component>,
        path: Path,
    ) -> Vec<(Path, Arc<Component>)> {
        let mut results = vec![(path.clone(), component.clone())];
        for child in component.children() {
            if let Component::ModInst(_loc, name, reference) = &*child {
                if let Some(moddef) = self.package().moddef(reference.name()) {
                    results.extend(
                        self.walk_instances_rec(moddef.clone(), path.join(child.name().into())),
                    );
                } else {
                    panic!("Undefined reference to ext: {name}")
                }
            } else {
                results
                    .extend(self.walk_instances_rec(child.clone(), path.join(child.name().into())));
            }
        }
        results
    }
}