# Copyright (c) 2024, NakaMetPy Develoers.
# Distributed under the terms of the BSD 3-Clause License.
# SPDX-License-Identifier: BSD-3-Clause
#
# Command Example1: python -m unittest tests/test_bufr.py -v
# Command Example2: python -m unittest tests.test_bufr -v
# Command Example3: python -m unittest tests.test_bufr.UtilTest.test_parse_tableB_into_dataframe_001 -v
# 
import unittest
from src.nakametpy.bufr import parse_tableB_into_dataframe, parse_tableD_into_dict,\
                        parse_codeFlag_into_dict, bufr
import os
import pandas as pd
import numpy as np

class UtilTest(unittest.TestCase):
  def test_parse_tableB_into_dataframe_001(self):
    """
    test case: test_parse_tableB_into_dataframe_001
    
    Method
    --------
      parse_tableB_into_dataframe
    Parameters
    --------
      version: `str`
    Notes
    --------
      `version`の指定なし
    """
    # print(self.test_parse_tableB_into_dataframe_001.__doc__)
    actual = parse_tableB_into_dataframe()
    actual_value = actual[actual["F-XX-YYY"] == "0-00-004"]["MNEMONIC"].values
    self.assertEqual(actual_value, "MTABL")
  
  def test_parse_tableB_into_dataframe_002(self):
    """
    test case: test_parse_tableB_into_dataframe_002
    
    Method
    --------
      parse_tableB_into_dataframe
    Parameters
    --------
      version: `str`
    Notes
    --------
      `version`の指定あり
    """
    # print(self.test_parse_tableB_into_dataframe_002.__doc__)
    for version, fxxyyy, expected in (("LOC_0_7_1", "0-01-195", "SACO"),
                                      ("STD_0_42", "0-01-024", "WSPDS")):
        with self.subTest(version=version, fxxyyy=fxxyyy, expected=expected):
          actual = parse_tableB_into_dataframe(version)
          # print(actual[actual["F-XX-YYY"] == fxxyyy])
          actual_value = actual[actual["F-XX-YYY"] == fxxyyy]["MNEMONIC"].values
          self.assertEqual(actual_value, expected)
  
  def test_parse_tableD_into_dict_001(self):
    """
    test case: test_parse_tableD_into_dict_001
    
    Method
    --------
      parse_tableD_into_dict
    Parameters
    --------
      version: `str`
    Notes
    --------
      `version`の指定なし
    """
    # print(self.test_parse_tableD_into_dict_001.__doc__)
    actual = parse_tableD_into_dict()
    self.assertEqual(actual["3-01-036"]["MNEMONIC"], "SHIPSEQ1")
    self.assertEqual(actual["3-01-036"]["NAME"], "Ship")
    self.assertEqual(actual["3-01-036"]["SEQUENCE"][2]["FXXYYY"], "3-01-011")
    self.assertEqual(actual["3-01-036"]["SEQUENCE"][2]["NAME"], "Year, month, day")

  def test_parse_tableD_into_dict_002(self):
    """
    test case: test_parse_tableD_into_dict_002
    
    Method
    --------
      parse_tableD_into_dict
    Parameters
    --------
      version: `str`
    Notes
    --------
      `version`の指定あり
    """
    # print(self.test_parse_tableD_into_dict_002.__doc__)
    for version, fxxyyy1, mnemonic, name1, fxxyyy2, name2 in (
      ("LOC_0_7_1", "3-52-003", "RCPTIM", "Report receipt time data", "0-04-204", "Receipt minute"),
      ("STD_0_30", "3-16-007", "FRONTSEQ", "Front", "0-31-001", "Delayed descriptor replication factor")):
      with self.subTest(version=version, fxxyyy1=fxxyyy1, mnemonic=mnemonic,
                        name1=name1, fxxyyy2=fxxyyy2, name2=name2):
        actual = parse_tableD_into_dict(version)
        self.assertEqual(actual[fxxyyy1]["MNEMONIC"], mnemonic)
        self.assertEqual(actual[fxxyyy1]["NAME"], name1)
        self.assertEqual(actual[fxxyyy1]["SEQUENCE"][5]["FXXYYY"], fxxyyy2)
        self.assertEqual(actual[fxxyyy1]["SEQUENCE"][5]["NAME"], name2)
  
  def test_parse_codeFlag_into_dict_001(self):
    """
    test case: test_parse_codeFlag_into_dict_001
    
    Method
    --------
      parse_codeFlag_into_dict
    Parameters
    --------
      version: `str`
    Notes
    --------
      `version`の指定なし
    """
    # print(self.test_parse_codeFlag_into_dict_001.__doc__)
    actual = parse_codeFlag_into_dict()
    # CODE, No dependency
    self.assertEqual(actual["0-01-007"]["MNEMONIC"], "SAID")
    self.assertEqual(actual["0-01-007"]["CODEFLAG"], "CODE")
    self.assertEqual(actual["0-01-007"]["HAS_DEPENDENCY"], False)
    self.assertEqual(actual["0-01-007"]["VALBITS"]["122"], "GCOM-W1")
    # FLAG, No dependency
    self.assertEqual(actual["0-02-002"]["MNEMONIC"], "TIWM")
    self.assertEqual(actual["0-02-002"]["CODEFLAG"], "FLAG")
    self.assertEqual(actual["0-02-002"]["HAS_DEPENDENCY"], False)
    self.assertEqual(actual["0-02-002"]["VALBITS"]["3"], "Originally measured in km h**-1")
    # CODE, has dependency
    self.assertEqual(actual["0-01-034"]["MNEMONIC"], "GSES")
    self.assertEqual(actual["0-01-034"]["CODEFLAG"], "CODE")
    self.assertEqual(actual["0-01-034"]["HAS_DEPENDENCY"], True)
    self.assertEqual(len(actual["0-01-034"]["VALBITS"].keys()), 3)
    self.assertEqual(len(actual["0-01-034"]["VALBITS"]["0-01-031"]["34"].keys()), 4)
    self.assertEqual(actual["0-01-034"]["VALBITS"]["0-01-031"]["34"]["240"], "Kiyose")
    self.assertEqual(actual["0-01-034"]["VALBITS"]["0-01-035"]["46"]["0"], "No sub-centre")
  
  def test_parse_codeFlag_into_dict_002(self):
    """
    test case: test_parse_codeFlag_into_dict_002
    
    Method
    --------
      parse_codeFlag_into_dict
    Parameters
    --------
      version: `str`
    Notes
    --------
      `version`の指定なし
    """
    # print(self.test_parse_codeFlag_into_dict_002.__doc__)
    actual = parse_codeFlag_into_dict("LOC_0_7_1")
    # CODE, No dependency
    self.assertEqual(actual["0-02-194"]["MNEMONIC"], "AUTO")
    self.assertEqual(actual["0-02-194"]["CODEFLAG"], "CODE")
    self.assertEqual(actual["0-02-194"]["HAS_DEPENDENCY"], False)
    self.assertEqual(actual["0-02-194"]["VALBITS"]["3"], "METAR/SPECI report with 'A01' found in report, but 'AUTO' not found in report")
    # FLAG, No dependency
    self.assertEqual(actual["0-33-200"]["MNEMONIC"], "WSEQC1")
    self.assertEqual(actual["0-33-200"]["CODEFLAG"], "FLAG")
    self.assertEqual(actual["0-33-200"]["HAS_DEPENDENCY"], False)
    self.assertEqual(actual["0-33-200"]["VALBITS"]["26"], "Rain flag based on TBs (or from SDR processor)")
    # CODE, has dependency
    self.assertEqual(actual["0-07-246"]["MNEMONIC"], "PQM")
    self.assertEqual(actual["0-07-246"]["CODEFLAG"], "CODE")
    self.assertEqual(actual["0-07-246"]["HAS_DEPENDENCY"], True)
    self.assertEqual(len(actual["0-07-246"]["VALBITS"].keys()), 1)
    self.assertEqual(len(actual["0-07-246"]["VALBITS"]["0-07-247"]["1"].keys()), 9)
    self.assertEqual(actual["0-07-246"]["VALBITS"]["0-07-247"]["1"]["15"], "Observation is flagged for non-use by analysis")
    self.assertEqual(actual["0-07-246"]["VALBITS"]["0-07-247"]["14"]["1"], "Good")
    
  def test_bufr_001(self):
    """
    Test for `Wind profiler`(BUFR)/`ウィンドプロファイラ`<br>
    Specification: 13601<br>
    Tech Info: 97,532<br>
    
    Class
    --------
      bufr
    Parameters
    --------
      file_path: `str`
    """
    # print(self.test_bufr_001.__doc__)
    for file_path in ("./data/bufr/bufr/IUPC41_RJTD_010000_202406010016132_001.send", # ウィンドプロファイラ
                      "./data/bufr/bufr/Z__C_RJTD_20200707000000_WPR_SEQ_RS-all_Pww_bufr4.bin", # ウィンドプロファイラ, ヘッダなし
                      ):
      with self.subTest(file_path=file_path):
        bufr_class = bufr(os.path.join(os.path.dirname(__file__), file_path))
        bufr_class.read_data()
    
  def test_bufr_002(self):
    """
    Test for `TEMP`(BUFR)/`高分解能地上高層実況気象報`<br>
    Specification: ----<br>
    Tech Info: 334,478<br>
    
    Class
    --------
      bufr
    Parameters
    --------
      file_path: `str`
    """
    # print(self.test_bufr_002.__doc__)
    for file_path in ("./data/bufr/bufr/IUKC65_2018053109_bufr4_noheader.bin", # 高分解能地上高層実況気象報, 100hPaまで
                      "./data/bufr/bufr/IUKC71_2018053109_bufr4_noheader.bin", # 高分解能地上高層実況気象報, 観測終了まで
                      "./data/bufr/bufr/IUSC65_2018053109_bufr4_noheader.bin", # 高分解能地上高層実況気象報, 100hPaまで
                      "./data/bufr/bufr/IUSC71_2018053109_bufr4_noheader.bin", # 高分解能地上高層実況気象報, 観測終了まで
                      ):
      with self.subTest(file_path=file_path):
        bufr_class = bufr(os.path.join(os.path.dirname(__file__), file_path))
        bufr_class.read_data()
    
  def test_bufr_003(self):
    """
    Test for `TEMP SHIP`(BUFR)/`高分解能海上高層実況気象報`<br>
    Specification: 30103<br>
    Tech Info: 618<br>
    
    Class
    --------
      bufr
    Parameters
    --------
      file_path: `str`
    """
    # print(self.test_bufr_003.__doc__)
    for file_path in ("./data/bufr/bufr/IUKC80_RJTD_011200_202410011245310_001.send", # 高分解能海上高層実況気象報, 100hPaまで, 凌風丸
                      "./data/bufr/bufr/IUKC81_RJTD_051200_202410051245312_001.send", # 高分解能海上高層実況気象報, 100hPaまで, 啓風丸
                      "./data/bufr/bufr/IUSC80_RJTD_011200_202410011345300_001.send", # 高分解能海上高層実況気象報, 観測終了まで, 凌風丸
                      "./data/bufr/bufr/IUSC81_RJTD_051200_202410051330311_001.send", # 高分解能海上高層実況気象報, 観測終了まで, 啓風丸
                      ):
      with self.subTest(file_path=file_path):
        bufr_class = bufr(os.path.join(os.path.dirname(__file__), file_path))
        bufr_class.read_data()
    
  def test_bufr_004(self):
    """
    Test for `CLIMAT`(BUFR)/`地上月気候統計値`<br>
    Specification: ----<br>
    Tech Info: 334<br>
    
    Class
    --------
      bufr
    Parameters
    --------
      file_path: `str`
    """
    # print(self.test_bufr_004.__doc__)
    for file_path in ("./data/bufr/bufr/ISCA01_LEMM_050000_202410051001020_001.send", # CLIMAT
                      "./data/bufr/bufr/ISCC01_RJTD_200000_202410200000311_001.send", # 東京編集の地上月気候統計値(CLIMAT)
                      ):
      with self.subTest(file_path=file_path):
        bufr_class = bufr(os.path.join(os.path.dirname(__file__), file_path))
        bufr_class.read_data()
    
  def test_bufr_005(self):
    """
    Test for `SAREP`(BUFR)/`気象衛星資料解析気象報`<br>
    Specification: 11905<br>
    Tech Info: 334<br>
    
    Class
    --------
      bufr
    Parameters
    --------
      file_path: `str`
    """
    # print(self.test_bufr_005.__doc__)
    for file_path in ("./data/bufr/bufr/IUCC10_RJTD_300000_202410300004300_001_68680.send", # 東京編集の気象衛星資料解析気象報★
                      ):
      with self.subTest(file_path=file_path):
        bufr_class = bufr(os.path.join(os.path.dirname(__file__), file_path))
        bufr_class.read_data()
    
  def test_bufr_006(self):
    """
    Test for `TEMP`(BUFR)/`地上高層実況気象報`<br>
    Specification: ----<br>
    Tech Info: 334<br>
    
    Class
    --------
      bufr
    Parameters
    --------
      file_path: `str`
    """
    # print(self.test_bufr_006.__doc__)
    for file_path in ("./data/bufr/bufr/IUKL01_RJTD_300000_202410300123114_001.send", # 東京編集の地上高層実況気象報
                      "./data/bufr/bufr/IUSC01_RJTD_300000_202410300123111_001.send", # 東京編集の地上高層実況気象報Ａ部
                      "./data/bufr/bufr/IUSC02_RJTD_300000_202410300123112_001.send", # 東京編集の地上高層実況気象報Ａ部
                      "./data/bufr/bufr/IUSC02_RJTD_300000_CCA_202410300157101_001.send", # 東京編集の地上高層実況気象報Ａ部 訂正報
                      "./data/bufr/bufr/IUSC03_RJTD_300000_202410300123113_001.send", # 東京編集の地上高層実況気象報Ａ部★
                      "./data/bufr/bufr/IUSC04_RJTD_300000_202410300125110_001.send", # 東京編集の地上高層実況気象報Ｂ部
                      "./data/bufr/bufr/IUSC04_RJTD_300000_CCA_202410300324110_001.send", # 東京編集の地上高層実況気象報Ｂ部 訂正報
                      "./data/bufr/bufr/IUSC05_RJTD_300000_202410300125120_001.send", # 東京編集の地上高層実況気象報Ｂ部
                      "./data/bufr/bufr/IUSC05_RJTD_300000_CCA_202410300324111_001.send", # 東京編集の地上高層実況気象報Ｂ部 訂正報
                      "./data/bufr/bufr/IUSC06_RJTD_300000_202410300125121_001.send", # 東京編集の地上高層実況気象報Ｂ部
                      "./data/bufr/bufr/IUSC06_RJTD_300000_CCA_202410300324112_001.send", # 東京編集の地上高層実況気象報Ｂ部 訂正報
                      "./data/bufr/bufr/IUSC07_RJTD_300000_202410300203111_001.send", # 東京編集の地上高層実況気象報Ｃ部
                      "./data/bufr/bufr/IUSC08_RJTD_300000_202410300203112_001.send", # 東京編集の地上高層実況気象報Ｃ部
                      "./data/bufr/bufr/IUSC09_RJTD_300000_202410300203113_001.send", # 東京編集の地上高層実況気象報Ｃ部
                      "./data/bufr/bufr/IUSC10_RJTD_300000_202410300212111_001.send", # 東京編集の地上高層実況気象Ｄ部
                      "./data/bufr/bufr/IUSC10_RJTD_300000_CCA_202410300405102_001.send", # 東京編集の地上高層実況気象Ｄ部 訂正報
                      "./data/bufr/bufr/IUSC11_RJTD_300000_202410300212112_001.send", # 東京編集の地上高層実況気象Ｄ部
                      "./data/bufr/bufr/IUSC12_RJTD_300000_202410300212113_001.send", # 東京編集の地上高層実況気象Ｄ部
                      # "./data/bufr/bufr/ISIC01_RJTD_300300_202410300319110_001.send", # 東京編集の地上気象実況報（03,09,15,21UTC）
                      ):
      with self.subTest(file_path=file_path):
        bufr_class = bufr(os.path.join(os.path.dirname(__file__), file_path))
        bufr_class.read_data()
    
  def test_bufr_007(self):
    """
    Test for `SYNOP`(BUFR)/`地上気象実況報`<br>
    Specification: 13401<br>
    Tech Info: 334,595<br>
    
    Class
    --------
      bufr
    Parameters
    --------
      file_path: `str`
    """
    # print(self.test_bufr_007.__doc__)
    for file_path in ("./data/bufr/bufr/ISIC01_RJTD_300300_202410300319110_001.send", # 東京編集の地上気象実況報（03,09,15,21UTC）
                      "./data/bufr/bufr/ISMC01_RJTD_300600_202410300619110_001.send", # 東京編集の地上気象実況報（00,06,12,18UTC）(SYNOP)
                      ):
      with self.subTest(file_path=file_path):
        bufr_class = bufr(os.path.join(os.path.dirname(__file__), file_path))
        bufr_class.read_data()
    
  def test_bufr_008(self):
    """
    Test for `PILOT`(BUFR)/`地上高層風実況気象報`<br>
    Specification: ----<br>
    Tech Info: 334<br>
    
    Class
    --------
      bufr
    Parameters
    --------
      file_path: `str`
    """
    # print(self.test_bufr_008.__doc__)
    for file_path in ("./data/bufr/bufr/IUWG01_WIIX_300600_202410300617189_001.send", # メルボルン編集の地上高層風実況気象報 (PILOT)
                      "./data/bufr/bufr/IUKN01_BABJ_300000_202410300231070_001.send", # 北京編集の地上高層風実況気象報Ａ部 (PILOT) 
                      ):
      with self.subTest(file_path=file_path):
        bufr_class = bufr(os.path.join(os.path.dirname(__file__), file_path))
        bufr_class.read_data()
    
  def test_bufr_009(self):
    """
    Test for `AMEDAS`(BUFR)/`地域気象観測(アメダス)`<br>
    Specification: 13301,13401<br>
    Tech Info: 273,595,623<br>
    
    Class
    --------
      bufr
    Parameters
    --------
      file_path: `str`
    """
    # print(self.test_bufr_009.__doc__)
    for file_path in ("./data/bufr/bufr/Z__C_RJTD_20241030000000_OBS_AMDS_Rjp_N1_bufr4.bin", # アメダス N1
                      "./data/bufr/bufr/Z__C_RJTD_20241030000000_OBS_AMDS_Rjp_N2_bufr4.bin", # アメダス N2
                      "./data/bufr/bufr/Z__C_RJTD_20241030010000_OBS_AMDSRR_Rjp_N1_bufr4.bin", # アメダス N1 遅延
                      ):
      with self.subTest(file_path=file_path):
        bufr_class = bufr(os.path.join(os.path.dirname(__file__), file_path), True)
        bufr_class.read_data()