# -*- python -*-
'''
xpybar – xmobar replacement written in python
Copyright © 2014, 2015  Mattias Andrée (maandree@member.fsf.org)

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
'''

import os

from util import *


class IPAddress:
    '''
    Multi-home aware retrieval of public and private IP addresses
    
    @variable  nics:dict<str,            The state and IP address for a network interface card
                         (state:int      Either of: `IPAddress.{DOWN,UNKOWN,ISOLATED,UP}`
                          private:str?   The interface's private IPv4 address
                          private6:str?  The interface's private IPv6 address
                          public:str?)>  The interface's public IP address on the Internet
    '''
    
    
    DOWN = 0
    '''
    The network interface is down
    '''
    
    UNKNOWN = 1
    '''
    The network interface's public IP address is unknown,
    but it is connected to the Internet
    '''
    
    ISOLATED = 2
    '''
    The network interface's public IP address is unknown
    because it does not appear to be connected to the Internet
    '''
    
    UP = 3
    '''
    The network interface is up and the public IP address is known
    '''
    
    
    def __init__(self, *exclude):
        '''
        Constructor
        
        @param  exclude:*str  Devices to exclude
        '''
        nics = [d for d in os.listdir('/sys/class/net') if d not in exclude]
        infos = [i for i in spawn_read('ifconfig').split('\n\n') if not i == '']
        self.nics = {}
        for nic in nics:
            state, private, private6, public = IPAddress.DOWN, None, None, None
            for info in infos:
                if info.startswith(nic + ': '):
                    info = [i.lstrip().split(' ') for i in info.split('\n')[1:]]
                    info = dict((i[0], i[1]) for i in info if len(i) > 1)
                    private = info['inet'] if 'inet' in info else None
                    private6 = info['inet6'] if 'inet6' in info else None
                    state = IPAddress.ISOLATED
                    break
            if not state == IPAddress.DOWN:
                self.__isolated = True
                download = lambda page : ('curl', '--interface', nic, page)
                public = self.__site_0(download)
                if public is None:  public = self.__site_1(download)
                if public is None:  public = self.__site_2(download)
                if public is None:  public = self.__site_3(download)
                if public is None:  public = self.__site_4(download)
                if public is None:  public = self.__site_5(download)
                if public is None:  public = self.__site_6(download)
                if public is None:  public = self.__site_7(download)
                if public is None:  public = self.__site_8(download)
                if public is not None:
                    state = IPAddress.UP
                elif not self.__isolated:
                    state = IPAddress.UNKNOWN
            self.nics[nic] = (state, private, private6, public)
    
    
    def public(self):
        '''
        Get all unique public IP address
        
        @return  :dist<address:str?, nics:list<str>>  The IP addresses and the interfaces with those addresses
        '''
        rc = {}
        for nic in self.nics.keys():
            if self.nics[nic][3] in rc:
                rc[self.nics[nic][3]].append(nic)
            else:
                rc[self.nics[nic][3]] = [nic]
        return rc
    
    
    def __site_0(self, download):
        try:
            data = spawn_read(*download('http://checkip.dyndns.org'))
            if not data == '':
                self.__isolated = False
            return data.split('<body>')[1].split('</body>')[0].split(': ')[1]
        except:
            return None
    
    def __site_1(self, download):
        try:
            data = spawn_read(*download('http://ipecho.net/plain'))
            if not data == '':
                self.__isolated = False
            data = data.strip()
            return data if not data == '' else None
        except:
            return None
    
    def __site_2(self, download):
        try:
            data = spawn_read(*download('http://www.checkmyipaddress.org'))
            if not data == '':
                self.__isolated = False
            data = [line.strip() for line in data.replace('\r\n', '\n').split('\n') if '</h3>' in line]
            data = [line.split('>')[1].split('<')[0] for line in data]
            data = [line for line in data if ' ' not in line]
            return data[0] if not len(data) == 0 else None
        except:
            return None
    
    def __site_3(self, download):
        try:
            data = spawn_read(*download('http://www.ip-address.org'))
            if not data == '':
                self.__isolated = False
            data = [line.strip(' \t') for line in data.replace('\r\n', '\n').split('\n') if 'ip += ' in line]
            data = [line.split('"')[1] for line in data if len(line) - len(line.replace('"', '')) == 2]
            data = [line.split('<')[0] for line in data]
            data_ = []
            for line in data:
                line_ = line
                for c in '0123456789abcdefABCDEF.:':
                    line_ = line_.replace(c, '')
                if not line_ == '':
                    data_.append(line_)
            return data_[0] if not len(data_) == 0 else None
        except:
            return None
    
    def __site_4(self, download):
        try:
            data = spawn_read(*download('http://www.myipnumber.com/my-ip-address.asp'))
            if not data == '':
                self.__isolated = False
            data = data.replace('\r\n', '\n').split('\nThe IP Address of this machine is:\n')[1]
            return data.lower().split('\n')[0].split('<b>\n')[1].split('\n</b>')[0]
        except:
            return None
    
    def __site_5(self, download):
        try:
            data = spawn_read(*download('http://www.findipinfo.com'))
            if not data == '':
                self.__isolated = False
            return data.split('Your IP Address Is: ')[1].split('<')[0]
        except:
            return None
    
    def __site_6(self, download):
        try:
            data = spawn_read(*download('http://what-ip.net'))
            if not data == '':
                self.__isolated = False
            return data.split('Your IP Address is : ')[1].split('<b>')[1].split('</b>')[0]
        except:
            return None
    
    def __site_7(self, download):
        try:
            data = spawn_read(*download('http://my-ip-address.com'))
            if not data == '':
                self.__isolated = False
            return data.split('<input ')[1].split('>')[0].split('value=')[1].split('"')[1]
        except:
            return None
    
    def __site_8(self, download):
        try:
            data = spawn_read(*download('https://duckduckgo.com?q=what is my ip address'))
            if not data == '':
                self.__isolated = False
            return data.split('"Answer":"Your IP address is ')[1].split(' ')[0]
        except:
            return None