import os
import sys
from math import sqrt
import numpy as np
from matplotlib import pyplot as plt
import pandas as pd


from tkpnjunction import tkPNJunction


e0 = 8.85e-12
e  = 1.602e-19  # C
pi = 3.1415926535


class tkParams():
    def __init__(self):
        pass


def initialize():
    cparams = tkParams()

    cparams.mode = 'NW'

    cparams.infile = 'C-V評価 生データ.xlsx'
    
    cparams.S   = 850e-6 * 850e-6 # m2
    cparams.Vbi = 1.0  # V
    cparams.V   = 0.0  # V

    cparams.dn   = 3.7e-6 # m
    cparams.ND   = 2.7e16 # cm-3
    cparams.epsn = 10     # e0

    cparams.dp   = 375e-9 # m
    cparams.NA   = 5.0e18 # cm-3
    cparams.epsp = 10     # e0

    cparams.Vmin = -800 # V
    cparams.Vmax = 0    # V
    cparams.nV   = 1001

    cparams.outfile = 'CV.xlsx'

    cparams.figsize             = [8, 6]
    cparams.fontsize            = 14
    cparams.legend_fontsize     = 12

    return cparams

def update_variables(cparams):
    argv = sys.argv
    nargs = len(argv)
    
    if nargs >= 2:
        cparams.mode = argv[1]
    if nargs >= 3:
        cparams.infile = argv[2]

def read_file(infile, cparams):
    if not os.path.isfile(infile):
        return None, None, None

    df = pd.read_excel(infile, header = None)
    labels = df.iloc[1, 1:].tolist()
    data = df.iloc[2:, 1:].values
    data_df = pd.DataFrame(data, columns = labels)
#    pd.options.display.float_format = '{:.5g}'.format
    print()
    print(f"Read data from [{infile}]")
    labels = data_df.columns.tolist()
    data_list = data_df.values.tolist()
    ndata = data_df.shape[0]
    nskip = max(1, int(ndata / 25))
    print("ndata=", ndata, nskip)
    print(f"{labels[0]:>10} {labels[1]:>10} {labels[1] + '(F/m2)':>10}")
    V_list   = [data_list[i][0] for i in range(ndata)]
    C_list   = [data_list[i][1] for i in range(ndata)]
    Cm2_list = [data_list[i][1] / cparams.S for i in range(ndata)]
#    print(data_list)
    for i in range(0, ndata, nskip):
        print(f"{V_list[i]:10.4g} {C_list[i]:10.4g} {Cm2_list[i]:10.4g}")
        
    return V_list, C_list, Cm2_list


def plot_NW(cparams):
    V_list, C_meas, Cm2_meas = read_file(cparams.infile, cparams)

    if V_list is not None:
        nV = len(V_list)
        Cm2inv_meas = [1.0 / Cm2_meas[i] / Cm2_meas[i] for i in range(nV)]
        V = V_list
    else:
        nV = cparams.nV
        C_meas = None
        Cm2_meas = None
        Cm2inv_meas = None
        Vstep = (cparams.Vmax - cparams.Vmin) / (nV - 1)
        V = [cparams.Vmin + i * Vstep for i in range(nV)]

    pnj = tkPNJunction(cparams.ND, cparams.epsn, cparams.dn, cparams.NA, cparams.epsp, cparams.dp)

    nskip = int(nV / 50)

    C = []
    C2inv = []
    Wn = []
    Wp = []
    W  = []
    Vn = []
    Vp = []
    Vstep = (cparams.Vmax - cparams.Vmin) / (nV - 1)
    nskip = int(cparams.nV / 50)
    for i in range(nV):
        _V = V[i]
        _Wn, _Wp, _W, _Vn, _Vp, _Vtot, _Cn, _Cp, _C = pnj.cal_depletion_layers(_V, cparams.Vbi)
        C.append(_C)
        _C2inv = 1.0 / _C / _C
        C2inv.append(_C2inv)
        Wn.append(_Wn)
        Wp.append(_Wp)
        W.append(_Wn + _Wp)
        Vn.append(_Vn)
        Vp.append(_Vp)
