#!/usr/bin/python3
from netaddr import IPNetwork
#from netaddr import IPAddress
from xmlrpc.client import ServerProxy
import sqlite3
import socket
import csv
import queue
import threading
import sys
import http.client

WORKERS = 10

if len(sys.argv) == 1:
    Nets = [
       '10.250.48.0/27',
       '10.250.48.32/27',
       '10.250.48.64/27',
       '10.250.48.96/27',
       '10.250.48.128/27',
       '10.250.48.160/27',
       '10.250.49.0/27',
       '10.250.49.32/27',
       '10.250.49.64/27',
       '10.250.49.128/27',
       '10.250.49.160/27',
       '10.250.50.0/27',
       '10.250.50.32/27',
       '10.250.50.65/27',
       '10.250.50.96/27',
       '10.250.50.128/27',
       '10.250.50.160/27',
       '10.250.50.192/27',
       '10.250.50.224/27',
       '10.250.51.0/27',
       '10.250.51.32/27',
       '10.250.51.64/27',
       '10.250.51.96/27',
       '10.250.51.128/27',
       '10.250.52.0/27',
       '10.250.52.32/27',
       '10.250.52.64/27',
       '10.250.52.96/27',
       '10.250.52.128/27',
       '10.250.52.160/27',
       '10.250.52.192/27'
        ]
else:
    Nets = sys.argv[1:]

#Nets = [
    #'10.250.48.0/27']

#print((Nets))

Settings = [
       'Site-Name',
       'Site-Notes',
       'Serial-Number',
       'Float-Voltage',
       'Operating-Voltage',
       'Battery-Capacity',
       'AC-Rectifier-Current-Limit',
       'High-Float-Threshold',
       'Enable-Active-Voltage-Control',
       'Enable-Temperature-Compensation',
       'Temperature-Compensation-Slope',
       'Temperature-Compensation-Reference-Temperature',
       'Temperature-Compensation-Upper-Limit',
       'Temperature-Compensation-Lower-Limit',
       'Enable-Equalize',
       'Equalize-Voltage',
       'Equalize-Duration',
       'Enable-Fast-Charge',
       'Fast-Charge-Voltage',
       'Fast-Charge-Voltage-Threshold',
       'Fast-Charge-Ampere-Hour-Threshold',
       'Fast-Charge-Recharge-Percentage',
       'Fast-Charge-Maximum-Duration',
       'Fast-Charge-Ampere-Hour-Stop-Threshold',
       'Enable-Battery-Current-Limit',
       'BCL-Limit',
       'Enable-Battery-Test',
       'Battery-Test-Duration',
       'Battery-Test-Termination-Voltage',
       'LVD-Disconnect-Voltage:1',
       'LVD-Reconnect-Voltage:1',
       'Number-Of-Registered-Rectifiers',
       'Number-Of-Rectifiers-Failed'
    ] + \
    ['Alarm-Name:' + repr(x) for x in range(59)] + \
    ['Alarm-Severity:' + repr(x) for x in range(59)]
#Settings = [
    #'Site-Name'
    #]


def Setup():
    db.execute('''CREATE TABLE SettingsValues (
    IP TEXT,
    SettingsID TEXT,
    Value TEXT)''')

    #db.execute('''CREATE TABLE Settings (
    #ID INTEGER PRIMARY KEY,
    #Name TEXT UNIQUE)''')

    #db.execute('''CREATE TABLE SC200 (
    #IP text PRIMARY KEY,
    #SiteName text,
    #SiteNotes text,
    #SerialNumber text,
    #FloatVoltage float,
    #OperatingVoltage float,
    #BatteryCapacity int,
    #ACRectifierCurrentLimit int,
    #HighFloatThreshold float,
    #EnableActiveVoltageControl bool,
    #EnableTemperatureCompensation bool,
    #TemperatureCompensationSlope float,
    #TemperatureCompensationReferenceTemperature float,
    #TemperatureCompensationUpperLimit float,
    #TemperatureCompensationLowerLimit float,
    #EnableEqualize bool,
    #EqualizeVoltage float,
    #EqualizeDuration int,
    #EnableFastCharge bool,
    #FastChargeVoltage float,
    #FastChargeVoltageThreshold float,
    #FastChargeAmpereHourThreshold int,
    #FastChargeRechargePercentage int,
    #FastChargeMaximumDuration int,
    #FastChargeAmpereHourStopThreshold int,
    #EnableBatterCurrentLimit bool,
    #BCLLimit int,
    #EnableBatterTest bool,
    #BatteryTestDuration int,
    #BatteryTestTerminationVoltage float,
    #LVDDisconnectVoltage float,
    #LVDReconnectVoltage float,
    #NumberOfRegisteredRectifiers int,
    #NumberOfRectifiersFailed int
    #)''')

    #SQL = '''CREATE TABLE AlarmNames (
    #SiteIP text primary key'''
    #for x in range(59):
        #SQL = SQL + ', Alarm' + repr(x) + ' text'
    #SQL = SQL + ')'

    #db.execute(SQL)

    #SQL = '''CREATE TABLE AlarmSeverities (
    #SiteIP text primary key'''
    #for x in range(59):
        #SQL = SQL + ', Alarm' + repr(x) + ' int'
    #SQL = SQL + ')'

    #db.execute(SQL)


def GetStatusCode(host, path="/"):
    try:
        conn = http.client.HTTPConnection(host)
        conn.request("GET", path)
        return conn.getresponse().status
    except Exception:
        return None


class Worker(threading.Thread):

    def __init__(self, IPs, Results):
        self.__IPs = IPs
        self.__Results = Results
        self.parent = threading.current_thread()
        threading.Thread.__init__(self)

    def run(self):
        retry = False
        socket.setdefaulttimeout(5)
        while 1:
            IP = self.__IPs.get()
            if IP is None:
                self.__Results.put(None)
                break

            if GetStatusCode(str(IP), "/languages") == 200:
                print((self.getName() + ' processing: ' + str(IP)))
                while True:
                    proxy = ServerProxy('http://%s/xmlrpc' % IP)
                    try:
                        Values = proxy.db.get(Settings)
                    except socket.timeout:
                        retry = True
                        continue

                    if retry:
                        retry = False
                    else:
                        break

                if len(Values) > 0:
                    Values.insert(0, str(IP))
                    self.__Results.put(Values)
            else:
                print((self.getName() + ' skipping: ' + str(IP)))


def Output():
    Count = WORKERS
    fieldNames = ['IP'] + Settings

    with open('/tmp/sc200.csv', 'w', newline='') as outFile:
        csvWriter = csv.DictWriter(outFile, fieldnames=fieldNames,
            delimiter=',', quotechar='"',
            quoting=csv.QUOTE_MINIMAL)

        csvWriter.writeheader()

        while 1:
            Row = Results.get()
            if Row is None:
                if Count > 1:
                    Count -= 1
                    #print(Count)
                else:
                    break
            else:
                csvWriter.writerow(dict(list(zip(fieldNames, Row))))

        outFile.close()


IPs = queue.Queue(0)
Results = queue.Queue(0)

for i in range(WORKERS):
    Worker(IPs, Results).start()

for SubNet in Nets:
    Net = IPNetwork(SubNet)

    for IP in Net:
        if ((IP != Net.network and IP != Net.broadcast) or
        Net.broadcast is None):
            IPs.put(IP)

for i in range(WORKERS):
    IPs.put(None)

if threading.current_thread() is not threading.main_thread():
    sys.exit(0)

Output()

sys.exit(0)

