#!/usr/bin/python3
# LAVA Box Agent for Windows - Copyright 2024 LAVA Controls - Stephen Loeckle

import argparse
import configparser
from lavaboxagentlib import configbuilder, devicereboot, netinfo
import os
import platform
import sqlite3
import sys
import traceback
from datetime import datetime, timedelta
from pathlib import Path

osplatform = platform.system().lower()

if osplatform == 'linux':
    configfile = ('/etc/lavaboxagent/lavaboxagent.conf')
    database = ('/var/lib/lavaboxagent/lavaboxagent.db')
    boxtype = 'display'
elif osplatform == 'windows':
    application_path = os.getcwd()
    configfile = ('{}\\conf\\lavaboxagent.conf'.format(application_path))
    database = ('{}\\db\\lavaboxagent.db'.format(application_path))
    boxtype = 'monitor'
    
def resetconfig(args):

    sysinfo = {}
    sysinfo['SYSTEM'] = {}
    sysinfo['SYSTEM']['LAVABOXAGENTCONFIGFILE'] = configfile

    if args.token:
        configbuilder(sysinfo, token=' ')

def configwork(args):

    sysinfo = {}
    sysinfo['SYSTEM'] = {}
    sysinfo['SYSTEM']['LAVABOXAGENTCONFIGFILE'] = configfile

    if args.token:
        configbuilder(sysinfo, token=args.token[0])
    if args.platform:
        configbuilder(sysinfo, platform=args.platform[0])
    if args.boxtype:
        configbuilder(sysinfo, boxtype=args.boxtype[0])
    if args.interval:
        configbuilder(sysinfo, interval=args.interval[0])
    if args.user:
        configbuilder(sysinfo, user=args.user[0])
    if args.loglevel:
        configbuilder(sysinfo, loglevel=args.loglevel[0])
    if args.smtphost:
        configbuilder(sysinfo, smtphost=args.smtphost[0])
    if args.emailnotification:
        configbuilder(sysinfo, email=args.emailnotification[0])
    if args.browsername:
        configbuilder(sysinfo, browsername=args.browsername[0])
    if args.browserpath:
        configbuilder(sysinfo, browserpath=args.browserpath[0])
    if args.browseroptions:
        configbuilder(sysinfo, browseroptions=args.browseroptions[0])
    if args.fullscreenmode:
        configbuilder(sysinfo, fullscreenmode=args.fullscreenmode[0])
    if args.httpproxy:
        configbuilder(sysinfo, httpproxy=args.httpproxy[0])
    if args.cleartoken:
        configbuilder(sysinfo, token='')
        mymac,myip,myiface = netinfo()
        print('Enter this MAC address into the LAVA platform: {}'.format(mymac))
    configbuilder(sysinfo, )
    if args.cleartoken:
        answer = input("Ready to reboot?")
        if answer.lower() in ["y","yes"]:
            devicereboot()


