"""
# =============================================================================

Copyright Government of Canada 2015

Written by: Eric Enns, Public Health Agency of Canada,
                       National Microbiology Laboratory
            Mark Iskander, Public Health Agency of Canada,
                       National Microbiology Laboratory
            Daniel Bouchard, Public Health Agency of Canada,
                       National Microbiology Laboratory

Funded by the National Micriobiology Laboratory

Licensed under the Apache License, Version 2.0 (the "License"); you may not use
this work except in compliance with the License. You may obtain a copy of the
License at:

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed
under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied. See the License for the
specific language governing permissions and limitations under the License.

# =============================================================================
"""
"""
Created on June 23rd, 2015
@currentauthor: Mark Iskander
@originalauthor: Daniel Bouchard
"""

import logging
import os
import re
import sys
sys.path.append("")
import unittest
import mockGalaxy as mg
import ymltests as yt
import dynamic_tool_destination.DynamicToolDestination as dt

from dynamic_tool_destination.DynamicToolDestination import map_tool_to_destination
from testfixtures import log_capture


theApp = mg.App( "waffles_default", "test_spec")

#======================Jobs====================================
zeroJob = mg.Job()

emptyJob = mg.Job()
emptyJob.add_input_dataset( mg.InputDataset("input1", mg.Dataset( (os.getcwd() + "/tests/data/test.empty"), "txt", 14)) )

failJob = mg.Job()
failJob.add_input_dataset( mg.InputDataset("input1", mg.Dataset( (os.getcwd() + "/tests/data/test1.full"), "txt", 15)) )

msfileJob = mg.Job()
msfileJob.add_input_dataset( mg.InputDataset("input1", mg.Dataset( (os.getcwd() + "/tests/data/not_here.full"), "txt", 15)) )

notfileinpJob = mg.Job()
msfileJob.add_input_dataset( mg.InputDataset("input1", mg.NotAFile() ) )

runJob = mg.Job()
runJob.add_input_dataset( mg.InputDataset("input1", mg.Dataset( (os.getcwd() + "/tests/data/test3.full"), "txt", 15)) )

vfJob = mg.Job()
vfJob.add_input_dataset( mg.InputDataset("input1", mg.Dataset( (os.getcwd() + "/tests/data/test3.full"), "txt", 15)) )
vfJob.set_arg_value( "mlst_or_genedb", {"vfdb_in": "-bact"} )

argJob = mg.Job()
argJob.add_input_dataset( mg.InputDataset("input1", mg.Dataset( (os.getcwd() + "/tests/data/test3.full"), "txt", 15)) )
argJob.set_arg_value( "careful", True )

argNotFoundJob = mg.Job()
argNotFoundJob.add_input_dataset( mg.InputDataset("input1", mg.Dataset( (os.getcwd() + "/tests/data/test3.full"), "txt", 15)) )
argNotFoundJob.set_arg_value( "careful", False )

notvfJob = mg.Job()
notvfJob.add_input_dataset( mg.InputDataset("input1", mg.Dataset( (os.getcwd() + "/tests/data/test3.full"), "txt", 15)) )
notvfJob.set_arg_value( "mlst_or_genedb", {"vfdb_in": "-not_here"} )

dbJob = mg.Job()
dbJob.add_input_dataset( mg.InputDataset("input1", mg.Dataset( (os.getcwd() + "/tests/data/test.fasta"), "fasta", 10)) )

dbcountJob = mg.Job()
dbcountJob.add_input_dataset( mg.InputDataset("input1", mg.Dataset( (os.getcwd() + "/tests/data/test.fasta"), "fasta", None)) )

vfdbJob = mg.Job()
vfdbJob.add_input_dataset( mg.InputDataset("input1", mg.Dataset( (os.getcwd() + "/tests/data/test.fasta"), "fasta", 6)) )
vfdbJob.set_arg_value( "mlst_or_genedb", {"vfdb_in": "-bact"} )

#======================Tools===================================
vanillaTool = mg.Tool( 'test' )

unTool = mg.Tool( 'unregistered' )

overlapTool = mg.Tool( 'test_overlap' )

defaultTool = mg.Tool( 'test_tooldefault' )

dbTool = mg.Tool( 'test_db' )
dbinfTool = mg.Tool( 'test_db_high' )

argTool = mg.Tool( 'test_arguments' )

vfdbTool = mg.Tool( 'test_db' )
vfdbTool.add_tool_dependency( mg.ToolDependency("vfdb", os.getcwd() + "/tests") )

noVBTool = mg.Tool( 'test_no_verbose' )

usersTool = mg.Tool( 'test_users' )

