#!/usr/bin/env python
import sys
import os
import io
import math
import PIL
import PySimpleGUI as sg
#import pkg_resources
#pkg_resources.require("matplotlib==3.0.3")
import matplotlib.pyplot as plt

VERBOS=1

def num(s):
  try: return float(s)
  except: return 0.

def extractFileName(s):
  head,tail= os.path.split(s)
  if '.' in tail:
    name_= tail.split('.')[0]
  else:
    name_= tail
  return name_
  
def lines2table(lines):
  from pylab import zeros
  lines= [x for x in lines if len(x.strip())>0] #remove empty lines
  lines= [x for x in lines if x[0] != '!'] #skip comment lines
  lines= [x for x in lines if x[0] != '_'] #skip comment lines
  if VERBOS: print(lines[0])
  labels= lines[0].split()
  if VERBOS: print(labels)
  TT= zeros((len(lines)-1,len(labels)),'float')
  for i,line in enumerate(lines):
    if i==0: continue #skip first line
    ww= line.split()
    for j in range(len(ww)): TT[i-1,j]= num(ww[j])
  Min= [min(TT[:,i]) for i in range(len(labels))]
  Max= [max(TT[:,i]) for i in range(len(labels))]
  return labels,TT,Min,Max
  
def table_read(new_file,initial_path):
  initial_folder,tail= os.path.split(initial_path)
  
  # Compute the relative file path to the given path   
  # from the given start directory. 
  # relative_path = os.path.relpath(path, start)
  if new_file:
    sg.SetOptions(auto_size_buttons=True)
    filepath= sg.PopupGetFile( 
                'input file', # location=[100,100],
                no_window=True,
                initial_folder= initial_folder,
                file_types=(("tab Files", "*.restab"),))
    if filepath == '':
      sys.exit(69)
  else:
    filepath= initial_path
  # button= sg.PopupYesNo('Does this file have column names already?')
  if filepath:
    try:
      with open(filepath,'r') as f:
        lines= f.readlines()
      f.close()
      # save the path for future work      
      with open("arximdraw.files",'w') as f:
        filepath= os.path.relpath(filepath)
        f.write(filepath+'\n')
      f.close()
    except:
      sg.PopupError('Error reading file')
      sys.exit(69)
  filename= extractFileName(filepath)
  return lines,filename
  
def table_show(header_list,data):
  layout=[[sg.Table(
             values=data,
             headings=header_list, 
             display_row_numbers=True,
             vertical_scroll_only=False,
             auto_size_columns=False, 
             num_rows=min(25,len(data)))]]

  window= sg.Window( 
             'Table', 
             # location=[100,100],
             grab_anywhere=False) 
             #If True can use mouse to click and drag to move the window
  event, values= window.Layout(layout).Read()