def dbwork(args):
    createdb = 0
    updatedb = 0
    resetstats = 0
    systemrecords = [['dbinit', 'datenow', 'strvalue'], ['remediation', '', 'strvalue'], ['browserpid', 0, 'value'],
                     ['checkfundamentalsruns', 0, 'value'], ['screenanalysisruns', 0, 'value'], ['activeproblemcount', 0, 'value'],
                     ['activeproblem', '', 'strvalue'], ['startuptime', '', 'strvalue'], ['startup', 1, 'value'], ['shutdown', 0, 'value'],
                     ['cloudcmdshutdowncomplete', 0, 'value'], ['systemanalysisshutdowncomplete', 0, 'value'], ['apishutdowncomplete', 0, 'value'], 
                     ['maintenance', 0, 'value']]
    cloudrecords = [['lastheaddate', '', 'strvalue'], ['lastcommand', 0, 'value'], ['samecommandcount', 0, 'value'], ['cmdtime', 0, 'value'],
                    ['lastupdated', 0, 'value'], ['urlerrors', 0, 'value'], ['gatewayerrors', 0, 'value'], ['lastsystemerror', 'none', 'strvalue']]
    errorsrecords = [['chromenotrunning', 0, 'value'], ['chromewrongsize', 0, 'value'], ['openterminal', 0, 'value'],
                    ['desktopshowing', 0, 'value'], ['chromehungonstartup', 0, 'value'], ['greyscreen', 0, 'value'],
                    ['blackscreen', 0, 'value'], ['singlecolorscreen', 0, 'value'], ['whitescreen', 0, 'value'], ['restorepagesdialog', 0, 'value'],
                    ['pagenotavailable', 0, 'value'], ['pageunresponsive', 0, 'value'], ['awsnap', 0, 'value'], ['whatsnewinchrome', 0, 'value'], ['webglcrash', 0, 'value'],
                    ['badrequest', 0, 'value'], ['500', 0, 'value'], ['503', 0, 'value'],
                    ['nginxerror', 0, 'value'], ['youtubeerror', 0, 'value'], ['sprcmdcenterplaylist', 0, 'value'],
                    ['sprcmdcenterlocked', 0, 'value'], ['videodrivererror', 0, 'value']]
    datenow = datetime.now().strftime('%Y-%m-%d %H:%M:%S')

    if args.clearlogs:
        if os.path.exists(database):
            conn = sqlite3.connect(database)
            c = conn.cursor()
            print('Clearing error logs table')
            c.execute('delete from errorlog')
            print('Error logs table cleared')
            conn.commit()
            conn.close()
        else:
            print('Database does not exist. Creating now.')
            createdb = 1
    if args.maintoff:
        if os.path.exists(database):
            conn = sqlite3.connect(database)
            c = conn.cursor()
            print('Resetting maintenance mode')
            c.execute('UPDATE system SET value = ? WHERE tags = ?', (0, 'maintenance'))
            print('Error logs table cleared')
            conn.commit()
            conn.close()
        else:
            print('Database does not exist. Creating now.')
            createdb = 1
    if args.resetstats:
        if os.path.exists(database):
            conn = sqlite3.connect(database)
            c = conn.cursor()
            print('Clearing error logs table')
            c.execute('delete from errorlog')
            print('Error logs table cleared')
            resetstats = 1
            conn.commit()
            conn.close()
        else:
            print('Database does not exist. Creating now.')
            createdb = 1
    if (not args.resetstats and not args.maintoff and not args.clearlogs):
        if os.path.exists(database):
            if args.force:
                print('Database found. Forcing database overwrite.')
                os.remove(database)
                createdb = 1
            else:
                print('Database found. Looking for Schema Updates.')
                updatedb = 1
        else:
            print('Database not found. Creating.')
            createdb = 1
    if updatedb == 1:
        conn = sqlite3.connect(database)
        c = conn.cursor()
        print('Updating schema.')
        c.execute('create table if not exists system (tags text, value int, strvalue text, td timestamp, notes text)')
        c.execute('create table if not exists cloud (tags text, value int, strvalue text, td timestamp)')
        c.execute('create table if not exists errors (tags text, value int, strvalue text, td timestamp, seq int)')
        c.execute('create table if not exists errorlog (logid integer PRIMARY KEY, tags text, td timestamp, ack int, notes text)')
        conn.commit()
        for (record, data, val) in systemrecords:
            c.execute('SELECT * FROM system WHERE tags = ?', (record,))
            row = c.fetchall()
            if len(row)==0:
                print('    system:{} not found'.format(record))
                if data == 'datenow':
                    c.execute('insert into system (tags, strvalue) values (?, ?) ', (record, datenow))
                    print('        Added system:{}'.format(record))
                elif val == 'value':
                    c.execute('insert into system (tags, value) values (?, ?) ', (record, data))
                    print('        Added system:{}'.format(record))
                elif val == 'strvalue':
                    c.execute('insert into system (tags, strvalue) values (?, ?) ', (record, data))
                    print('        Added system:{}'.format(record))
                else:
                    print('        system:{} failed'.format(record))
