#!/usr/bin/env python3
####################################################################################
# satpy selector
# Hilversum   , 2022/04/22       License GPL3          (c) Rob Alblas
####################################################################################
# Needs zero or one argument which selects a path to data; see data_loc table in satpy_settings.py
# Files found in that location will be used to determine which command to use.
#   (Data from different sats may be in one location.)
#
####################################################################################
version='23-01-03'
#scriptversion: 3 (v3.0 version) or 4 (SPS-version)
script_version=4
#
import os,sys
from os import walk
import fnmatch
from glob import glob
from datetime import datetime,timedelta

from tkinter import *
import tkinter as tk

from satpy_settings import data_loc

#Base command
# May be:
#  'python3 <location_of_script>
# or:
#  ''
exe_cmd='python3 ./'
#exe_cmd=''

# tle file (full path!); if not filled in: default (defined in script used) (!Check age and update!)
# This file is NOT used if 'Hist tle' is ticked. 
file_tle    =""

if script_version==3:
  # Next: detected file via filter sets ID for that file and the command to use.
  #                id         file filter(s)                              command to use
  geosattypes = [['MSG'     ,['H-000-MSG*'                              ],exe_cmd+'MSGx.py'      ],
                 ['MSGn'    ,['MSG*-SEVI*'                              ],exe_cmd+'MSGx.py'      ],
                 ['MTG'     ,['W_XX-EUMETSAT-*BODY*'                    ],exe_cmd+'MTGx.py'      ],
                 ['GOES'    ,['OR_ABI-*'                                ],exe_cmd+'GOESx.py'     ],
                 ['HIMA'    ,['IMG_DK01*'                               ],exe_cmd+'HIMAx.py'     ]]

  leosattypes = [['Metop'   ,['AVHR_xxx_1B_M0*'                         ],exe_cmd+'Metop.py'     ],
                 ['NOAA'    ,['SV*C_j01_d*'                             ],exe_cmd+'NOAA.py'      ],
                 ['SUOMI'   ,['SV*C_npp_d*'                             ],exe_cmd+'NOAA.py'      ],
                 ['FY3D'    ,['FY3D*1000M_L1B.HDF','FY3D*GEO1K_L1B.HDF' ],exe_cmd+'FY3D.py'      ],
                 ['Aqua'    ,['thin_MYD021KM.A*'                        ],exe_cmd+'AquaTerra.py' ],
                 ['Terra'   ,['thin_MOD021KM.A*'                        ],exe_cmd+'AquaTerra.py' ],
                 ['Sentinel',['S3*_OL_1_ERR____*'                       ],exe_cmd+'Sentinel3.py' ]]
  #               ['Sentinel',['S3*_OL_1_EFR____*'                       ],exe_cmd+'Sentinel3.py' ]]
else:
  # Next: detected file via filter sets ID for that file and the command to use.
  #                id         file filter(s)                              command to use
  geosattypes = [['MSG'     ,['H-000-MSG*'                              ],exe_cmd+'MSG.py'      ],
                 ['MSGn'    ,['MSG*-SEVI*'                              ],exe_cmd+'MSG.py'      ],
                 ['MTG'     ,['W_XX-EUMETSAT-*BODY*'                    ],exe_cmd+'MTI.py'      ],
                 ['GOES'    ,['OR_ABI-*'                                ],exe_cmd+'GOES.py'     ],
                 ['HIMA'    ,['IMG_DK01*'                               ],exe_cmd+'HIMA.py'     ]]

  leosattypes = [['Metop'   ,['AVHR_xxx_1B_M0*'                         ],exe_cmd+'Metop.py'     ],
                 ['NOAA'    ,['SV*C_j01_d*'                             ],exe_cmd+'NOAA.py'      ],
                 ['SUOMI'   ,['SV*C_npp_d*'                             ],exe_cmd+'NOAA.py'      ],
                 ['FY3D'    ,['FY3D*1000M_L1B.HDF','FY3D*GEO1K_L1B.HDF' ],exe_cmd+'FY3D.py'      ],
                 ['Aqua'    ,['thin_MYD021KM.A*'                        ],exe_cmd+'AquaTerra.py' ],
                 ['Terra'   ,['thin_MOD021KM.A*'                        ],exe_cmd+'AquaTerra.py' ],
                 ['Sentinel',['S3*_OL_1_ERR____*'                       ],exe_cmd+'Sen3.py' ]]
  #               ['Sentinel',['S3*_OL_1_EFR____*'                       ],exe_cmd+'Sen3.py' ]]


