# from msilib.schema import tables
from sqlite3 import dbapi2
import xml.etree.cElementTree as ET
from flask import Flask, url_for, jsonify, render_template, request, redirect, logging, send_file
import flask
from flask_login import LoginManager, UserMixin, login_user, logout_user, login_required
import multiprocessing.connection as mp_con
import time
import json
import os, sys
import numpy
import string

base_dir = '../../'
output_dir = base_dir + 'OutputResults/'

ServeFilePath = 'server_main'
SamplesPath = ServeFilePath + '/Samples/'
DataPath = ServeFilePath + '/DataDir/'
OutputPath = ServeFilePath + '/OutputResults/'
ResultsQueue = ServeFilePath + '/ResultsQueue/'

sys.path.append(base_dir)
from ProcessResultsStorage import get_db, select_from, read_rows_from_db, read_rows_from_db_compare, get_combos, get_runs
from ProcessResults import cycle_slip_analysis
from mutils import vd2arr

# Get para from config.xml
config_XML = ET.parse(base_dir+"config.xml")
spirent_host_IP = config_XML.find('SpirentSimultor/HostIP').text
spirent_host_port = config_XML.find('SpirentSimultor/Port').text
jamming_host_IP = config_XML.find('JammingSource/HostIP').text
jamming_host_port = config_XML.find('JammingSource/Port').text
control_port = int(config_XML.find('control_port').text)
web_port = int(config_XML.find('web_addr').text.split(':')[-1])
web_notes = config_XML.find('web_notes').text

# Communicate with RunAntiJam.py
msg_addr = ('localhost',control_port)

app = Flask(__name__)
LOG = flask.logging.create_logger(app)

# make sure OrderedDict() is honored by jsonify()
app.config['JSON_SORT_KEYS'] = False

app.config["SECRET_KEY"] = "SOME_SECRET"
login_manager = LoginManager(app)
login_manager.init_app(app)


class User(UserMixin):
    # proxy for a database of user:password
    user_database = {"Stinger": "StingerTeam"}

    def __init__(self, username, password):
        self.id = username
        self.name = username
        self.password = password

    @classmethod
    def get_valid_user(cls, username, password):
        try:
            if cls.user_database[username] == password:
                return cls(username, password)
        except:
            pass
        return None

    @classmethod
    def get(cls,name):
        return cls.user_database.get(name)

@login_manager.user_loader
def load_user(user_id):
    pw = User.get(user_id)
    if pw is None:
        return None
    else:
        return User(user_id,pw)

@app.route('/logout')
def logout():
    logout_user()
    return flask.redirect(flask.url_for('main'))

@app.route('/login', methods=['GET', 'POST'])
def login():
    try:
        username = request.form['Username']
        password = request.form['Password']
    except:
        return flask.render_template('login.html')

    user = User.get_valid_user(username,password)
    if user is not None:
        flask.session.permanent = True
        login_user(user)
        return flask.redirect(flask.url_for('main'))
    return flask.redirect(flask.url_for('login'))


def msg_send_recv( x ):
    '''Inputs:  x = string - message to be sent to client
              msg_addr = string - client ip address
    '''  
    result = {}
    try:
        client = mp_con.Client(msg_addr)
        client.send(x)
        result = client.recv()
        client.close()
    except:
        LOG.warning("msg_send_recv error {}".format(x))
        print("msg_send_recv error {}".format(x))
        pass
    return result

def msg_send( x ):
    client = mp_con.Client(msg_addr)
    client.send(x)
    client.close()

@app.route("/site-map")
def siteMap():
    '''Return url with .../api/... not in order
    '''
    data_dict = {}
    for rule in app.url_map.iter_rules():
      options = {}
      for arg in rule.arguments:
        options[arg] = "[{0}]".format(arg)
      methods = ','.join(rule.methods)
      url = url_for(rule.endpoint, **options)
      line = str("{:s} {:s} {:s}".format(url, rule.endpoint, methods))
      key =  str("{:s}".format(url))
      print(key, len(key) > 4)
      if len(key) > 4 and key[:4] == '/api':
        data_dict[ str("{:s}".format(url)) ] = str("{:s}".format(methods))
    host_url = request.host_url
    return render_template('site_map.html', data=data_dict, host=host_url[:-1])

