# coding: utf-8
# Copyright (c) Pymatgen Development Team.
# Distributed under the terms of the MIT License.

from __future__ import division, unicode_literals

"""
This module implements defect equivalents of the basic ComputedEntry objects, 
which is the basic entity that can be used to perform defect thermodynamic analyses
"""

__author__ = "Danny Broberg, Shyam Dwaraknath, Bharat Medasani, Nils E. R. Zimmermann, Geoffroy Hautier"
__copyright__ = "Copyright 2018, The Materials Project"
__version__ = "1.0"
__maintainer__ = "Shyam Dwaraknath"
__email__ = "shyamd@lbl.gov"
__status__ = "Development"
__date__ = "Mar 15, 2018"

import abc
import six
import numpy as np

from monty.json import MSONable
from pymatgen.entries.computed_entry import ComputedStructureEntry

logger = logging.getLogger(__name__)

class DefectEntry(MSONable):
    """
    An lightweight DefectEntry object containing key computed data
    for many defect analysis.
    """

    def __init__(self, defect, uncorrected_energy, corrections={}, parameters = {}, entry_id=None):
        """
        Args:
            defect:
                A Defect object from pymatgen.analysis.defects.core
            uncorrected_energy (float): Energy of the defect entry. Usually the difference between
            	the final calculated energy for the defect supercell - the perfect 
            	supercell energy
            corrections:
                List of Correction classes (from pymatgen.analysis.defects.corrections)
                which correct energy due to charge (e.g. Freysoldt or Kumagai)
                or other factors (e.g. Shallow level shifts)
            parameters (dict): An optional dict of calculation parameters and data to 
            	use with correction schemes
            entry_id (obj): An id to uniquely identify this defect, can be any MSONable
            	type
        """
        self.defect = defect
        self.uncorrected_energy = uncorrected_energy
        self.corrections = corrections
        self.entry_id = entry_id
        self.parameter = parameters

    @property
    def site(self):
        return self.defect.site

    @property
    def multiplicty(self):
        return defect.multiplicty

    @property
    def charge(self):
        return defect.charge

    @property
    def energy(self):
        """
        Returns the *corrected* energy of the entry.
        """
        return self.uncorrected_energy + np.sum(self.correction.values())

    def __repr__(self):
        output = ["DefectEntry {} - {}".format(self.entry_id,
                                                 self.defect.name),
                  "Energy = {:.4f}".format(self.energy),
                  "Correction = {:.4f}".format(np.sum(self.correction.values())),
                  "Parameters:"]
        for k, v in self.parameters.items():
            output.append("\t{} = {}".format(k, v))
        return "\n".join(output)

    def __str__(self):
        return self.__repr__()
@@ -153,17 +153,16 @@
 iterals%0A
-%0A
 %22%22%22%0AThis
@@ -702,75 +702,8 @@
 able
-%0Afrom pymatgen.entries.computed_entry import ComputedStructureEntry
 %0A%0Alo
@@ -738,16 +738,17 @@
 ame__)%0A%0A
+%0A
 class De
@@ -932,16 +932,23 @@
 _energy,
+ vbm=0,
  correct
@@ -966,19 +966,17 @@
 rameters
- = 
+=
 %7B%7D, entr
@@ -1212,17 +1212,20 @@
         
-%09
+    
 the fina
@@ -1296,17 +1296,20 @@
         
-%09
+    
 supercel
@@ -1329,27 +1329,61 @@
         
-corrections
+vbm: %0A%0A            corrections (%5BCorrection%5D)
 :%0A      
@@ -1703,17 +1703,20 @@
         
-%09
+    
 use with
@@ -1839,9 +1839,12 @@
     
-%09
+    
 type
@@ -2355,17 +2355,16 @@
 he entry
-.
 %0A       
@@ -2455,110 +2455,400 @@
 def 
-__repr__(self):%0A        output = %5B%22DefectEntry %7B%7D - %7B%7D%22.format(self.entry_id,%0A                
+formation_energy(self, chemical_potentials, fermi_level=0):%0A        %22%22%22%0A        Computes the formation energy for a defect taking into account a given chemical potential and fermi_level%0A        %22%22%22%0A        chempot_correction = sum(%5B%0A            chem_pot * (self.defec.structure.composition%5Bel%5D - self.defect.defect_composition%5Bel%5D)%0A            for el, chem_pot in chemical_potentials%0A
         
     
@@ -2839,32 +2839,36 @@
 als%0A        
+%5D)%0A%0A
         
             
@@ -2859,61 +2859,417 @@
     
-                 self.defect.name),%0A                 
+formation_energy = self.energy + chempot_correction%0A%0A        if %22vbm%22 in self.parameters:%0A            formation_energy += self.charge * (self.parameters%5B%22vbm%22%5D + fermi_level)%0A%0A        return formation_energy%0A%0A    def __repr__(self):%0A        %22%22%22%0A        Human readable string representation of this entry%0A        %22%22%22%0A        output = %5B%0A            %22DefectEntry %7B%7D - %7B%7D%22.format(self.entry_id, self.defect.name),
  %22En
@@ -3304,22 +3304,16 @@
 nergy),%0A
-      
         
@@ -3383,26 +3383,8 @@
 ))),
-%0A                 
  %22Pa
@@ -3393,16 +3393,25 @@
 meters:%22
+%0A        
 %5D%0A      

Add in formation energy