#--------------------------------------- PASTE YOUR MATPLOTLIB CODE HERE
def build_figure(data,ix,iy,minmax,options,LegLoc):
  import matplotlib.axes as ax
  from pylab import zeros, vstack
  
  couleur= "grey indianred darkred red orange gold greenyellow lightgreen limegreen teal dodgerblue blue darkviolet violet deeppink"
  colors= couleur.split()
  symbols=['o' ,'s','+','x','*','D','d','H','p','.','>','v','|','1','2','3','4']
  
  labels,datas,Min,Max= data
  xAuto,yAuto,xmin,xmax,ymin,ymax,relatif= minmax
  xLog,yLog,Stacking= options
  if xLog: plt.xscale('log')
  if yLog: plt.yscale('log')
  # fig.set_ylabel(titY)
  
  fontsize=12
  if len(iy)>4: fontsize=8
  
  if len(iy)>1:
    plt.xlabel(labels[ix])
    if relatif: plt.ylabel("relative to initial")
    if not xAuto: plt.xlim(xmin,xmax)
    if not yAuto: plt.ylim(ymin,ymax)
    x= datas[:,ix]
    # color,scale,marker,label= 'red',60,'-o','red'
    if Stacking:
      #ystack= vstack(datas[:,j] for j in iy)
      ystack= []
      for j in iy:
        ystack.append(datas[:,j])
      couleurs= (colors[j] for j in iy)
      lbs= (labels[j] for j in iy)
      plt.stackplot(x,ystack,colors=couleurs,linewidth=1.0,labels=lbs)
      plt.legend(loc=LegLoc,fontsize=fontsize)
    else:
      for k,j in enumerate(iy):
        # color=colors[k]
        lb= labels[j].replace("PHIM_","")
        lb= labels[j].replace("LogQsK_","")
        sy= symbols[(k)%len(symbols)]
        y=  datas[:,j]
        if relatif:
          y0= y[0]
          y=  y -y0
        # plt.plot(x,y, '-o', c=color, label=lb,linewidth= 1) #, s=scale, marker=marker
        plt.plot(x,y, sy, linestyle='-',linewidth=1.0,label=lb)
        plt.legend(loc=LegLoc,fontsize=fontsize)
    plt.grid(True)
    #for lb in legend.get_texts(): lb.set_fontsize('small')
  else:
    # fig,ax= plt.subplots()
    plt.xlabel(labels[ix])
    plt.ylabel(labels[iy[0]])
    if not xAuto: plt.xlim(xmin,xmax)
    if not yAuto: plt.ylim(ymin,ymax)
    x= datas[:,ix]
    y= datas[:,iy[0]] # -Min[iy[0]]
    # print(x)
    # print(y)
    # input()
    color,scale,marker= '0.5',90,'o'
    plt.plot(x,y, c=color, marker=marker,linewidth= 1)
    plt.grid(True) 
    # scatter(x, y1, s= 130, c= 'yellow', marker= '*', edgecolors= 'green')
    # scatter(x, y2, s= 50, c= 'red', marker= '+', linewidth= 3)
    # scatter(x, y3, s= 50, c= 'cyan', marker= 'o', edgecolors= 'none')
      
  # plt.subplots_adjust(left=1.0, right=2.0, bottom=1.0, top=1.0)
  fig= plt.gcf()
  if 0: fig.set_size_inches(8.*1.2,6.*1.2, forward=True)
  else: fig.set_size_inches(1.,1., forward=True) 
  
  return fig # ,figure_w, figure_h
#------------------------------------------- END OF YOUR MATPLOTLIB CODE

def screensize():
  import tkinter
  root= tkinter.Tk()
  width= root.winfo_screenwidth()
  height= root.winfo_screenheight()
  root.destroy()
  del root
  return width,height

def convert_to_bytes(file_or_bytes, resize=None):
  '''
  Will convert into bytes and optionally resize an image that is a file or a base64 bytes object.
  Turns into  PNG f, edgecolor='black', linewidth='1'ormat in the process so that can be displayed by tkinter
  :param file_or_bytes: either a string filename or a bytes base64 image object
  :type file_or_bytes:  (Union[str, bytes])
  :param resize:  optional new size
  :type resize: (Tuple[int, int] or None)
  :return: (bytes) a byte-string object
  :rtype: (bytes)
  '''
  if isinstance(file_or_bytes, str):
    img = PIL.Image.open(file_or_bytes)
  else:
    try:
      img = PIL.Image.open(io.BytesIO(base64.b64decode(file_or_bytes)))
    except Exception as e:
      dataBytesIO = io.BytesIO(file_or_bytes)
      img = PIL.Image.open(dataBytesIO)

  cur_width, cur_height = img.size
  if resize:
    new_width, new_height = resize
    scale = min(new_height/cur_height, new_width/cur_width)
    img = img.resize((int(cur_width*scale), int(cur_height*scale)), PIL.Image.ANTIALIAS)
  with io.BytesIO() as bio:
    img.save(bio, format="PNG")
    del img
    return bio.getvalue()

# ------------------------------------------------------ GUI Starts Here
w,h= screensize()
if h<800:
  fig_w, fig_h= 640,480
else:  
  fig_w, fig_h= 800,600
