#!/usr/bin/env python3
#-*- coding:utf-8 -*-
try:
    import sys
    import importlib
    importlib.reload(sys)
    import socket
    import re
    import binascii
    from gspylib.inspection.common import SharedFuncs
    from gspylib.inspection.common.CheckItem import BaseItem
    from gspylib.inspection.common.CheckResult import ResultStatus
    from gspylib.os.gsnetwork import g_network
except Exception as ie:
    raise Exception("[GAUSS-52200] : Unable to import module: %s." % str(ie))


class CheckRouting(BaseItem):
    def __init__(self):
        super(CheckRouting, self).__init__(self.__class__.__name__)

    @staticmethod
    def getBinaryAddr(ipAddr):
        """
        function:
            Convert a IP into a integer(IPv4) or long integer(IPv6).
            By the type of integer, it is easy to calculate the bit-and, bit-xor, etc..
        input:
            ipAddr:
                The IP in string to be converted.
        output:
            The integer result.
        """
        if 4 == g_network.getIPType(ipAddr):
            return int(binascii.hexlify(socket.inet_pton(socket.AF_INET, ipAddr)), 16)
        else:
            return int(binascii.hexlify(socket.inet_pton(socket.AF_INET6, ipAddr)), 16)

    @staticmethod
    def getBinaryAddrCIDR(ipAndMask):
        """
        function:
            Convert the IP and it's mask into a integer(IPv4), or a long integer(IPv6).
            By the type of integer, it is easy to calculate the bit-and, bit-xor, etc..
        input:
            ipAndMask: the IP string in CIDR format.
        output:
            The integer tuple(ip, mask)
        """
        (ip, mask) = ipAndMask.split('/')
        mask = int(mask, 10)
        if 4 == g_network.getIPType(ip):
            ipbinary = CheckRouting.getBinaryAddr(ip)
            maskbinary = int('0b' + '1' * mask + '0' * (32 - mask), 2)
        else:
            ipbinary = CheckRouting.getBinaryAddr(ip)
            maskbinary = int('0b' + '1' * mask + '0' * (128 - mask), 2)

        return ipbinary, maskbinary

    def getBinaryRouting(self, ipAndMask):
        """
        function:
            Convert the IP and it's mask into integer, and then calculate the net masks( IP bit-and mask).
        input:
            ipAndMask: The plain text of IP and it's mask.
                There are two formats in history:
                1. xxx.xxx.xxx.xxx:255.255.254.0, which is the old format, and it's equal to 'xxx.xxx.xxx.xxx/23'
                2. xxxx:xxxx::xxxx:xxxx/64, which is in CIDR format.
        output:
            The result of (IP bit-and mask) in string.
        """
        ip = ""
        netMask = ""
        # It's in old format 'xxx.xxxx.xxx.xxx:255.255.254.0', which is equal to
        # 'xxx.xxx.xxx.xxx/23'
        if re.match('^\d+\.\d+\.\d+\.\d+:\d+\.\d+\.\d+\.\d+$', ipAndMask) is not None:
            (ip, netMask) = ipAndMask.split(':')
            ipBinary = self.getBinaryAddr(ip)
            maskBinary = self.getBinaryAddr(netMask)
        else:
            # It's CIDR format.
            (ipBinary, maskBinary) = self.getBinaryAddrCIDR(ipAndMask)

        return str(ipBinary & maskBinary)

    def doCheck(self):
        routingBinary = self.getBinaryRouting(self.routing)
        ipList = SharedFuncs.getIPAndMaskList()

        self.result.raw = "Routing: %s [bit]%s\nlocalIP:\n%s"\
                          % (self.routing, bin(int(routingBinary, 10)), "\n".join(ipList))

        commIP = []
        for ipMask in ipList:
            ipBinary = self.getBinaryRouting(ipMask)
            if (ipBinary == routingBinary):
                commIP.append(ipMask)

        if (len(commIP) > 1):
            self.result.rst = ResultStatus.WARNING
        else:
            self.result.rst = ResultStatus.OK
        self.result.val = "Business network segment IP: " + ", ".join(commIP)