@app.route("/site-map2")
def siteMap2():
    '''Return all url
    '''
    data_dict = {}
    f = open('app.py','r')
    fs = f.readlines()
    for l in fs:
        if l[:len('@app.route(')] == '@app.route(':
            ch = '"' if l.find('"') != -1 else  "'"
            url = l.split(ch)[1]
            data_dict[ str("{:s}".format(url)) ] = ""
    host_url = request.host_url
    return render_template('site_map.html', data=data_dict, host=host_url[:-1])

@app.route("/getRegressionDiag")
def getRegressionDiag():
    rt = msg_send_recv(['getRegressionDiag'])
    return rt

@app.route("/getRegressionDetail")
def getRegressionDetail():
    d = {}
    d.update( msg_send_recv(['getRegressionInfo']) )
    d.update( msg_send_recv(['getRegressionProgress']) )
    d.update( msg_send_recv(['getRegressionStopStatus']) )
    print(d)
    return jsonify(d)

@app.route("/putUserRequest", methods=['POST'])
@login_required
def putUserRequest():
    d = {}
    d['name'] = request.form['name']
    d['desc'] = request.form['desc']
    seconds_left = 0
    try:
        seconds_left = int(request.form['hours'])*60*60
    except:
        pass
    d['end_time'] = time.strftime("%a, %d %b %Y %H:%M:%S",
                                  time.localtime(time.time()+seconds_left))
    msg_send(['userInfo',d])
    return "This is some response.  Hello " + json.dumps(d)

@app.route("/getUserStatus")
def getUserStatus():
    d = msg_send_recv(['getUserInfo'])
    return jsonify(d)

@app.route("/api/kill")
def kill():
    msg_send(['kill'])
    return redirect(url_for("siteMap2"))

@app.route("/api/getConfigInfo")
def getConfigInfo():
    rt = msg_send_recv(['getConfigInfo'])
    return jsonify( rt )

@app.route("/api/getScenarioDefConfig")
def getScenarioDefConfig():
    return send_file("scenario_defconfigs.json")

@app.route("/api/getGlobalDefConfig")
def getGlobalDefConfig():
    return send_file("global_defconfigs.json")

# Get Spirent Simulator Info
@app.route("/api/getSpirentSimulatorStatus")
def getSpirentSimulatorStatus():
    rt = msg_send_recv(['getSpirentSimulatorStatus'])
    return jsonify( rt )

@app.route("/api/getSpirentSimulationTOW")
def getSpirentSimulationTOW():
    rt = msg_send_recv(['getSpirentSimulationTOW'])
    return jsonify( rt )

@app.route("/api/getSpirentScenario")
def getSpirentScenario():
    rt = msg_send_recv(['getSpirentScenario'])
    return jsonify( rt )

# Get Jamming Device Info
@app.route("/api/getHP8648CStatus/<gpib_address>")
def getHP8648CStatus(gpib_address):
    rt = msg_send_recv(['getHP8648CStatus', gpib_address])
    return jsonify( rt )

@app.route("/api/getDAT64LStatus/<com_port>")
def getDAT64LStatus(com_port):
    rt = msg_send_recv(['getDAT64LStatus', com_port])
    return jsonify( rt )

@app.route("/api/getChirpStatus")
def getChirpStatus():
    rt = msg_send_recv(['getChirpStatus'])
    return jsonify( rt )

@app.route("/api/getHackRFStatus")
def getHackRFStatus():
    rt = msg_send_recv(['getHackRFStatus'])
    return jsonify( rt )

