# -*- coding: utf-8 -*-
from __future__ import (absolute_import, division, print_function)

import pytest

from ..parsing import (
    formula_to_composition, formula_to_html, formula_to_latex, formula_to_unicode,
    parsing_library, to_reaction
)
from ..testing import requires


@requires(parsing_library)
def test_formula_to_composition():
    assert formula_to_composition('H2O') == {1: 2, 8: 1}
    assert formula_to_composition('Fe/3+') == {0: 3, 26: 1}
    assert formula_to_composition('Fe+3') == {0: 3, 26: 1}
    assert formula_to_composition('Na/+') == {0: 1, 11: 1}
    assert formula_to_composition('Na+1') == {0: 1, 11: 1}
    assert formula_to_composition('Na+') == {0: 1, 11: 1}
    assert formula_to_composition('Cl/-') == {0: -1, 17: 1}
    assert formula_to_composition('Cl-') == {0: -1, 17: 1}
    assert formula_to_composition('NaCl') == {11: 1, 17: 1}
    assert formula_to_composition('NaCl(s)') == {11: 1, 17: 1}
    assert formula_to_composition('Fe(SCN)2/+') == {
        0: 1, 6: 2, 7: 2, 16: 2, 26: 1}
    assert formula_to_composition('Fe(SCN)2+') == {
        0: 1, 6: 2, 7: 2, 16: 2, 26: 1}
    assert formula_to_composition('Fe(SCN)2+1') == {
        0: 1, 6: 2, 7: 2, 16: 2, 26: 1}
    assert formula_to_composition('((H2O)2OH)12') == {1: 60, 8: 36}

    # Special case: solvated electron:
    assert formula_to_composition('e-') == {0: -1}
    assert formula_to_composition('e-1') == {0: -1}
    assert formula_to_composition('e-(aq)') == {0: -1}
    assert formula_to_composition('SO4-2(aq)') == {0: -2, 8: 4, 16: 1}

    # prefixes and suffixes
    assert formula_to_composition('.NO2(g)') == {7: 1, 8: 2}
    assert formula_to_composition('.NH2') == {1: 2, 7: 1}
    assert formula_to_composition('ONOOH') == {1: 1, 7: 1, 8: 3}
    assert formula_to_composition('.ONOO') == {7: 1, 8: 3}
    assert formula_to_composition('.NO3/2-') == {0: -2, 7: 1, 8: 3}
    assert formula_to_composition('.NO3-2') == {0: -2, 7: 1, 8: 3}

    with pytest.raises(ValueError):
        formula_to_composition('F-F')

    assert formula_to_composition('alpha-FeOOH(s)') == {1: 1, 8: 2, 26: 1}
    assert formula_to_composition('epsilon-Zn(OH)2(s)') == {1: 2, 8: 2, 30: 1}

    # crystal water
    assert formula_to_composition('Na2CO3.7H2O(s)') == {11: 2, 6: 1, 8: 10, 1: 14}


