#!python

# Copyright (C) 2018 Antti Karttunen (antti.j.karttunen@iki.fi)
# All rights reserved.
#
# This file is part of phonopy.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# * Redistributions of source code must retain the above copyright
#   notice, this list of conditions and the following disclaimer.
#
# * Redistributions in binary form must reproduce the above copyright
#   notice, this list of conditions and the following disclaimer in
#   the documentation and/or other materials provided with the
#   distribution.
#
# * Neither the name of the phonopy project nor the names of its
#   contributors may be used to endorse or promote products derived
#   from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.

from __future__ import print_function
import sys
import numpy as np

def get_options():
    # Parse options
    import argparse
    parser = argparse.ArgumentParser(
        description="Phonopy crystal-born command-line-tool")
    parser.add_argument(
        "filename", nargs='*',
        help="Filename: CRYSTAL output file (default: crystal.o)")
    args = parser.parse_args()
    return args

def read_crystal_epsilon(epscol, epslines):
    # XX, XY, XZ, YY, YZ, ZZ are given (6 rows). YX = XY, ZX = XZ, ZY = YZ 
    # Format for CRYSTAL17 (epscol == 4):
    # 0.000   XX      57.1760       0.0000       3.2117       0.0000       2.2117
    # Format for CRYSTAL14 (epscol == 3):
    # XX      57.1760        0.0000        3.2117        2.2117
    eps = [] # Will have 9 elements 0..8
    eps.append(float(epslines[0].split()[epscol])) # XX (0)
    eps.append(float(epslines[1].split()[epscol])) # XY (1)
    eps.append(float(epslines[2].split()[epscol])) # XZ (2)
    eps.append(eps[1])                             # YX = XY (3)
    eps.append(float(epslines[3].split()[epscol])) # YY (4)
    eps.append(float(epslines[4].split()[epscol])) # YZ (5)
    eps.append(eps[2])                             # ZX = XZ (6)
    eps.append(eps[5])                             # ZY = YZ (7)
    eps.append(float(epslines[5].split()[epscol])) # ZZ (8)
    return eps

def main(args):
    if args.filename:
        crystal_filename = args.filename[0]
    else:
        crystal_filename = "crystal.o"

    # Read in the output file
    try:
        with open(crystal_filename, "r") as crystal_file:
            lines = crystal_file.readlines()
    except OSError:
        print("CRYSTAL output file {} cannot be opened for reading".format(crystal_filename))
        sys.exit(1)
    
    # Recommended CRYSTAL calculation type: 
    # Gamma-point FREQCALC with INTCPHF and INTENS
    # The file will include both dielectric tensor and effective Born charges
    epsilon = []
    zeff = []
    l = 0
    while l < len(lines):
        line = lines[l]
        # Parse the information about atoms
        if 'PRIMITIVE CELL - CENTRING CODE' in line:
            l += 4
            # ATOMS IN THE ASYMMETRIC UNIT    2 - ATOMS IN THE UNIT CELL:    6
            N_asym_atoms = int(lines[l].split()[5])
            N_atoms = int(lines[l].split()[12])
            l += 3
            # Check for each atom if it belongs to the asymmetric unit
            # 1 T  22 TI    4.721218104494E-21  3.307446203077E-21  1.413771901417E-21
            is_asym = []
            for atom in range(0, N_atoms):
                atomdata = lines[l].split()
                is_asym.append(atomdata[1])
                l += 1

        # Parse dielectric tensor from INTCPHF
        elif 'FR.(eV) COMP.   ALPHA(Re,Im)           EPSILON(Re,Im)' in line:
            # CRYSTAL17
            epsilon = read_crystal_epsilon(4, lines[l+1:l+7])
            l += 7
        elif 'COMPONENT    ALPHA(REAL, IMAGINARY)         EPSILON       CHI(1)' in line:
            epsilon = read_crystal_epsilon(3, lines[l+1:l+7])
            l += 7

        # Parse Born charges
        elif 'ATOMIC BORN CHARGE TENSOR' in line:
            l += 6
            for atom in range(0, N_atoms):
                if is_asym[atom] == 'T':
                    zeffatom = []
                    for i in range(0, 3):
                        # 1     8.3860E-01  3.4861E-01  3.4861E-01
                        zeffatom += [float(x) for x in lines[l].split()[1:4]]
                        l += 1
                    zeff.append(zeffatom)
                    l += 4
                else:
                    l += 7
        l += 1 # while l < len(lines)

    # Output BORN if epsilon and zeff are available
    if len(epsilon) == 9 and len(zeff) == N_asym_atoms: 
        # Conversion factor
        bornlines = ("default\n")
        # Dielectric tensor
        bornlines += ("%6.4f " * 9 + "\n") % tuple(epsilon)
        # Effective charges
        for atom in range(0, N_asym_atoms):
            bornlines += ("%6.4f " * 9 + "\n") % tuple(zeff[atom])
        print(bornlines, end='')
        
if __name__ == "__main__":
    main(get_options())
