#!/usr/bin/env python3
# -*- coding: utf-8 -*-

#**************************************************************************
#   Copyright (C) 2017, Paul Lutus                                        *
#                                                                         *
#   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 2 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, write to the                         *
#   Free Software Foundation, Inc.,                                       *
#   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
#**************************************************************************

import os
import re
import base64
import getpass
import requests
import ezodf

def read_file(path):
  with open(path) as f:
    return f.read()

def write_file(path, data):
  with open(path, 'w') as f:
    f.write(data)

# quits the program if no entry

def user_input(prompt):
  result = input(prompt).strip()
  if result:
    return result
  print("No entry, quitting.")
  quit()


# returns true on success

def ping_device(device, wait=300):
  return os.system('ping -c 1 -w %d %s > /dev/null 2>&1' % (wait, device)) == 0

# change these values as required

router_name_prefix = 'pl-wireless'

router_name_suffix = user_input('Which router (a-d):')

ping_url = '%s-%s' % (router_name_prefix, router_name_suffix)

# verify router is online

if not ping_device(ping_url, 3):
  print("router %s not online, quitting." % ping_url)
  quit()

password = getpass.getpass('Enter router password:')

# change username as required

user_pw_str = 'root:%s' % password

# this is the source for the encoded user:password datum

authorization = base64.b64encode(user_pw_str.encode()).decode('ascii')

# construct HTTP URL for target router

base_url = 'http://%s' % ping_url

# get a session instance to avoid having to copy state
# from one router acccess to another

rs = requests.session()

# the following two items -- 'Cookie' and 'Referer' --
# are all that are required to access the router
# any number of times

rs.headers['Cookie'] = 'Authorization=Basic%20' + authorization

# the Referer item tells the router that the network
# accesses are emanating from the router itself

rs.headers['Referer'] = base_url

# Router access 1: test login validity

response = rs.get(base_url)

# quit if login test fails

if re.search('(?i)username or password is incorrect', response.text):
  print('Wrong username and/or password, quitting.')
  quit()

print('Username and password validated with %s, continuing.' % ping_url)

# change the spreadsheet document name/path as required

ss_doc_name = 'name_MAC_IP_master_list.ods'

print("Reading spreadsheet %s ..." % ss_doc_name)

doc = ezodf.opendoc(ss_doc_name)

sheet = doc.sheets[0]

first_record = True

for record in sheet.rows():
  # first spreadsheet record contains field names
  if first_record:
    ss_names = [field.value for field in record]
    # use field names as keys to fields
    ss_data = {name:[] for name in ss_names}
    first_record = False
  else:
    # move record data
    name_iter = iter(ss_names)
    for field in record:
      ss_data[next(name_iter)].append(field.value)

print('Creating name/ip data arrays ...')

data_dict = {}

mac_iter = iter(ss_data['MAC'])
ip_iter = iter(ss_data['IP'])

for name in ss_data['Name']:
  mac = next(mac_iter)
  ip = next(ip_iter)
  # verify that the record contains non-empty fields
  if name and mac and ip:
    # create reliably sortable IP string
    long_ip = '.'.join([ns.zfill(3) for ns in re.findall(r'\d+', ip)])
    # t-link routers require a nonstandard mac syntax: : -> -
    router_mac = re.sub(':', '-', mac)
    # data_dict uses sortable long form ip address
    data_dict[long_ip] = [ip, name, mac, router_mac]

# Router access 2: wipe any existing reserved address list

print('Deleting all prior reserved addresses in %s ...' % ping_url)

url = "%s/userRpm/FixMapCfgRpm.htm?doAll=DelAll&Page=1" % base_url
rs.get(url)

# create hosts_insert data
hosts_insert = "# this data insert created by %s\n" % os.path.realpath(__file__)

table_content = ''

# Router access 3: create new reserved address list

print('Creating new reserved addresses in %s ...' % ping_url)

total = 0
for long_ip in sorted(data_dict):
  ip, name, mac, router_mac = data_dict[long_ip]
  hosts_insert += "%-16s %12s %12s.com\n" % (ip, name, name)
  s = "Name: %-18s MAC: %s IP: %s" % (name, mac, long_ip)
  print(s)
  table_content += "%s\n" % s
  # exclude router from reserved address list
  if not re.search(router_name_prefix, name):
    url = '%s/userRpm/FixMapCfgRpm.htm' % base_url + \
    '?Mac=%s&Ip=%s&State=1&Changed=0' % (router_mac, ip) + \
    '&SelIndex=0&Page=1&Save=Save'
    rs.get(url)
    total += 1

print('Created %d reserved addresses in %s.' % (total, ping_url))

write_file('name_mac_ip_table.txt', table_content)

# insert generated IP/name list into the system "hosts" file
# which contains insertion comment marks:
# # BEGIN_INSERT and # END_INSERT

# change this path as required

hosts_path = '/netbackup/data/python_projects/hosts_file/hosts_base_do_not_delete'

hosts = read_file(hosts_path)
hosts = re.sub('(?s)(?<=# BEGIN_INSERT\n)(.*?)(?=# END_INSERT)', hosts_insert, hosts)
write_file(hosts_path, hosts)

# Router access 4: reboot router

response = user_input('Okay to reboot router %s (y/n): ' % ping_url)

if response.lower() == 'y':
  reboot_url = "%s/userRpm/SysRebootRpm.htm?Reboot=Reboot" % base_url
  rs.get(reboot_url)

print('Router %s rebooted, done.' % ping_url)