#            else:
#                print('    system:{} found'.format(record))
        for (record, data, val) in cloudrecords:
            c.execute('SELECT * FROM cloud WHERE tags = ?', (record,))
            row = c.fetchall()
            if len(row)==0:
                print('    cloud:{} not found'.format(record))
                if val == 'value':
                    c.execute('insert into cloud (tags, value) values (?, ?) ', (record, data))
                    print('        Added cloud:{}'.format(record))
                elif val == 'strvalue':
                    c.execute('insert into cloud (tags, strvalue) values (?, ?) ', (record, data))
                    print('        Added cloud:{}'.format(record))
                else:
                    print('        cloud:{} failed'.format(record))
#            else:
#                print('    cloud:{} found'.format(record))
        for (record, data, val) in errorsrecords:
            c.execute('SELECT * FROM errors WHERE tags = ?', (record,))
            row = c.fetchall()
            if len(row)==0:
                print('    errors:{} not found'.format(record))
                if val == 'value':
                    c.execute('insert into errors (tags, value) values (?, ?) ', (record, data))
                    print('        Added errors:{}'.format(record))
                elif val == 'strvalue':
                    c.execute('insert into errors (tags, strvalue) values (?, ?) ', (record, data))
                    print('        Added errors:{}'.format(record))
                else:
                    print('        errors:{} failed'.format(record))
#            else:
#                print('    errors:{} found'.format(record))
        print('Done.')
        conn.commit()
        conn.close()
    if createdb == 1:
        conn = sqlite3.connect(database)
        c = conn.cursor()
        print('Building schema.')
        c.execute('create table if not exists system (tags text, value int, strvalue text, td timestamp, notes text)')
        c.execute('create table if not exists cloud (tags text, value int, strvalue text, td timestamp)')
        c.execute('create table if not exists errors (tags text, value int, strvalue text, td timestamp, seq int)')
        c.execute('create table if not exists errorlog (logid integer PRIMARY KEY, tags text, td timestamp, ack int, notes text)')
        conn.commit()
        for (record, data, val) in systemrecords:
            if data == 'datenow':
                c.execute('insert into system (tags, strvalue) values (?, ?) ', (record, datenow))
                print('    Added system:{}'.format(record))
            elif val == 'value':
                c.execute('insert into system (tags, value) values (?, ?) ', (record, data))
                print('    Added system:{}'.format(record))
            elif val == 'strvalue':
                c.execute('insert into system (tags, strvalue) values (?, ?) ', (record, data))
                print('    Added system:{}'.format(record))
            else:
                print('    system:{} failed'.format(record))
        for (record, data, val) in cloudrecords:
            if val == 'value':
                c.execute('insert into cloud (tags, value) values (?, ?) ', (record, data))
                print('    Added cloud:{}'.format(record))
            elif val == 'strvalue':
                c.execute('insert into cloud (tags, strvalue) values (?, ?) ', (record, data))
                print('    Added cloud:{}'.format(record))
            else:
                print('    cloud:{} failed'.format(record))
        for (record, data, val) in errorsrecords:
            if val == 'value':
                c.execute('insert into errors (tags, value) values (?, ?) ', (record, data))
                print('    Added errors:{}'.format(record))
            elif val == 'strvalue':
                c.execute('insert into errors (tags, strvalue) values (?, ?) ', (record, data))
                print('    Added errors:{}'.format(record))
            else:
                print('    errors:{} failed'.format(record))
        print('Done.')
        conn.commit()
        conn.close()
    if resetstats == 1:
        conn = sqlite3.connect(database)
        c = conn.cursor()
        print('Resetting stats.')
        for (record, data, val) in cloudrecords:
            c.execute('SELECT * FROM cloud WHERE tags = ?', (record,))
            row = c.fetchall()
            if len(row)==0:
                print('    cloud:{} not found'.format(record))
                if val == 'value':
                    c.execute('insert into cloud (tags, value) values (?, ?) ', (record, data))
                    print('        Added cloud:{}'.format(record))
                elif val == 'strvalue':
                    c.execute('insert into cloud (tags, strvalue) values (?, ?) ', (record, data))
                    print('        Added cloud:{}'.format(record))
                else:
                    print('        cloud:{} failed'.format(record))
            else:
                c.execute('UPDATE cloud SET value = ?, strvalue = ?, td = ? WHERE tags = ?', (0,'','',record))