# detect sat from filename
# return: (id,command)
def detect(fn):
  for st in geosattypes+leosattypes:
    for nn in st[1]:
      if fnmatch.fnmatch(fn,nn):
        return (st[0],st[2])
  return (' ',' ')

ftbl=[]
# table: satname, date, time, nr. files, filename, sid, sc
def make_tbl(ftbl,sat,date,time,fn,sc,sid):
  for n in ftbl:
    if sat == n[0] and date == n[1] and (time == None or time == n[2]):
      n[3]=n[3]+1
      return
#  print('b: ftbl='+str(ftbl))
  row=[]
  row.append(sat)
  row.append(date)
  if time != None:
    row.append(time)
  else:
    row.append('')

  row.append(1)
  row.append(fn)
  row.append(sid)
  row.append(sc)
  ftbl.append(row)
#  print('c: ftbl='+str(ftbl))

#H-000-MSG1__-MSG1_IODC___-IR_097___-000008___-201712170830-C_
#H-000-MSG4__-MSG4________-IR_120___-000006___-201204081230-C_
#H-000-MSG3__-MSG3_RSS____-IR_120___-000006___-201204081230-C_
#012345678901234567890123456789012345678901234567890123456789
#0         1         2         3         4         5         
def collect_msg(ftbl,fn,sc):
  sat=fn[13:22]
  date=fn[46:54]
  time=fn[54:58]
#  if sat[5:9]=='IODC':
#    sid=sat[5:9]
#  elif sat[5:8]=='RSS':
#    sid=sat[5:8]
#  else:
  sid=sat[3]
  make_tbl(ftbl,sat,date,time,fn,sc,sid)

#MSG3-SEVI-MSG15-0100-NA-20220918164418.769000000Z-NA.nat
#01234567890123456789012345678901234567890123456789012345
#0         1         2         3         4         5         
def collect_msgn(ftbl,fn,sc):
  sat=fn[0:4]
  date=fn[24:32]
  time=fn[32:36]
  if script_version==3:
    sid=sat[3]
    sc=sc+' -nat'
  else:
    sid=sat[3]+'n'
  make_tbl(ftbl,sat,date,time,fn,sc,sid)


#W_XX-EUMETSAT-Darmstadt,IMG+SAT,MTI1+FCI-1C-RRAD-FDHSI-FD--CHK-TRAIL---NC4E_C_EUMT_20170920120422_GTT_DEV_20170920115008_20170920115922_N__T_0072_0041.nc
#0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
#0         1         2         3         4         5         6         7         8         9
def collect_mtg(ftbl,fn,sc):
  sat=fn[32:36]
  date=fn[82:90]
  time=fn[90:94]
  sid=sat[3]
  dt1=datetime(int(date[0:4]),int(date[4:6]),int(date[6:8]),int(time[0:2]),int(time[2:4]))
  dt2=dt1+timedelta(minutes=5)
  Date=dt2.strftime('%Y%m%d')
  Time=dt2.strftime('%H00')
  make_tbl(ftbl,sat,Date,Time,fn,sc,sid)

#OR_ABI-L1b-RadF-M6C10_G16_s20220332350207_e20220332359526_c20220332359574.nc
#012345678901234567890123456789012345678901234567890123456789
#0         1         2         3         4         5
def collect_goes(ftbl,fn,sc):
  sat='GOES'+fn[23:25]
  dt=datetime.strptime(fn[27:34],"%Y%j")
  date=dt.strftime("%Y%m%d")
  time=fn[34:38]
  sid=sat[4:6]
  make_tbl(ftbl,sat,date,time,fn,sc,sid)