@requires(parsing_library)
def test_to_reaction():
    from chempy.chemistry import Reaction, Equilibrium
    rxn = to_reaction(
        "H+ + OH- -> H2O; 1.4e11; ref={'doi': '10.1039/FT9908601539'}",
        'H+ OH- H2O'.split(), '->', Reaction)
    assert rxn.__class__ == Reaction

    assert rxn.reac['H+'] == 1
    assert rxn.reac['OH-'] == 1
    assert rxn.prod['H2O'] == 1
    assert rxn.param == 1.4e11
    assert rxn.ref['doi'].startswith('10.')

    eq = to_reaction("H+ + OH- = H2O; 1e-14; ref='rt, [H2O] == 1 M'",
                     'H+ OH- H2O'.split(), '=', Equilibrium)
    assert eq.__class__ == Equilibrium

    assert eq.reac['H+'] == 1
    assert eq.reac['OH-'] == 1
    assert eq.prod['H2O'] == 1
    assert eq.ref.startswith('rt')

    for s in ['2 e-(aq) + (2 H2O) -> H2 + 2 OH- ; 1e6 ; ',
              '2 * e-(aq) + (2 H2O) -> 1 * H2 + 2 * OH- ; 1e6 ; ']:
        rxn2 = to_reaction(s, 'e-(aq) H2 OH- H2O'.split(), '->', Reaction)
        assert rxn2.__class__ == Reaction
        assert rxn2.reac['e-(aq)'] == 2
        assert rxn2.inact_reac['H2O'] == 2
        assert rxn2.prod['H2'] == 1
        assert rxn2.prod['OH-'] == 2
        assert rxn2.param == 1e6

    r1 = to_reaction("-> H2O", None, '->', Reaction)
    assert r1.reac == {}
    assert r1.prod == {'H2O': 1}
    assert r1.param is None

    r2 = to_reaction("H2O ->", None, '->', Reaction)
    assert r2.reac == {'H2O': 1}
    assert r2.prod == {}
    assert r2.param is None

    from chempy.kinetics.rates import MassAction
    ma = MassAction([3.14])
    r3 = to_reaction("H+ + OH- -> H2O", None, '->', Reaction, param=ma)
    assert r3.param.args == [3.14]

    rxn3 = to_reaction("H2O + H2O -> H3O+ + OH-", 'H3O+ OH- H2O'.split(), '->', Reaction)
    assert rxn3.reac == {'H2O': 2} and rxn3.prod == {'H3O+': 1, 'OH-': 1}

    rxn4 = to_reaction("2 e-(aq) + (2 H2O) + (2 H+) -> H2 + 2 H2O", 'e-(aq) H2 H2O H+'.split(), '->', Reaction)
    assert rxn4.reac == {'e-(aq)': 2} and rxn4.inact_reac == {'H2O': 2, 'H+': 2} and rxn4.prod == {'H2': 1, 'H2O': 2}


@requires(parsing_library)
def test_formula_to_latex():
    assert formula_to_latex('H2O') == 'H_{2}O'
    assert formula_to_latex('C6H6/+') == 'C_{6}H_{6}^{+}'
    assert formula_to_latex('Fe(CN)6/3-') == 'Fe(CN)_{6}^{3-}'
    assert formula_to_latex('Fe(CN)6-3') == 'Fe(CN)_{6}^{3-}'
    assert formula_to_latex('C18H38/2+') == 'C_{18}H_{38}^{2+}'
    assert formula_to_latex('C18H38/+2') == 'C_{18}H_{38}^{2+}'
    assert formula_to_latex('C18H38+2') == 'C_{18}H_{38}^{2+}'
    assert formula_to_latex('((H2O)2OH)12') == '((H_{2}O)_{2}OH)_{12}'
    assert formula_to_latex('NaCl') == 'NaCl'
    assert formula_to_latex('NaCl(s)') == 'NaCl(s)'
    assert formula_to_latex('e-(aq)') == 'e^{-}(aq)'
    assert formula_to_latex('Ca+2(aq)') == 'Ca^{2+}(aq)'
    assert formula_to_latex('.NO2(g)') == r'^\bullet NO_{2}(g)'
    assert formula_to_latex('.NH2') == r'^\bullet NH_{2}'
    assert formula_to_latex('ONOOH') == 'ONOOH'
    assert formula_to_latex('.ONOO') == r'^\bullet ONOO'
    assert formula_to_latex('.NO3/2-') == r'^\bullet NO_{3}^{2-}'
    assert formula_to_latex('.NO3-2') == r'^\bullet NO_{3}^{2-}'
    assert formula_to_latex('alpha-FeOOH(s)') == r'\alpha-FeOOH(s)'
    assert formula_to_latex('epsilon-Zn(OH)2(s)') == (
        r'\varepsilon-Zn(OH)_{2}(s)')
    assert formula_to_latex('Na2CO3.7H2O(s)') == 'Na_{2}CO_{3}\cdot 7H_{2}O(s)'
    assert formula_to_latex('Na2CO3.1H2O(s)') == 'Na_{2}CO_{3}\cdot H_{2}O(s)'