# Get random frequency list for scenario 11b
@app.route("/api/getRandomFrequencyList")
def getRandomFrequencyList():
    '''Usage example:
        fermion.eng.trimble.com:10004/api/getRandomFrequencyList?random_seed=221&start_freq_MHz=1555&stop_freq_MHz=1625&n_points=10
    '''
    random_seed = request.args.get("random_seed")
    start_freq_MHz = request.args.get('start_freq_MHz')
    stop_freq_MHz = request.args.get('stop_freq_MHz')
    n_points = request.args.get('n_points')
    rt = msg_send_recv(['getRandomFrequencyList', random_seed, start_freq_MHz, stop_freq_MHz, n_points])
    return jsonify( rt )

# For feature to stop current run and do post-processing
@app.route("/api/stopAndWrapUpRun", methods=['POST'])
def stopAndWrapUpRun():
    rt = msg_send_recv(['stopAndWrapUpRun'])
    return jsonify( rt )

# For antenna switch
@app.route("/api/switchAntenna/<ant_id>", methods=['POST'])
def switchAntenna(ant_id):
    rt = msg_send_recv(['switchAntenna',ant_id])
    return jsonify( rt )

@app.route("/api/getAntennaSwitchStatus", methods=['GET'])
def getAntennaSwitchStatus():
    rt = msg_send_recv(['getAntennaSwitchStatus'])
    return jsonify( rt )

# For standpoint switch
@app.route("/api/switchStandpoint/<ant_id>", methods=['POST'])
def switchStandpoint(ant_id):
    rt = msg_send_recv(['switchStandpoint',ant_id])
    return jsonify( rt )

@app.route("/api/getStandpointSwitchStatus", methods=['GET'])
def getStandpointSwitchStatus():
    rt = msg_send_recv(['getStandpointSwitchStatus'])
    return jsonify( rt )

# Mainly used to check .timg with full path exist or not on server
@app.route("/api/checkFileExist")
def checkFileExist():
    full_file_path = request.args.get("fpath")
    print(request.args)
    rt = msg_send_recv(['checkFileExist', full_file_path])
    return jsonify( rt )

@app.route("/api/checkFilesExist")
def checkFilesExist():
    full_file_path_list = request.args.getlist('fpath_list[]')
    files_exist = True
    files_exist_list = []
    for fs in full_file_path_list:
        print(fs)
        rt = msg_send_recv(['checkFileExist', fs])
        files_exist = files_exist and rt
        files_exist_list.append(rt)
    print(files_exist_list)
    data = {
        "fpath_list" : full_file_path_list,
        "fpath_list_exist" : files_exist_list
    }
    return jsonify( data )

@app.route("/api/listDataDir")
def listDataDir():

    rt = {}
    rt['all_runs'] = []

    # 1. Reading run_num =[0,190] from path/json for historical old data
    # rt = msg_send_recv(['listDataDir'])
    
    # 2. Reading run info from from db to speed up
    try:
        db = get_db()
    except:
        return jsonify( rt )
    
    all_runs = []
    with get_db() as db:
        db_c = db.cursor()

        # 2a. Load table NOTES_DESCS
        rows_notes = select_from(db_c, 'NOTES_DESC', [])
        # print('rows_notes', rows_notes)
        d_notes = {}
        for row in rows_notes:
            d_notes[row['notes_ID']] = row['notes']

        rows_from_db = get_runs(db_c, 'SD_ALL_RESULTS', 250)
        
        for data in rows_from_db:
            rx_run = 'RX'+str(data['rx_num'])+'-'+str(data['run_num'])
            curr = {}
            curr['start_time'] = data['run_date']
            curr['data_dir'] = rx_run
            curr['scn_id'] = data['scenario_ID']
            curr['freq_type'] = data['freq_type']
            if os.path.isfile(f'../../DataDir/{rx_run}/humanReadableOutlier.txt'):
                curr['summary_path'] = f'{rx_run}/humanReadableOutlier.txt'
            elif os.path.isfile(f'../../DataDir/{rx_run}/humanReadableOutlier.txt'):
                curr['summary_path'] = f'{rx_run}/humanReadable.txt'
            else:
                curr['summary_path'] = ""
            # curr['notes'] = data['notes']
            curr['notes'] = d_notes[data['notes_ID']]
            curr['desc'] = 'desc?'
            curr['results_queue'] = './ResultsQueue/' + rx_run + '.xml'
            curr['output_results'] = './OutputResults/' + rx_run
            all_runs.append(curr)                
    
    return jsonify( all_runs )

