#!python

from xlrd import XLRDError
import argparse
import os
import sys
import re
import subprocess
import logging

logging.basicConfig(filename='GENEWIZ_template_validation.log',
                    filemode='w', level=logging.DEBUG)
sample_template_logger = logging.getLogger("sample_template")
container_template_logger = logging.getLogger("container_template")


def install(package):
    subprocess.call(["pip", "install", package])


try:
    import xlrd
except ImportError as e:
    print("Module xlrd not found. You need to install it. Try pip install xlrd. If pip is not found, see https://pip.pypa.io/en/stable/installing/")
    exit(1)


CONTAINER_COLUMN_NAME = "Container Name"
PRIMER_COLUMN_NAME = "My Primers per Container"


def validate_plate_well_id_1(ERROR_FLAG, samplemap_template_name, value, expected):
    if not re.match(expected, value):
        sample_template_logger.error("{}.\n\tCan't find {} in {}".format(
            samplemap_template_name, expected, value))
        ERROR_FLAG = True
    return ERROR_FLAG


def validate_plate_well_id_2(ERROR_FLAG, samplemap_template_name, value):
    tokens = value.split("_")
    if not len(tokens) == 6:
        sample_template_logger.error("{}. Invalid format found for {} : not enough entries. Found {} but expected 6.".format(
            samplemap_template_name, value, len(tokens)))
        ERROR_FLAG = True
    if not len(tokens[0]) == 9:
        sample_template_logger.error("{}. Invalid PTID format {}. Length is {} but expected {}.".format(
            samplemap_template_name, tokens[0], len(tokens[0]), 9))
        ERROR_FLAG = True
    if not re.match("G0015[89][0-9]{3}", tokens[0]):
        sample_template_logger.error(
            "in {}. Invalid PTID format {}. Should be G0015[89][0-9]{3}".format(samplemap_template_name, tokens[0]))
        ERROR_FLAG = True
    if not tokens[1] in ['V02', 'V03', 'V03A', 'V03B', 'V04', 'V05', 'V06', 'V07', 'V07A', 'V08', 'V09', 'V10']:
        sample_template_logger.error("{}. Invalid Visit format. Found {}, but expected one of {}".format(
            samplemap_template_name, tokens[1], ['V02', 'V03', 'V03A', 'V03B', 'V04', 'V05', 'V06', 'V07', 'V07A', 'V08', 'V09', 'V10']))
        ERROR_FLAG = True
    if not re.match("P[01][0-9]", tokens[2]):
        sample_template_logger.error("{}. Invalid plate format {}. Expecting P01, P02, and so forth.".format(
            samplemap_template_name, tokens[2]))
        ERROR_FLAG = True
    if not re.match("R2", tokens[3]):
        sample_template_logger.error("{}. Invalid Round format {}. Expecting R2.".format(
            samplemap_template_name, tokens[3]))
        ERROR_FLAG = True
    if not re.match("[HKL]C", tokens[4]):
        sample_template_logger.error("{}. Invalid chain format {}. Expecting HC LC KC".format(
            samplemap_template_name, tokens[4]))
        ERROR_FLAG = True
    if not re.match("[A-H][01][0-9]", tokens[5]):
        sample_template_logger.error(
            "{}. Invalid well format {}. Expecting A01-A12, B01-B12 and so forth.".format(samplemap_template_name, tokens[5]))
        ERROR_FLAG = True
    return ERROR_FLAG


parser = argparse.ArgumentParser(description="Validate Genewiz Template Files")
parser.add_argument("containers", metavar="container_template_name.xlsx",
                    help="The name of the container template.", nargs=1)
parser.add_argument("samplemap", metavar="sample_template_name.xlsx",
                    help="The name of the sample map template.", nargs='+')
