import os
import stat
import re
import time
from datetime import datetime
import numpy as np
from numpy import exp, log, log10, sin, cos, tan
import pandas as pd
import openpyxl


from tklib.tkfile import tkFile
from tklib.tkutils import pint, pfloat
from tklib.tkvariousdata import tkVariousData
from tklib.tktemplate import convert_file


def conv_input(template_path, output_path, replace_dict, print_level = 0):
    convert_file(template_path, output_path, replace_dict, print_level = print_level)

def convert_by_scale(v, scale, forward = True, eps = None):
    if scale == 'log':
        if forward:
            if eps is not None and v <= 0.0:
                return log(eps)
            return log(v)
        else:
            return exp(v)

    return v

def save_data(path, labels, data_list, template = None):
    if os.path.exists(path):
        try:
            os.remove(path)
        except:
            print(f"Warning in tkFit_lib.save_data(): Could not delete [{path}]. Saving data was cancelled.")
            return False

#    df = pd.DataFrame(np.array(data_list).T, columns = labels)
#    df.to_excel(path, index = False, header = True)
    tkVariousData().to_excel(path, labels, data_list, template = template) 

    if os.path.isfile(path):
        return True

    return False

def convert_scale(x, y_scale = 'log', eps = None):
    if y_scale == '': return x

    if x == 0.0:
        if eps is not None: return log(eps) / 2.0
        return -100.0

    if x < 0.0:
        if eps is not None: return log(eps)
        return -log(-x)

    return log(x)

def P(yerr2_sum, yerr_var, P0):
    return P0 * exp(-yerr2_sum / yerr_var / 2.0)

def inf_format_func(plotevent, sel, iline, idata, label, inf, x = 0, y = 0, opt = None, format = format):
    if inf is None:
        return

    fit = inf["fit"]
    index = inf["index"][idata]
    x     = inf["x"][idata]
    y     = inf["y"][idata]
    print(f"{label}: line#{iline} data#{idata}: index={index}")
    for label, xlist in zip(fit.x_labels, fit.x_list):
        print(f"  {label:10}: {xlist[idata]:g}")
    for label, ylist in zip(fit.y_labels, fit.y_list):
        print(f"  {label:10}: {ylist[idata]:g}")
    print(f"  {'x':10}: {x:g}")
    print(f"  {'y':10}: {y:g}")



def add_history_csv(historyfile, varnames, xk, fmin, xdiff = None, save_time = False, print_level = 1):
    if os.path.exists(historyfile):
        if not os.access(historyfile, os.W_OK): return False

    if not os.path.isfile(historyfile):
        print(f"Create [{historyfile}]")
        with open(historyfile, 'w') as out:
            if save_time:
                out.write(f"'-iter,'-time,min:fmin")
            else:
                out.write(f"-iter,min:fmin")

            if xdiff is not Noen:
                out.write(f"-xdiff")

            for i in range(len(xk)):
                out.write(f",{varnames[i]}")
            out.write("\n")

    if os.path.isfile(historyfile):
        print(f"Add fmin and xk to [{historyfile}]")
        iter = -1
        with open(historyfile, 'r') as fp:
            for l in fp:
                aa = l.split(',')
                idx = pint(aa[0], 0)
                if idx > iter:
                    iter = idx
#                iter += 1
        iter += 1
        try:
            out = open(historyfile, 'a')
        except Exception as e:
            print(f"Warning in tkFit_lib.add_history_csv(): Could not write to [{historyfile}] due to error [{e}]. Ignore")
            return iter

        if save_time:
            stime = time.time()
            strtime = datetime.fromtimestamp(stime).strftime('%H:%M:%S %Y/%m/%d')
            out.write(f"{iter},{strtime},{fmin}")
        else:
            out.write(f"{iter},{fmin}")

        if xdiff is not None:
            out.write(f"{xdiff}")
            
        for x in xk:
            out.write(f",{x}")
        out.write("\n")
        out.close()

    return iter

def add_history_xlsx(historyfile, varnames, xk, fmin, xdiff = None, wb = None, ws = None, save_time = False, print_level = 1):
    if wb is not None:
        ws = wb.active
    elif historyfile is not None:
        if not os.path.isfile(historyfile):
#            print(f"tkFit_lib.add_history() 102 **create [{historyfile}]")
            wb = openpyxl.Workbook()
        else:
#        print(f"Permit write to [{historyfile}]")
#            os.chmod(historyfile, stat.S_IWRITE)
#            print(f"tkFit_lib.add_history() 105 **add to [{historyfile}]")
            wb = openpyxl.load_workbook(historyfile)

        ws = wb.active
    
    max_row = ws.max_row
    max_col = ws.max_column
#    print("max_row=", max_row)

    if max_row <= 1 and ws.cell(row = 1, column = 1).value is None:
        ws.cell(row = 1, column = 1, value = '-iter')
        if save_time:
#            print("'-time")
            ws.cell(row = 1, column = 2, value = '-time')
            ioffset = 3
        else:
            ioffset = 2
        ws.cell(row = 1, column = ioffset, value = 'min:fmin')
        ioffset += 1
        if xdiff is not None:
            ws.cell(row = 1, column = ioffset, value = '-xdiff')
            ioffset += 1
 
        for i in range(len(xk)):
            ws.cell(row = 1, column = ioffset + i, value=varnames[i])
        iter = 1
    else:
        iter = ws.cell(row = max_row, column = 1).value
        if type(iter) is str:
            iter = 0
        else:
            iter += 1
    
    ws.cell(row = max_row + 1, column = 1, value = iter)

    if save_time:
        stime = time.time()
        strtime = datetime.fromtimestamp(stime).strftime('%H:%M:%S %Y/%m/%d')
        ws.cell(row = max_row + 1, column = 2, value = strtime)
        ioffset = 3
    else:
        ioffset = 2

    ws.cell(row = max_row + 1, column = ioffset, value = fmin)

    ioffset += 1
    if xdiff is not None:
        ws.cell(row = max_row + 1, column = ioffset, value = xdiff)
        ioffset += 1

    for i in range(len(xk)):
        ws.cell(row = max_row + 1, column = ioffset + i, value = xk[i]) 

    if historyfile is not None:
        try:
            if print_level >= 2:
                print(f"tkFit_lib.add_history() 158 **save to [{historyfile}]")
            wb.save(historyfile)
        except Exception as e:
            print(f"Warning in tkFit_lib.add_history_xlsx(): Could not write to [{historyfile}] due to error [{e}]. Ignore")
            return iter
#            exit()

#    print(f"Forbit write to [{historyfile}]")
#    os.chmod(historyfile, stat.S_IREAD)
#    print(f"history file size: ", os.path.getsize(historyfile))

    return iter

def add_history(historyfile, varnames, xk, fmin, xdiff = None, wb = None, ws = None, save_time = False, print_level = 1):
    if historyfile is None:
        return add_history_xlsx(historyfile, varnames, xk, fmin, wb = wb, ws = ws, save_time = save_time, print_level = print_level)
    else:
        ext = os.path.splitext(historyfile)[1]
        if ext.lower() == ".csv":
            return add_history_csv(historyfile, varnames, xk, fmin, xdiff, save_time = save_time, print_level = print_level)
        elif ext.lower() == ".xlsx":
            return add_history_xlsx(historyfile, varnames, xk, fmin, xdiff, wb = wb, ws = ws, save_time = save_time, print_level = print_level)
        else:
            print(f"Warning: Unsupported extension [{ext}] for history file")
            return
