#!/usr/bin/python
# -*- coding: UTF-8 -*-
'''Analyze two linux commands ("ip address" and "ip route" ), show everything
in neat and compact way and update this info every second. This tool maight be
of your interest in times when you are elaborating with netwok and its
configuration.'''

import commands, os, datetime, time

def get_ip(mode):
    '''Return output of "ip a" or "ip r".'''
    return commands.getoutput('ip ' + mode)

def clean_output(txt):
    '''get_ip() fetch output in the way where every letter is followed by 
    newline, we have to filtre it out.'''
    output = []
    line = ''
    
    for letter in txt:
        if letter == '\n':
            output.append(line)
            line = ''
        else:
            line += letter[:1]
    
    output.append(line)
    return output

def get_nterfaces():
    '''Parse from "ip a" command and store it into doc interfaces in usable
    form.'''
    ipa = clean_output(get_ip('a'))
    interfaces = {'keys' : []}
    
    for line in ipa:
        if (line[1:2] == ':') or (line [2:3] == ':'):
            number = int(line.split(':')[0])
            interfaces['keys'].append(number)
            interfaces[number] = {'name' : line.split(':')[1][1:]}
            interfaces[number]['inet']    = []
            interfaces[number]['inet6'] = []
    
        if line.split(' ')[4] == 'inet':
            interfaces[number]['inet'].append(line.split(' ')[5])
            
        if line.split(' ')[4] == 'inet6':
            interfaces[number]['inet6'].append(line.split(' ')[5])

    interfaces['keys'].sort()
    return interfaces

def get_ipr(mode, interfaces):
    '''Parse from "ip r" command and store it into list ipr in usable form.'''
    ipr_all = clean_output(get_ip(mode + ' r'))
    ipr = {}
    
    for number in interfaces['keys']:
        ipr[interfaces[number]['name']] = []
    
    return (ipr, ipr_all)

def get_ipr4(mode, interfaces):
    '''Parse IPv4 addresses.'''
    (ipr, ipr_all) = get_ipr(mode, interfaces)
    
    for line in ipr_all:
        if line[:7] == 'default':
            ipr[line.split('dev')[1].split(' ')[1]].append('0.0.0.0/0')
        else:
            if len(line) > 0:
                ipr[line.split('dev')[1].split(' ')[1]].append(
                line.split(' ')[0])
    
    return ipr

def get_ipr6(mode, interfaces):
    '''Parse IPv6 addresses'''
    (ipr, ipr_all) = get_ipr(mode, interfaces)
    
    for line in ipr_all:
        if line[:7] == 'default':
            ipr[line.split('dev')[1].split(' ')[1]].append('::/0')
        else: 
            if len(line) > 0:
                ipr[line.split('dev')[1].split(' ')[1]].append(
                line.split(' ')[0])
    
    return ipr

def sort_ipr(ipr):
    '''Sort IP addresses.'''
    ipr_mash = []
    
    for route in ipr:
        spl = '.'
        mmask = '32'
        
        if route.find(':') > -1:
            spl = ':'
            mmask = '128'
            route += 's'
            if route.find('::') > -1:
                route = route.replace('::', 'x')
        
        con = mmask if route.find('/') < 0 else (3 - len(
                            route.split('/')[1])) * '0' + route.split('/')[1]
        
        for part in route.split('/')[0].split(spl):
            con += '-' + (4 - len(part)) * '0' + part if spl == ':' else '-' + (
            3 - len(part)) * '0' + part
        
        ipr_mash.append(con)
    
    ipr_mash.sort()
    ipr = []
    
    for route in ipr_mash:
        spl = '.'
        if route.find('s') > -1:
            spl = ':'
            route = route.replace('s', '')
        
        con = ''
        mask = ''
        
        for i in range(len(route.split('-'))):
            part = route.split('-')[i]
            while part.find('0') == 0 and len(part) > 1:
                part = part[1:]
            if i == 0:
                mask = part
            else:
                con += part + spl
        
        con = con[:-1].replace('x', '::') if mask == '' else con[
                                        :-1].replace('x', '::') + '/' + mask
        
        ipr.append(con)
    
    return ipr

def print_inet(inet, txt):
    '''Prepare given inet for print and atach it to previous text.'''
    for ip_address in inet:
        txt += ' ' + ip_address
    return txt

def stuff(txt, max_len):
    '''Stuff spaces for good looking output.'''
    return (max_len - 3 - len(txt.split('/')[0])) * ' ' + txt + (
                                            4 - len(txt.split('/')[1])) * ' '

def print_routes(ipr, txt):
    '''Prepare given routes for print and atach it to previous text.'''
    max_len = len(max(ipr, key=len))
    rows = len(ipr) / 3 + len(ipr) % 3
    
    for i in range(rows):
        txt += ' ' if len(txt) < 11 else '\n                     '
        if i + 2 * rows < len(ipr):
            txt += stuff(ipr[i], max_len) + ' ' + stuff(
                ipr[i+rows], max_len) + ' ' + stuff(ipr[i + 2 * rows], max_len)
        elif i+rows < len(ipr):
            txt += stuff(ipr[i], max_len) + ' ' + stuff(ipr[i + rows], max_len)
        else: txt += stuff(ipr[i], max_len)
    
    return txt

def print_neti(interfaces, ipr4, ipr6):
    '''Print the output.'''
    os.system('clear')
    print datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    
    for number in interfaces['keys']:
        txt =    str(number) + (3-len(str(number))
        ) * ' ' + interfaces[number]['name']
        
        if len(interfaces[number]['inet']) > 0:
            txt += ' inet:'
            txt = print_inet(interfaces[number]['inet'], txt)
        
        if len(interfaces[number]['inet6']) > 0:
            txt += ' inet6:'
            txt = print_inet(interfaces[number]['inet6'], txt)
        
        print txt
        txt = '     routes:'
        ipv4 = ipr4[interfaces[number]['name']]
        ipv6 = ipr6[interfaces[number]['name']]
        if len(ipv4 + ipv6) > 0:
            txt = print_routes(sort_ipr(ipv4) + sort_ipr(ipv6), txt)
        if len(txt) > 10:
            print txt

try:
    while True:
        IFCS = get_nterfaces() #Interfaces
        print_neti(IFCS, get_ipr4('-4', IFCS), get_ipr6('-6', IFCS))
        
        SEC = datetime.datetime.now().strftime("%S")
        while SEC == datetime.datetime.now().strftime("%S"):
            time.sleep(0.1)
except KeyboardInterrupt: # Interrupting by <ctrl+c>
    print ' '

