"""Matcher for IGS SP3 files.""" from .matcher import Matcher __all__ = ["SP3Matcher", "LegacySP3Matcher"] class SP3Matcher(Matcher): """Matcher for SP3 files. This class is designed to match the new name format for SP3 files since GPS Week 2238. The SP3 file format is described at: - https://cddis.nasa.gov/Data_and_Derived_Products/GNSS/orbit_products.html Attributes: sp3_pattern (str): Regular expression pattern for matching SP3 file names. """ sp3_pattern = r"^([A-Z]{3})0([A-Z]{3})([A-Z]{3})_(\d{4})(\d{3})(\d{2})(\d{2})_([A-Z0-9]{3})_([A-Z0-9]{3})_([A-Z]{3})\.([A-Z0-9]{3})\.gz" def __init__( self, ) -> None: """Initialize the Matcher for SP3 files.""" super().__init__(pattern=self.sp3_pattern) def extract_metadata(self, filename: str) -> dict: """Extract metadata from the filename. Args: filename (str): Filename to extract metadata from. Returns: dict: Extracted metadata from the filename. """ match = self.pattern.match(filename) if match: return { "analysis_center": match.group(1), "campaign": match.group(2), "solution_type": match.group(3), "year": match.group(4), "day": match.group(5), "hour": match.group(6), "minute": match.group(7), "length": match.group(8), "sampling": match.group(9), "content": match.group(10), "format": match.group(11), } return {} def invert( self, year: int, day: int, hour: int = 00, minute: int = 00, analysis_center: str = "IGS", campaign: str = "OPS", solution_type: str = "FIN", length: str = "01D", sampling: str = "15M", content: str = "ORB", format: str = "SP3", ) -> str: """Invert the metadata back to a filename. Args: year (int): The year of the metadata. day (int): The day of the metadata. hour (int): The hour of the metadata. minute (int): The minute of the metadata. analysis_center (str, optional): The analysis center. Defaults to "IGS". campaign (str, optional): The campaign. Defaults to "OPS". solution_type (str, optional): The solution type. Defaults to "FIN". length (str, optional): The length of the metadata. Defaults to "01D". sampling (str, optional): The sampling rate of the metadata. Defaults to "15M". content (str, optional): The content of the metadata. Defaults to "ORB". format (str, optional): The format of the metadata. Defaults to "SP3". Returns: str: The inverted filename. """ # Assert that the metadata is valid assert len(str(year)) == 4, "Year must be 4 digits long" assert day <= 366, "Day must be between 0 and 365" assert hour <= 24, "Hour must be between 0 and 23" assert minute <= 60, "Minute must be between 0 and 59" assert len(analysis_center) == 3, "Analysis center must be 3 characters long" assert len(campaign) == 3, "Campaign must be 3 characters long" assert len(solution_type) == 3, "Solution type must be 3 characters long" assert len(length) == 3, "Length must be 3 characters long" assert len(sampling) == 3, "Sampling must be 3 characters long" assert len(content) == 3, "Content must be 3 characters long" assert len(format) == 3, "Format must be 3 characters long" return f"{analysis_center}0{campaign}{solution_type}_{str(int(year)).zfill(4)}{str(int(day)).zfill(3)}{str(int(hour)).zfill(2)}{str(int(minute)).zfill(2)}_{length}_{sampling}_{content}.{format}.gz" class LegacySP3Matcher(Matcher): """Matcher for legacy SP3 files. This class is designed to match the legacy name format for SP3 files before GPS Week 2237. The SP3 file format is described at: - https://cddis.nasa.gov/Data_and_Derived_Products/GNSS/orbit_products.html Attributes: sp3_pattern (str): Regular expression pattern for matching SP3 file names. """ sp3_pattern = r"^([a-z]{3})(\d{4})([0-7]{1})\.([a-z0-9]{3})\.Z" def __init__( self, ) -> None: """Initialize the Matcher for SP3 files.""" super().__init__(pattern=self.sp3_pattern) def extract_metadata(self, filename: str) -> dict | None: """Extract metadata from the filename. Args: filename (str): Filename to extract metadata from. Returns: dict: Extracted metadata from the filename. """ match = self.pattern.match(filename) if match: return { "analysis_center": match.group(1), "gps_week": match.group(2), "day": match.group(3), "format": match.group(4), } return None def invert( self, gps_week: int, day: int, analysis_center: str = "igs", format: str = "sp3", ) -> str: """Invert the metadata back to a filename. Args: gps_week (int): _description_ day (int): _description_ analysis_center (str, optional): _description_. Defaults to "igs". format (str, optional): _description_. Defaults to "sp3". Returns: str: _description_ """ # Assert that the metadata is valid assert day in range(8), "Day must be between 0 and 7" assert len(analysis_center) == 3, "Analysis center must be 3 characters long" assert len(format) == 3, "Format must be 3 characters long" return f"{analysis_center}{str(gps_week).zfill(4)}{str(int(day)).zfill(1)}.{format}.Z"