import numpy as np
import matplotlib.pyplot as plt
import sympy as sym
import math
import os
import subprocess
import fileinput
import re
import matlab.engine
from HelperFunctions import *
from ClassifyMin import *

import matplotlib.ticker as tickers
import matplotlib as mpl
from matplotlib.ticker import MultipleLocator,FormatStrFormatter,MaxNLocator
import pandas as pd

import tikzplotlib
# from pylab import *
from tikzplotlib import save as tikz_save


# Needed ?
mpl.use('pdf')

# from subprocess import Popen, PIPE
#import sys

###################### makePlot.py #########################
#  Generalized Plot-Script giving the option to define
#  quantity of interest and the parameter it depends on
#  to create a plot
#
#  Input: Define y & x for "x-y plot" as Strings
#  - Run the 'Cell-Problem' for the different Parameter-Points
#  (alternatively run 'Compute_MuGamma' if quantity of interest
#   is q3=muGamma for a significant Speedup)

###########################################################



# figsize argument takes inputs in inches
# and we have the width of our document in pts.
# To set the figure size we construct a function
# to convert from pts to inches and to determine
# an aesthetic figure height using the golden ratio:
def set_size(width, fraction=1):
    """Set figure dimensions to avoid scaling in LaTeX.

    Parameters
    ----------
    width: float
            Document textwidth or columnwidth in pts
    fraction: float, optional
            Fraction of the width which you wish the figure to occupy

    Returns
    -------
    fig_dim: tuple
            Dimensions of figure in inches
    """
    # Width of figure (in pts)
    fig_width_pt = width * fraction

    # Convert from pt to inches
    inches_per_pt = 1 / 72.27

    # Golden ratio to set aesthetic figure height
    # https://disq.us/p/2940ij3
    golden_ratio = (5**.5 - 1) / 2

    # Figure width in inches
    fig_width_in = fig_width_pt * inches_per_pt
    # Figure height in inches
    fig_height_in = fig_width_in * golden_ratio

    fig_dim = (fig_width_in, fig_height_in)

    return fig_dim




