Skip to main content

forge_foundation/edition/
card_edition.rs

1use std::collections::HashMap;
2
3use serde::{Deserialize, Serialize};
4
5use crate::sealed_product::foil_type::FoilType;
6use crate::sealed_product::rarity::Rarity;
7use crate::sealed_product::sealed_template::SealedTemplate;
8
9#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, Default)]
10pub enum EditionType {
11    Core,
12    Expansion,
13    Reprint,
14    Online,
15    Starter,
16    Commander,
17    Planechase,
18    Archenemy,
19    Promo,
20    Token,
21    Other,
22    #[default]
23    Unknown,
24}
25
26impl EditionType {
27    pub fn parse(s: &str) -> Self {
28        match s.trim().to_ascii_lowercase().as_str() {
29            "core" => Self::Core,
30            "expansion" => Self::Expansion,
31            "reprint" | "masters" | "anthology" | "draft_innovation" => Self::Reprint,
32            "online" | "digital" => Self::Online,
33            "starter" => Self::Starter,
34            "commander" => Self::Commander,
35            "planechase" => Self::Planechase,
36            "archenemy" => Self::Archenemy,
37            "promo" => Self::Promo,
38            "token" => Self::Token,
39            _ if s.is_empty() => Self::Unknown,
40            _ => Self::Other,
41        }
42    }
43}
44
45#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
46pub struct EditionEntry {
47    pub collector_number: String,
48    pub rarity: Rarity,
49    pub name: String,
50    pub artist: Option<String>,
51}
52
53#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
54pub struct CardEdition {
55    pub code: String,
56    pub code2: Option<String>,
57    pub scryfall_code: Option<String>,
58    pub name: String,
59    pub date: Option<String>,
60    pub edition_type: EditionType,
61
62    pub foil_type: FoilType,
63    pub foil_chance_in_booster: f64,
64    pub foil_always_in_common_slot: bool,
65    pub additional_sheet_for_foils: Option<String>,
66    pub chance_replace_common_with: f64,
67    pub slot_replace_common_with: Option<String>,
68    pub booster_must_contain: Option<String>,
69    pub booster_replace_slot_from_print_sheet: Option<String>,
70    pub sheet_replace_card_from_sheet: Option<String>,
71    pub sheet_replace_card_from_sheet2: Option<String>,
72
73    pub alias: Option<String>,
74    pub booster_covers: u32,
75    pub booster_box_count: u32,
76    pub fat_pack_count: u32,
77    pub prerelease: Option<String>,
78    pub additional_unlock_set: Option<String>,
79    pub small_set_override: bool,
80
81    pub booster: Option<String>,
82    pub draft_booster: Option<String>,
83    pub extra_boosters: HashMap<String, String>,
84    pub custom_sheets: HashMap<String, Vec<String>>,
85
86    pub cards: Vec<EditionEntry>,
87}
88
89impl CardEdition {
90    pub fn to_sealed_template(&self) -> Option<SealedTemplate> {
91        self.to_sealed_template_named(None)
92    }
93
94    pub fn to_sealed_template_named(&self, variant: Option<&str>) -> Option<SealedTemplate> {
95        let primary = self.booster.as_ref().or(self.draft_booster.as_ref());
96        let line = match variant {
97            Some(v) if !v.is_empty() => self.extra_boosters.get(v).or(primary)?.as_str(),
98            _ => primary?.as_str(),
99        };
100        let slots = crate::sealed_product::sealed_template::parse_slots(line);
101        if slots.is_empty() {
102            return None;
103        }
104        let label = match variant {
105            Some(v) if !v.is_empty() => format!("{} {v}", self.code),
106            _ => self.code.clone(),
107        };
108        let mut tpl = SealedTemplate::new(Some(label), slots);
109        tpl.foil_type = self.foil_type;
110        tpl.foil_chance = self.foil_chance_in_booster;
111        tpl.foil_always_in_common_slot = self.foil_always_in_common_slot;
112        tpl.additional_sheet_for_foils = self.additional_sheet_for_foils.clone();
113        tpl.chance_replace_common_with = self.chance_replace_common_with;
114        tpl.slot_replace_common_with = self.slot_replace_common_with.clone();
115        tpl.booster_must_contain = self.booster_must_contain.clone();
116        tpl.booster_replace_slot_from_print_sheet =
117            self.booster_replace_slot_from_print_sheet.clone();
118        tpl.sheet_replace_card_from_sheet = self.sheet_replace_card_from_sheet.clone();
119        tpl.sheet_replace_card_from_sheet2 = self.sheet_replace_card_from_sheet2.clone();
120        Some(tpl)
121    }
122
123    pub fn variant_names(&self) -> Vec<String> {
124        let mut names: Vec<String> = self.extra_boosters.keys().cloned().collect();
125        names.sort();
126        names
127    }
128}