#!/usr/bin/env python
from datetime import datetime, timedelta
import re, string
import numpy as np
import os, glob

from utility import list_leoatt_files, list_leornx_files
from utility import str2date, leofile_time_range

__authors__ = ["Ming Chen"]
__license__ = "Public Domain"
__maintainer__ = "Ming Chen"
__email__ = "ming.chen@noaa.gov"
__date__  = "July 1, 2023"

'''
#####################################################################
# 
# bern_sessions.py
#
# Purpose:
# This python script is used to handle the BERNESE hourly sessions.
##
# History:  
#       Created by: Ming Chen 2023/07/01
#                   ming.chen@noaa.gov
# 
# Usage: from bern_sessions import bern_sessions
#
#
#####################################################################

'''


class bern_sessions(object):


   def overlap(window_hours):
       sessions=[]
       dt=window_hours
       if ((dt > 3) or (dt < 1)):
          print("error: window_hours must be less than 3 ...")
       dt=dt*60/2
 
       for i in range(24):
           sessions.append([i*60-dt, i*60+dt])
       return (sessions)

   def non_overlap(window_hours, end_offset=0, offset=0):
       sessions=[]
       dt = window_hours
       if ((dt > 12) or (24%dt != 0)):
          print("error: window_hours must be the factor of 24 and <=12 ...")
          return
       
       n = 24//dt
       
       for i in range(n):
           sessions.append([i*dt*60-offset, (i+1)*dt*60+offset])
       sessions[0][0] = sessions[0][0] - end_offset
       sessions[n-1][1] = sessions[n-1][1] + end_offset
       return (sessions)

   def from_time_range(t_start,t_end):
       sessions=[]
       #tstart = t_start.strftime("%Y%m%dT%H%M%S")
       #tend = t_end.strftime("%Y%m%dT%H%M%S")
       tstart = datetime.strptime(t_start, "%Y%m%dT%H:%M:%S")
       tend = datetime.strptime(t_end, "%Y%m%dT%H:%M:%S")
       mydate = tend.strftime("%Y%m%d")
       mydate = datetime.strptime(mydate, "%Y%m%d")
       t1 = (tstart - mydate).total_seconds()/60.0
       t2 = (tend- mydate).total_seconds()/60.0

       sessions.append([t1, t2])
       return (sessions)

   def customized(case=1):
       sessions=[]
       if case == 1:
         w  = [-1, 3, 6, 10, 15, 20, 25]
         for i in range(len(w)-1):
            sessions.append([w[i], w[i+1]])

       return (sessions)

   def from_leo_files(datestr, filelist, stype='hourly'):
       mydate = str2date(datestr)
       nFiles = len(filelist)
       alpha=list(string.ascii_uppercase)
       if stype == 'daily':
         alpha = ['0']
       sessions=[]
       if(nFiles > len(alpha) or nFiles < 1):
          print("error: filelist, total num of files s hould be <=26, and in A->Z order")
          return (sessions)
       for i in range(len(filelist)): 
           filename = filelist[i]
           basename = os.path.basename(filename)
           #if alpha[i]+'.ATT' not in basename: 
           #print(basename)
           if not re.search(r"^\w{4}\d{3,5}"+alpha[i]+".",basename): 
              #print('{}, file is not in the consecutive order from A-Z, not included ..'.format(filename))
              return(sessions)
           if os.path.exists(filename) and os.stat(filename).st_size != 0:
              stime, etime = leofile_time_range(filename)
              #print(stime, etime)
              stime = datetime.strptime(stime,'%Y%m%dT%H:%M:%S.%f')
              etime = datetime.strptime(etime,'%Y%m%dT%H:%M:%S.%f')

              t1 = (stime - mydate).total_seconds()/60.0
              t2 = (etime - mydate).total_seconds()/60.0
              sessions.append([t1,t2])
           else:  break
       return sessions

   def from_leo_files2(datestr, att_filelist, rnx_filelist, stype='hourly'):

       mydate = str2date(datestr)
       att_nFiles = len(att_filelist)
       rnx_nFiles = len(rnx_filelist)
       alpha=list(string.ascii_uppercase)
       if stype == 'daily':
         alpha = ['0']
       sessions=[]
       if rnx_nFiles != att_nFiles:
          print(f"error att_nFiles is not euqal to rnx_nFiles ....")
          return (sessions)
       nFiles = att_nFiles 
       if(nFiles > len(alpha) or nFiles < 1):
          print("error: filelist, total num of files s hould be <=26, and in A->Z order")
          return (sessions)
       for i in range(len(att_filelist)): 
           att_filename = att_filelist[i]
           att_basename = os.path.basename(att_filename)
           rnx_filename = rnx_filelist[i]
           rnx_basename = os.path.basename(rnx_filename)
           #if alpha[i]+'.ATT' not in basename: 
           if not re.search(r"^\w{4}\d{3,5}"+alpha[i]+".",att_basename): 
              #print('{}, file is not in the consecutive order from A-Z, not included ..'.format(filename))
              return(sessions)
           if not re.search(r"^\w{4}\d{3,5}"+alpha[i]+".",rnx_basename): 
              return(sessions)
           if os.path.exists(att_filename) and os.stat(att_filename).st_size != 0 and \
              os.path.exists(rnx_filename) and os.stat(rnx_filename).st_size != 0:
              att_stime, att_etime = leofile_time_range(att_filename)
              rnx_stime, rnx_etime = leofile_time_range(rnx_filename)	       #print(stime, etime)
              stime = att_stime if att_stime > rnx_stime else rnx_stime
              etime = att_etime if att_etime < rnx_etime else rnx_etime
              stime = datetime.strptime(stime,'%Y%m%dT%H:%M:%S.%f')
              etime = datetime.strptime(etime,'%Y%m%dT%H:%M:%S.%f')

              t1 = (stime - mydate).total_seconds()/60.0
              t2 = (etime - mydate).total_seconds()/60.0
              sessions.append([t1,t2])
           else:  break
       return sessions


  
   def is_valid_session(sessions):
       s = np.array(sessions).shape
       valid=True
       if (len(s) != 2 or s[1] != 2):
          print("error: invalid sessions setting ..., sessions must be 2D array")
          valid = False
       return(valid)

   def print_bern_session(sessions, stype='hourly'):
       if not bern_sessions.is_valid_session(sessions): return
       lines=[]  
       alpha=list(string.ascii_uppercase)
       s = np.array(sessions).shape
       if stype == 'daily' and s[0] != 1:
           print("error: there must be just one daily session ")         

       for i in range(s[0]): 
           t1, t2 = sessions[i][:]
           t1 = int(t1*60) ; t2 = int(t2*60) - 1 # minus 1 sec or simply set s2 to 59
           h1 = t1//3600 ; m1 = (t1-h1*3600)//60 ; s1 = t1 - (h1*3600 + m1*60)
           h2 = t2//3600 ; m2 = (t2-h2*3600)//60 ; s2 = t2 - (h2*3600 + m2*60)
           if stype.lower() == 'daily':
              line = '  "???{}" "" "{:02d} {:02d} {:02d}" "" "{:02d} {:02d} {:02d}"'.format(
	           '0', h1, m1, s1, h2, m2, s2)
              if h2 > 23 : 
                 h2 = h2 - 23
                 line = '  "???{}" "" "{:02d} {:02d} {:02d}" "" "{:+d} {:02d} {:02d}"'.format(
	           '0', h1, m1, s1, h2, m2, s2)
              lines.append(line)
           else:
              line = '  "???{}" "" "{:02d} {:02d} {:02d}" "" "{:02d} {:02d} {:02d}"'.format(
	           alpha[i], h1, m1, s1, h2, m2, s2)
              if h2 > 23 : 
                 h2 = h2 - 23
                 line = '  "???{}" "" "{:02d} {:02d} {:02d}" "" "{:+d} {:02d} {:02d}"'.format(
	           alpha[i], h1, m1, s1, h2, m2, s2)
              lines.append(line)

	   
       #print("\n")
        # "???A" "" "00 00 00" "" "01 59 59"
        # "???B" "" "01 00 00" "" "02 59 59"
       if s[0] == 1:
          print('\nLIST_OF_SESSIONS {}{}'.format(s[0], lines[0]))
       else:
          print('\nLIST_OF_SESSIONS {}'.format(s[0]))
          for i in range(s[0]): 
              print(lines[i])
 
       note1 = '\n'.join([
        '  ## widget = uniline; check_strlen.1 = 4; numlines = 24',
        '  ## check_type.3 = time; check_type.5 = time',
        ])
       print(note1+"\n")

       print('MSG_LIST_OF_SESSIONS 1  "List of sessions"'+"\n\n")

       note2 = '\n'.join([
        '# BEGIN_PANEL NO_CONDITION #####################################################',
        '# SESSION TABLE                                                                #',
        '#                                                                              #',
        '#                START EPOCH         END EPOCH                                 #',
        '#    > ID__ yyyy_mm_dd hh_mm_ss yyyy_mm_dd hh_mm_ss     <                      # LIST_OF_SESSIONS',
        '#                                                                              #',
        '# END_PANEL ####################################################################',
        ])
       print(note2+"\n")



