# This file is part of xrayutilities.
#
# xrayutilities is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, see <http://www.gnu.org/licenses/>.
#
# Copyright (c) 2013-2020, 2023 Dominik Kriegner <dominik.kriegner@gmail.com>

import numpy

from . import elements as e
from .heuslerlib import *  # noqa: F401, F403
from .material import (
    Crystal,
    CubicAlloy,
    CubicElasticTensor,
    HexagonalElasticTensor,
    WZTensorFromCub,
)
from .spacegrouplattice import SGLattice

# some predefined materials
# PLEASE use N/m^2 as unit for cij for newly entered material ( 1 dyn/cm^2 =
# 0.1 N/m^2 = 0.1 GPa)
# Use Kelvin as unit for the Debye temperature
# ref http://www.semiconductors.co.uk/propiviv5431.htm
C = Crystal(
    "C",
    SGLattice(
        "227:1",
        3.5668,
        atoms=[
            e.C,
        ],
        pos=[
            "8a",
        ],
    ),
    CubicElasticTensor(1.0764e12, 0.125e12, 0.577e12),
)
C_HOPG = Crystal(
    "HOPG", SGLattice(194, 2.4612, 6.7079, atoms=[e.C, e.C], pos=["2b", "2c"])
)
Si = Crystal(
    "Si",
    SGLattice(
        "227:1",
        5.43104,
        atoms=[
            e.Si,
        ],
        pos=[
            "8a",
        ],
    ),
    CubicElasticTensor(165.77e9, 63.93e9, 79.62e9),
    thetaDebye=640,
)
Ge = Crystal(
    "Ge",
    SGLattice(
        "227:1",
        5.65785,
        atoms=[
            e.Ge,
        ],
        pos=[
            "8a",
        ],
    ),
    CubicElasticTensor(128.5e9, 48.3e9, 66.8e9),
    thetaDebye=374,
)
InAs = Crystal(
    "InAs",
    SGLattice(216, 6.0583, atoms=[e.In, e.As], pos=["4a", "4c"]),
    CubicElasticTensor(8.34e10, 4.54e10, 3.95e10),
    thetaDebye=280,
)
InP = Crystal(
    "InP",
    SGLattice(216, 5.8687, atoms=[e.In, e.P], pos=["4a", "4c"]),
    CubicElasticTensor(10.11e10, 5.61e10, 4.56e10),
    thetaDebye=425,
)
InSb = Crystal(
    "InSb",
    SGLattice(216, 6.47937, atoms=[e.In, e.Sb], pos=["4a", "4c"]),
    CubicElasticTensor(6.66e10, 3.65e10, 3.02e10),
    thetaDebye=160,
)
GaP = Crystal(
    "GaP",
    SGLattice(216, 5.4505, atoms=[e.Ga, e.P], pos=["4a", "4c"]),
    CubicElasticTensor(14.05e10, 6.20e10, 7.03e10),
    thetaDebye=445,
)
GaAs = Crystal(
    "GaAs",
    SGLattice(216, 5.65325, atoms=[e.Ga, e.As], pos=["4a", "4c"]),
    CubicElasticTensor(11.9e10, 5.34e10, 5.96e10),
    thetaDebye=360,
)
# data updated from Appl. Phys. Lett. 66, 682–684 (1995)
AlAs = Crystal(
    "AlAs",
    SGLattice(216, 5.66172, atoms=[e.Al, e.As], pos=["4a", "4c"]),
    CubicElasticTensor(11.99e10, 5.75e10, 5.66e10),
    thetaDebye=446,
)
GaSb = Crystal(
    "GaSb",
    SGLattice(216, 6.09593, atoms=[e.Ga, e.Sb], pos=["4a", "4c"]),
    CubicElasticTensor(8.83e10, 4.02e10, 4.32e10),
    thetaDebye=266,
)
AlSb = Crystal(
    "AlSb",
    SGLattice(216, 6.1355, atoms=[e.Al, e.Sb], pos=["4a", "4c"]),
    CubicElasticTensor(8.769e10, 4.341e10, 4.076e10),
    thetaDebye=370,
)
# from Cryst. Growth Des. 15, 4795-4803 (2015)
GaAsWZ = Crystal(
    "GaAs(WZ)",
    SGLattice(
        186,
        3.9845,
        6.5701,
        atoms=[e.Ga, e.As],
        pos=[("2b", 0), ("2b", 3 / 8.0)],
    ),
    WZTensorFromCub(11.9e10, 5.34e10, 5.96e10),
)
GaAs4H = Crystal(
    "GaAs(4H)",
    SGLattice(
        186,
        3.9900,
        13.0964,
        atoms=[e.Ga, e.Ga, e.As, e.As],
        pos=[("2a", 0), ("2b", 1 / 4.0), ("2a", 3 / 16.0), ("2b", 7 / 16.0)],
    ),
)
# from Phys. Rev. B 88, 115315 (2013)
GaPWZ = Crystal(
    "GaP(WZ)",
    SGLattice(
        186,
        3.8419,
        6.3353,
        atoms=[e.Ga, e.P],
        pos=[("2b", 0), ("2b", 0.37385)],
    ),
    WZTensorFromCub(14.05e10, 6.20e10, 7.03e10),
)
# from Nanotechnology 22 425704 (2011)
InPWZ = Crystal(
    "InP(WZ)",
    SGLattice(
        186,
        4.1423,
        6.8013,
        atoms=[e.In, e.P],
        pos=[("2b", 0), ("2b", 3 / 8.0)],
    ),
    WZTensorFromCub(10.11e10, 5.61e10, 4.56e10),
)
# from Nano Lett., 2011, 11 (4), pp 1483-1489
InAsWZ = Crystal(
    "InAs(WZ)",
    SGLattice(
        186,
        4.2742,
        7.0250,
        atoms=[e.In, e.As],
        pos=[("2b", 0), ("2b", 3 / 8.0)],
    ),
    WZTensorFromCub(8.34e10, 4.54e10, 3.95e10),
)
InAs4H = Crystal(
    "InAs(4H)",
    SGLattice(
        186,
        4.2780,
        14.0171,
        atoms=[e.In, e.In, e.As, e.As],
        pos=[("2a", 0), ("2b", 1 / 4.0), ("2a", 3 / 16.0), ("2b", 7 / 16.0)],
    ),
)
InSbWZ = Crystal(
    "InSb(WZ)",
    SGLattice(
        186,
        4.5712,
        7.5221,
        atoms=[e.In, e.Sb],
        pos=[("2b", 0), ("2b", 3 / 8.0)],
    ),
    WZTensorFromCub(6.66e10, 3.65e10, 3.02e10),
)
InSb4H = Crystal(
    "InSb(4H)",
    SGLattice(
        186,
        4.5753,
        15.0057,
        atoms=[e.In, e.In, e.Sb, e.Sb],
        pos=[("2a", 0), ("2b", 1 / 4.0), ("2a", 3 / 16.0), ("2b", 7 / 16.0)],
    ),
)

