# Path: photometry/plots.py
# def plots_interactive(backend=('Qt5Agg', 'MacOSX', 'Qt4Agg', 'Qt5Cairo', 'TkAgg')):
# def plots_noninteractive():
# def plot_image(image, ax=None, scale='log', cmap=None, origin='lower', xlabel=None,
# 	ylabel=None, cbar=None, clabel='Flux ($e^{-}s^{-1}$)', cbar_ticks=None,
# 	cbar_ticklabels=None, cbar_pad=None, cbar_size='5%', title=None,
# 	percentile=95.0, vmin=None, vmax=None, offset_axes=None, color_bad='k', **kwargs):
# def plot_image_fit_residuals(fig, image, fit, residuals=None, percentile=95.0):
# def plot_outline(img, ax=None, threshold=0.5, **kwargs):
# def save_figure(path, fig=None, fmt='png', **kwargs):
# 
# Path: photometry/quality.py
# class PixelQualityFlags(QualityFlagsBase):
# 	"""
# 	This class encodes the meaning of the various TESS QUALITY bitmask flags.
# 	"""
# 	NotUsedForBackground = 1
# 	ManualExclude = 2
# 	BackgroundShenanigans = 4
# 
# 	# Default bitmask
# 	DEFAULT_BITMASK = (ManualExclude)
# 
# 	# Pretty string descriptions for each flag
# 	STRINGS = {
# 		NotUsedForBackground: "Pixel was not used in background calculation",
# 		ManualExclude: "Manual exclude",
# 		BackgroundShenanigans: "Background Shenanigans detected in pixel",
# 	}
# 
# Path: photometry/utilities.py
# @lru_cache(maxsize=32)
# def find_hdf5_files(rootdir, sector=None, camera=None, ccd=None):
# 	"""
# 	Search the input directory for HDF5 files matching constraints.
# 
# 	Parameters:
# 		rootdir (str): Directory to search for HDF5 files.
# 		sector (int, list or None, optional): Only return files from the given sectors.
# 			If ``None``, files from all TIC numbers are returned.
# 		camera (int, list or None, optional): Only return files from the given camera.
# 			If ``None``, files from all cameras are returned.
# 		ccd (int, list or None, optional): Only return files from the given ccd.
# 			If ``None``, files from all ccds are returned.
# 
# 	Returns:
# 		list: List of paths to HDF5 files matching constraints.
# 	"""
# 
# 	sector = to_tuple(sector, (None,))
# 	camera = to_tuple(camera, (1,2,3,4))
# 	ccd = to_tuple(ccd, (1,2,3,4))
# 
# 	filelst = []
# 	for sector, camera, ccd in itertools.product(sector, camera, ccd):
# 		sector_str = '???' if sector is None else f'{sector:03d}'
# 		filelst += glob.glob(os.path.join(rootdir, f'sector{sector_str:s}_camera{camera:d}_ccd{ccd:d}.hdf5'))
# 
# 	return filelst
# 
# class TqdmLoggingHandler(logging.Handler):
# 	def __init__(self, *args, **kwargs):
# 		super().__init__(*args, **kwargs)
# 
# 	def emit(self, record):
# 		try:
# 			msg = self.format(record)
# 			tqdm.tqdm.write(msg)
# 			self.flush()
# 		except (KeyboardInterrupt, SystemExit): # pragma: no cover
# 			raise
# 		except: # noqa: E722, pragma: no cover
# 			self.handleError(record)
# 
# def to_tuple(inp, default=None):
# 	"""
# 	Convert iterable or single values to tuple.
# 
# 	This function is used for converting inputs, perticularly for
# 	preparing input to functions cached with :func:`functools.lru_cache`,
# 	to ensure inputs are hashable.
# 
# 	Parameters:
# 		inp: Input to convert to tuple.
# 		default: If ``input`` is ``None`` return this instead.
# 
# 	Returns:
# 		tuple: ``inp`` converted to tuple.
# 	"""
# 	if inp is None:
# 		return default
# 	if isinstance(inp, (list, set, frozenset, np.ndarray)):
# 		return tuple(inp)
# 	if isinstance(inp, (int, float, bool, str)):
# 		return (inp, )
# 	return inp


import argparse
import logging
import numpy as np
import h5py
import os.path
import functools
import multiprocessing
import re
import copy
from tqdm import tqdm, trange
from photometry.plots import plt, plot_image
from matplotlib import animation
from matplotlib.colors import ListedColormap
from photometry.quality import PixelQualityFlags
from photometry.utilities import find_hdf5_files, TqdmLoggingHandler, to_tuple

	group = parser.add_argument_group('Filter which FFIs to process')
	group.add_argument('--sector', type=int, default=None, action='append', help='TESS Sector. Default is to run all sectors.')
	parser.add_argument('files', help='Directory or HDF5 file to create movie from.', nargs='+')
	args = parser.parse_args()

	logging_level = logging.INFO
	if args.quiet:
		logging_level = logging.WARNING
	elif args.debug:
		logging_level = logging.DEBUG

	# Setup logging:
	formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
	logger = logging.getLogger(__name__)
	logger.setLevel(logging_level)
	console = TqdmLoggingHandler()
	console.setFormatter(formatter)
	logger_parent = logging.getLogger('photometry')
	logger_parent.setLevel(logging_level)
	if not logger.hasHandlers():
		logger.addHandler(console)
	if not logger_parent.hasHandlers():
		logger_parent.addHandler(console)

	# If the user provided the path to a single directory,
	# find all the HDF5 files in that directory and process them:
	run_full_directory = None
	if len(args.files) == 1 and os.path.isdir(args.files[0]):
		run_full_directory = args.files[0]