args = parser.parse_args()
# ['test_data/September 18, 2019 GENEWIZ_SinglePass_Containers.xlsx',
#                           'test_data/G00158003_V06_P1_R2_HC_GENEWIZ_SinglePass_SampleMap.xlsx',
#                           'test_data/G00158003_V06_P1_R2_KC_GENEWIZ_SinglePass_SampleMap.xlsx',
#                           'test_data/G00158003_V06_P1_R2_LC_GENEWIZ_SinglePass_SampleMap.xlsx',
#                           'test_data/G00158005_V08_P1_R2_HC_GENEWIZ_SinglePass_SampleMap.xlsx',
#                           'test_data/G00158005_V08_P1_R2_KC_GENEWIZ_SinglePass_SampleMap.xlsx',
#                           'test_data/G00158005_V08_P1_R2_LC_GENEWIZ_SinglePass_SampleMap.xlsx',
#                           'test_data/G00158005_V08_P2_R2_HC_GENEWIZ_SinglePass_SampleMap.xlsx',
#                           'test_data/G00158005_V08_P2_R2_KC_GENEWIZ_SinglePass_SampleMap.xlsx',
#                           'test_data/G00158005_V08_P2_R2_LC_GENEWIZ_SinglePass_SampleMap.xlsx',
#                           'test_data/G00158005_V10_P1_R2_HC_GENEWIZ_SinglePass_SampleMap.xlsx',
#                           'test_data/G00158005_V10_P1_R2_KC_GENEWIZ_SinglePass_SampleMap.xlsx',
#                           'test_data/G00158005_V10_P1_R2_LC_GENEWIZ_SinglePass_SampleMap.xlsx',
#                           'test_data/G00158005_V10_P2_R2_HC_GENEWIZ_SinglePass_SampleMap.xlsx',
#                           'test_data/G00158005_V10_P2_R2_KC_GENEWIZ_SinglePass_SampleMap.xlsx',
#                           'test_data/G00158005_V10_P2_R2_LC_GENEWIZ_SinglePass_SampleMap.xlsx',
#                           'test_data/G00158008_V06_P1_R2_HC_GENEWIZ_SinglePass_SampleMap.xlsx',
#                           'test_data/G00158008_V06_P1_R2_KC_GENEWIZ_SinglePass_SampleMap.xlsx',
#                           'test_data/G00158008_V06_P1_R2_LC_GENEWIZ_SinglePass_SampleMap.xlsx',
#                           'test_data/G00158008_V08_P1_R2_HC_GENEWIZ_SinglePass_SampleMap.xlsx',
#                           'test_data/G00158008_V08_P1_R2_KC_GENEWIZ_SinglePass_SampleMap.xlsx',
#                           'test_data/G00158008_V08_P1_R2_LC_GENEWIZ_SinglePass_SampleMap.xlsx',
#                           'test_data/G00158021_V07_P1_R2_HC_GENEWIZ_SinglePass_SampleMap.xlsx',
#                           'test_data/G00158021_V07_P1_R2_KC_GENEWIZ_SinglePass_SampleMap.xlsx',
#                           'test_data/G00158021_V07_P1_R2_LC_GENEWIZ_SinglePass_SampleMap.xlsx']
ERROR_FLAG = False

# Check if the specified container template exists.
if not os.path.exists(args.containers[0]):
    container_template_logger.error(
        "{} file not found.".format(args.containers[0]))
    print("Container template file can't be found:\n\t {}".format(
        args.containers[0]))
    print("Did you forget to specify the full path to the file?")
    ERROR_FLAG = True

# Check if all the sample templates exist.
samples_not_found = [
    sample for sample in args.samplemap if not os.path.exists(sample)]
if len(samples_not_found) != 0:
    print("Sample map file not found:")
    for s in ["\t"+s for s in samples_not_found]:
        sample_template_logger.error("{} file not found.".format(s))
        print(s)
    print("Did you forget to specify the full path to the file?")
    ERROR_FLAG = True

if not ERROR_FLAG:
    print("Found all specified files.")
    print("Validating Container Template {}".format(args.containers[0]))
else:
    print("Errors detected. See GENEWIZ_template_validation.log for more information.")
    sys.exit(1)

print("Validating Container Template Contents.")
container_template = xlrd.open_workbook(args.containers[0])
try:
    sheet = container_template.sheet_by_name("SinglePass Containers")
except XLRDError as e:
    container_template_logger.error(
        "No sheet named SinglePass Container in {}".format(args.containers[0]))
    print("Errors detected. See GENEWIZ_template_validation.log for more information.")
    sys.exit(1)

