import jinja2
import six
import abc
import os

from check_versions.common import const

pkg_dir = os.path.dirname(__file__)
pkg_dir = os.path.join(pkg_dir, os.pardir)
pkg_dir = os.path.normpath(pkg_dir)


def shortname(node_fqdn):
    # form shortname out of node fqdn
    return node_fqdn.split(".", 1)[0]


def is_equal(pkg_dict):
    # compare versions of given package
    return pkg_dict['installed'] == pkg_dict['candidate']


def is_active(node_dict):
    # check node status in node dict
    return node_dict['status'] == const.NODE_UP


def line_breaks(text):
    # replace python linebreaks with html breaks
    return text.replace("\n", "<br />")


@six.add_metaclass(abc.ABCMeta)
class _Base(object):
    def __init__(self):
        self.jinja2_env = self.init_jinja2_env()

    @abc.abstractmethod
    def __call__(self, payload):
        pass

    @staticmethod
    def init_jinja2_env():
        return jinja2.Environment(
            loader=jinja2.FileSystemLoader(os.path.join(pkg_dir, 'templates')),
            trim_blocks=True,
            lstrip_blocks=True)


class _TMPLBase(_Base):
    @abc.abstractproperty
    def tmpl(self):
        pass

    @staticmethod
    def _count_totals(data):
        data['counters']['total_nodes'] = len(data['nodes'])

    def __call__(self, nodes):
        # init data structures
        data = self.common_data()
        data.update({
            "nodes": nodes
        })

        # add template specific data
        self._extend_data(data)

        # do counts global
        self._count_totals(data)

        # specific filters
        self.jinja2_env.filters['shortname'] = shortname
        self.jinja2_env.filters['is_equal'] = is_equal
        self.jinja2_env.filters['is_active'] = is_active
        self.jinja2_env.filters['linebreaks'] = line_breaks

        # render!
        tmpl = self.jinja2_env.get_template(self.tmpl)
        return tmpl.render(data)

    def common_data(self):
        return {
            'counters': {},
            'salt_info': {}
        }

    def _extend_data(self, data):
        pass


# Package versions report
class HTMLPackageCandidates(_TMPLBase):
    tmpl = "pkg_versions_tmpl.j2"

    @staticmethod
    def is_fail_uniq(p_dict, p_name, nodes, node_name):
        # look up package fail for nodes with similar role
        _tgroup = nodes[node_name]['node_group']
        # filter all nodes with the same role
        _nodes_list = filter(
            lambda nd: nodes[nd]['node_group'] == _tgroup and nd != node_name,
            nodes
        )
        # lookup same package
        _fail_uniq = False
        for _node_name in _nodes_list:
            # check if there is a package present on node
            _nd = nodes[_node_name]['packages']
            if p_name not in _nd:
                continue
            # if both backages has same version and differ from candidate
            if p_dict['candidate'] == _nd[p_name]['candidate'] \
                    and _nd[p_name]['candidate'] == _nd[p_name]['installed']:
                # it is not uniq, mark and break
                _fail_uniq = True
        return _fail_uniq

    def _extend_data(self, data):
        _all_pkg = 0
        for key, value in data['nodes'].iteritems():
            # add count of packages for this node to total
            _all_pkg += len(value.keys())

            # count differences
            data['counters'][key] = {}
            data['counters'][key]['packages'] = len(value['packages'].keys())
            data['counters'][key]['package_diff'] = 0
            for pkg_name, pkg_value in value['packages'].iteritems():
                if pkg_value['installed'] != pkg_value['candidate']:
                    pkg_value['is_equal'] = False
                    pkg_value['fail_uniq'] = self.is_fail_uniq(
                        pkg_value,
                        pkg_name,
                        data['nodes'],
                        key
                    )
                    data['counters'][key]['package_diff'] += 1
                else:
                    pkg_value['is_equal'] = True
                    pkg_value['fail_uniq'] = False

        data['counters']['total_packages'] = _all_pkg


class ReportToFile(object):
    def __init__(self, report, target):
        self.report = report
        self.target = target

    def __call__(self, payload):
        payload = self.report(payload)

        if isinstance(self.target, six.string_types):
            self._wrapped_dump(payload)
        else:
            self._dump(payload, self.target)

    def _wrapped_dump(self, payload):
        with open(self.target, 'wt') as target:
            self._dump(payload, target)

    @staticmethod
    def _dump(payload, target):
        target.write(payload)
