use once_cell::sync::Lazy;
use std::collections::HashMap;
#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
pub enum MessageCategory {
LinearEquation,
QuadraticEquation,
SystemEquation,
PolynomialEquation,
Algebra,
Calculus,
GeneralMath,
Verification,
Error,
NoncommutativeAlgebra,
OrdinaryDifferentialEquation,
PartialDifferentialEquation,
}
#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
pub enum MessageType {
Introduction,
Strategy,
Step,
Calculation,
Result,
Verification,
Insight,
Error,
DerivativePowerRule,
DerivativeChainRule,
DerivativeProductRule,
DerivativeQuotientRule,
DerivativeConstant,
DerivativeVariable,
DerivativeImplicit,
DerivativeHigherOrder,
IntegralPowerRule,
IntegralConstant,
IntegralUSubstitution,
IntegralByParts,
IntegralDefinite,
LimitDirect,
LimitIndeterminate,
LimitLHopital,
LimitLaws,
LimitOneSided,
SummationIntroduction,
SummationArithmeticSeries,
SummationGeometricSeries,
SummationPowerSum,
SummationConvergence,
SummationFormula,
SummationSubstitution,
SummationResult,
SimplifyCombineLike,
SimplifyIdentity,
ExpandDistributive,
ExpandFOIL,
ExpandBinomial,
FactorCommon,
FactorGrouping,
FactorQuadratic,
RationalSimplify,
SystemSubstitution,
SystemElimination,
SystemMatrix,
PolynomialRationalRoot,
PolynomialSyntheticDivision,
PolynomialFactorization,
LeftMultiplyInverse,
RightMultiplyInverse,
NoncommutativeWarning,
CommutatorExplanation,
OrderMatters,
ODESeparable,
ODELinear,
ODEHomogeneous,
ODEExact,
ODEBernoulli,
ODEConstantCoefficients,
ODECauchyEuler,
ODEUndeterminedCoefficients,
ODEVariationParameters,
ODECharacteristicEquation,
ODEIntegratingFactor,
ODESubstitution,
}
#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
pub struct MessageKey {
pub category: MessageCategory,
pub message_type: MessageType,
pub variant: u8,
}
impl MessageKey {
pub const fn new(category: MessageCategory, message_type: MessageType, variant: u8) -> Self {
Self {
category,
message_type,
variant,
}
}
}
#[derive(Debug, Clone)]
pub struct MessageTemplate {
pub title: &'static str,
pub content: &'static str,
pub placeholders: &'static [&'static str],
}
impl MessageTemplate {
pub const fn new(
title: &'static str,
content: &'static str,
placeholders: &'static [&'static str],
) -> Self {
Self {
title,
content,
placeholders,
}
}
}
pub fn initialize_linear_messages(registry: &mut HashMap<MessageKey, MessageTemplate>) {
registry.insert(
MessageKey::new(MessageCategory::LinearEquation, MessageType::Introduction, 0),
MessageTemplate::new(
"Given Equation",
"We need to solve: {equation} = 0\nThis is a linear equation because {variable} appears only to the first power.",
&["equation", "variable"]
)
);
registry.insert(
MessageKey::new(MessageCategory::LinearEquation, MessageType::Strategy, 0),
MessageTemplate::new(
"Solution Strategy",
"To solve ax + b = 0, we isolate {variable} by using inverse operations.\nWe'll work step by step to get {variable} by itself.",
&["variable"]
)
);
registry.insert(
MessageKey::new(MessageCategory::LinearEquation, MessageType::Step, 0),
MessageTemplate::new(
"Move Constant Term",
"First, move the constant term to the other side.\nFrom {equation}, we get: {variable_term} = {isolated_constant}",
&["equation", "variable_term", "isolated_constant"]
)
);
registry.insert(
MessageKey::new(MessageCategory::LinearEquation, MessageType::Calculation, 0),
MessageTemplate::new(
"Divide by Coefficient",
"Now divide both sides by the coefficient of {variable}.\n{variable} = {numerator} / {denominator} = {result}",
&["variable", "numerator", "denominator", "result"]
)
);
registry.insert(
MessageKey::new(MessageCategory::LinearEquation, MessageType::Result, 0),
MessageTemplate::new(
"Solution Found",
"The solution is: {variable} = {solution}\nThis means when {variable} equals {solution}, the original equation is satisfied.",
&["variable", "solution"]
)
);
registry.insert(
MessageKey::new(MessageCategory::LinearEquation, MessageType::Verification, 0),
MessageTemplate::new(
"Verify Solution",
"Let's check: substitute {variable} = {solution} into the original equation.\nResult: {verification} = 0",
&["variable", "solution", "verification"]
)
);
registry.insert(
MessageKey::new(MessageCategory::LinearEquation, MessageType::Error, 0),
MessageTemplate::new(
"No Solution",
"This equation has no solution.\nWe get {contradiction}, which is impossible.",
&["contradiction"],
),
);
registry.insert(
MessageKey::new(MessageCategory::LinearEquation, MessageType::Error, 1),
MessageTemplate::new(
"Infinite Solutions",
"This equation has infinitely many solutions.\nAny value of {variable} satisfies the equation {equation}.",
&["variable", "equation"]
)
);
}
pub fn initialize_quadratic_messages(registry: &mut HashMap<MessageKey, MessageTemplate>) {
registry.insert(
MessageKey::new(MessageCategory::QuadraticEquation, MessageType::Introduction, 0),
MessageTemplate::new(
"Quadratic Equation",
"We need to solve: {equation} = 0\nThis is a quadratic equation because the highest power of {variable} is 2.",
&["equation", "variable"]
)
);
registry.insert(
MessageKey::new(MessageCategory::QuadraticEquation, MessageType::Strategy, 0),
MessageTemplate::new(
"Quadratic Formula",
"For quadratic equations ax^2 + bx + c = 0, we use the quadratic formula:\nx = (-b +/- sqrt(b^2 - 4ac)) / (2a)",
&[]
)
);
registry.insert(
MessageKey::new(MessageCategory::QuadraticEquation, MessageType::Step, 0),
MessageTemplate::new(
"Identify Coefficients",
"From our equation, we identify:\na = {a_coeff} (coefficient of {variable}^2)\nb = {b_coeff} (coefficient of {variable})\nc = {c_coeff} (constant term)",
&["a_coeff", "b_coeff", "c_coeff", "variable"]
)
);
registry.insert(
MessageKey::new(MessageCategory::QuadraticEquation, MessageType::Calculation, 0),
MessageTemplate::new(
"Calculate Discriminant",
"The discriminant Delta = b^2 - 4ac = ({b_coeff})^2 - 4({a_coeff})({c_coeff}) = {discriminant}\n{discriminant_meaning}",
&["b_coeff", "a_coeff", "c_coeff", "discriminant", "discriminant_meaning"]
)
);
registry.insert(
MessageKey::new(MessageCategory::QuadraticEquation, MessageType::Result, 0),
MessageTemplate::new(
"Solutions",
"Using the quadratic formula:\n{variable} = {solution_formula}\nSolutions: {solutions}",
&["variable", "solution_formula", "solutions"],
),
);
}
pub fn initialize_system_messages(registry: &mut HashMap<MessageKey, MessageTemplate>) {
registry.insert(
MessageKey::new(MessageCategory::SystemEquation, MessageType::Introduction, 0),
MessageTemplate::new(
"System of Equations",
"We have a system of {equation_count} equations with {variable_count} variables:\n{system_display}",
&["equation_count", "variable_count", "system_display"]
)
);
registry.insert(
MessageKey::new(MessageCategory::SystemEquation, MessageType::Strategy, 0),
MessageTemplate::new(
"Solution Method",
"We'll use {method} to solve this system.\nThis method systematically eliminates variables to find the solution.",
&["method"]
)
);
}
pub fn initialize_general_messages(registry: &mut HashMap<MessageKey, MessageTemplate>) {
registry.insert(
MessageKey::new(MessageCategory::GeneralMath, MessageType::Insight, 0),
MessageTemplate::new(
"Mathematical Insight",
"Key principle: What we do to one side of an equation, we must do to the other side.\nThis keeps the equation balanced and valid.",
&[]
)
);
registry.insert(
MessageKey::new(MessageCategory::GeneralMath, MessageType::Insight, 1),
MessageTemplate::new(
"Problem-Solving Tip",
"Strategy: Work backwards from what you want to find.\nIf you want {variable} alone, undo the operations applied to {variable}.",
&["variable"]
)
);
}
pub static MESSAGE_REGISTRY: Lazy<HashMap<MessageKey, MessageTemplate>> = Lazy::new(|| {
let mut registry = HashMap::new();
initialize_linear_messages(&mut registry);
initialize_quadratic_messages(&mut registry);
initialize_system_messages(&mut registry);
initialize_general_messages(&mut registry);
super::calculus::initialize_calculus_messages(&mut registry);
super::algebra::initialize_algebra_messages(&mut registry);
super::solvers::initialize_solver_messages(&mut registry);
super::noncommutative::initialize_noncommutative_messages(&mut registry);
super::ode::initialize_ode_messages(&mut registry);
registry
});
pub struct MessageBuilder {
key: MessageKey,
substitutions: HashMap<String, String>,
}
impl MessageBuilder {
pub fn new(category: MessageCategory, message_type: MessageType, variant: u8) -> Self {
Self {
key: MessageKey::new(category, message_type, variant),
substitutions: HashMap::new(),
}
}
pub fn with_substitution<K: Into<String>, V: Into<String>>(mut self, key: K, value: V) -> Self {
self.substitutions.insert(key.into(), value.into());
self
}
pub fn build(self) -> Option<crate::educational::step_by_step::Step> {
if let Some(template) = MESSAGE_REGISTRY.get(&self.key) {
let title = template.title.to_owned();
let mut content = template.content.to_owned();
for (placeholder, value) in &self.substitutions {
let placeholder_pattern = format!("{{{}}}", placeholder);
content = content.replace(&placeholder_pattern, value);
}
Some(crate::educational::step_by_step::Step::new(title, content))
} else {
None
}
}
}
pub struct MessageHashSystem;
impl MessageHashSystem {
pub fn hash_message_key(
category: MessageCategory,
message_type: MessageType,
variant: u8,
) -> u64 {
use std::collections::hash_map::DefaultHasher;
use std::hash::{Hash, Hasher};
let mut hasher = DefaultHasher::new();
category.hash(&mut hasher);
message_type.hash(&mut hasher);
variant.hash(&mut hasher);
hasher.finish()
}
pub fn get_message_by_hash(_hash: u64) -> Option<&'static MessageTemplate> {
MESSAGE_REGISTRY.values().next()
}
pub fn validate_registry() -> bool {
MESSAGE_REGISTRY
.values()
.all(|template| !template.title.is_empty() && !template.content.is_empty())
}
}