# Path: photometry/plots.py
# def plots_interactive(backend=('Qt5Agg', 'MacOSX', 'Qt4Agg', 'Qt5Cairo', 'TkAgg')):
# def plots_noninteractive():
# def plot_image(image, ax=None, scale='log', cmap=None, origin='lower', xlabel=None,
# 	ylabel=None, cbar=None, clabel='Flux ($e^{-}s^{-1}$)', cbar_ticks=None,
# 	cbar_ticklabels=None, cbar_pad=None, cbar_size='5%', title=None,
# 	percentile=95.0, vmin=None, vmax=None, offset_axes=None, color_bad='k', **kwargs):
# def plot_image_fit_residuals(fig, image, fit, residuals=None, percentile=95.0):
# def plot_outline(img, ax=None, threshold=0.5, **kwargs):
# def save_figure(path, fig=None, fmt='png', **kwargs):
# 
# Path: photometry/quality.py
# class PixelQualityFlags(QualityFlagsBase):
# 	"""
# 	This class encodes the meaning of the various TESS QUALITY bitmask flags.
# 	"""
# 	NotUsedForBackground = 1
# 	ManualExclude = 2
# 	BackgroundShenanigans = 4
# 
# 	# Default bitmask
# 	DEFAULT_BITMASK = (ManualExclude)
# 
# 	# Pretty string descriptions for each flag
# 	STRINGS = {
# 		NotUsedForBackground: "Pixel was not used in background calculation",
# 		ManualExclude: "Manual exclude",
# 		BackgroundShenanigans: "Background Shenanigans detected in pixel",
# 	}
# 
# Path: photometry/utilities.py
# @lru_cache(maxsize=32)
# def find_hdf5_files(rootdir, sector=None, camera=None, ccd=None):
# 	"""
# 	Search the input directory for HDF5 files matching constraints.
# 
# 	Parameters:
# 		rootdir (str): Directory to search for HDF5 files.
# 		sector (int, list or None, optional): Only return files from the given sectors.
# 			If ``None``, files from all TIC numbers are returned.
# 		camera (int, list or None, optional): Only return files from the given camera.
# 			If ``None``, files from all cameras are returned.
# 		ccd (int, list or None, optional): Only return files from the given ccd.
# 			If ``None``, files from all ccds are returned.
# 
# 	Returns:
# 		list: List of paths to HDF5 files matching constraints.
# 	"""
# 
# 	sector = to_tuple(sector, (None,))
# 	camera = to_tuple(camera, (1,2,3,4))
# 	ccd = to_tuple(ccd, (1,2,3,4))
# 
# 	filelst = []
# 	for sector, camera, ccd in itertools.product(sector, camera, ccd):
# 		sector_str = '???' if sector is None else f'{sector:03d}'
# 		filelst += glob.glob(os.path.join(rootdir, f'sector{sector_str:s}_camera{camera:d}_ccd{ccd:d}.hdf5'))
# 
# 	return filelst
# 
# class TqdmLoggingHandler(logging.Handler):
# 	def __init__(self, *args, **kwargs):
# 		super().__init__(*args, **kwargs)
# 
# 	def emit(self, record):
# 		try:
# 			msg = self.format(record)
# 			tqdm.tqdm.write(msg)
# 			self.flush()
# 		except (KeyboardInterrupt, SystemExit): # pragma: no cover
# 			raise
# 		except: # noqa: E722, pragma: no cover
# 			self.handleError(record)
# 
# def to_tuple(inp, default=None):
# 	"""
# 	Convert iterable or single values to tuple.
# 
# 	This function is used for converting inputs, perticularly for
# 	preparing input to functions cached with :func:`functools.lru_cache`,
# 	to ensure inputs are hashable.
# 
# 	Parameters:
# 		inp: Input to convert to tuple.
# 		default: If ``input`` is ``None`` return this instead.
# 
# 	Returns:
# 		tuple: ``inp`` converted to tuple.
# 	"""
# 	if inp is None:
# 		return default
# 	if isinstance(inp, (list, set, frozenset, np.ndarray)):
# 		return tuple(inp)
# 	if isinstance(inp, (int, float, bool, str)):
# 		return (inp, )
# 	return inp


# Path: run_ffimovie.py
import argparse
import logging
import numpy as np
import h5py
import os.path
import functools
import multiprocessing
import re
import copy
from tqdm import tqdm, trange
from photometry.plots import plt, plot_image
from matplotlib import animation
from matplotlib.colors import ListedColormap
from photometry.quality import PixelQualityFlags
from photometry.utilities import find_hdf5_files, TqdmLoggingHandler, to_tuple


	group = parser.add_argument_group('Filter which FFIs to process')
	group.add_argument('--sector', type=int, default=None, action='append', help='TESS Sector. Default is to run all sectors.')
	parser.add_argument('files', help='Directory or HDF5 file to create movie from.', nargs='+')
	args = parser.parse_args()

	logging_level = logging.INFO
	if args.quiet:
		logging_level = logging.WARNING
	elif args.debug:
		logging_level = logging.DEBUG

	# Setup logging:
	formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
	logger = logging.getLogger(__name__)
	logger.setLevel(logging_level)
	console = TqdmLoggingHandler()
	console.setFormatter(formatter)
	logger_parent = logging.getLogger('photometry')
	logger_parent.setLevel(logging_level)
	if not logger.hasHandlers():
		logger.addHandler(console)
	if not logger_parent.hasHandlers():
		logger_parent.addHandler(console)

	# If the user provided the path to a single directory,
	# find all the HDF5 files in that directory and process them:
	run_full_directory = None
	if len(args.files) == 1 and os.path.isdir(args.files[0]):
		run_full_directory = args.files[0]

		args.files = find_hdf5_files(run_full_directory, sector=to_tuple(args.sector))