"""Test fixtures."""

import lxml
import pytest
from napalm_base.test import conftest as parent_conftest

from napalm_base.test.double import BaseTestDouble

from napalm_junos import junos


@pytest.fixture(scope='class')
def set_device_parameters(request):
    """Set up the class."""
    def fin():
        request.cls.device.close()
    request.addfinalizer(fin)

    request.cls.driver = junos.JunOSDriver
    request.cls.patched_driver = PatchedJunOSDriver
    request.cls.vendor = 'junos'
    parent_conftest.set_device_parameters(request)


def pytest_generate_tests(metafunc):
    """Generate test cases dynamically."""
    parent_conftest.pytest_generate_tests(metafunc, __file__)


class PatchedJunOSDriver(junos.JunOSDriver):
    """Patched JunOS Driver."""

    def __init__(self, hostname, username, password, timeout=60, optional_args=None):
        optional_args['config_lock'] = False  # to not try lock on open()
        super(self.__class__, self).__init__(hostname, username, password, timeout, optional_args)

        self.patched_attrs = ['device']
        self.device = FakeJunOSDevice()

    def is_alive(self):
        return {
            'is_alive': True  # always alive during the tests...
        }


class FakeJunOSDevice(BaseTestDouble):

    def __init__(self):
        self.rpc = FakeRPCObject(self)
        self._conn = FakeConnection(self.rpc)
        self.ON_JUNOS = True  # necessary for fake devices
        self.facts = {
            'domain': None,
            'hostname': 'vsrx',
            'ifd_style': 'CLASSIC',
            '2RE': False,
            'serialnumber': 'beb914a9cca3',
            'fqdn': 'vsrx',
            'virtual': True,
            'switch_style': 'NONE',
            'version': '12.1X47-D20.7',
            'HOME': '/cf/var/home/vagrant',
            'srx_cluster': False,
            'model': 'FIREFLY-PERIMETER',
            'RE0': {
                'status': 'Testing',
                'last_reboot_reason': 'Router rebooted after a normal shutdown.',
                'model': 'FIREFLY-PERIMETER RE',
                'up_time': '1 hour, 13 minutes, 37 seconds'
            },
            'vc_capable': False,
            'personality': 'SRX_BRANCH'
        }

    def open(self):
        pass

    def close(self):
        pass

    def bind(*args, **kvargs):
        pass

    def cli(self, command=''):
        filename = '{safe_command}.txt'.format(safe_command=self.sanitize_text(command))
        fielpath = self.find_file(filename)
        return self.read_txt_file(fielpath)


class FakeRPCObject:

    """
    Fake RPC caller.
    """

    def __init__(self, device):
        self._device = device

    def __getattr__(self, item):
        self.item = item
        return self

    def response(self, **rpc_args):
        instance = rpc_args.pop('instance', '')

        filename = '{item}{instance}.xml'.format(
            item=self.item, instance=instance
        )
        filepathpath = self._device.find_file(filename)
        xml_string = self._device.read_txt_file(filepathpath)

        return lxml.etree.fromstring(xml_string)

    def get_config(self, get_cmd=None, filter_xml=None, options={}):

        # get_cmd is an XML tree that requests a specific part of the config
        # E.g.: <configuration><protocols><bgp><group/></bgp></protocols></configuration>

        if get_cmd is not None:
            get_cmd_str = lxml.etree.tostring(get_cmd).decode('utf-8')
            filename = self._device.sanitize_text(get_cmd_str)

        # no get_cmd means it should mock the eznc get_config
        else:
            filename = 'get_config__' + '__'.join(
                ['{0}_{1}'.format(k, v) for k, v in sorted(options.items())]
            )

        filename = '{filename}.xml'.format(filename=filename[0:150])
        filepathpath = self._device.find_file(filename)
        xml_string = self._device.read_txt_file(filepathpath)

        return lxml.etree.fromstring(xml_string)

    __call__ = response


class FakeConnectionRPCObject:

    """
    Will make fake RPC requests that usually are directly made via netconf.
    """

    def __init__(self, rpc):
        self._rpc = rpc

    def response(self, non_std_command=None):
        class RPCReply:
            def __init__(self, reply):
                self._NCElement__doc = reply
        rpc_reply = RPCReply(self._rpc.get_config(get_cmd=non_std_command))
        return rpc_reply

    __call__ = response


class FakeConnection:

    def __init__(self, rpc):
        self.rpc = FakeConnectionRPCObject(rpc)
        self._session = FakeSession()


class FakeSession:
    def __init__(self):
        self.transport = FakeTransport()


class FakeTransport:
    def set_keepalive(self, keepalive):
        self.keepalive = keepalive

@@ -27,16 +27,28 @@
 rt lxml%0A
+import yaml%0A
 import p
@@ -53,16 +53,16 @@
  pytest%0A
-
 from nap
@@ -1379,24 +1379,74 @@
 n(self.rpc)%0A
+        self.alternative_facts_file = 'facts.yml'%0A
         self
@@ -1505,16 +1505,24 @@
    self.
+default_
 facts = 
@@ -2279,16 +2279,16 @@
 BRANCH'%0A
-
         
@@ -2290,16 +2290,502 @@
      %7D%0A%0A
+    @property%0A    def facts(self):%0A        try:%0A            alt_facts_filepath = self.find_file(self.alternative_facts_file)%0A        except IOError:%0A            self._facts = self.default_facts%0A            return self._facts%0A        with open(alt_facts_filepath, 'r') as alt_facts:%0A            try:%0A                self._facts.update(yaml.load(alt_facts))%0A            except (yaml.YAMLError, AttributeError):%0A                self._facts = self.default_facts%0A        return self._facts%0A%0A
     def 

Allow facts per testcase