@requires(parsing_library)
def test_formula_to_unicoce():
    assert formula_to_unicode('NH4+') == u'NH₄⁺'
    assert formula_to_unicode('H2O') == u'H₂O'
    assert formula_to_unicode('C6H6/+') == u'C₆H₆⁺'
    assert formula_to_unicode('Fe(CN)6/3-') == u'Fe(CN)₆³⁻'
    assert formula_to_unicode('Fe(CN)6-3') == u'Fe(CN)₆³⁻'
    assert formula_to_unicode('C18H38/2+') == u'C₁₈H₃₈²⁺'
    assert formula_to_unicode('C18H38/+2') == u'C₁₈H₃₈²⁺'
    assert formula_to_unicode('C18H38+2') == u'C₁₈H₃₈²⁺'
    assert formula_to_unicode('((H2O)2OH)12') == u'((H₂O)₂OH)₁₂'
    assert formula_to_unicode('NaCl') == u'NaCl'
    assert formula_to_unicode('NaCl(s)') == u'NaCl(s)'
    assert formula_to_unicode('e-(aq)') == u'e⁻(aq)'
    assert formula_to_unicode('Ca+2(aq)') == u'Ca²⁺(aq)'
    assert formula_to_unicode('.NO2(g)') == u'⋅NO₂(g)'
    assert formula_to_unicode('.NH2') == u'⋅NH₂'
    assert formula_to_unicode('ONOOH') == u'ONOOH'
    assert formula_to_unicode('.ONOO') == u'⋅ONOO'
    assert formula_to_unicode('.NO3/2-') == u'⋅NO₃²⁻'
    assert formula_to_unicode('.NO3-2') == u'⋅NO₃²⁻'
    assert formula_to_unicode('alpha-FeOOH(s)') == u'α-FeOOH(s)'
    assert formula_to_unicode('epsilon-Zn(OH)2(s)') == u'ε-Zn(OH)₂(s)'
    assert formula_to_unicode('Na2CO3.7H2O(s)') == u'Na₂CO₃·7H₂O(s)'
    assert formula_to_unicode('Na2CO3.1H2O(s)') == u'Na₂CO₃·H₂O(s)'


@requires(parsing_library)
def test_formula_to_html():
    assert formula_to_html('H2O') == 'H<sub>2</sub>O'
    assert formula_to_html('C6H6/+') == 'C<sub>6</sub>H<sub>6</sub><sup>+</sup>'
    assert formula_to_html('Fe(CN)6/3-') == 'Fe(CN)<sub>6</sub><sup>3-</sup>'
    assert formula_to_html('Fe(CN)6-3') == 'Fe(CN)<sub>6</sub><sup>3-</sup>'
    assert formula_to_html('C18H38/2+') == 'C<sub>18</sub>H<sub>38</sub><sup>2+</sup>'
    assert formula_to_html('C18H38/+2') == 'C<sub>18</sub>H<sub>38</sub><sup>2+</sup>'
    assert formula_to_html('C18H38+2') == 'C<sub>18</sub>H<sub>38</sub><sup>2+</sup>'
    assert formula_to_html('((H2O)2OH)12') == '((H<sub>2</sub>O)<sub>2</sub>OH)<sub>12</sub>'
    assert formula_to_html('NaCl') == 'NaCl'
    assert formula_to_html('NaCl(s)') == 'NaCl(s)'
    assert formula_to_html('e-(aq)') == 'e<sup>-</sup>(aq)'
    assert formula_to_html('Ca+2(aq)') == 'Ca<sup>2+</sup>(aq)'
    assert formula_to_html('.NO2(g)') == r'&sdot;NO<sub>2</sub>(g)'
    assert formula_to_html('.NH2') == r'&sdot;NH<sub>2</sub>'
    assert formula_to_html('ONOOH') == 'ONOOH'
    assert formula_to_html('.ONOO') == r'&sdot;ONOO'
    assert formula_to_html('.NO3/2-') == r'&sdot;NO<sub>3</sub><sup>2-</sup>'
    assert formula_to_html('.NO3-2') == r'&sdot;NO<sub>3</sub><sup>2-</sup>'
    assert formula_to_html('alpha-FeOOH(s)') == r'&alpha;-FeOOH(s)'
    assert formula_to_html('epsilon-Zn(OH)2(s)') == (
        r'&epsilon;-Zn(OH)<sub>2</sub>(s)')
    assert formula_to_html('Na2CO3.7H2O(s)') == 'Na<sub>2</sub>CO<sub>3</sub>&sdot;7H<sub>2</sub>O(s)'
    assert formula_to_html('Na2CO3.1H2O(s)') == 'Na<sub>2</sub>CO<sub>3</sub>&sdot;H<sub>2</sub>O(s)'
