#!/usr/bin/python
#
# Copyright 2016 Canonical Ltd
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file 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.

import os

from mock import MagicMock
from mock import patch

from charmhelpers.contrib.hardware import pci
from tests.contrib.hardware import pci_responses
from tests.contrib.hardware.test_utils import patch_open


def check_device(device, attr_dict):
    equal = (
        device.interface_name == attr_dict["interface_name"] and
        device.mac_address == attr_dict["mac_address"] and
        device.pci_address == attr_dict["pci_address"] and
        device.state == attr_dict["state"]
    )
    return equal


def mocked_subprocess(subproc_map=None):
    def _subproc(cmd, stdin=None):
        for key in pci_responses.COMMANDS.keys():
            if pci_responses.COMMANDS[key] == cmd:
                return subproc_map[key]
            elif pci_responses.COMMANDS[key] == cmd[:-1]:
                return subproc_map[cmd[-1]][key]

    if not subproc_map:
        subproc_map = pci_responses.NET_SETUP
    return _subproc


class mocked_filehandle(object):
    def _setfilename(self, fname, omode):
        self.FILENAME = fname

    def _getfilecontents_read(self):
        try:
            return pci_responses.FILE_CONTENTS[self.FILENAME]
        except KeyError:
            raise OSError()

    def _getfilecontents_readlines(self):
        return pci_responses.FILE_CONTENTS[self.FILENAME].split("\n")


def mocked_globs(path):
    check_path = path.split("*")[0].rstrip("/")
    dirs = []
    for sdir in pci_responses.SYS_TREE:
        if check_path in sdir:
            dirs.append(sdir)
    return dirs


def mocked_islink(link):
    resolved_relpath = mocked_resolve_link(link)
    if pci_responses.SYS_TREE.get(resolved_relpath):
        return True
    else:
        return False


def mocked_resolve_link(link):
    resolved_relpath = None
    for sdir in pci_responses.SYS_TREE:
        if sdir in link:
            rep_dir = "{}/{}".format(
                os.path.dirname(sdir), pci_responses.SYS_TREE[sdir]
            )
            resolved_symlink = link.replace(sdir, rep_dir)
            resolved_relpath = os.path.abspath(resolved_symlink)
    return resolved_relpath


def mocked_realpath(link):
    resolved_link = mocked_resolve_link(link)
    return pci_responses.SYS_TREE[resolved_link]


def mocked_listdir(path):
    return pci_responses.NETDEVS[path]


@patch("pci.cached")
@patch("pci.log")
@patch("pci.subprocess.Popen")
@patch("pci.subprocess.check_output")
@patch("pci.glob.glob")
@patch("pci.os.path.islink")
def pci_devs(
    _osislink, _glob, _check_output, _Popen, _log, _cached, subproc_map=None
):
    _glob.side_effect = mocked_globs
    _osislink.side_effect = mocked_islink
    _check_output.side_effect = mocked_subprocess(subproc_map=subproc_map)

    with patch_open() as (_open, _file), patch(
        "pci.os.path.realpath"
    ) as _realpath:
        super_fh = mocked_filehandle()
        _file.readlines = MagicMock()
        _open.side_effect = super_fh._setfilename
        _file.read.side_effect = super_fh._getfilecontents_read
        _file.readlines.side_effect = super_fh._getfilecontents_readlines
        _realpath.side_effect = mocked_realpath
        devices = pci.PCINetDevices()
    return devices
