# Path: metatlas/datastructures/metatlas_objects.py
# class LcmsRun(MetatlasObject):
#     """An LCMS run is the reference to a file prepared with liquid
#     chromatography and mass spectrometry.
# 
#     The msconvert program is used to convert raw data (centroided is prefered)
#     to mzML.
# 
#     Note: These objects are not intented to be created directly, but by putting
#     the files in /project/projectdirs/metatlas/raw_data/<username> or by
#     running `load_lcms_files()`.
#     """
#     method = MetInstance(Method)
#     experiment = MetUnicode(help='The name of the experiment')
#     hdf5_file = MetUnicode(help='Path to the HDF5 file at NERSC')
#     mzml_file = MetUnicode(help='Path to the MZML file at NERSC')
#     acquisition_time = MetInt(help='Unix timestamp when data was acquired creation')
#     injection_volume = MetFloat()
#     injection_volume_units = MetEnum(('uL', 'nL'), 'uL')
#     pass_qc = MetBool(help= 'True/False for if the LCMS Run has passed a quality control assessment')
#     sample = MetInstance(Sample)
# 
# def store(objects, **kwargs):
#     """Store Metatlas objects in the database.
# 
#     Parameters
#     ----------
#     objects: Metatlas object or list of Metatlas Objects
#         Object(s) to store in the database.
#     """
#     workspace = Workspace.get_instance()
#     workspace.save_objects(objects, **kwargs)
#     workspace.close_connection()
# 
# def retrieve(object_type, **kwargs):
#     """Get objects from the Metatlas object database.
# 
#     This will automatically select only objects created by the current
#     user unless `username` is provided. Use `username='*'` to search
#     against all users.
# 
#     Parameters
#     ----------
#     object_type: string
#       The type of object to search for (i.e. "Groups").
#     **kwargs
#       Specific search queries (i.e. name="Sargasso").
#       Use '%' for wildcard patterns (i.e. description='Hello%').
#       If you want to match a '%' character, use '%%'.
# 
#     Returns
#     -------
#     objects: list
#       List of Metatlas Objects meeting the criteria.  Will return the
#       latest version of each object.
#     """
#     workspace = Workspace.get_instance()
#     out = workspace.retrieve(object_type, **kwargs)
#     workspace.close_connection()
#     return out
# 
# Path: metatlas/io/system_utils.py
# def send_mail(subject, username, body, force=False):
#     """Send the mail only once per day."""
# 
#     now = datetime.now()
#     if force or dtime(00, 00) <= now.time() <= dtime(00, 10):
#         sender = 'pasteur@nersc.gov'
#         receivers = [f"{username}@lbl.gov", "bpbowen@lbl.gov"]
#         message = """\
# From: %s
# To: %s
# Subject: %s
# 
# %s
#         """ % (sender, ", ".join(receivers), subject, body)
#         try:
#             smtpObj = smtplib.SMTP('smtp.lbl.gov')
#             smtpObj.sendmail(sender, receivers, message)
#             sys.stdout.write("Successfully sent email to %s\n" % username)
#             sys.stdout.flush()
#         except smtplib.SMTPException:
#             sys.stderr.write("Error: unable to send email to %s\n" % username)
#             sys.stdout.flush()


import argparse
import functools
import logging
import os
import re
import shutil
import subprocess
import sys
import time
import traceback
from datetime import datetime
from subprocess import check_output
from metatlas.datastructures.metatlas_objects import LcmsRun, store, retrieve
from metatlas.io.mzml_loader import mzml_to_hdf
from metatlas.io.mzml_loader import VERSION_TIMESTAMP
from metatlas.io.system_utils import send_mail


def update_metatlas(directory):
    """
    Converts all files to HDF in metatlas. Emails the user if there was
    any kind of error with converting a file.
    """
    mzml_files = check_output(f'find {directory} -name "*.mzML"', shell=True)
    mzml_files = mzml_files.decode('utf-8').splitlines()

    # Find valid h5 files newer than the format version timestamp.
    delta = int((time.time() - VERSION_TIMESTAMP) / 60)
    check = f'find {directory} -name "*.h5" -mmin -{delta} -size +2k'
    valid_files = set(check_output(check, shell=True).decode('utf-8').splitlines())
    new_files = [file for file in mzml_files if file.replace('.mzML', '.h5') not in valid_files]

    if new_files:
        logger.info("Found %d files", len(new_files))
        for ind, ffff in enumerate(new_files):
            convert(ind, ffff)
        if readonly_files:
            for (username, dirnames) in readonly_files.items():
                logger.info("Sending email to %s about inaccessible files.", username)
                body = ("Please log in to NERSC and run 'chmod g+rwXs' on the "
                        "following directories:\n%s" % ('\n'.join(dirnames)))
                send_mail('Metatlas Files are Inaccessible', username, body)
        if other_errors:
            for (username, errors) in other_errors.items():
                logger.info("Sending email to %s about conversion error.", username)
                body = ('Errored files found while loading in Metatlas files:\n\n%s' %
                        '\n********************************\n'.join(errors))