numinputsTool = mg.Tool( 'test_num_input_datasets' )

#=======================YML file================================
path = os.getcwd() + "/tests/data/tool_destination.yml"
priority_path = os.getcwd() + "/tests/data/priority_tool_destination.yml"
broken_default_dest_path = os.getcwd() + "/tests/data/dest_fail.yml"
no_verbose_path = os.getcwd() + "/tests/data/test_no_verbose.yml"
users_test_path = os.getcwd() + "/tests/data/test_users.yml"
num_input_datasets_test_path = os.getcwd() + "/tests/data/test_num_input_datasets.yml"

#======================Test Variables=========================
value = 1
valueK = value * 1024
valueM = valueK * 1024
valueG = valueM * 1024
valueT = valueG * 1024
valueP = valueT * 1024
valueE = valueP * 1024
valueZ = valueE * 1024
valueY = valueZ * 1024


class TestDynamicToolDestination(unittest.TestCase):
    def setUp(self):
        self.maxDiff = None
        logger = logging.getLogger()

    #=======================map_tool_to_destination()================================

    @log_capture()
    def test_brokenDestYML(self, l):
        self.assertRaises(mg.JobMappingException, map_tool_to_destination, runJob, theApp, vanillaTool, "user@email.com", True, broken_default_dest_path)

        l.check(
            ('dynamic_tool_destination.DynamicToolDestination', 'DEBUG', 'Running config validation...'),
            ('dynamic_tool_destination.DynamicToolDestination', 'DEBUG', 'No global default destination specified in config!'),
            ('dynamic_tool_destination.DynamicToolDestination', 'DEBUG', 'Finished config validation.'),
            ('dynamic_tool_destination.DynamicToolDestination', 'DEBUG', 'Loading file: input1' + os.getcwd() + '/tests/data/test3.full'),
            ('dynamic_tool_destination.DynamicToolDestination', 'DEBUG', 'Total size: 3.23 KB')
        )

    @log_capture()
    def test_filesize_empty(self, l):
        self.assertRaises(mg.JobMappingException, map_tool_to_destination, emptyJob, theApp, vanillaTool, "user@email.com", True, path)
        self.assertRaises(mg.JobMappingException, map_tool_to_destination, emptyJob, theApp, vanillaTool, "user@email.com", True, priority_path)

        l.check(
            ('dynamic_tool_destination.DynamicToolDestination', 'DEBUG', 'Running config validation...'),
            ('dynamic_tool_destination.DynamicToolDestination', 'DEBUG', 'Finished config validation.'),
            ('dynamic_tool_destination.DynamicToolDestination', 'DEBUG', 'Loading file: input1' + os.getcwd() + '/tests/data/test.empty'),
            ('dynamic_tool_destination.DynamicToolDestination', 'DEBUG', 'Total size: 0.00 B'),
            ('dynamic_tool_destination.DynamicToolDestination', 'DEBUG', 'Total number of files: 1'),
            ('dynamic_tool_destination.DynamicToolDestination', 'DEBUG', 'Running config validation...'),
            ('dynamic_tool_destination.DynamicToolDestination', 'DEBUG', 'Finished config validation.'),
            ('dynamic_tool_destination.DynamicToolDestination', 'DEBUG', 'Loading file: input1' + os.getcwd() + '/tests/data/test.empty'),
            ('dynamic_tool_destination.DynamicToolDestination', 'DEBUG', 'Total size: 0.00 B'),
            ('dynamic_tool_destination.DynamicToolDestination', 'DEBUG', 'Total number of files: 1')
        )

    @log_capture()
    def test_filesize_zero(self, l):
        self.assertRaises(mg.JobMappingException, map_tool_to_destination, zeroJob, theApp, vanillaTool, "user@email.com", True, path)
        self.assertRaises(mg.JobMappingException, map_tool_to_destination, zeroJob, theApp, vanillaTool, "user@email.com", True, priority_path)

        l.check(
            ('dynamic_tool_destination.DynamicToolDestination', 'DEBUG', 'Running config validation...'),
            ('dynamic_tool_destination.DynamicToolDestination', 'DEBUG', 'Finished config validation.'),
            ('dynamic_tool_destination.DynamicToolDestination', 'DEBUG', 'Total size: 0.00 B'),
            ('dynamic_tool_destination.DynamicToolDestination', 'DEBUG', 'Total number of files: 0'),
            ('dynamic_tool_destination.DynamicToolDestination', 'DEBUG', 'Running config validation...'),
            ('dynamic_tool_destination.DynamicToolDestination', 'DEBUG', 'Finished config validation.'),
            ('dynamic_tool_destination.DynamicToolDestination', 'DEBUG', 'Total size: 0.00 B'),
            ('dynamic_tool_destination.DynamicToolDestination', 'DEBUG', 'Total number of files: 0')
        )

    @log_capture()
    def test_filesize_fail(self, l):
        self.assertRaises(mg.JobMappingException, map_tool_to_destination, failJob, theApp, vanillaTool, "user@email.com", True, path)
        self.assertRaises(mg.JobMappingException, map_tool_to_destination, failJob, theApp, vanillaTool, "user@email.com", True, priority_path)

        l.check(
            ('dynamic_tool_destination.DynamicToolDestination', 'DEBUG', 'Running config validation...'),
            ('dynamic_tool_destination.DynamicToolDestination', 'DEBUG', 'Finished config validation.'),
            ('dynamic_tool_destination.DynamicToolDestination', 'DEBUG', 'Loading file: input1' + os.getcwd() + '/tests/data/test1.full'),
            ('dynamic_tool_destination.DynamicToolDestination', 'DEBUG', 'Total size: 293.00 B'),
            ('dynamic_tool_destination.DynamicToolDestination', 'DEBUG', 'Total number of files: 1'),
            ('dynamic_tool_destination.DynamicToolDestination', 'DEBUG', 'Running config validation...'),
            ('dynamic_tool_destination.DynamicToolDestination', 'DEBUG', 'Finished config validation.'),
            ('dynamic_tool_destination.DynamicToolDestination', 'DEBUG', 'Loading file: input1' + os.getcwd() + '/tests/data/test1.full'),
            ('dynamic_tool_destination.DynamicToolDestination', 'DEBUG', 'Total size: 293.00 B'),
            ('dynamic_tool_destination.DynamicToolDestination', 'DEBUG', 'Total number of files: 1')
        )

    @log_capture()
    def test_filesize_run(self, l):
        job = map_tool_to_destination( runJob, theApp, vanillaTool, "user@email.com", True, path )
        self.assertEquals( job, 'Destination1' )
        priority_job = map_tool_to_destination( runJob, theApp, vanillaTool, "user@email.com", True, priority_path )
        self.assertEquals( priority_job, 'Destination1_high' )

        l.check(
            ('dynamic_tool_destination.DynamicToolDestination', 'DEBUG', 'Running config validation...'),
            ('dynamic_tool_destination.DynamicToolDestination', 'DEBUG', 'Finished config validation.'),
            ('dynamic_tool_destination.DynamicToolDestination', 'DEBUG', 'Loading file: input1' + os.getcwd() + '/tests/data/test3.full'),
            ('dynamic_tool_destination.DynamicToolDestination', 'DEBUG', 'Total size: 3.23 KB'),
            ('dynamic_tool_destination.DynamicToolDestination', 'DEBUG', 'Total number of files: 1'),
            ('dynamic_tool_destination.DynamicToolDestination', 'DEBUG', "Running 'test' with 'Destination1'."),
            ('dynamic_tool_destination.DynamicToolDestination', 'DEBUG', 'Running config validation...'),
            ('dynamic_tool_destination.DynamicToolDestination', 'DEBUG', 'Finished config validation.'),
            ('dynamic_tool_destination.DynamicToolDestination', 'DEBUG', 'Loading file: input1' + os.getcwd() + '/tests/data/test3.full'),
            ('dynamic_tool_destination.DynamicToolDestination', 'DEBUG', 'Total size: 3.23 KB'),
            ('dynamic_tool_destination.DynamicToolDestination', 'DEBUG', 'Total number of files: 1'),
            ('dynamic_tool_destination.DynamicToolDestination', 'DEBUG', "Running 'test' with 'Destination1_high'.")
        )

    @log_capture()
    def test_default_tool(self, l):
        job = map_tool_to_destination( runJob, theApp, defaultTool, "user@email.com", True, path )
        self.assertEquals( job, 'waffles_default' )
        priority_job = map_tool_to_destination( runJob, theApp, defaultTool, "user@email.com", True, priority_path )
        self.assertEquals( priority_job, 'waffles_default_high' )

        l.check(
            ('dynamic_tool_destination.DynamicToolDestination', 'DEBUG', 'Running config validation...'),
            ('dynamic_tool_destination.DynamicToolDestination', 'DEBUG', 'Finished config validation.'),
            ('dynamic_tool_destination.DynamicToolDestination', 'DEBUG', "Tool 'test_tooldefault' not specified in config. Using default destination."),
            ('dynamic_tool_destination.DynamicToolDestination', 'DEBUG', "Running 'test_tooldefault' with 'waffles_default'."),
            ('dynamic_tool_destination.DynamicToolDestination', 'DEBUG', 'Running config validation...'),
            ('dynamic_tool_destination.DynamicToolDestination', 'DEBUG', 'Finished config validation.'),
            ('dynamic_tool_destination.DynamicToolDestination', 'DEBUG', "Tool 'test_tooldefault' not specified in config. Using default destination."),
            ('dynamic_tool_destination.DynamicToolDestination', 'DEBUG', "Running 'test_tooldefault' with 'waffles_default_high'.")
        )

    @log_capture()
    def test_arguments_tool(self, l):
        job = map_tool_to_destination( argJob, theApp, argTool, "user@email.com", True, path )
        self.assertEquals( job, 'Destination6' )
        priority_job = map_tool_to_destination( argJob, theApp, argTool, "user@email.com", True, priority_path )
        self.assertEquals( priority_job, 'Destination6_med' )

        l.check(
            ('dynamic_tool_destination.DynamicToolDestination', 'DEBUG', 'Running config validation...'),
            ('dynamic_tool_destination.DynamicToolDestination', 'DEBUG', 'Finished config validation.'),
            ('dynamic_tool_destination.DynamicToolDestination', 'DEBUG', "Running 'test_arguments' with 'Destination6'."),
            ('dynamic_tool_destination.DynamicToolDestination', 'DEBUG', 'Running config validation...'),
            ('dynamic_tool_destination.DynamicToolDestination', 'DEBUG', 'Finished config validation.'),
            ('dynamic_tool_destination.DynamicToolDestination', 'DEBUG', "Running 'test_arguments' with 'Destination6_med'.")
        )

    @log_capture()
    def test_arguments_arg_not_found(self, l):
        job = map_tool_to_destination( argNotFoundJob, theApp, argTool, "user@email.com", True, path )
        self.assertEquals( job, 'waffles_default' )
        priority_job = map_tool_to_destination( argNotFoundJob, theApp, argTool, "user@email.com", True, priority_path )
        self.assertEquals( priority_job, 'waffles_default_high' )

        l.check(
            ('dynamic_tool_destination.DynamicToolDestination', 'DEBUG', 'Running config validation...'),
            ('dynamic_tool_destination.DynamicToolDestination', 'DEBUG', 'Finished config validation.'),
            ('dynamic_tool_destination.DynamicToolDestination', 'DEBUG', "Running 'test_arguments' with 'waffles_default'."),
            ('dynamic_tool_destination.DynamicToolDestination', 'DEBUG', 'Running config validation...'),
            ('dynamic_tool_destination.DynamicToolDestination', 'DEBUG', 'Finished config validation.'),
            ('dynamic_tool_destination.DynamicToolDestination', 'DEBUG', "Running 'test_arguments' with 'waffles_default_high'.")
        )

    @log_capture()
    def test_tool_not_found(self, l):
        job = map_tool_to_destination( runJob, theApp, unTool, "user@email.com", True, path )
        self.assertEquals( job, 'waffles_default' )
        priority_job = map_tool_to_destination( runJob, theApp, unTool, "user@email.com", True, priority_path )
        self.assertEquals( priority_job, 'waffles_default_high' )

        l.check(
            ('dynamic_tool_destination.DynamicToolDestination', 'DEBUG', 'Running config validation...'),
            ('dynamic_tool_destination.DynamicToolDestination', 'DEBUG', 'Finished config validation.'),
            ('dynamic_tool_destination.DynamicToolDestination', 'DEBUG', "Tool 'unregistered' not specified in config. Using default destination."),
            ('dynamic_tool_destination.DynamicToolDestination', 'DEBUG', "Running 'unregistered' with 'waffles_default'."),
            ('dynamic_tool_destination.DynamicToolDestination', 'DEBUG', 'Running config validation...'),
            ('dynamic_tool_destination.DynamicToolDestination', 'DEBUG', 'Finished config validation.'),
            ('dynamic_tool_destination.DynamicToolDestination', 'DEBUG', "Tool 'unregistered' not specified in config. Using default destination."),
            ('dynamic_tool_destination.DynamicToolDestination', 'DEBUG', "Running 'unregistered' with 'waffles_default_high'.")
        )

    @log_capture()
    def test_fasta(self, l):
        job = map_tool_to_destination( dbJob, theApp, dbTool, "user@email.com", True, path )
        self.assertEquals( job, 'Destination4' )
        priority_job = map_tool_to_destination( dbJob, theApp, dbTool, "user@email.com", True, priority_path )
        self.assertEquals( priority_job, 'Destination4_high' )

        l.check(