use wasm_bindgen::prelude::*;
use serde::{Serialize, Deserialize};
use alloc::string::{String, ToString};
#[derive(Debug, Clone, Serialize, Deserialize)]
#[wasm_bindgen(getter_with_clone)]
pub struct DashaInfo {
pub mahadasha: String,
pub antardasha: String,
pub pratyantardasha: String,
pub mahadasha_end_date: f64,
pub antardasha_end_date: f64,
pub pratyantardasha_end_date: f64,
pub nakshatra_name: String,
pub nakshatra_pada: u8,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[wasm_bindgen(getter_with_clone)]
pub struct YoginiInfo {
pub mahadasha: String,
pub antardasha: String,
pub mahadasha_end_date: f64,
pub antardasha_end_date: f64,
}
const NAKSHATRA_SPAN: f64 = 360.0 / 27.0;
const DASHA_LORDS: [(&str, f64); 9] = [
("Ketu", 7.0),
("Venus", 20.0),
("Sun", 6.0),
("Moon", 10.0),
("Mars", 7.0),
("Rahu", 18.0),
("Jupiter", 16.0),
("Saturn", 19.0),
("Mercury", 17.0),
];
const YOGINI_LORDS: [(&str, f64); 8] = [
("Mangala", 1.0),
("Pingala", 2.0),
("Dhanya", 3.0),
("Bhramari", 4.0),
("Bhadrika", 5.0),
("Ulka", 6.0),
("Siddha", 7.0),
("Sankata", 8.0),
];
pub fn calculate_vimshottari(moon_long: f64, birth_time_ms: f64, current_time_ms: f64) -> DashaInfo {
let mut normalized_moon = moon_long % 360.0;
if normalized_moon < 0.0 {
normalized_moon += 360.0;
}
let nakshatra_val = normalized_moon / NAKSHATRA_SPAN;
let nak_index = nakshatra_val.floor() as usize; let fraction = nakshatra_val - nakshatra_val.floor();
let pada = (fraction * 4.0).floor() as u8 + 1;
let start_dasha_idx = nak_index % 9;
let (_start_lord, start_duration) = DASHA_LORDS[start_dasha_idx];
let balance_years = start_duration * (1.0 - fraction);
let ms_per_year = 365.25 * 24.0 * 3600.0 * 1000.0;
let elapsed_years = (current_time_ms - birth_time_ms) / ms_per_year;
let mut current_mahadasha_idx = start_dasha_idx;
let mut time_in_dasha;
if elapsed_years < balance_years {
time_in_dasha = (DASHA_LORDS[start_dasha_idx].1 - balance_years) + elapsed_years;
} else {
time_in_dasha = elapsed_years - balance_years;
current_mahadasha_idx = (current_mahadasha_idx + 1) % 9;
while time_in_dasha >= DASHA_LORDS[current_mahadasha_idx].1 {
time_in_dasha -= DASHA_LORDS[current_mahadasha_idx].1;
current_mahadasha_idx = (current_mahadasha_idx + 1) % 9;
}
}
let (md_lord, md_duration) = DASHA_LORDS[current_mahadasha_idx];
let md_remaining = md_duration - time_in_dasha;
let md_end_ms = current_time_ms + (md_remaining * ms_per_year);
let mut current_antardasha_idx = current_mahadasha_idx;
let mut time_in_ad = time_in_dasha;
let mut ad_duration;
loop {
let (_ad_lord_name, ad_lord_dur) = DASHA_LORDS[current_antardasha_idx];
ad_duration = md_duration * (ad_lord_dur / 120.0);
if time_in_ad < ad_duration {
break;
}
time_in_ad -= ad_duration;
current_antardasha_idx = (current_antardasha_idx + 1) % 9;
}
let (ad_lord, _) = DASHA_LORDS[current_antardasha_idx];
let ad_remaining = ad_duration - time_in_ad;
let ad_end_ms = current_time_ms + (ad_remaining * ms_per_year);
let mut current_pd_idx = current_antardasha_idx;
let mut time_in_pd = time_in_ad;
let mut pd_duration;
loop {
let (_pd_lord, pd_lord_dur) = DASHA_LORDS[current_pd_idx];
pd_duration = ad_duration * (pd_lord_dur / 120.0);
if time_in_pd < pd_duration {
break;
}
time_in_pd -= pd_duration;
current_pd_idx = (current_pd_idx + 1) % 9;
}
let (pd_lord, _) = DASHA_LORDS[current_pd_idx];
let pd_remaining = pd_duration - time_in_pd;
let pd_end_ms = current_time_ms + (pd_remaining * ms_per_year);
use crate::vedic::nakshatra::NAKSHATRA_NAMES;
let nak_name = if nak_index < 27 {
NAKSHATRA_NAMES[nak_index].to_string()
} else {
"Unknown".to_string()
};
DashaInfo {
mahadasha: md_lord.to_string(),
antardasha: ad_lord.to_string(),
pratyantardasha: pd_lord.to_string(),
mahadasha_end_date: md_end_ms,
antardasha_end_date: ad_end_ms,
pratyantardasha_end_date: pd_end_ms,
nakshatra_name: nak_name,
nakshatra_pada: pada,
}
}
pub fn calculate_yogini(moon_long: f64, birth_time_ms: f64, current_time_ms: f64) -> YoginiInfo {
let mut normalized_moon = moon_long % 360.0;
if normalized_moon < 0.0 { normalized_moon += 360.0; }
let nakshatra_val = normalized_moon / NAKSHATRA_SPAN;
let nak_index = nakshatra_val.floor() as usize;
let fraction = nakshatra_val - nakshatra_val.floor();
let start_idx = (nak_index + 3) % 8;
let (_start_lord, start_duration) = YOGINI_LORDS[start_idx];
let balance_years = start_duration * (1.0 - fraction);
let ms_per_year = 365.25 * 24.0 * 3600.0 * 1000.0;
let elapsed_years = (current_time_ms - birth_time_ms) / ms_per_year;
let mut current_md_idx = start_idx;
let mut time_in_dasha;
if elapsed_years < balance_years {
time_in_dasha = (start_duration - balance_years) + elapsed_years;
} else {
time_in_dasha = elapsed_years - balance_years;
current_md_idx = (current_md_idx + 1) % 8;
while time_in_dasha >= YOGINI_LORDS[current_md_idx].1 {
time_in_dasha -= YOGINI_LORDS[current_md_idx].1;
current_md_idx = (current_md_idx + 1) % 8;
}
}
let (md_lord_name, md_duration) = YOGINI_LORDS[current_md_idx];
let md_remaining = md_duration - time_in_dasha;
let md_end_ms = current_time_ms + (md_remaining * ms_per_year);
let mut current_ad_idx = current_md_idx;
let mut time_in_ad = time_in_dasha;
let mut ad_duration;
loop {
let (_, ad_lord_dur) = YOGINI_LORDS[current_ad_idx];
ad_duration = md_duration * (ad_lord_dur / 36.0);
if time_in_ad < ad_duration {
break;
}
time_in_ad -= ad_duration;
current_ad_idx = (current_ad_idx + 1) % 8;
}
let (ad_lord_name, _) = YOGINI_LORDS[current_ad_idx];
let ad_remaining = ad_duration - time_in_ad;
let ad_end_ms = current_time_ms + (ad_remaining * ms_per_year);
YoginiInfo {
mahadasha: md_lord_name.to_string(),
antardasha: ad_lord_name.to_string(),
mahadasha_end_date: md_end_ms,
antardasha_end_date: ad_end_ms,
}
}