print(fig_w, fig_h)

lisPosition=['best','Up-right','Up-left','Low-left','Low-right','Right',\
             'Cent-left','Cent-right','Low-cent','Up-cent','Center']
lisFigSize=  ["16*12","8*6","8*8","12*12"]

initial_path= ""
if os.path.exists("arximdraw.files"):
  with open("arximdraw.files",'r') as f: lines= f.readlines()
  f.close()
  for ll in lines:
    if ll.strip()!='':
      initial_path= ll.strip()
new_file= initial_path == ""

ix= 0
iy= [0]

LowerLimit= -3.
All= 1
end= False

while True:
  
  lines,fname= table_read(new_file,initial_path)
  labels,datas,Min,Max= lines2table(lines)
  
  if end: break
  
  vmin= 0. #[min(datas[:,i]) for i in range(len(labels))]
  vmax= 1. #[max(datas[:,i]) for i in range(len(labels))]

  xmin,xmax=0.0,1.0
  ymin,ymax=0.0,1.0 
  minmax= xmin,xmax,ymin,ymax
  xLog= False
  yLog= False
  Stacking= False
  xAuto= True
  yAuto= True
  Relatif= False
  
  #--------------------------------------------------x-y coord's selection
  header_list= [v for v in labels]
  header_list= [labels[i] for i in range(len(labels)) if All or Max[i]>LowerLimit]
  x_box= 12
  y_box= min(24,len(header_list))
  colXsel=[
    [sg.Text('X-coord')],
    [sg.Listbox(
      values= header_list,
      select_mode=sg.LISTBOX_SELECT_MODE_SINGLE, 
      size=(x_box,y_box))],
    [sg.CBox('X-Log',   key='_xlog_', default=xLog)],
  ]
  colYsel=[
    [sg.Text('Y-coord(s)')],
    [sg.Listbox(
      values= header_list,
      select_mode=sg.LISTBOX_SELECT_MODE_MULTIPLE,
      size=(x_box,y_box))],
    [sg.CBox('Y-Log',   key='_ylog_', default=yLog)],
  ]
  colLeg=[
    [sg.Listbox(
      values= lisPosition,
      select_mode=sg.LISTBOX_SELECT_MODE_SINGLE,
      size=(8,4))],
    [sg.Text('Position')]
  ]
  colSiz=[
    [sg.Listbox(
      values= lisFigSize,
      select_mode=sg.LISTBOX_SELECT_MODE_SINGLE,
      size=(8,4))],
    [sg.Text('Fig Size')]
  ]
  # layout= [[sg.Column(colXsel),sg.Column(colYsel)],
  #           [sg.OK(),sg.Exit()]]
  #------------------------------------------------//x-y coord's selection
  colX= [
    [sg.CBox('auto', key='_xauto_',default=xAuto)],
    [sg.T('MAX'), sg.In(default_text=str(xmax), size=(8,1), key='_xmax_')],
    [sg.T('MIN'), sg.In(default_text=str(xmin), size=(8,1), key='_xmin_')],
    # [sg.Text('X-axis')] 
  ]
  colY= [
    [sg.CBox('auto', key='_yauto_',default=yAuto)],
    [sg.T('MAX'), sg.In(default_text=str(ymax), size=(8,1), key='_ymax_')],
    [sg.T('MIN'), sg.In(default_text=str(ymin), size=(8,1), key='_ymin_')],
    # [sg.Text('Y-axis')]
  ]
  colOptions= [ 
    [sg.CBox('Stacked',   key='_stack_',  default=Stacking) ],
    [sg.CBox('y(t)-y(0)', key='_relatif_',default=Relatif)],
  ]

  sg.ChangeLookAndFeel('LightGreen')
  
  # define the form layout
  layout= [
    [
      sg.Column(colXsel,key='x-coord'),
      sg.Column(colYsel,key='y-coord'),
      sg.Image(key='-IMAGE-') 
    ],
    [
      sg.Column(colX,key='x-minmax'),
      sg.Column(colY,key='y-minmax'),
      sg.Column(colLeg,key='position'),
      sg.Column(colOptions,key='options'),
    ],
      # sg.Column(colSiz,key='fig-size'),],
    [
      sg.OK('Draw'),
      sg.Button('Save on File'),
      sg.Button('Save on Screen'),
      sg.Button('New file'),
      sg.Button('Exit'),
    ]
  ]

  # create the form and show it without the plot
  # window= sg.Window('ArximDraw', grab_anywhere=False).Layout(layout)
  # window.Finalize()
  titlebar= "ArximDraw on " + fname
  window= sg.Window(titlebar, layout, location=(0,0), finalize=True)

  LegLoc=  0
  FigSize= 0
  I=0
  
  while True:
    event, values= window.Read()
    if VERBOS: print(event)
    if VERBOS: print(values)
    # show it all again and get buttons
    if event=='New file':
      window.Close()
      new_file= True
      break
    if event is None or event == 'Exit':
      window.Close()
      end=True
      break
    iy=[]
    breakk= False
    for key, val in list(values.items()):
      # print(key,val,len(val))
      if key==0: 
        if len(val)>0:
          ix=labels.index(val[0])
        else:
          sg.popup("No X Coord selected")
          breakk= True
      if key==1:
        if len(val)>0:
          for s in val: iy.append(labels.index(s))
        else:
          sg.popup("No Y Coord selected")
          breakk= True
      if key==2: 
        if len(val)>0: LegLoc= lisPosition.index(val[0])
      # if key==3: 
      #   if len(val)>0: FigSize= lisFigSize.index(val[0])
    
    if breakk: continue
    
    xmin= 0. #math.floor(vmin[ix]*100.)/100.
    xmax= 1. #math.ceil(vmax[ix]*100.)/100.
    for key, val in list(values.items()):
      # print(key,val,len(val))
      try: x= float(val)
      except: x= 0.0 #"Not a Real !!"
      if key=='_xmax_': xmax=x
      if key=='_xmin_': xmin=x
      if key=='_ymax_': ymax=x
      if key=='_ymin_': ymin=x
    for key, val in list(values.items()):
      if key=='_xlog_': xLog= val
      if key=='_ylog_': yLog= val
      if key=='_stack_': Stacking= val
      if key=='_relatif_': Relatif= val
      if key=='_xauto_': xAuto= val
      if key=='_yauto_': yAuto= val
    if VERBOS: print(("ix=",ix))
    if VERBOS: print(("iy=",iy))
    minmax=xAuto,yAuto,xmin,xmax,ymin,ymax,Relatif
    if VERBOS: print(("minmax=",minmax))
    loglog= xLog,yLog,Stacking
    
    if ix<0:
      sg.PopupError('X not Selected')
      continue
    
    data= labels,datas,Min,Max
    plt.clf()
    fig= build_figure(data,ix,iy,minmax,loglog,LegLoc)
    
    fw,fh= 16., 12.
    fig.set_size_inches(fw/2.54,fh/2.54)
    picture_buf= io.BytesIO()
    plt.savefig(picture_buf,format='png')
    
    new_size= 640,480
    picture_buf.seek(0)
    byttes=convert_to_bytes(picture_buf.read(), resize=new_size)
    
    window['-IMAGE-'].update(data=byttes)
    
    if event=='Save on Screen':
      im = PIL.Image.open(picture_buf)
      im.show()     
    if event=='Save on File':
      I+=1
      fn= fname+'_'+str(I)
      # ["16*12","8*6","8*8","12*12"]
      # if FigSize==0:
      #   fw,fh= 16., 12.
      # elif FigSize==1:
      #   fw,fh= 8., 6.
      # elif FigSize==2:
      #   fw,fh= 8., 8.
      # elif FigSize==3:
      #   fw,fh= 12., 12.
      fw,fh= 16., 12.
      fig.set_size_inches(fw/2.54,fh/2.54)
      plt.savefig(fn+'.eps')
      plt.savefig(fn+'.png')

  if end: break