@app.route("/putRegression", methods=['POST'])
@login_required
def putRegression():
    d = msg_send_recv(['getRegressionInfo'])
    if request.form['action']=="kill" and d['status'] == "Running":
        msg_send(['kill'])
    return "OK"

@app.route("/putRegressionList", methods=['POST'])
@login_required
def putRegressionList():
    d = msg_send_recv(['getRegressionInfo'])
    # receiver_status = msg_send_recv(['getReceiverInfo'])
    # print("DEBUG", request.form['run_list'])

    if d['status'] != "Running":

        try:
            n_loop = int(request.form['n_loop'])
            if n_loop < 0:
                raise ValueError
        except ValueError:
            return "Invalid # of run"

        skip_build = True if 'skip_build' in request.form else False
        skip_reboot = True if 'skip_reboot' in request.form else False
        skip_post = True if 'skip_post' in request.form else False
        run_list_json_to_dict = json.loads(request.form['run_list'])
        
        send_list = ['playList', run_list_json_to_dict, n_loop, skip_build, skip_reboot, skip_post]
        # print('Send:')
        # print(send_list[2:])
        # print(send_list[1])
        msg_send(send_list)

    return "OK"

@app.route("/getJammingDeviceInfo", methods=['GET'])
@login_required
def getJammingDeviceInfo():
    jamming_device_status = msg_send_recv(['getJammingDeviceInfo'])
    return jamming_device_status

@app.route("/")
def main():
    user_status = msg_send_recv(['getUserInfo'])
    regression_status = msg_send_recv(['getRegressionInfo'])
    receiver_status = msg_send_recv(['getReceiverInfo'])
    jamming_device_status = msg_send_recv(['getJammingDeviceInfo'])
    return render_template("index.html",
                           web_notes=web_notes,
                           usage=user_status,
                           receiver=receiver_status,
                           jamming_device=jamming_device_status,
                           regression=regression_status)

@app.route("/regression.html")
def regression():
    status = msg_send_recv(['getRegressionInfo'])
    progress = msg_send_recv(['getRegressionProgress'])
    return render_template("regression.html", status=status, progress=progress)

# render receivers top to bottom then left to right, assuming 2 columns.
def rearrange_devices(devs):
    n = len(devs)
    y = range(n)
    return [x for x,_ in sorted(zip(devs,y), key=lambda xy: [xy[1]%(n/2), xy[1]] )]

@app.route("/resultlist.html")
def result():
    info = {}
    info['test_type'] = 'default'
    return render_template("resultlist.html",
                           info=info,
                           url_root=request.url_root,
                           DataPath=DataPath,
                           OutputPath=OutputPath,
                           ResultsQueue=ResultsQueue
                          )

def getMenuOptions():
    '''
        Return menu_data = eg. {"1":{"GPS": {"L1": ["CA"], "L2": ["E"]}, "GLN": {"L1": ["CA"], "L2": ["CA"]}, "Gal": {"L1": ["BOC_1_1_DP_MBOC"]}}}
    '''
    menu_data = {}

    # Method 1: load from output_dir + '/menu.json'
    # menu_file = output_dir + '/menu.json'
    # if os.path.isfile(menu_file):
    #     # Load current menu optiones
    #     with open(menu_file, "r") as jsonFile:
    #         menu_data = json.load(jsonFile)
    # print('Method 1: menu_data',menu_data)

    # Method 2: load menu combos from table ALL_COMBOS in db
    try:
        db = get_db()
    except:
        return menu_data
    
    with get_db() as db:
        db_c = db.cursor()
        rows_notes = select_from(db_c, 'ALL_COMBOS', [])
        for row in rows_notes:
            if row['scenario_ID'] not in menu_data:
                menu_data[row['scenario_ID']] = {}
            if row['sat_type'] not in menu_data[row['scenario_ID']]:
                menu_data[row['scenario_ID']][row['sat_type']] = {}
            if row['band'] not in menu_data[row['scenario_ID']][row['sat_type']]:
                menu_data[row['scenario_ID']][row['sat_type']][row['band']] = []
            if row['track'] not in menu_data[row['scenario_ID']][row['sat_type']][row['band']]:
                menu_data[row['scenario_ID']][row['sat_type']][row['band']].append(row['track'])
    # print('Method 2: menu_data',menu_data)
    keys = [x for x in menu_data]
    keys.sort() # key = lambda x: (int(x[0])))
    for k in keys:
        print(k, menu_data[k])
    return menu_data