#                print('    cloud:{} reset'.format(record))           
        for (record, data, val) in errorsrecords:
            c.execute('SELECT * FROM errors WHERE tags = ?', (record,))
            row = c.fetchall()
            if len(row)==0:
                print('    errors:{} not found'.format(record))
                if val == 'value':
                    c.execute('insert into errors (tags, value) values (?, ?) ', (record, data))
                    print('        Added errors:{}'.format(record))
                elif val == 'strvalue':
                    c.execute('insert into errors (tags, strvalue) values (?, ?) ', (record, data))
                    print('        Added errors:{}'.format(record))
                else:
                    print('        errors:{} failed'.format(record))
            else:
                c.execute('UPDATE errors SET value = ?, strvalue = ?, td = ?, seq = ? WHERE tags = ?', (0,'','',0,record))
#                print('    errors:{} reset'.format(record))
        print('Done.')
        conn.commit()
        conn.close()

def main():

    parser = argparse.ArgumentParser(description='LAVA Box Agent Setup')
    subparsers = parser.add_subparsers()
    
    parser_db = subparsers.add_parser('db')
    parser_db.add_argument('-f', '--force', help = 'Force overwrite on database', action="store_true")
    parser_db.add_argument('-cl', '--clearlogs', help = 'Empty errorlogs table', action="store_true")
    parser_db.add_argument('-mo', '--maintoff', help = 'Force maintenance mode off', action="store_true")
    parser_db.add_argument('-rs', '--resetstats', help = 'Reset stats in errors table', action="store_true")
    parser_db.set_defaults(func=dbwork)
    
    parser_config = subparsers.add_parser('config')
    parser_config.add_argument('-ct', '--cleartoken', help = 'Clear authorization token.', action="store_true")
    parser_config.add_argument('-t', '--token', help = 'Set authorization token.', nargs=1)
    parser_config.add_argument('-p', '--platform', help = 'Set platform. Options are lava or lava-dev', nargs=1)
    parser_config.add_argument('-b', '--boxtype', help = 'Set box type.', choices=['display','control'], nargs=1)
    parser_config.add_argument('-i', '--interval', help = 'Set cloud check interval.', nargs=1)
    parser_config.add_argument('-u', '--user', help = 'Set run-as user.', nargs=1)
    parser_config.add_argument('-log', '--loglevel', help = 'Set loglevel.', choices=[10,20,30,40,50], nargs=1)
    parser_config.add_argument('-smtp', '--smtphost', help = 'Set smtp host.', nargs=1)
    parser_config.add_argument('-e', '--emailnotification', help = 'Set email notification parameter.', nargs=1)
    parser_config.add_argument('-bn', '--browsername', help = 'Set browser name, e.g. chrome.', nargs=1)
    parser_config.add_argument('-bp', '--browserpath', help = 'Set browser path, e.g. /usr/bin/google-chrome', nargs=1)
    parser_config.add_argument('-bo', '--browseroptions', help = 'Set browser options (must be in quotes), e.g. --disable-session-crashed-bubble --disable-infobars --kiosk http://lucidnetworks.net', nargs=1)
    parser_config.add_argument('-fs', '--fullscreenmode', help = 'Set browser full screen mode. 0 for no full screen, 1 for standard full screen, 2 for kiosk mode', nargs=1)
    parser_config.add_argument('-hp', '--httpproxy', help = 'Set network http proxy, e.g. http://proxy.lavaboxagent.com:8080 (This will cover http and https proxy environment variable)', nargs=1)
    parser_config.set_defaults(func=configwork)
    
    args = parser.parse_args()
    
    if len(sys.argv) == 1:
        parser.print_help()
    else:
        args.func(args)

if __name__ == '__main__':
   main()