container_column = sheet.col(2)  # Container Name should be column 3
primer_column = sheet.col(3)  # MyPrimers per Container should be column 4

ACCUMULATED_ERRORS = []
if not str(container_column[0].value) == CONTAINER_COLUMN_NAME:
    container_template_logger.error("Column \"{}\" not found in {}".format(
        CONTAINER_COLUMN_NAME, args.containers[0]))
    ACCUMULATED_ERRORS.append("Column \"{}\" not found in {}".format(
        CONTAINER_COLUMN_NAME, args.containers[0]))
    ERROR_FLAG = True

if not str(primer_column[0].value) == PRIMER_COLUMN_NAME:
    container_template_logger.error("Column \"{}\" not found in {}".format(
        PRIMER_COLUMN_NAME, args.containers[0]))
    ACCUMULATED_ERRORS.append("Column \"{}\" not found in {}".format(
        PRIMER_COLUMN_NAME, args.containers[0]))
    ERROR_FLAG = True

containers = [str(s.value) for s in container_column[1:] if str(s.value) != '']


for container in containers:
    if not container in [os.path.basename(sample).split(".")[0].replace("_GENEWIZ_SinglePass_SampleMap", "") for sample in args.samplemap]:
        container_template_logger.error(
            "No SampleMap template xlsx file provided for container {} listed in {}".format(container, args.containers[0]))
        ACCUMULATED_ERRORS.append(
            "No SampleMap template xlsx file provided for container {} listed in {}".format(container, os.path.basename(args.containers[0])))
        ERROR_FLAG = True

for samplemap in [os.path.basename(sample).split(".")[0].replace("_GENEWIZ_SinglePass_SampleMap", "") for sample in args.samplemap]:
    if not samplemap in containers:
        container_template_logger.error(
            "No container entry specified for SampleMap template {}".format(samplemap))
        ACCUMULATED_ERRORS.append(
            "No container entry specified for SampleMap template {}".format(samplemap))
        ERROR_FLAG = True

if ERROR_FLAG:
    print("Errors validating containers and sample map templates. See GENEWIZ_template_validation.log for more information.")
    for e in ACCUMULATED_ERRORS:
        print(str(e))
    ACCUMULATED_ERRORS = []

print("Validating Sample Map Templates.")
try:
    for samplemap_template_name in args.samplemap:
        samplemap_template = xlrd.open_workbook(samplemap_template_name)
        sheet = samplemap_template.sheet_by_name("SinglePass Sample Map")
        # check that cell F1 matches the expected name of the template.
        if not str(sheet.cell(0, 5).value) in os.path.basename(samplemap_template_name).split(".")[0]:
            sample_template_logger.error("Sample Map Template {} doesn't match sheet contents at cell F1. \n\tFound {}".format(
                os.path.basename(samplemap_template_name).split(".")[0], str(sheet.cell(0, 5).value)))
            ACCUMULATED_ERRORS.append("Sample Map Template {} doesn't match sheet contents at cell F1.\n\t Found {}".format(
                os.path.basename(samplemap_template_name).split(".")[0], str(sheet.cell(0, 5).value)))
            ERROR_FLAG = True
        for v in [str(val.value) for val in sheet.col(4)[2:]]:
            ERROR_FLAG = validate_plate_well_id_1(
                ERROR_FLAG, samplemap_template_name, v, expected=str(sheet.cell(0, 5).value))
            ERROR_FLAG = validate_plate_well_id_2(
                ERROR_FLAG, samplemap_template_name, v)

except XLRDError as e:
    sample_template_logger.error(
        "No sheet named SinglePass Sample Map in {}".format(samplemap_template))
    print("Errors detected. See GENEWIZ_template_validation.log for more information.")
    sys.exit(1)

except Exception as e:
    print("Something went wrong reading a genewiz sample map template.")
    print(str(e))
    sys.exit(1)

if ERROR_FLAG:
    print("There were validation errors. See GENEWIZ_template_validation.log for more information.")
    sys.exit(1)
else:
    print("All templates validated successfully.")
    sys.exit(0)