@app.route("/results.html")
def results():
    info = {}
    all_info = msg_send_recv(['getTestFileInfoAll'])
    info['tests'] = [ test[0]+') '+test[1].replace('\n',',')+': '+test[-1] for test in all_info['tests'] ]
    info['desc'] = request.args.get('desc')
    info['run_para'] = request.args.get('run_para')
    info['st_type'] = request.args.get('st_type')
    info['band'] = request.args.get('band')
    info['track'] = request.args.get('track')
    info['menu'] = getMenuOptions()
    # print("info['menu'] :",info['menu'])
    return render_template("results.html",
                           info=info,
                           url_root=request.url_root,
                           DataPath=DataPath,
                           OutputPath=OutputPath
                          )


@app.route("/results_comparison.html")
def results_comparison():
    info = {}
    all_info = msg_send_recv(['getTestFileInfoAll'])
    info['tests'] = {}
    for test in all_info['tests']:
        info['tests'][test[0]] = {}
        info['tests'][test[0]]['name'] = test[1]
        info['tests'][test[0]]['desc'] = test[-1]
        
    info['desc'] = request.args.get('desc')
    info['run_para'] = request.args.get('run_para')
    info['st_type'] = request.args.get('st_type')
    info['band'] = request.args.get('band')
    info['track'] = request.args.get('track')
    info['menu'] = getMenuOptions()
    info['combos'] = get_combos()

    with open("alert_thresholds.json") as f:
        thresholds = json.load(f)
    # print("info['menu'] :",info['menu'])
    return render_template("results_comparison.html",
                           info=info,
                           url_root=request.url_root,
                           DataPath=DataPath,
                           OutputPath=OutputPath,
                           thresholds=thresholds
                          )


@app.route("/test_cycle_slips.html")
def test_cs():
    sy_para = request.args.get('sy', 0, type=int)
    freq_para = request.args.get('freq', 0, type=int)
    t04 = '/mnt/data_drive/Run_Test_Automation_Website/DataDir/RX0-1466/rcvr.T04'
    d,k = (vd2arr(t04, '-d35:19'))
    print(d[:,1])
    out1, out2 = cycle_slip_analysis(d, k, rec='-d35:19',sy=sy_para,freq=freq_para,track=[0],intervals=[[432300,432350], [432350, 432400], [432400, 432450], [432450, 432500]  ])
    out1 = [str(elem) for elem in out1]
    out2 = [str(elem) for elem in out2]
    print(out1)
    print(out2)

    return f"<img src=test_cycle_slips.png></br>" + \
           f"antenna 0:</br> {'</br>'.join(out1)}</br>" + \
           f"antenna 1:</br> {'</br>'.join(out2)}"

@app.route("/test_cycle_slips.png")
def test_cs_png():
    return flask.current_app.send_static_file('GPS_L1_cycle_slip.png')


@app.route("/setup.html")
def setup():
    receiver_status = msg_send_recv(['getReceiverInfo'])
    # receiver_status['devs'] = rearrange_devices(receiver_status['devs'])
    # regression_status = msg_send_recv(['getRegressionInfo'])
    return render_template("setup.html",
                           url_root=request.url_root,
                           receiver=receiver_status
                          )