#        if i % nskip == 0:
#            print(f"{_V:10.4g} {_Wn*1e9:10.4g} {_Wp*1e9:10.4g} {_C:10.4g} {_C2inv:10.4g}")

    diff = []
    N = []
    diff_meas = []
    N_meas = []
    W_meas = []
    print()
    if C_meas:
        print(f"{'V':>10} {'Vn':>10} {'Vp':>10} {'W (nm)':>10} {'N(W) (cm-3)':>10} {'N_meas(W) (cm-3)':>10} {'Wn (nm)':>10} {'Wp (nm)':>10} {'C (F/m2)':>10} {'1/C^2 (m^2F^-2)':>10} {'Wmeas (nm)':>10} {'Cmeas (F/m2)':>10} {'1/Cmeas^2 (m4F^-2)':>10}")
    else:
        print(f"{'V':>10} {'Vn':>10} {'Vp':>10} {'W (nm)':>10} {'N(W) (cm-3)':>10} {'Wn (nm)':>10} {'Wp (nm)':>10} {'C (F/m2)':>10} {'1/C^2 (m^2F^-2)':>10}")
    for i in range(nV):
        _W, _N = pnj.cal_N_W(i, V, C2inv, Wn, Wp)
        N.append(_N)
        if C_meas:
            _W, _N = pnj.cal_N_W(i, V, Cm2inv_meas, Wn, Wp)
            N_meas.append(_N)
            W_meas.append(_W)

        if i % nskip == 0:
            if C_meas:
                print(f"{V[i]:10.4g} {Vn[i]:10.4g} {Vp[i]:10.4g} {W[i]*1e9:10.4g} {N[i]*1.0e-6:10.4g} {N_meas[i]*1.0e-6:10.4g} {Wn[i]*1e9:10.4g} {Wp[i]*1e9:10.4g} {C[i]:10.4g} {C2inv[i]:10.4g} {_W*1e9:10.4g} {Cm2_meas[i]:10.4g} {Cm2inv_meas[i]:10.4g}")
            else:
                print(f"{V[i]:10.4g} {Vn[i]:10.4g} {Vp[i]:10.4g} {W[i]*1e9:10.4g} {N[i]*1.0e-6:10.4g} {Wn[i]*1e9:10.4g} {Wp[i]*1e9:10.4g} {C[i]:10.4g} {C2inv[i]:10.4g}")
            
    S = cparams.S
    print()
    print(f"Save data to {cparams.outfile}")
    if C_meas:
        df = pd.DataFrame({'V (V)': V, 'W (nm)': np.array(W) * 1.0e9, 'N (cm^-3)': np.array(N) * 1.0e-6, 'N_meas (cm^-3)': np.array(N_meas) * 1.0e-6, 
                       'Wn (m)': np.array(Wn) * 1.0e9, 'Wp (m)': np.array(Wp) * 1.0e9,
                       'C (F/m^2)': C, '1/C2 (m^4/F^-2)': C2inv, 
                       'C (F)': np.array(C)*S, '1/C2 (F^-2)': np.array(C2inv)/S/S, 
                       'Cmeas (F/m2)': Cm2_meas, '1/Cmeas2 (m^4F^-2)': Cm2inv_meas})
    else:
        df = pd.DataFrame({'V (V)': V, 'W (nm)': np.array(W) * 1.0e9, 'N (cm^-3)': np.array(N) * 1.0e-6, 
                       'Wn (m)': np.array(Wn) * 1.0e9, 'Wp (m)': np.array(Wp) * 1.0e9,
                       'C (F/m^2)': C, '1/C2 (m^4/F^-2)': C2inv, 
                       'C (F)': np.array(C)*S, '1/C2 (F^-2)': np.array(C2inv)/S/S})
    df.to_excel(cparams.outfile, index = False)


    plt.rcParams['font.size'] = cparams.fontsize
    fig = plt.figure(figsize = (8, 8))
    ax1 = fig.add_subplot(2, 2, 1)
    ax2 = fig.add_subplot(2, 2, 2)
    ax3 = fig.add_subplot(2, 2, 3)
    ax4 = fig.add_subplot(2, 2, 4)

    ax1.plot(V, np.array(C2inv),       label = '1/$C^2$', linestyle = '', marker = 'o', markersize = 5.0)
    if C_meas:
        ax1.plot(V, np.array(Cm2inv_meas), label = '1/$C_{meas}^2$', color = 'black')
    ax1.set_xlabel('V (V)', fontsize = cparams.fontsize)
    ax1.set_ylabel('1/$C^2$ (m$^4$F$^{-2}$)',        fontsize = cparams.fontsize)
    ax1.set_ylabel('1/$C_{meas}^2$ (m$^4$F$^{-2}$)', fontsize = cparams.fontsize)