def format_func(value, tick_number):
    # # find number of multiples of pi/2
    # N = int(np.round(2 * value / np.pi))
    # if N == 0:
    #     return "0"
    # elif N == 1:
    #     return r"$\pi/2$"
    # elif N == 2:
    #     return r"$\pi$"
    # elif N % 2 > 0:
    #     return r"${0}\pi/2$".format(N)
    # else:
    #     return r"${0}\pi$".format(N // 2)
    # find number of multiples of pi/2
    N = int(np.round(4 * value / np.pi))
    if N == 0:
        return "0"
    elif N == 1:
        return r"$\pi/4$"
    elif N == 2:
        return r"$\pi/2$"
    elif N % 2 > 0:
        return r"${0}\pi/2$".format(N)
    else:
        return r"${0}\pi$".format(N // 2)





def find_nearest(array, value):
    array = np.asarray(array)
    idx = (np.abs(array - value)).argmin()
    return array[idx]


def find_nearestIdx(array, value):
    array = np.asarray(array)
    idx = (np.abs(array - value)).argmin()
    return idx



# TODO
# - Fallunterscheidung (Speedup) falls gesuchter value mu_gamma = q3
# - Also Add option to plot Minimization Output


# ----- Setup Paths -----
# InputFile  = "/inputs/cellsolver.parset"
# OutputFile = "/outputs/output.txt"

InputFile  = "/inputs/computeMuGamma.parset"
OutputFile = "/outputs/outputMuGamma.txt"

# path = os.getcwd()
# InputFilePath = os.getcwd()+InputFile
# OutputFilePath = os.getcwd()+OutputFile
# --------- Run  from src folder:
path_parent = os.path.dirname(os.getcwd())
os.chdir(path_parent)
path = os.getcwd()
print(path)
InputFilePath = os.getcwd()+InputFile
OutputFilePath = os.getcwd()+OutputFile
print("InputFilepath: ", InputFilePath)
print("OutputFilepath: ", OutputFilePath)
print("Path: ", path)

#---------------------------------------------------------------

print('---- Input parameters: -----')
mu1 = 10.0
# lambda1 = 10.0
rho1 = 1.0
alpha = 5.0
beta = 10.0
theta = 1.0/4.0

lambda1 = 0.0
gamma = 1.0/4.0

gamma = 'infinity'  #Elliptic Setting
# gamma = '0'       #Hyperbolic Setting
# gamma = 0.5


print('mu1: ', mu1)
print('rho1: ', rho1)
print('alpha: ', alpha)
print('beta: ', beta)
print('theta: ', theta)
print('gamma:', gamma)
print('----------------------------')


# TODO? : Ask User for Input ...
# function = input("Enter value you want to plot (y-value):\n")
# print(f'You entered {function}')
# parameter = input("Enter Parameter this value depends on (x-value) :\n")
# print(f'You entered {parameter}')

# Add Option to change NumberOfElements used for computation of Cell-Problem


# --- Define Quantity of interest:
# Options: 'q1', 'q2', 'q3', 'q12' ,'q21', 'q31', 'q13' , 'q23', 'q32' , 'b1', 'b2' ,'b3'
# TODO: EXTRA (MInimization Output) 'Minimizer (norm?)' 'angle', 'type', 'curvature'
# yName = 'q12'
# # yName = 'b1'
# yName = 'q3'
yName = 'angle'
# yName = 'curvature'

# --- Define Parameter this function/quantity depends on:
# Options: mu1 ,lambda1, rho1 , alpha, beta, theta, gamma
# xName = 'theta'
# xName = 'gamma'
# xName = 'lambda1'
xName = 'theta'


# --- define Interval of x-va1ues:
xmin = 0.01
xmax = 0.41

# xmin = 0.18           #Achtung bei manchen werten von theta ist integration in ComputeMuGama/Cell_problem schlecht!
# xmax = 0.41           # Materialfunktion muss von Gitter aufgelöst werden
                      # müssen vielfache von (1/2^i) sein wobei i integer


# xmin = 0.18           #Achtung bei manchen werten von theta ist integration in ComputeMuGama/Cell_problem schlecht!
# xmax = 0.23




# xmin = 0.01
# xmax = 3.0
numPoints = 200
# numPoints = 101
X_Values = np.linspace(xmin, xmax, num=numPoints)
print(X_Values)


Y_Values = []








for theta in X_Values:

    print('Situation of Lemma1.4')
    q12 = 0.0
    q1 = (1.0/6.0)*harmonicMean(mu1, beta, theta)
    q2 = (1.0/6.0)*arithmeticMean(mu1, beta, theta)
    b1 = prestrain_b1(rho1, beta, alpha,theta)
    b2 = prestrain_b2(rho1, beta, alpha,theta)
    b3 = 0.0
    # if gamma == '0':
    #     q3 = q2
    # if gamma == 'infinity':
    #     q3 = q1
    q3 = GetMuGamma(beta,theta,gamma,mu1,rho1,InputFilePath ,OutputFilePath)


    if yName == 'q1':                   # TODO: Better use dictionary?...
        print('q1 used')
        Y_Values.append(q1)
    elif yName =='q2':
        print('q2 used')
        Y_Values.append(q2)
    elif yName =='q3':
        print('q3 used')
        Y_Values.append(q3)
    elif yName =='q12':
        print('q12 used')
        Y_Values.append(q12)
    elif yName =='b1':
        print('b1 used')
        Y_Values.append(b1)
    elif yName =='b2':
        print('b2 used')
        Y_Values.append(b2)
    elif yName =='b3':
        print('b3 used')
        Y_Values.append(b3)
    elif yName == 'angle' or yName =='type' or yName =='curvature':
        G, angle, Type, curvature = classifyMin_ana(alpha,beta,theta, q3,  mu1, rho1)
        if yName =='angle':
            print('angle used')
            Y_Values.append(angle)
        if yName =='type':
            print('angle used')
            Y_Values.append(type)
        if yName =='curvature':
            print('angle used')
            Y_Values.append(curvature)


print("(Output) Values of " + yName + ": ", Y_Values)


idx = find_nearestIdx(Y_Values, 0)
print(' Idx of value  closest to 0', idx)
ValueClose = Y_Values[idx]
print('GammaValue(Idx) with mu_gamma closest to q_3^*', ValueClose)



# Find Indices where the difference between the next one is larger than epsilon...
jump_idx = []
jump_xValues = []
jump_yValues = []
tmp = X_Values[0]
for idx, x in enumerate(X_Values):
    print(idx, x)
    if idx > 0:
        if abs(Y_Values[idx]-Y_Values[idx-1]) > 1:
            print('jump candidate')
            jump_idx.append(idx)
            jump_xValues.append(x)
            jump_yValues.append(Y_Values[idx])







print("Jump Indices", jump_idx)
print("Jump X-values:", jump_xValues)
print("Jump Y-values:", jump_yValues)

y_plotValues = [Y_Values[0]]
x_plotValues = [X_Values[0]]
# y_plotValues.extend(jump_yValues)
for i in jump_idx:
    y_plotValues.extend([Y_Values[i-1], Y_Values[i]])
    x_plotValues.extend([X_Values[i-1], X_Values[i]])


y_plotValues.append(Y_Values[-1])
# x_plotValues = [X_Values[0]]
# x_plotValues.extend(jump_xValues)
x_plotValues.append(X_Values[-1])


print("y_plotValues:", y_plotValues)
print("x_plotValues:", x_plotValues)
# Y_Values[np.diff(y) >= 0.5] = np.nan


#get values bigger than jump position
# gamma = infty
# x_rest = X_Values[X_Values>x_plotValues[1]]
# Y_Values = np.array(Y_Values)  #convert the np array
# y_rest = Y_Values[X_Values>x_plotValues[1]]
#
#
# # gamma = 0
# x_rest = X_Values[X_Values>x_plotValues[3]]
# Y_Values = np.array(Y_Values)  #convert the np array
# y_rest = Y_Values[X_Values>x_plotValues[3]]

# gamma between
# Y_Values = np.array(Y_Values)  #convert the np array
# X_Values = np.array(X_Values)  #convert the np array
#
# x_one = X_Values[X_Values>x_plotValues[3]]
# # ax.scatter(X_Values, Y_Values)
# y_rest = Y_Values[X_Values>x_plotValues[3]]
# ax.plot(X_Values[X_Values>0.135], Y_Values[X_Values<0.135])
#
#
#


# y_rest = Y_Values[np.nonzero(X_Values>x_plotValues[1]]
# print('X_Values:', X_Values)
# print('Y_Values:', Y_Values)
# print('x_rest:', x_rest)
# print('y_rest:', y_rest)
# print('np.nonzero(X_Values>x_plotValues[1]', np.nonzero(X_Values>x_plotValues[1]) )




# --- Convert to numpy array
Y_Values = np.array(Y_Values)
X_Values = np.array(X_Values)

# ---------------- Create Plot -------------------

#--- change plot style:  SEABORN
# plt.style.use("seaborn-paper")


#--- Adjust gobal matplotlib variables
# mpl.rcParams['pdf.fonttype'] = 42
# mpl.rcParams['ps.fonttype'] = 42
mpl.rcParams['text.usetex'] = True
mpl.rcParams["font.family"] = "serif"
mpl.rcParams["font.size"] = "11"


# plt.rc('font', family='serif', serif='Times')
# plt.rc('font', family='serif')
# # plt.rc('text', usetex=True)  #also works...
# plt.rc('xtick', labelsize=8)
# plt.rc('ytick', labelsize=8)
# plt.rc('axes', labelsize=8)





#---- Scale Figure apropriately to fit tex-File Width
# width = 452.9679

# width as measured in inkscape
width = 6.28
height = width / 1.618

#setup canvas first
fig = plt.figure()      #main
# fig, ax = plt.subplots()
# fig, (ax, ax2) = plt.subplots(ncols=2)
# fig,axes = plt.subplots(nrows=1,ncols=2,figsize=(width,height)) # more than one plot


# fig.subplots_adjust(left=.15, bottom=.16, right=.99, top=.97)  #TEST


# TEST
# mpl.rcParams['figure.figsize'] = (width+0.1,height+0.1)
# fig = plt.figure(figsize=(width+0.1,height+0.1))


# mpl.rcParams['figure.figsize'] = (width,height)
# fig = plt.figure(figsize=(10,6)) # default is [6.4,4.8] 6.4 is the width, 4.8 is the height
# fig = plt.figure(figsize=(width,height)) # default is [6.4,4.8] 6.4 is the width, 4.8 is the height
# fig = plt.figure(figsize=set_size(width))
# fig = plt.subplots(1, 1, figsize=set_size(width))

# --- To create a figure half the width of your document:#
# fig = plt.figure(figsize=set_size(width, fraction=0.5))



#--- You must select the correct size of the plot in advance
# fig.set_size_inches(3.54,3.54)

# ax = plt.axes((0.1,0.1,0.5,0.8))
# ax = plt.axes((0.1,0.1,1,1))
ax = plt.axes()

# ax.spines['right'].set_visible(False)
# ax.spines['left'].set_visible(False)
# ax.spines['bottom'].set_visible(False)
# ax.spines['top'].set_visible(False)
# ax.tick_params(axis='x',which='major',direction='out',length=10,width=5,color='red',pad=15,labelsize=15,labelcolor='green',
#                labelrotation=15)
ax.tick_params(axis='x',which='major', direction='out',pad=5,labelsize=10)
ax.tick_params(axis='y',which='major', length=5, width=1, direction='out',pad=5,labelsize=10)
ax.xaxis.set_major_locator(MultipleLocator(0.05))
ax.xaxis.set_minor_locator(MultipleLocator(0.025))


#---- print data-types
print(ax.xaxis.get_major_locator())
print(ax.xaxis.get_minor_locator())
print(ax.xaxis.get_major_formatter())
print(ax.xaxis.get_minor_formatter())

#---- Hide Ticks or Labels
# ax.yaxis.set_major_locator(plt.NullLocator())
# ax.xaxis.set_major_formatter(plt.NullFormatter())

#---- Reducing or Increasing the Number of Ticks
# ax.xaxis.set_major_locator(plt.MaxNLocator(3))
# ax.yaxis.set_major_locator(plt.MaxNLocator(3))


#----- Fancy Tick Formats
ax.yaxis.set_major_locator(plt.MultipleLocator(np.pi / 4))
ax.yaxis.set_minor_locator(plt.MultipleLocator(np.pi / 12))


# ax.set_yticks([0, np.pi/8, np.pi/4 ])

ax.yaxis.set_major_formatter(plt.FuncFormatter(format_func))



# --- manually change ticks&labels:
# ax.set_xticks([0.2,1])
# ax.set_xticklabels(['pos1','pos2'])

# ax.set_yticks([0, np.pi/8, np.pi/4 ])
# labels = ['$0$',r'$\pi/8$', r'$\pi/4$']
# ax.set_yticklabels(labels)

a=ax.yaxis.get_major_locator()
b=ax.yaxis.get_major_formatter()
c = ax.get_xticks()
d = ax.get_xticklabels()
print('xticks:',c)
print('xticklabels:',d)

ax.grid(True,which='major',axis='both',alpha=0.3)



# plt.figure()

# f,ax=plt.subplots(1)

# plt.title(r''+ yName + '-Plot')
# plt.plot(X_Values, Y_Values,linewidth=2, '.k')
# plt.plot(X_Values, Y_Values,'.k',markersize=1)
# plt.plot(X_Values, Y_Values,'.',markersize=0.8)

# plt.plot(X_Values, Y_Values)

# ax.plot([[0],X_Values[-1]], [Y_Values[0],Y_Values[-1]])



# Gamma = '0'
# ax.plot([x_plotValues[0],x_plotValues[1]], [y_plotValues[0],y_plotValues[1]] , 'b')
#
# ax.plot([x_plotValues[1],x_plotValues[3]], [y_plotValues[2],y_plotValues[3]] , 'b')
#
# ax.plot(x_rest, y_rest, 'b')


# Gamma between

# x jump values (gamma 0): [0.13606060606060608, 0.21090909090909093]

# ax.plot([[0,jump_xValues[0]], [0, 0]] , 'b')
# ax.plot([jump_xValues[0],xmin], [y_plotValues[2],y_plotValues[2]] , 'b')

# ax.plot([[0,0.13606060606060608], [0, 0]] , 'b')
# ax.plot([[0.13606060606060608,xmin], [(math.pi/2),(math.pi/2)]], 'b')

# jump_xValues[0]



# --- leave out jumps:
# ax.scatter(X_Values, Y_Values)




# --- leave out jumps:
if gamma == 'infinity':
    ax.plot(X_Values[X_Values>=jump_xValues[0]], Y_Values[X_Values>=jump_xValues[0]] , 'royalblue')
    ax.plot(X_Values[X_Values<jump_xValues[0]], Y_Values[X_Values<jump_xValues[0]], 'royalblue')
    # ax.plot(X_Values[X_Values>=jump_xValues[0]], Y_Values[X_Values>=jump_xValues[0]])
    # ax.plot(X_Values[X_Values<jump_xValues[0]], Y_Values[X_Values<jump_xValues[0]])




# ax.plot(X_Values[X_Values>0.136], Y_Values[X_Values>0.136])
# ax.plot(X_Values[X_Values<0.135], Y_Values[X_Values<0.135])
# ax.scatter(X_Values, Y_Values)
# ax.plot(X_Values, Y_Values)

# plt.plot(x_plotValues, y_plotValues,'.')
# plt.scatter(X_Values, Y_Values, alpha=0.3)
# plt.scatter(X_Values, Y_Values)
# plt.plot(X_Values, Y_Values,'.')
# plt.plot([X_Values[0],X_Values[-1]], [Y_Values[0],Y_Values[-1]])
# plt.axis([0, 6, 0, 20])

# ax.set_xlabel(r"volume fraction $\theta$", size=11)
# ax.set_ylabel(r"angle $\angle$",  size=11)
ax.set_xlabel(r"volume fraction $\theta$")
ax.set_ylabel(r"angle $\angle$")

# plt.ylabel('$\kappa$')

# ax.yaxis.set_major_formatter(ticker.FormatStrFormatter('%g $\pi$'))
# ax.yaxis.set_major_locator(ticker.MultipleLocator(base=0.1))




# Plot every other line.. not the jumps...

if gamma == '0':
    tmp = 1
    for idx, x in enumerate(x_plotValues):
        if idx > 0 and tmp == 1:
            # plt.plot([x_plotValues[idx-1],x_plotValues[idx]] ,[y_plotValues[idx-1],y_plotValues[idx]] )
            ax.plot([x_plotValues[idx-1],x_plotValues[idx]] ,[y_plotValues[idx-1],y_plotValues[idx]], 'royalblue' )
            tmp = 0
        else:
            tmp = 1

# plt.plot([x_plotValues[0],x_plotValues[1]] ,[y_plotValues[0],y_plotValues[1]] )
# plt.plot([x_plotValues[2],x_plotValues[3]] ,[y_plotValues[2],y_plotValues[3]] )
# plt.plot([x_plotValues[4],x_plotValues[5]] ,[y_plotValues[4],y_plotValues[5]] )
# plt.plot([x_plotValues[6],x_plotValues[7]] ,[y_plotValues[6],y_plotValues[7]] )


for x in jump_xValues:
    plt.axvline(x,ymin=0, ymax= 1, color = 'orange',alpha=0.5, linestyle = 'dashed',  label=r'$\theta_*$')

# plt.axvline(x_plotValues[1],ymin=0, ymax= 1, color = 'g',alpha=0.5, linestyle = 'dashed')

# plt.axhline(y = 1.90476, color = 'b', linestyle = ':', label='$q_1$')
# plt.axhline(y = 2.08333, color = 'r', linestyle = 'dashed', label='$q_2$')
# plt.legend()

# ax.legend(prop={'size': 11})
ax.legend()

# ------------------ SAVE FIGURE
# tikzplotlib.save("TesTout.tex")
# plt.close()
# mpl.rcParams.update(mpl.rcParamsDefault)

# plt.savefig("graph.pdf",
#             #This is simple recomendation for publication plots
#             dpi=1000,
#             # Plot will be occupy a maximum of available space
#             bbox_inches='tight',
#             )
# plt.savefig("graph.pdf")



fig.set_size_inches(width, height)
fig.savefig('plot.pdf')




# tikz_save('someplot.tex', figureheight='5cm', figurewidth='9cm')

# tikz_save('fig.tikz',
#            figureheight = '\\figureheight',
#            figurewidth = '\\figurewidth')

# ----------------------------------------


plt.show()
# #---------------------------------------------------------------