1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
use data_sep::*;
use math::{ gcd };
use reaction::{ ElemReaction };
use trait_element::{ Element };
use trait_properties::{ Properties };
use trait_reaction::{ Reaction };
use types::*;


#[derive(Debug, Eq, PartialEq, Clone)]
/// A Redox reaction
pub struct RedoxReaction<E: Element> {
    /// The reductor
    pub reductor: ElemReaction<E>,


    /// The oxidator
    pub oxidator: ElemReaction<E>
}


impl<E: Element> Reaction<E> for RedoxReaction<E> {
    fn equalise(&self) -> bool {
        // NOTE: This edits a clone, so doesn't do much!
        self.elem_reaction().equalise()
    }


    fn is_valid(&self) -> bool {
        // oxidator > reductor
        get_sep(&self.oxidator) > get_sep(&self.reductor) && self.elem_reaction().is_valid()
    }


    fn energy_cost(&self) -> Energy {
        self.reductor.energy_cost() + self.oxidator.energy_cost()
    }


    fn elem_reaction(&self) -> ElemReaction<E> {
        // Assuming .rhs and .lhs are equalised

        let red_charge;
        let oxi_charge;


        // ehm... let me explain these two
        // FIXME: Cleanup

        // Get reductor charge by searching for the electron, then getting that amount
        if let Some(red_elec_pos) = self.reductor.rhs.compounds.iter().position(|x|
            x.element.get_molecule().unwrap()
            .compounds.get(0).unwrap()
            .atom.number == 0
        ) {
            red_charge = self.reductor.rhs.compounds.get(red_elec_pos).unwrap().amount;
        } else if let Some(red_elec_pos) = self.reductor.lhs.compounds.iter().position(|x|
            x.element.get_molecule().unwrap()
            .compounds.get(0).unwrap()
            .atom.number == 0
        ) {
            red_charge = self.reductor.lhs.compounds.get(red_elec_pos).unwrap().amount;
        } else {
            panic!("Reductor has no electrons!");
        }


        // Get oxidator charge by searching for the electron, then getting that amount
        if let Some(oxi_elec_pos) = self.oxidator.lhs.compounds.iter().position(|x|
            x.element.get_molecule().unwrap()
            .compounds.get(0).unwrap()
            .atom.number == 0
        ) {
            oxi_charge = self.oxidator.lhs.compounds.get(oxi_elec_pos).unwrap().amount;
        } else if let Some(oxi_elec_pos) = self.oxidator.rhs.compounds.iter().position(|x|
            x.element.get_molecule().unwrap()
            .compounds.get(0).unwrap()
            .atom.number == 0
        ) {
            oxi_charge = self.oxidator.rhs.compounds.get(oxi_elec_pos).unwrap().amount;
        } else {
            panic!("Oxidator has no electrons!");
        }


        // Make sure that 4/2 or 2/4 gets converted to 2/1 or 1/2 first
        let gcd = gcd(red_charge as i32, oxi_charge as i32) as u16;
        let red_mult = oxi_charge / gcd;
        let oxi_mult = red_charge / gcd;


        ElemReaction {
            lhs: self.reductor.lhs.clone() * red_mult + self.oxidator.lhs.clone() * oxi_mult,
            rhs: self.reductor.rhs.clone() * red_mult + self.oxidator.rhs.clone() * oxi_mult,

            is_equilibrium: true
        }
    }
}


impl<E: Element> Properties for RedoxReaction<E> {
    fn symbol(&self) -> String {
        let mut symbol = String::new();

        symbol += "oxidator: ";
        symbol += &self.oxidator.symbol();
        symbol += "\n";
        symbol += "reductor: ";
        symbol += &self.reductor.symbol();

        return symbol;
    }


    fn name(&self) -> String {
        let mut name = String::new();

        name += "oxidator: ";
        name += &self.oxidator.name();
        name += "\n";
        name += "reductor: ";
        name += &self.reductor.name();

        return name;
    }


    fn mass(&self) -> AtomMass {
        // Law of Conservation of Mass
        0.0
    }
}