#    ax1.set_yscale('log')
    ax1.legend(fontsize = cparams.legend_fontsize)

    ax2.plot(V, np.array(C),        label = 'C', linestyle = '', marker = 'o', markersize = 5.0)
    if C_meas:
        ax2.plot(V, np.array(Cm2_meas), label = 'C$_{meas}$', color = 'black')
    ax2.set_xlabel('V (V)', fontsize = cparams.fontsize)
    ax2.set_ylabel('C (F)', fontsize = cparams.fontsize)
#    ax2.set_yscale('log')
    ax2.legend(fontsize = cparams.legend_fontsize)

    colors = []
    for i in range(len(Wn)):
        if Wn[i] >= cparams.dn and Wp[i] >= cparams.dp:
            colors.append('black')
        elif Wn[i] >= cparams.dn:
            colors.append('red')
        else:
            colors.append('blue')

    ax3.plot(V, np.array(Wn) * 1.0e9, label = '$W_n$ (nm)', color = 'red', linewidth = 0.5)
    ax3.scatter(V, np.array(Wn) * 1.0e9, color = colors, marker = '>', s = 3.0)
    ax3.plot(V, np.array(Wp) * 1.0e9, label = '$W_p$ (nm)', color = 'blue', linewidth = 0.5)
    ax3.scatter(V, np.array(Wp) * 1.0e9, color = colors, marker = '^', s = 3.0)
    ax3.plot(V, np.array(W) * 1.0e9,  label = '$W$ (nm)',   color = 'black', linewidth = 1.0)
    ax3.scatter(V, np.array(W) * 1.0e9, color = colors, marker = 'o', s = 6.0)
    ax3.set_xlabel('V (V)', fontsize = cparams.fontsize)
    ax3.set_ylabel('W (nm)', fontsize = cparams.fontsize)
    ax3.set_yscale('log')
    ax3.legend(fontsize = cparams.legend_fontsize)

    if C_meas:
        wnm = np.array(W_meas) * 1.0e9
        ax4.plot(wnm, np.array(N) * 1.0e-6, label = '$N$ (cm$^{-3}$)')
        ax4.plot(wnm, np.array(N_meas) * 1.0e-6, label = '$N_{meas}$ (cm$^{-3}$)')
        ax4.set_xlabel('W (nm)',        fontsize = cparams.fontsize)
    else:
        ax4.plot(V, np.array(N) * 1.0e-6, label = '$N$ (cm$^{-3}$)')
        ax4.plot(V, np.array(N_meas) * 1.0e-6, label = '$N_{meas}$ (cm$^{-3}$)')
        ax4.set_xlabel('V (V)',        fontsize = cparams.fontsize)
    ax4.set_ylabel('N (cm$^{-3}$)', fontsize = cparams.fontsize)
    ax4.set_yscale('log')
    ax4.legend(fontsize = cparams.legend_fontsize)

    plt.tight_layout()

    plt.pause(0.0001)
    input("\nPress ENTER to terminate>>")


def main():
    cparams = initialize()
    update_variables(cparams)
    
    if cparams.mode == 'NW':
        plot_NW(cparams)
    else:
        print(f"\nError in main(): Invalide mode [{cparams.mode}]\n")
        input("Press ENTER to terminate>>")
        exit()

    exit()


if __name__ == "__main__":
    main()