#IMG_DK01VIS_201809130339_010.bz2
#01234567890123456789012345678901
#0         1         2         3 
def collect_hima(ftbl,fn,sc):
  sat='HIMA8'
  date=fn[12:20]
  time=fn[20:24]
  sid=sat[4]
  make_tbl(ftbl,sat,date,time,fn,sc,sid)

#AVHR_xxx_1B_M03_20220324195203...
#012345678901234567890123456789
def collect_metop(ftbl,fn,sc):
  if fn[14]=='1':
    sat='METOP-B'
  elif  fn[14]=='2':
    sat='METOP-A'
  elif  fn[14]=='3':
    sat='METOP-C'
  else:
    sat='METOP-?'

  date=fn[16:24]
  time=fn[24:30]
  sid=sat[6]

  make_tbl(ftbl,sat,date,None,fn,sc,sid)

#SVMC_j01_d20220215_t1359144_e1400372_b21994_c20220215141054000943_eum_ops.h5
#SVDNBC_j01_d20220215_t1042555_e1044200_b21992_c20220215105650000435_eum_ops.h5
#SVMC_npp_d20151119_t22*eum_ops.h5
#012345678901234567890123456789
def collect_noaa(ftbl,fn,sc):
  dpos=fn.find('_d',0)+2
  tpos=fn.find('_t',0)+2
  sat='NOAA20'
  date=fn[dpos:dpos+8]
  time=fn[tpos:tpos+4]
  if fn.find('_npp_',0)>0:
    sat='SUOMI'
    sid='SUO'
  else:
    sat='NOAA20'
    sid='N20'
  make_tbl(ftbl,sat,date,None,fn,sc,sid)

#FY3D_20220302_215300_215400_22265_MERSI_GEO1K_L1B.HDF
#012345678901234567890123456789
def collect_fy3d(ftbl,fn,sc):
  sat='FY3D'
  date=fn[5:13]
  time=fn[14:20]
  sid=sat
  make_tbl(ftbl,sat,date,None,fn,sc,sid)

#thin_MOD021KM.A2022069.1500.061.2022069162753.NRT.hdf
#thin_MYD021KM.A2022069.1535.061.2022069165545.NRT.hdf
#012345678901234567890123456789
def collect_aqua(ftbl,fn,sc):
  sat='Aqua'
  dt=datetime.strptime(fn[15:22],"%Y%j")
  date=dt.strftime("%Y%m%d")
  time=fn[23:27]
  sid=sat[0]
  make_tbl(ftbl,sat,date,None,fn,sc,sid)

def collect_terra(ftbl,fn,sc):
  sat='Terra'
  dt=datetime.strptime(fn[15:22],"%Y%j")
  date=dt.strftime("%Y%m%d")
  time=fn[23:27]
  sid=sat[0]
  make_tbl(ftbl,sat,date,None,fn,sc,sid)

#S3B_OL_1_EFR____20220310T091806_20220310T092106_20220311T143704_0179_063_264_2340_MAR_O_NT_002.SEN3.tar
#0123456789012345678901234567890
def collect_sentinel(ftbl,fn,sc):
  sat='Sentinel-'+fn[1:3]
  date=fn[16:24]
  time=fn[25:31]
  sid=fn[2]
  
  make_tbl(ftbl,sat,date,None,fn,sc,sid)