# ? Unit of elastic constants for CdTe, PbTe, PbSe ?
PbTe = Crystal(
    "PbTe",
    SGLattice(225, 6.464, atoms=[e.Pb, e.Te], pos=["4a", "4b"]),
    CubicElasticTensor(93.6, 7.7, 13.4),
)
PbSe = Crystal(
    "PbSe",
    SGLattice(225, 6.128, atoms=[e.Pb, e.Se], pos=["4a", "4b"]),
    CubicElasticTensor(123.7, 19.3, 15.9),
)
CdTe = Crystal(
    "CdTe",
    SGLattice(216, 6.482, atoms=[e.Cd, e.Te], pos=["4a", "4c"]),
    CubicElasticTensor(53.5, 36.7, 19.9),
)
CdSe = Crystal(
    "CdSe",
    SGLattice(
        186,
        4.5712,
        7.5221,
        atoms=[e.In, e.Sb],
        pos=[("2b", 0), ("2b", 3 / 8.0)],
    ),
    HexagonalElasticTensor(7.490e10, 4.609e10, 3.926e10, 8.451e10, 1.315e10),
)
CdSe_ZB = Crystal(
    "CdSe(ZB)", SGLattice(216, 6.052, atoms=[e.Cd, e.Se], pos=["4a", "4c"])
)
HgSe = Crystal(
    "HgSe",
    SGLattice(216, 6.085, atoms=[e.Hg, e.Se], pos=["4a", "4c"]),
    CubicElasticTensor(6.1e10, 4.4e10, 2.2e10),
)
NaCl = Crystal(
    "NaCl", SGLattice(225, 5.6402, atoms=[e.Na, e.Cl], pos=["4a", "4b"])
)
MgO = Crystal(
    "MgO", SGLattice(225, 4.212, atoms=[e.Mg, e.O], pos=["4a", "4b"])
)
GaN = Crystal(
    "GaN",
    SGLattice(
        186, 3.189, 5.186, atoms=[e.Ga, e.N], pos=[("2b", 0), ("2b", 3 / 8.0)]
    ),
    HexagonalElasticTensor(390.0e9, 145.0e9, 106.0e9, 398.0e9, 105.0e9),
    thetaDebye=600,
)
BaF2 = Crystal(
    "BaF2", SGLattice(225, 6.2001, atoms=[e.Ba, e.F], pos=["4a", "8c"])
)
SrF2 = Crystal(
    "SrF2", SGLattice(225, 5.8007, atoms=[e.Sr, e.F], pos=["4a", "8c"])
)
CaF2 = Crystal(
    "CaF2", SGLattice(225, 5.4631, atoms=[e.Ca, e.F], pos=["4a", "8c"])
)
MnO = Crystal(
    "MnO", SGLattice(225, 4.444, atoms=[e.Mn, e.O], pos=["4a", "4b"])
)
MnTe = Crystal(
    "MnTe",
    SGLattice(194, 4.1429, 6.7031, atoms=[e.Mn, e.Te], pos=["2a", "2c"]),
)
GeTe = Crystal(
    "GeTe",
    SGLattice(
        "160:R",
        5.996,
        88.18,
        atoms=[e.Ge, e.Ge, e.Te, e.Te],
        pos=[
            ("1a", -0.237),
            ("3b", (0.5 - 0.237, -0.237)),
            ("1a", 0.237),
            ("3b", (0.5 + 0.237, +0.237)),
        ],
    ),
)
SnTe = Crystal(
    "SnTe", SGLattice(225, 6.3268, atoms=[e.Sn, e.Te], pos=["4a", "4b"])
)
Al = Crystal(
    "Al",
    SGLattice(
        225,
        4.04958,
        atoms=[
            e.Al,
        ],
        pos=[
            "4a",
        ],
    ),
)
Au = Crystal(
    "Au",
    SGLattice(
        225,
        4.0782,
        atoms=[
            e.Au,
        ],
        pos=[
            "4a",
        ],
    ),
)
Fe = Crystal(
    "Fe",
    SGLattice(
        229,
        2.8665,
        atoms=[
            e.Fe,
        ],
        pos=[
            "2a",
        ],
    ),
)
Cr = Crystal(
    "Cr",
    SGLattice(
        229,
        2.910,
        atoms=[
            e.Cr,
        ],
        pos=[
            "2a",
        ],
    ),
)
Co = Crystal(
    "Co",
    SGLattice(
        194,
        2.5071,
        4.0695,
        atoms=[
            e.Co,
        ],
        pos=[
            "2c",
        ],
    ),
)
Ti = Crystal(
    "Ti",
    SGLattice(
        194,
        2.9508,
        4.6855,
        atoms=[
            e.Ti,
        ],
        pos=[
            "2c",
        ],
    ),
)
Mo = Crystal(
    "Mo",
    SGLattice(
        229,
        3.147,
        atoms=[
            e.Mo,
        ],
        pos=[
            "2a",
        ],
    ),
)
Ru = Crystal(
    "Ru",
    SGLattice(
        194,
        2.7059,
        4.2815,
        atoms=[
            e.Ru,
        ],
        pos=[
            "2c",
        ],
    ),
)
Rh = Crystal(
    "Rh",
    SGLattice(
        225,
        3.8034,
        atoms=[
            e.Rh,
        ],
        pos=[
            "4a",
        ],
    ),
)
V = Crystal(
    "V",
    SGLattice(
        229,
        3.024,
        atoms=[
            e.V,
        ],
        pos=[
            "2a",
        ],
    ),
)
Ta = Crystal(
    "Ta",
    SGLattice(
        229,
        3.306,
        atoms=[
            e.Ta,
        ],
        pos=[
            "2a",
        ],
    ),
)
Nb = Crystal(
    "Nb",
    SGLattice(
        229,
        3.3004,
        atoms=[
            e.Nb,
        ],
        pos=[
            "2a",
        ],
    ),
)
Pt = Crystal(
    "Pt",
    SGLattice(
        225,
        3.9242,
        atoms=[
            e.Pt,
        ],
        pos=[
            "4a",
        ],
    ),
)
W = Crystal(
    "W",
    SGLattice(
        229,
        3.1652,
        atoms=[
            e.W,
        ],
        pos=[
            "2a",
        ],
    ),
)
Ag2Se = Crystal(
    "Ag2Se",
    SGLattice(
        19,
        4.333,
        7.062,
        7.764,
        atoms=[e.Ag, e.Ag, e.Se],
        pos=[
            ("4a", (0.107, 0.369, 0.456)),
            ("4a", (0.728, 0.029, 0.361)),
            ("4a", (0.358, 0.235, 0.149)),
        ],
    ),
)
TiO2 = Crystal(
    "TiO2",
    SGLattice(136, 4.59, 2.96, atoms=[e.Ti, e.O], pos=["2a", ("4f", 0.30479)]),
)
MnO2 = Crystal(
    "MnO2",
    SGLattice(136, 4.40, 2.87, atoms=[e.Mn, e.O], pos=["2a", ("4f", 0.30479)]),
)
VO2_Rutile = Crystal(
    "VO2",
    SGLattice(136, 4.55, 2.88, atoms=[e.V, e.O], pos=["2a", ("4f", 0.305)]),
)
VO2_Baddeleyite = Crystal(
    "VO2",
    SGLattice(
        14,
        5.75,
        5.42,
        5.38,
        122.6,
        atoms=[e.V, e.O, e.O],
        pos=[
            ("4e", (0.242, 0.975, 0.025)),
            ("4e", (0.1, 0.21, 0.20)),
            ("4e", (0.39, 0.69, 0.29)),
        ],
    ),
)
SiO2 = Crystal(
    "SiO2",
    SGLattice(
        154,
        4.916,
        5.4054,
        atoms=[e.Si, e.O],
        pos=[("3a", 0.46970), ("6c", (0.41350, 0.26690, 0.11910 + 2 / 3.0))],
    ),
)
In = Crystal(
    "In",
    SGLattice(
        139,
        3.2523,
        4.9461,
        atoms=[
            e.In,
        ],
        pos=[
            "2a",
        ],
    ),
)
Sb = Crystal(
    "Sb",
    SGLattice(
        "166:H",
        4.307,
        11.273,
        atoms=[
            e.Sb,
        ],
        pos=[
            ("6c", 0.23349),
        ],
    ),
)
Sn = Crystal(
    "Sn",
    SGLattice(
        "141:1",
        5.8197,
        3.17488,
        atoms=[
            e.Sn,
        ],
        pos=[
            "4a",
        ],
    ),
)
Ag = Crystal(
    "Ag",
    SGLattice(
        225,
        4.0853,
        atoms=[
            e.Ag,
        ],
        pos=[
            "4a",
        ],
    ),
)
SnAlpha = Crystal(
    "Sn-alpha",
    SGLattice(
        "227:1",
        6.4912,
        atoms=[
            e.Sn,
        ],
        pos=[
            "8a",
        ],
    ),
)
Cu = Crystal(
    "Cu",
    SGLattice(
        225,
        3.61496,
        atoms=[
            e.Cu,
        ],
        pos=[
            "4a",
        ],
    ),
)
CaTiO3 = Crystal(
    "CaTiO3",
    SGLattice(221, 3.795, atoms=[e.Ca, e.Ti, e.O], pos=["1a", "1b", "3c"]),
)
SrTiO3 = Crystal(
    "SrTiO3",
    SGLattice(221, 3.905, atoms=[e.Sr, e.Ti, e.O], pos=["1a", "1b", "3c"]),
)
BaTiO3 = Crystal(
    "BaTiO3",
    SGLattice(
        99,
        3.992,
        4.036,
        atoms=[e.Ba, e.Ti, e.O, e.O],
        pos=[("1a", 1.000), ("1b", 0.5274), ("1b", 0.9993), ("2c", 0.5125)],
    ),
)
# BiFeO3 = Crystal("BiFeO3", SGLattice())
# BiFeO3 = Crystal(
#    "BiFeO3",
#    lattice.PerovskiteTypeRhombohedral(elements.Bi, elements.Fe, elements.O,
#                                       3.965, 89.3))
FeO = Crystal(
    "FeO", SGLattice(225, 4.332, atoms=[e.Fe, e.O], pos=["4a", "4b"])
)
CoO = Crystal(
    "CoO", SGLattice(225, 4.214, atoms=[e.Co, e.O], pos=["4a", "4b"])
)
Fe3O4 = Crystal(
    "Fe3O4",
    SGLattice(
        "227:2",
        8.3958,
        atoms=[e.Fe, e.Fe, e.O],
        pos=["8a", "16d", ("32e", 0.255)],
    ),
)
Co3O4 = Crystal(
    "Co3O4",
    SGLattice(
        "227:2",
        8.0821,
        atoms=[e.Co, e.Co, e.O],
        pos=["8a", "16d", ("32e", 0.255)],
    ),
)
FeRh = Crystal(
    "FeRh", SGLattice(221, 2.993, atoms=[e.Fe, e.Rh], pos=["1a", "1b"])
)
Ir20Mn80 = Crystal(
    "Ir20Mn80",
    SGLattice(
        225, 3.780, atoms=[e.Ir, e.Mn], pos=["4a", "4a"], occ=[0.2, 0.8]
    ),
)
CoFe = Crystal(
    "CoFe", SGLattice(221, 2.8508, atoms=[e.Co, e.Fe], pos=["1a", "1b"])
)
CoGa = Crystal(
    "CoGa", SGLattice(221, 2.883, atoms=[e.Co, e.Ga], pos=["1a", "1b"])
)
LaB6 = Crystal(
    "LaB6",
    SGLattice(221, 4.15692, atoms=[e.La, e.B], pos=["1a", ("6f", 0.19750)]),
)
Al2O3 = Crystal(
    "Al2O3",
    SGLattice(
        "167:H",
        4.7602,
        12.9933,
        atoms=[e.Al, e.O],
        pos=[("12c", 0.35216), ("18e", 0.30624)],
    ),
)
CuMnAs = Crystal(
    "CuMnAs",
    SGLattice(
        "129:2",
        3.8200,
        6.3180,
        atoms=[e.Cu, e.Mn, e.As],
        pos=["2b", ("2c", -0.8300), ("2c", -0.2347)],
        occ=[1, 0.86, 0.96],
        b=[3.5531, 1.8950, 1.2633],
    ),
)
Mn3Ge_cub = Crystal(
    "Mn3Ge (cub)",
    SGLattice("221", 3.8019, atoms=[e.Mn, e.Ge], pos=["3c", "1a"]),
)
Mn3Ge = Crystal(
    "Mn3Ge (hex)",
    SGLattice(
        "194", 5.34, 4.31, atoms=[e.Mn, e.Ge], pos=[("6h", 1 / 6.0), "2d"]
    ),
)
Pt3Cr = Crystal(
    "Pt3Cr", SGLattice("221", 3.876, atoms=[e.Pt, e.Cr], pos=["3c", "1a"])
)
TiN = Crystal(
    "TiN", SGLattice(225, 4.235, atoms=[e.Ti, e.N], pos=["4a", "4b"])
)


# Alloys with special properties
class SiGe(CubicAlloy):
    def __init__(self, x):
        """
        Si_{1-x} Ge_x cubic compound
        """
        super().__init__(Si, Ge, x)

    @staticmethod
    def lattice_const_AB(latA, latB, x):
        """
        method to calculate the lattice parameter of the SiGe alloy with
        composition Si_{1-x}Ge_x
        """
        return latA + (0.2 * x + 0.027 * x**2) * (
            latB - latA
        ) / numpy.linalg.norm(latB - latA)


class AlGaAs(CubicAlloy):
    def __init__(self, x):
        """
        Al_{1-x} Ga_x As cubic compound
        """
        super().__init__(AlAs, GaAs, x)
