use std::fmt::Display;
use std::fmt::Formatter;
use tyme4rs::tyme::culture::Direction;
use tyme4rs::tyme::culture::Terrain;
use tyme4rs::tyme::culture::star::ten::TenStar;
use tyme4rs::tyme::sixtycycle::EarthBranch;
use tyme4rs::tyme::sixtycycle::HeavenStem;
use crate::auspice::Auspice;
use crate::element::Element;
use crate::element::ElementRelation;
use crate::enums::QimenChartType;
use crate::enums::QimenDoor;
use crate::enums::QimenGod;
use crate::enums::QimenMethod;
use crate::enums::QimenStar;
use crate::hexagram::Hexagram;
use crate::pattern::Pattern;
use crate::shensha::ShenSha;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct QimenOptions {
pub method: QimenMethod,
pub chart_type: QimenChartType,
}
impl Default for QimenOptions {
fn default() -> Self { Self { method: QimenMethod::Time, chart_type: QimenChartType::SanYuan } }
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct QimenDutyStar {
pub(crate) star: QimenStar,
pub(crate) original_palace: u8,
pub(crate) palace: u8,
}
impl QimenDutyStar {
pub fn star(&self) -> QimenStar { self.star }
pub fn original_palace(&self) -> u8 { self.original_palace }
pub fn palace(&self) -> u8 { self.palace }
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct QimenDutyDoor {
pub(crate) door: QimenDoor,
pub(crate) original_palace: u8,
pub(crate) palace: u8,
}
impl QimenDutyDoor {
pub fn door(&self) -> QimenDoor { self.door }
pub fn original_palace(&self) -> u8 { self.original_palace }
pub fn palace(&self) -> u8 { self.palace }
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct QimenHeavenStemPlacement {
pub(crate) palace: u8,
pub(crate) heaven_stem: HeavenStem,
}
impl QimenHeavenStemPlacement {
pub fn palace(&self) -> u8 { self.palace }
pub fn heaven_stem(&self) -> &HeavenStem { &self.heaven_stem }
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct QimenPalace {
pub(crate) number: u8,
pub(crate) name: &'static str,
pub(crate) direction: Direction,
pub(crate) earth_branches: Vec<EarthBranch>,
pub(crate) earth_heaven_stem: HeavenStem,
pub(crate) san_qi_liu_yi: HeavenStem,
pub(crate) heaven_heaven_stem: HeavenStem,
pub(crate) hidden_heaven_stem: HeavenStem,
pub(crate) star: Option<QimenStar>,
pub(crate) door: Option<QimenDoor>,
pub(crate) god: Option<QimenGod>,
pub(crate) ten_star: Option<TenStar>,
pub(crate) terrain: Option<Terrain>,
pub(crate) hexagram: Option<Hexagram>,
pub(crate) patterns: Vec<Pattern>,
pub(crate) shen_sha: Vec<ShenSha>,
}
impl QimenPalace {
pub fn number(&self) -> u8 { self.number }
pub fn name(&self) -> &'static str { self.name }
pub fn direction(&self) -> &Direction { &self.direction }
pub fn earth_branches(&self) -> &[EarthBranch] { &self.earth_branches }
pub fn earth_heaven_stem(&self) -> &HeavenStem { &self.earth_heaven_stem }
pub fn san_qi_liu_yi(&self) -> &HeavenStem { &self.san_qi_liu_yi }
pub fn heaven_heaven_stem(&self) -> &HeavenStem { &self.heaven_heaven_stem }
pub fn hidden_heaven_stem(&self) -> &HeavenStem { &self.hidden_heaven_stem }
pub fn star(&self) -> Option<QimenStar> { self.star }
pub fn door(&self) -> Option<QimenDoor> { self.door }
pub fn god(&self) -> Option<QimenGod> { self.god }
pub fn element(&self) -> Element { Element::from_palace(self.number) }
pub fn ten_star(&self) -> Option<&TenStar> { self.ten_star.as_ref() }
pub fn terrain(&self) -> Option<&Terrain> { self.terrain.as_ref() }
pub fn hexagram(&self) -> Option<&Hexagram> { self.hexagram.as_ref() }
pub fn patterns(&self) -> &[Pattern] { &self.patterns }
pub fn shen_sha(&self) -> &[ShenSha] { &self.shen_sha }
pub fn door_palace_relation(&self) -> Option<PalaceRelation> {
let door = self.door()?;
Some(PalaceRelation::for_subject(&door.to_string(), door.element(), self.element()))
}
pub fn star_palace_relation(&self) -> Option<PalaceRelation> {
let star = self.star()?;
Some(PalaceRelation::for_subject(&star.to_string(), star.element(), self.element()))
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct PalaceRelation {
description: String,
element_relation: ElementRelation,
auspice: Auspice,
}
impl PalaceRelation {
pub(crate) fn for_subject(subject_name: &str, subject_el: Element, palace_el: Element) -> Self {
let element_relation = subject_el.relation_to(palace_el);
let description = match element_relation {
ElementRelation::Same => format!("{subject_name}与宫比和"),
ElementRelation::Generated => format!("宫生{subject_name}"), ElementRelation::Generates => format!("{subject_name}生宫"), ElementRelation::Restrained => format!("宫克{subject_name}"), ElementRelation::Restrains => format!("{subject_name}克宫"), };
Self { description, element_relation, auspice: element_relation.auspice_as_self() }
}
pub fn description(&self) -> &str { &self.description }
pub fn element_relation(&self) -> ElementRelation { self.element_relation }
pub fn auspice(&self) -> Auspice { self.auspice }
}
impl Display for PalaceRelation {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { write!(f, "{}[{}]", self.description, self.auspice) }
}
#[cfg(test)]
mod tests {
use super::*;
fn rel(subject_el: Element, palace_el: Element) -> PalaceRelation {
PalaceRelation::for_subject("伤门", subject_el, palace_el)
}
#[test]
fn description_word_for_each_relation() {
let r = rel(Element::Wood, Element::Wood);
assert_eq!(r.description(), "伤门与宫比和");
assert_eq!(r.auspice(), Auspice::Neutral);
let r = rel(Element::Wood, Element::Fire);
assert_eq!(r.description(), "伤门生宫");
assert_eq!(r.auspice(), Auspice::Inauspicious);
let r = rel(Element::Wood, Element::Water);
assert_eq!(r.description(), "宫生伤门");
assert_eq!(r.auspice(), Auspice::Auspicious);
let r = rel(Element::Wood, Element::Earth);
assert_eq!(r.description(), "伤门克宫");
assert_eq!(r.auspice(), Auspice::Neutral);
let r = rel(Element::Wood, Element::Metal);
assert_eq!(r.description(), "宫克伤门");
assert_eq!(r.auspice(), Auspice::Inauspicious);
}
#[test]
fn star_subject_format() {
let r = PalaceRelation::for_subject("禽芮", Element::Earth, Element::Wood);
assert_eq!(r.description(), "宫克禽芮");
assert_eq!(r.auspice(), Auspice::Inauspicious);
}
}