####################################################################################
sel_area=''
sel_comp=''
def setup_gui(collection_list,sel_sat):
  import tkinter.ttk as ttk
  import tkinter.font as tkFont
  from satpy_areas import collect_all_areas,create_regioarea,regio_list
  global entry1
  global area
  global sel_area
  global sel_comp
  def handle_keypress1(event):
    items = tree.focus()
    stype=tree.set(items,column=0)
    date=tree.set(items,column=1)
    time=tree.set(items,column=2)
    sid=tree.set(items,column=4)
    sc=tree.set(items,column=5)
    doit(wnd,stype,date,time,sc,True,sid,day_night.get(),histtle.get(),stacked.get())

  def handle_keypress2(event):
    items = tree.focus()
    stype=tree.set(items,column=0)
    date=tree.set(items,column=1)
    time=tree.set(items,column=2)
    sid=tree.set(items,column=4)
    sc=tree.set(items,column=5)
    doit(wnd,stype,date,time,sc,False,sid,day_night.get(),histtle.get(),stacked.get())

  def do_selitem():
    si=sel_item.get()
    tree.delete(*tree.get_children())
    ftbl=[]
    #hierna vullen
    load_item(si,ftbl,tree)

 #   tree.insert('','end',values=si)
  col_vg =1
  col_sat=2
  col_are=3
  col_com=4
  col_dn =5
  col_hs =6
  col_inf=7

  header = ['sat', 'date','time','# files',' ',' ']
  wnd = tk.Tk()
  wnd.title('Satpy selector')
  frame = ttk.Frame()
  frame.pack(fill='both', expand=True)
  tree = ttk.Treeview(columns=header, show="headings")
  vsb = ttk.Scrollbar(orient="vertical",command=tree.yview)
  hsb = ttk.Scrollbar(orient="horizontal",command=tree.xview)
  tree.configure(yscrollcommand=vsb.set,xscrollcommand=hsb.set);
  tree.grid(column=0, row=0, sticky='nsew', in_=frame)
  vsb.grid(column=1, row=0, sticky='ns', in_=frame)
  hsb.grid(column=0, row=1, sticky='ew', in_=frame)
  frame.grid_columnconfigure(0, weight=1)
  frame.grid_rowconfigure(0, weight=1)

  frame1=Frame(wnd)


  but1=tk.Button(frame1,text="View")
  but1.bind("<Button-1>",handle_keypress1)
  but1.grid(column=col_vg,row=1)

  but2=tk.Button(frame1,text="Gen.")
  but2.bind("<Button-1>",handle_keypress2)
  but2.grid(column=col_vg,row=2)

  day_night = IntVar()
  butd=Radiobutton(frame1,text='Day  ',value=0,variable=day_night)
  butn=Radiobutton(frame1,text='Night',value=1,variable=day_night)
  butd.grid(column=col_dn,row=1)
  butn.grid(column=col_dn,row=2)

  histtle = IntVar()
  but3=Checkbutton(frame1,text='Hist tle',onvalue=1,variable=histtle)
  but3.grid(column=col_hs,row=1)

  stacked = IntVar()
  but4=Checkbutton(frame1,text='Stacked',onvalue=1,variable=stacked)
  but4.grid(column=col_hs,row=2)

  ##### create item menu #####
  slabel=tk.Label(frame1,text='Satellite')
  sel_item = tk.StringVar(value=sel_sat) # data_loc[0][0])
  menubutton2 = tk.Menubutton(frame1, textvariable=sel_item ,indicatoron=True,borderwidth=1, relief="raised")
  menu2 = tk.Menu(menubutton2, tearoff=True)
  menubutton2.configure(menu=menu2)
  for dl in data_loc:
    menu2.add_radiobutton(value=dl[0], label=dl[0], variable=sel_item,command=do_selitem)
  smenu=menubutton2

  slabel.grid(column=col_sat,row=1)
  smenu.grid(column=col_sat,row=2)

  ##### create area menu #####
  areas=collect_all_areas()
  regio_area=create_regioarea(regio_list,areas)

  alabel=tk.Label(frame1,text='Area')

  sel_area = tk.StringVar(value="default")
  amenubutton = tk.Menubutton(frame1, textvariable=sel_area, indicatoron=True,borderwidth=1, relief="raised")
  main_menu = tk.Menu(amenubutton, tearoff=True)
  amenubutton.configure(menu=main_menu)

  # Create 2D area menu
  p=regio_area.head
  while p is not None:
    a_menu = tk.Menu(main_menu, tearoff=True)
    main_menu.add_cascade(label=p.name, menu=a_menu)
    q=p.area.head
    while q is not None:
      a_menu.add_radiobutton(value=q.name, label=q.name, variable=sel_area)
      q=q.next
    p=p.next
  amenu=amenubutton

  alabel.grid(column=col_are,row=1)
  amenu.grid(column=col_are,row=2)

  ##### create composite menu #####
  clabel=tk.Label(frame1,text='Composite')
  sel_comp = tk.StringVar(value="default")
  cmenubutton = tk.Menubutton(frame1, textvariable=sel_comp, indicatoron=True,borderwidth=1, relief="raised")
  main_menu = tk.Menu(cmenubutton, tearoff=True)
  cmenubutton.configure(menu=main_menu)

  from satpy_settings import composite_list
  for st in composite_list:
    c_menu = tk.Menu(main_menu, tearoff=True)
    main_menu.add_cascade(label=st[0], menu=c_menu)
    for c in st[1]:
      c_menu.add_radiobutton(value=c, label=c, variable=sel_comp)
  cmenu=cmenubutton

