# Copyright 2026 Gaofeng Fan
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""
Built-in device definitions.

All devices are defined as Circuit objects. The difference between built-in
devices and user-defined circuits is that built-ins have no internal instances
(the simulator knows what they are).

Usage:
    from analogpy import Circuit, resistor, capacitor, iprobe, cccs

    # In a circuit:
    my_circuit.instantiate(resistor, "R1", p=vdd, n=gnd, r=1000)
    my_circuit.instantiate(iprobe, "I_SENSE", p=input, n=output)

    # For Verilog-A models, use Circuit directly:
    oled_lut = Circuit("oled_LUT_dc_with_mag_factor", ports=["p", "n"])
    my_circuit.instantiate(oled_lut, "I_oled", p=anode, n=cathode,
                           tmdata="model.txt", area=938.488)
"""

from .circuit import Circuit

# =============================================================================
# Passive Components
# =============================================================================

resistor = Circuit("resistor", ports=["p", "n"])
resistor._is_primitive = True
resistor._primitive_spectre_type = "resistor"
"""Resistor with ports p (positive) and n (negative). Parameter: r (ohms)"""

capacitor = Circuit("capacitor", ports=["p", "n"])
capacitor._is_primitive = True
capacitor._primitive_spectre_type = "capacitor"
"""Capacitor with ports p (positive) and n (negative). Parameter: c (farads)"""

inductor = Circuit("inductor", ports=["p", "n"])
inductor._is_primitive = True
inductor._primitive_spectre_type = "inductor"
"""Inductor with ports p (positive) and n (negative). Parameter: l (henries)"""

# =============================================================================
# MOSFETs
# =============================================================================

nmos = Circuit("nmos", ports=["d", "g", "s", "b"])
nmos._is_primitive = True
nmos._primitive_spectre_type = "nmos"
"""NMOS transistor. Ports: d (drain), g (gate), s (source), b (bulk).
Parameters: w (width), l (length), nf (fingers), model name via 'model' param."""

pmos = Circuit("pmos", ports=["d", "g", "s", "b"])
pmos._is_primitive = True
pmos._primitive_spectre_type = "pmos"
"""PMOS transistor. Ports: d (drain), g (gate), s (source), b (bulk).
Parameters: w (width), l (length), nf (fingers), model name via 'model' param."""

# =============================================================================
# Diode
# =============================================================================

diode = Circuit("diode", ports=["p", "n"])
diode._is_primitive = True
diode._primitive_spectre_type = "diode"
"""Diode with ports p (anode) and n (cathode).
Parameters: area, pj, is, n, rs, etc."""

# =============================================================================
# BJT (Bipolar Junction Transistor)
# =============================================================================

bjt = Circuit("bjt", ports=["c", "b", "e", "s"])
bjt._is_primitive = True
bjt._primitive_spectre_type = "bjt"
"""BJT transistor. Ports: c (collector), b (base), e (emitter), s (substrate).
Parameters: area, model name via 'model' param.
Use type=npn or type=pnp in model statement."""

# =============================================================================
# JFET (Junction Field-Effect Transistor)
# =============================================================================

jfet = Circuit("jfet", ports=["d", "g", "s", "b"])
jfet._is_primitive = True
jfet._primitive_spectre_type = "jfet"
"""JFET transistor. Ports: d (drain), g (gate), s (source), b (bulk).
Parameters: w (width), l (length), area, model name via 'model' param.
Use type=njf or type=pjf in model statement."""

# =============================================================================
# Sources
# =============================================================================

vsource = Circuit("vsource", ports=["p", "n"])
vsource._is_primitive = True
vsource._primitive_spectre_type = "vsource"
"""Voltage source. Ports: p (positive), n (negative).
Parameters: dc (DC voltage), mag (AC magnitude), type (pulse/sine/etc)."""

isource = Circuit("isource", ports=["p", "n"])
isource._is_primitive = True
isource._primitive_spectre_type = "isource"
"""Current source. Ports: p (positive, current exits), n (negative, current enters).
Parameters: dc (DC current), mag (AC magnitude)."""

# =============================================================================
# Controlled Sources
# =============================================================================

vcvs = Circuit("vcvs", ports=["p_out", "n_out", "p_in", "n_in"])
vcvs._is_primitive = True
vcvs._primitive_spectre_type = "vcvs"
"""Voltage-Controlled Voltage Source.
Ports: p_out/n_out (output), p_in/n_in (control input).
Parameter: gain (voltage gain)."""

vccs = Circuit("vccs", ports=["p_out", "n_out", "p_in", "n_in"])
vccs._is_primitive = True
vccs._primitive_spectre_type = "vccs"
"""Voltage-Controlled Current Source.
Ports: p_out/n_out (output), p_in/n_in (control input).
Parameter: gm (transconductance in A/V)."""

ccvs = Circuit("ccvs", ports=["p", "n"])
ccvs._is_primitive = True
ccvs._primitive_spectre_type = "ccvs"
"""Current-Controlled Voltage Source (Spectre syntax).
Ports: p (positive output), n (negative output).
Parameters: probe (iprobe instance name), rm (transresistance in V/A)."""

cccs = Circuit("cccs", ports=["p", "n"])
cccs._is_primitive = True
cccs._primitive_spectre_type = "cccs"
"""Current-Controlled Current Source (Spectre syntax).
Ports: p (positive output), n (negative output).
Parameters: probe (iprobe instance name), gain (current gain), td (time delay)."""

# =============================================================================
# Probes
# =============================================================================

iprobe = Circuit("iprobe", ports=["p", "n"])
iprobe._is_primitive = True
iprobe._primitive_spectre_type = "iprobe"
"""Current probe. Measures current flowing from p to n.
Zero-resistance element. No parameters."""

# =============================================================================
# Mutual Inductor (Transformer Coupling)
# =============================================================================

mutual_inductor = Circuit("mutual_inductor", ports=[])
mutual_inductor._is_primitive = True
mutual_inductor._primitive_spectre_type = "mutual_inductor"
"""Mutual inductor for transformer coupling between two inductors.
No physical ports - references inductor instances by name.
Parameters: ind1 (first inductor name), ind2 (second inductor name),
            coupling (coupling coefficient k, 0 to 1)."""

# =============================================================================
# Port (RF S-Parameter Source)
# =============================================================================

port = Circuit("port", ports=["p", "n"])
port._is_primitive = True
port._primitive_spectre_type = "port"
"""Independent resistive source for S-parameter analysis.
Ports: p (positive), n (negative).
Parameters: r (resistance, default 50), num (port number),
            dc (DC voltage), mag (AC magnitude)."""

# =============================================================================
# Note: For Verilog-A and custom models, use Circuit directly:
#
#     oled_lut = Circuit("oled_LUT_dc_with_mag_factor", ports=["p", "n"])
#     my_circuit.instantiate(oled_lut, "I_oled", p=anode, n=cathode,
#                            tmdata="model.txt", area=938.488)
#
# Circuit with no internal instances is treated as a built-in device.
# =============================================================================
