#!/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))


def Setup():
    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)
        #print ('Started')
        while 1:
            IP = self.__IPs.get()
            #print((self.getName()))
            if IP is None:
                self.__Results.put(None)
                #print('Exiting')
                break

            #s = socket.socket()
            #if s.connect_ex((str(IP), 80)) == 0:
            if GetStatusCode(str(IP), "/languages") == 200:
                print((self.getName() + ' processing: ' + str(IP)))
                #print(('Socket OK: %s' % IP))
                #print(('%s' % IP))
                while True:
                    proxy = ServerProxy('http://%s/xmlrpc' % IP)
                    try:
                        Values = proxy.db.get([
                           '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'
                       ])
                    except socket.timeout:
                        retry = True
                        continue

                    if retry:
                        retry = False
                    else:
                        break

                if len(Values) > 0:
                    Values.insert(0, str(IP))
                    self.__Results.put(['SC200', Values])

                    AlarmNames = ['Alarm-Name:' + repr(x) for x in range(59)]
                    while True:
                        try:
                            Values = proxy.db.get(AlarmNames)
                        except socket.timeout:
                            retry = True
                            continue

                        if retry:
                            retry = False
                        else:
                            break

                    Values.insert(0, str(IP))

                    self.__Results.put(['AlarmNames', Values])

                    AlarmSeverities = ['Alarm-Severity:' + repr(x)
                    for x in range(59)]
                    Values = proxy.db.get(AlarmSeverities)

                    Values.insert(0, str(IP))

                    self.__Results.put(['AlarmSeverities', Values])
            #s.close()
            else:
                print((self.getName() + ' skipping: ' + str(IP)))


def Loader():
    Count = WORKERS
    c = db.cursor()

    while 1:
        Row = Results.get()
        if Row is None:
            if Count > 1:
                Count -= 1
                print(Count)
            else:
                break
        else:
            print(('Loading: %s %s' % (Row[1][0], Row[0])))
            SQL = 'INSERT INTO %s VALUES (' % Row[0]
            for i in Row[1]:
                SQL += '?,'
            SQL = SQL[:-1]
            SQL += ')'

            c.execute(SQL, Row[1])
    db.commit()


def Output():
    c = db.cursor()
    with open('/tmp/sc200.csv', 'w', newline='') as outFile:
        csvWriter = csv.writer(outFile, delimiter=',', quotechar='"',
            quoting=csv.QUOTE_MINIMAL)
        c.execute('''SELECT * FROM SC200 ORDER BY IP''')
        csvWriter.writerow([col[0] for col in c.description])
        for row in c:
            csvWriter.writerow(row)
    outFile.close()

    with open('/tmp/sc200-alarms.csv', 'w', newline='') as outFile:
        csvWriter = csv.writer(outFile, delimiter=',', quotechar='"',
            quoting=csv.QUOTE_MINIMAL)
        c.execute('''SELECT * FROM AlarmNames LIMIT 1''')
        for row in c:
            csvWriter.writerow(row)
        c.execute('''SELECT * FROM AlarmSeverities''')
        for row in c:
            csvWriter.writerow(row)
    outFile.close()

db = sqlite3.connect(':memory:')
#db = sqlite3.connect('/tmp/sc200.db')

Setup()
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:
            #print(('Queued: ' + str(IP)))
            IPs.put(IP)

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

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

Loader()
Output()

sys.exit(0)