# Path: metatlas/datastructures/metatlas_objects.py
# class LcmsRun(MetatlasObject):
#     """An LCMS run is the reference to a file prepared with liquid
#     chromatography and mass spectrometry.
# 
#     The msconvert program is used to convert raw data (centroided is prefered)
#     to mzML.
# 
#     Note: These objects are not intented to be created directly, but by putting
#     the files in /project/projectdirs/metatlas/raw_data/<username> or by
#     running `load_lcms_files()`.
#     """
#     method = MetInstance(Method)
#     experiment = MetUnicode(help='The name of the experiment')
#     hdf5_file = MetUnicode(help='Path to the HDF5 file at NERSC')
#     mzml_file = MetUnicode(help='Path to the MZML file at NERSC')
#     acquisition_time = MetInt(help='Unix timestamp when data was acquired creation')
#     injection_volume = MetFloat()
#     injection_volume_units = MetEnum(('uL', 'nL'), 'uL')
#     pass_qc = MetBool(help= 'True/False for if the LCMS Run has passed a quality control assessment')
#     sample = MetInstance(Sample)
# 
# def store(objects, **kwargs):
#     """Store Metatlas objects in the database.
# 
#     Parameters
#     ----------
#     objects: Metatlas object or list of Metatlas Objects
#         Object(s) to store in the database.
#     """
#     workspace = Workspace.get_instance()
#     workspace.save_objects(objects, **kwargs)
#     workspace.close_connection()
# 
# def retrieve(object_type, **kwargs):
#     """Get objects from the Metatlas object database.
# 
#     This will automatically select only objects created by the current
#     user unless `username` is provided. Use `username='*'` to search
#     against all users.
# 
#     Parameters
#     ----------
#     object_type: string
#       The type of object to search for (i.e. "Groups").
#     **kwargs
#       Specific search queries (i.e. name="Sargasso").
#       Use '%' for wildcard patterns (i.e. description='Hello%').
#       If you want to match a '%' character, use '%%'.
# 
#     Returns
#     -------
#     objects: list
#       List of Metatlas Objects meeting the criteria.  Will return the
#       latest version of each object.
#     """
#     workspace = Workspace.get_instance()
#     out = workspace.retrieve(object_type, **kwargs)
#     workspace.close_connection()
#     return out
# 
# Path: metatlas/io/system_utils.py
# def send_mail(subject, username, body, force=False):
#     """Send the mail only once per day."""
# 
#     now = datetime.now()
#     if force or dtime(00, 00) <= now.time() <= dtime(00, 10):
#         sender = 'pasteur@nersc.gov'
#         receivers = [f"{username}@lbl.gov", "bpbowen@lbl.gov"]
#         message = """\
# From: %s
# To: %s
# Subject: %s
# 
# %s
#         """ % (sender, ", ".join(receivers), subject, body)
#         try:
#             smtpObj = smtplib.SMTP('smtp.lbl.gov')
#             smtpObj.sendmail(sender, receivers, message)
#             sys.stdout.write("Successfully sent email to %s\n" % username)
#             sys.stdout.flush()
#         except smtplib.SMTPException:
#             sys.stderr.write("Error: unable to send email to %s\n" % username)
#             sys.stdout.flush()


# Path: metatlas/io/file_converter.py
import argparse
import functools
import logging
import os
import re
import shutil
import subprocess
import sys
import time
import traceback
from datetime import datetime
from subprocess import check_output
from metatlas.datastructures.metatlas_objects import LcmsRun, store, retrieve
from metatlas.io.mzml_loader import mzml_to_hdf
from metatlas.io.mzml_loader import VERSION_TIMESTAMP
from metatlas.io.system_utils import send_mail


def update_metatlas(directory):
    """
    Converts all files to HDF in metatlas. Emails the user if there was
    any kind of error with converting a file.
    """
    mzml_files = check_output(f'find {directory} -name "*.mzML"', shell=True)
    mzml_files = mzml_files.decode('utf-8').splitlines()

    # Find valid h5 files newer than the format version timestamp.
    delta = int((time.time() - VERSION_TIMESTAMP) / 60)
    check = f'find {directory} -name "*.h5" -mmin -{delta} -size +2k'
    valid_files = set(check_output(check, shell=True).decode('utf-8').splitlines())
    new_files = [file for file in mzml_files if file.replace('.mzML', '.h5') not in valid_files]

    if new_files:
        logger.info("Found %d files", len(new_files))
        for ind, ffff in enumerate(new_files):
            convert(ind, ffff)
        if readonly_files:
            for (username, dirnames) in readonly_files.items():
                logger.info("Sending email to %s about inaccessible files.", username)
                body = ("Please log in to NERSC and run 'chmod g+rwXs' on the "
                        "following directories:\n%s" % ('\n'.join(dirnames)))
                send_mail('Metatlas Files are Inaccessible', username, body)
        if other_errors:
            for (username, errors) in other_errors.items():
                logger.info("Sending email to %s about conversion error.", username)
                body = ('Errored files found while loading in Metatlas files:\n\n%s' %
                        '\n********************************\n'.join(errors))

                send_mail('Errors loading Metatlas files', username, body)