#  comps1=['default','overview','natural_color']

#  comp = StringVar()
#  comp.set(comps1[0])

#  clabel=tk.Label(frame1,text='Composite')
#  cmenu=OptionMenu(frame1,comp,*comps1)

  clabel.grid(column=col_com,row=1)
  cmenu.grid(column=col_com,row=2)

  ##### info entry #####
  elabel=tk.Label(frame1,text='Info')
  entry1=Entry(frame1,font=('Arial', 12, 'bold'),width=9)
  elabel.grid(column=col_inf,row=1)
  entry1.grid(column=col_inf,row=2)

  set_entry(entry1,'V '+version)

  frame1.pack(side=tk.TOP,fill="x")

  tree["displaycolumns"]=(header[0],header[1],header[2],header[3])

  for col in header:
    tree.heading(col, text=col.title())
    tree.column(col,width=tkFont.Font().measure(col.title()))
  for item in collection_list:
    itemx=item[0:4]               # name, date, time, nr.; hidden: filename
    itemx.append(item[5])         # hidden: sattype
    itemx.append(item[6])         # hidden: script
    tree.insert('','end',values=itemx)
#    for ix, val in enumerate(item):
#       if ix<4:
#         col_w = tkFont.Font().measure(val)
#         if tree.column(header[ix],width=None)<col_w:
#             tree.column(header[ix], width=col_w+20)
  wnd.mainloop()

def set_entry(w,s):
  w.delete(0,END)
  if (len(s)>=1):
    w.insert(0,s)

#loc_src repareren!
loc_src=''
def load_item(satid,ftbl,tree):
  global loc_src
  loc_src=''
  for dtype in data_loc:
    if satid == dtype[0]:
      if dtype[1]!='':
        loc_src=dtype[1]
      else:
        print('No location defined for '+dtype[0])
      break
  if loc_src!='':
    # Get files from loc_src
    _, _, filenames = next(walk(loc_src), (None, None, []))
    ftbl=[]
    for fn in filenames:
      (nn,sc)=detect(fn)
      if nn=='MSG':
        collect_msg(ftbl,fn,sc)
      elif nn=='MSGn':
        collect_msgn(ftbl,fn,sc)
      elif nn=='MTG':
        collect_mtg(ftbl,fn,sc)
      elif nn=='GOES':
        collect_goes(ftbl,fn,sc)
      elif nn=='HIMA':
        collect_hima(ftbl,fn,sc)
      elif nn=='Metop':
        collect_metop(ftbl,fn,sc)
      elif nn=='NOAA':
        collect_noaa(ftbl,fn,sc)
      elif nn=='SUOMI':
        collect_noaa(ftbl,fn,sc)
      elif nn=='FY3D':
        collect_fy3d(ftbl,fn,sc)
      elif nn=='Aqua':
        collect_aqua(ftbl,fn,sc)
      elif nn=='Terra':
        collect_terra(ftbl,fn,sc)
      elif nn=='Sentinel':
        collect_sentinel(ftbl,fn,sc)
      elif nn==None:
        None
      else:
        None

    # recreate table after changing satellite
    collection_list=sorted(ftbl,key=lambda ftbl:ftbl[0]+ftbl[1]+ftbl[2])
    for item in collection_list:
      itemx=item[0:4]               # name, date, time, nr.; hidden: filename
      itemx.append(item[5])         # hidden: sattype
      itemx.append(item[6])         # hidden: script
      tree.insert('','end',values=itemx)
#      for ix, val in enumerate(item):
#         if ix<4:
#           col_w=10