@app.route("/text_setup.html")
def text_setup():
    receiver_status = msg_send_recv(['getReceiverInfo'])
    # receiver_status['devs'] = rearrange_devices(receiver_status['devs'])
    # regression_status = msg_send_recv(['getRegressionInfo'])
    json_file = open('scenario_defconfigs.json')
    return render_template("text_setup.html",
                           url_root=request.url_root,
                           receiver=receiver_status,
                           scenarios=json.load(json_file)
                          )

def to_pretty_json(value):
    return json.dumps(value, indent=2)

app.jinja_env.filters['tojson_pretty'] = to_pretty_json

@app.route("/getResults", methods=['GET','POST'])
def getResults():
    """Each element in all_data.json is for a single receiver and a single test.
    The web wants data for a single test but _all_ receivers.  This function
    goes through the data and formats it for web display.
    """

    want_desc = request.form['desc']
    want_scn_num = want_desc.split(')')[0]                  # compare with eg. data['test_num']
    want_run_para = request.form['run_para']                # compare with eg. data['test_para_default']
    want_st_type = request.form['st_type']                  # compare with eg. data['stats']['sd']['GPS']
    want_band = request.form['band']                        # compare with eg. data['stats']['sd']['GPS']
    want_track = request.form['track']                      # compare with eg. data['stats']['sd']['GPS']
    want_filters = request.form.getlist('selected_filters') # compare with data['filter_type']
    
    print('want_st_type\t',want_st_type)
    print('want_band\t',want_band)
    print('want_track\t',want_track)
    print('want_scn_num\t',want_scn_num)
    # print('want_filters\t',want_filters)

    d = {}

    # Load data from db
    # Filter by want_st_type, want_band, want_track, want_scn_num, want_filters
    mask = []
    mask.append( 'version=1.1')
    mask.append( 'scenario_ID='+'\''+str(want_scn_num)+'\'' )
    mask.append( 'sat_type='+'\''+str(want_st_type)+'\'')
    mask.append( 'band='+'\''+str(want_band)+'\'')
    mask.append( 'track='+'\''+str(want_track)+'\'')
    mask.append( 'valid='+'\''+str(1)+'\'')
    if want_run_para == 'Default':
        mask.append( 'default_para=\'1\'' )
    elif want_run_para == 'Modified':
        mask.append( 'default_para=\'0\'' )
    if len(want_filters) > 0:
        mask_by_filter_type = '(' + ' OR '.join(['rx_filter_type='+'\''+x+'\'' for x in want_filters]) + ')' 
        mask.append( mask_by_filter_type )
    
    # Novatel OEM 729 is single antenna receiver, which does not have data to be plotted. eg. S.D. CNo
    mask.append( 'rx_type!=\''+'novatel'+'\'' )

    d = {}

    read_rows_from_db(d, mask)

    # print(json.dumps(d, indent=2))
    return jsonify(d)