if __name__ == "__main__":
   import argparse

   parser = argparse.ArgumentParser(description='Main program')
   parser.add_argument("-v","--verbose", action='store_true',  help="print info for debug")

   subs = parser.add_subparsers(dest='command',required = True)
   overlap = subs.add_parser('overlap_window', help='BERN sessions defined by sliding overlap windows')
   overlap.add_argument("-t", "--window-hours", type=int,  default=1,
         help="time window  length of each hourly sessions(hours)")
   non_overlap = subs.add_parser('non_overlap_window', help='BERN sessions defined by non-overlap windows')
   non_overlap.add_argument("-t", "--window-hours", type=int, default=1,
         help="time window  length of each hourly sessions(hours)")
   non_overlap.add_argument("-offset", "--end-offset", type=int, default=0,
         help="time offset added to the begining and the endding sessions (minutes)")

   leoatt_list = subs.add_parser('leoatt_files', help='BERN sessions to be defined by the LEO attitude files')
   leoatt_list.add_argument("mission", type=str,  help="cosmic1 or cosmic2, sipre")
   leoatt_list.add_argument("satidx", type=int,  help="cosmic2 satidx 1-6, sipre 24")
   leoatt_list.add_argument("datestr", type=str,  help="date in yyyymndd or yyyyddd")
   leoatt_list.add_argument("-stype","--session-type", type=str, default='hourly', help="daily or hourly")

   leornx_list = subs.add_parser('leornx_files', help='BERN sessions to be defined by the LEO attitude files')
   leornx_list.add_argument("mission", type=str,  help="cosmic1 or cosmic2, sipre")
   leornx_list.add_argument("satidx", type=int,  help="cosmic2 satidx 1-6, sipre 24 ")
   leornx_list.add_argument("antidx", type=int,  help="cosmic2 antenna index 1-2, sipre 1")
   leornx_list.add_argument("datestr", type=str,  help="date in yyyymndd or yyyyddd")
   leornx_list.add_argument("-stype","--session-type", type=str, default='hourly', help="daily or hourly")
  
   attrnx_list = subs.add_parser('attrnx_files', help='BERN sessions to be defined by the LEO attitude files')
   attrnx_list.add_argument("mission", type=str,  help="cosmic1 or cosmic2, sipre")
   attrnx_list.add_argument("satidx", type=int,  help="cosmic2 satidx 1-6, sipre 24")
   attrnx_list.add_argument("antidx", type=int,  help="cosmic2 antenna index 1-2, sipre 1")
   attrnx_list.add_argument("datestr", type=str,  help="date in yyyymndd or yyyyddd")
   attrnx_list.add_argument("-stype","--session-type", type=str, default='hourly', help="daily or hourly")


   time_range = subs.add_parser('start_end_times', help='BERN sessions to be defined start and end time')
   time_range.add_argument("tstart", type=str,  help="start time in yyyymnddTH:M:S")
   time_range.add_argument("tend", type=str,  help="end time in yyyymnddTH:M:S")
   time_range.add_argument("-stype","--session-type", type=str, default='daily', help="daily or hourly")

  
   args = parser.parse_args()
   if args.command == 'overlap_window':
      window_hours = args.window_hours
      sessions = bern_sessions.overlap(window_hours)
   if args.command == 'non_overlap_window':
      window_hours = args.window_hours
      end_offset = args.end_offset
      sessions = bern_sessions.non_overlap(window_hours, end_offset=end_offset)
   if args.command == 'leoatt_files':
      mission=args.mission ; satidx=args.satidx; datestr=args.datestr
      session=args.session_type
      filelist=list_leoatt_files(mission, satidx, datestr,session=session)
      #print(filelist)
      sessions = bern_sessions.from_leo_files(datestr, filelist, stype=session)
   
   if args.command == 'leornx_files':
      mission=args.mission ; datestr=args.datestr
      satidx=args.satidx; antidx=args.antidx
      session = args.session_type
      filelist=list_leornx_files(mission, satidx, antidx, datestr, session=session)
      #print(filelist)
      sessions = bern_sessions.from_leo_files(datestr, filelist, stype=session)
   if args.command == 'attrnx_files':
      mission=args.mission ;  datestr=args.datestr
      satidx=args.satidx; antidx=args.antidx
      session = args.session_type
      att_filelist=list_leoatt_files(mission, satidx, datestr,session=session)
      rnx_filelist=list_leornx_files(mission, satidx, antidx, datestr,session=session)
      #print(filelist)
      sessions = bern_sessions.from_leo_files2(datestr, att_filelist, rnx_filelist, stype=session)
 
   if args.command == 'start_end_times':
      tstart=args.tstart ;  tend=args.tend
      session = args.session_type
      sessions = bern_sessions.from_time_range(tstart, tend)
 
   bern_sessions.print_bern_session(sessions, stype=session)