# time=='': no time -> polar, else geo
def doit(wnd,stype,date,time,script,do_view,sid,dn,do_histtle,do_stacked):
  if time=='':
    if script_version==3:
      if dn==0:
        sidn=sid+'D'
      else:
        sidn=sid+'N'
    else:
      if dn==0:
        sidn=sid+' -dn D'
      else:
        sidn=sid+' -dn N'
  else:
    sidn=sid
  
  if sidn=='':
    cmd=script + ' -t '+ date+time+ ' -src ' +loc_src
  else:
    cmd=script + ' -t '+ date+time+' -sat ' + sidn + ' -src ' +loc_src

  if time=='':
    if file_tle!='':
      cmd=cmd+' -tle '+ file_tle

  selected_area = sel_area.get()
  if selected_area!='default' and selected_area!='':
    cmd=cmd+' -area '+str(selected_area)

  selected_comp = sel_comp.get()
  if selected_comp!='default':
    cmd=cmd+' -composite '+selected_comp

  if do_view:
    cmd=cmd+' -v '

  #Only add -histtle and -mp option if no time spec., equals it's a polar sat.
  if time=='':
    if do_histtle:
      cmd=cmd+' -histtle'
    if do_stacked:
      if script_version==3:
        cmd=cmd+' -sp'
      else:
        cmd=cmd+' -mp'

  set_entry(entry1,"Running")
  wnd.update()
  print(cmd)

  os.system(cmd)
  set_entry(entry1,"Ready")

def usage(prog):
  print('usage:')
  print('  '+prog+' [options]')
  print('   [options]:')
  for n in data_loc:
    print('     {:10s} (location: {:s})'.format(n[0],n[1]))

################################################################################
# Main part
#
print('Use settings in satpy_settings.py')

sat=''
if len(sys.argv) >1:
  if sys.argv[1]=='-h':
    usage(sys.argv[0])
    quit()

if len(sys.argv) <=1:
  for dtype in data_loc:
    if dtype[1]!='':
      sat=dtype[0]
      loc_src=dtype[1]
      break
#      print(dtype[0]+' (data at: '+dtype[1]+')')
#  print('Or full path to data.')
else:
  sat=sys.argv[1]
  for dtype in data_loc:
    if sat == dtype[0]:
      if dtype[1]!='':
        loc_src=dtype[1]
      else:
        sys.exit('No location defined for '+dtype[0])
      break

  if loc_src=='':
    loc_src=sys.argv[1]

print("Selected file location: " + loc_src)
if loc_src[0:1]!='/' and loc_src[1:2]!=':' :
  print("ERROR: This doesn't look like a full path! Check pathes near 'Specify locations'")

# Get files from loc_src
_, _, filenames = next(walk(loc_src), (None, None, []))

ftbl=[]
for fn in filenames:
  (nn,sc)=detect(fn)
  if nn=='MSG':
    collect_msg(ftbl,fn,sc)
  elif nn=='MSGn':
    collect_msgn(ftbl,fn,sc)
  elif nn=='MTG':
    collect_mtg(ftbl,fn,sc)
  elif nn=='GOES':
    collect_goes(ftbl,fn,sc)
  elif nn=='HIMA':
    collect_hima(ftbl,fn,sc)
  elif nn=='Metop':
    collect_metop(ftbl,fn,sc)
  elif nn=='NOAA':
    collect_noaa(ftbl,fn,sc)
  elif nn=='SUOMI':
    collect_noaa(ftbl,fn,sc)
  elif nn=='FY3D':
    collect_fy3d(ftbl,fn,sc)
  elif nn=='Aqua':
    collect_aqua(ftbl,fn,sc)
  elif nn=='Terra':
    collect_terra(ftbl,fn,sc)
  elif nn=='Sentinel':
    collect_sentinel(ftbl,fn,sc)
  elif nn==None:
    None
  else:
    None

ftbl=sorted(ftbl,key=lambda ftbl:ftbl[0]+ftbl[1]+ftbl[2])
wnd=setup_gui(ftbl,sat)

#if __name__ == "__main__":
#  main(sys.argv[1:])