@app.route("/getResultsComparison", methods=['GET','POST'])
def getResultsComparison():
    """Each element in all_data.json is for a single receiver and a single test.
    The web wants data for a single test but _all_ receivers.  This function
    goes through the data and formats it for web display.
    """

    receivers = ['RX0', 'RX1', 'RX2', 'RX3', 'RX4', 'RX5', 'RX6', 'RX7', 'RX8','RX9','RX10','RX11','RX12','RX13']
    formatting_errors = []

    # Get user inputted query string and format to remove whitespace and lowercase
    test_group_str = request.form['test_groups']
    test_group_str = ''.join([c for c in test_group_str if c not in string.whitespace])
    test_group_str = test_group_str.upper()

    # Each ; separates a different group
    test_groups = []
    test_group_receivers = test_group_str.split(';')
    for receiver in test_group_receivers:
        
        # Each group must have the RX followed by a - then the ranges
        rx_runs = receiver.split('-')
        if len(rx_runs) < 2:
            formatting_errors.append(
                f"'{receiver}' - Formatting error: Missing '-'"
            )
            continue
        if len(rx_runs) > 2:
            formatting_errors.append(
                f"'{receiver}' - Formatting error: Too many '-' in group"
            )
            continue
        
        # Receiver must be in the list of known receivers
        rx = rx_runs[0]
        if rx not in receivers:
            formatting_errors.append(
                f"'{receiver}' - Formatting error: No such receiver"
            )
            continue

        # You can have multiple ranges separated by ,
        runs = rx_runs[1].split(',')
        for run in runs:
            
            # Each range can be a singleton, or start:end
            range = run.split(':')
            if len(range) > 2:
                formatting_errors.append(
                    f"'{receiver}' - Formatting error: Multiple ':' in range"
                )
                continue
            elif len(range) == 2 and int(range[1]) < int(range[0]):
                formatting_errors.append(
                    f"'{receiver}' - Formatting error: Start is greater than end"
                )
                continue
            else:
                test_groups.append((rx[2:], range))

    # Load data from db
    # Filter by want_st_type, want_band, want_track, want_filters
    mask = []
    
    mask.append( "version=1.1" )
    
    mask.append( "(" + 
        ' OR '.join([
          f"(rx_num={tg[0]} AND run_num={tg[1][0]})" if len(tg[1]) == 1 else
          f"(rx_num={tg[0]} AND run_num>={tg[1][0]} AND run_num<={tg[1][1]})" for
          tg in test_groups 
        ]) + 
      ")"
    ) 

    mask.append( "valid='1'" )
    
    # Novatel OEM 729 is single antenna receiver, which does not have data to be plotted. eg. S.D. CNo
    mask.append( "rx_type!='novatel'" )

    d = {}
    read_rows_from_db_compare(d, mask)
    d['warnings'] = formatting_errors
    print(json.dumps(d, indent=2))
    return jsonify(d)


@app.route("/getTestFileInfoAll")
def getTestFileInfoAll():
    tests = msg_send_recv(['getTestFileInfoAll'])
    return jsonify(tests)


@app.route('/%s'%ServeFilePath, defaults={'req_path': ''})
@app.route('/%s/'%ServeFilePath, defaults={'req_path': ''})
@app.route('/%s/<path:req_path>'%ServeFilePath)
def dir_listing(req_path):
    # Joining the base and the requested path
    abs_path = os.path.join(base_dir, req_path)

    # Return 404 if path doesn't exist
    if not os.path.exists(abs_path):
        return flask.abort(404)

    # Check if path is a file and serve
    if os.path.isfile(abs_path):
        return flask.send_file(abs_path)

    def sizeof_fmt(num, suffix='B'):
        for unit in ['','Ki','Mi','Gi','Ti','Pi','Ei','Zi']:
            if abs(num) < 1024.0:
                return "%3.1f%s%s" % (num, unit, suffix)
            num /= 1024.0
        return "%.1f%s%s" % (num, 'Yi', suffix)

    # Show directory contents
    files = []
    for filename in sorted(os.listdir(abs_path)):
        # Append / if it is missing
        if abs_path.endswith('/'):
            abs_filename = abs_path + filename
        else:
            abs_filename = abs_path + '/' + filename

        curr_file = {}
        if os.path.isfile(abs_filename):
            curr_file['type'] = 'text'
            curr_file['name'] = filename
        else:
            curr_file['type'] = 'folder'
            curr_file['name'] = filename
            if not curr_file['name'].endswith('/'):
                curr_file['name'] += '/'
        curr_file['time'] = time.ctime(os.path.getmtime(abs_filename))
        curr_file['size'] = sizeof_fmt(os.path.getsize(abs_filename))
        files.append(curr_file)

    return render_template(
        'files.html',
        path=os.path.abspath(abs_path),
        url_root=request.url_root,
        base_url=request.base_url,
        files=files
    )

if __name__ == "__main__":
    app.run(host='0.0.0.0',port=web_port,debug=True,threaded=True)
