#!/usr/bin/python3

############################################################################################################################
# Setting up the program
############################################################################################################################

# These are the generic imports that are imported for a cgi file. Not sure if they're all relevant here


import cgitb
import cgi
import pandas as pd
from scipy.stats import gennorm
import math
import numpy
import datetime
import json
import sqlite3
from db import *
from globalSettings import *
from global_func import *
print("Content-type:/text/html\r\n\r\n")


cgitb.enable()

# These are the imports from demo_mode_comb_profiled.py


device = DeviceName
# Connect to the Database

conn = sqlite3.connect(DBPath)
conn.text_factory = str
c = conn.cursor()

# Path to where the csv file will be saved

#path = "pilot/demographs/"
path = demoGraphs

# Decide whether the script will be run using the GUI, CCM, or neither

true = 0
false = 1

GUI = true

if(GUI == true):
    form = cgi.FieldStorage()
    request_Type = form.getvalue('requestType')

else:
    print("1. Create csv files")

    choice = int(input("select cgi Function===>"))
    if choice == 1:
        request_Type = 'create_csv'

    else:
        print("Enter Valid choice")

    print("Request_Type="+str(request_Type))


############################################################################################################################
# Defining Lorentzian_lineshape()
############################################################################################################################


def Lorentzian_lineshape(x_range, gamma):

    # Return Lorentzian line shape at x with HWHM gamma

    return gamma / numpy.pi / (x_range**2 + gamma**2)


############################################################################################################################
# Defining gaussian()
############################################################################################################################

def gaussian(x, mu, sig):

    # Spectrum-shaping

    return numpy.exp(-numpy.power(x - mu, 2.) / (2 * numpy.power(sig, 2.)))


############################################################################################################################
# Defining demo_mode_comb()
############################################################################################################################

def demo_mode_comb(central_wavelength, FSR, nb_tones):

    # Constant Values

    optical_power = 1
    linewidth = 0.3

# Path to where the csv file will be saved

    comb_name = "comb_demo_mode_" + str(datetime.datetime.now())
    comb_name = "comb_demo_mode_example_1000p"
    comb_full_path = path + comb_name + ".csv"

# central_wavelength (nm), FSR = (GHz), optical_power(mW), linewidth = (MHz)

    # gamma is linewidth/2 and in GHz units
    gamma = float(linewidth) / 2 / 1e3
    # in GHz
    resolution = 0.2
    # total number of points per tone
    points = float(FSR) / resolution
    # divided by 125 to change into nm
    spacing_nm = float(FSR) / 125
    # x-axis for one comb tone - therefore, tone_span is from -spacing_nm/2 to spacing_nm/2
    tone_span = numpy.linspace(-spacing_nm / 2, spacing_nm / 2, int(points))
    # spectra of one tone with a Lorentzian profile
    Lorentzian_tone_spectra = Lorentzian_lineshape(tone_span, gamma)

    x = tone_span
    y = Lorentzian_tone_spectra

    for i in range(nb_tones - 1):
        x1 = tone_span + (i + 1) * spacing_nm
        x = numpy.append(x, x1)
        y = numpy.append(y, Lorentzian_tone_spectra)

    # shift whole spectrum to central_wavelength
    x = [j + central_wavelength - (nb_tones - 1) * spacing_nm / 2 for j in x]
    # normalize spectrum amplitude
    y = [j * optical_power / max(y) for j in y]
    # y = [10 * math.log10(j) for j in y]                                                                                    # change to dB

# Shape to comb-bandwidth profile

    beta = 3.5
    x2 = numpy.linspace(-2, 2, len(x))
    comb_filter = gennorm.pdf(x2, beta)
    comb_filter = [j * optical_power / max(comb_filter) for j in comb_filter]
    y = numpy.multiply(y, comb_filter)
    y = [10 * math.log10(j) for j in y]

# Filter values above -40 dB

    ind = [i for i in range(len(y)) if y[i] > -60]
    y = [y[i] for i in ind]
    x = [x[i] for i in ind]

# Saves the data to a .csv file

    data = [x, y]
    data = pd.DataFrame(data).T
    data.to_csv(comb_full_path, index=False, header=False)

    print((json.JSONEncoder().encode(
        {"status": "success", "description": "Successfully Created"})))


############################################################################################################################
# Defining demo_mode_demux()
############################################################################################################################

def demo_mode_demux(central_wavelength, FSR, nb_tones, demux_set_tone, index):

    # Constant Values

    demux_set_power = 1
    demux_smsr = 30
    linewidth = 0.3

# Path to where the csv file will be saved

    demux_name = "demux" + str(index)
    demux_full_path = path + demux_name + ".csv"

#central_wavelength (nm), FSR (GHz), optical_power (mW), linewidth (MHz), demux_set_power (mW), demux_smsr (dB)

    # gamma is linewidth/2 and in GHz units
    gamma = float(linewidth) / 2 / 1e3
    # in GHz
    resolution = 0.1
    points = float(FSR) / resolution
    # divided by 125 to change into nm
    spacing_nm = float(FSR) / 125

    # x-axis for one tone - therefore, tone_span is from -spacing_nm/2 to spacing_nm/2
    tone_span = numpy.linspace(-spacing_nm / 2, spacing_nm / 2, int(points))
    # spectrum of one tone with a Lorentzian profile
    Lorentzian_tone_spectra = Lorentzian_lineshape(tone_span, gamma)

    # demux tone Lorentzian lineshape
    demux_tone_y = Lorentzian_tone_spectra
    # normalize spectrum amplitude
    demux_tone_y = [j * demux_set_power /
                    max(demux_tone_y) for j in demux_tone_y]
    demux_tone_y_dB = [10 * math.log10(j) for j in demux_tone_y]
    # demux_x = [j + central_wavelength + demux_set_tone*spacing_nm - (nb_tones-1)*spacing_nm/2 for j in tone_span]          #shifts spectrum to correct wavelength

    # maximum power in dBm of a suppressed comb tone
    max_power_suppressed = max(demux_tone_y_dB) - demux_smsr
    # in mW
    max_power_suppressed_mW = 10 ** (max_power_suppressed / 10)
    # creates Lorentzian profile of a suppressed tone
    tones_suppressed = [j * max_power_suppressed_mW /
                        max(Lorentzian_tone_spectra) for j in Lorentzian_tone_spectra]
    # in dB
    tones_suppressed_dB = [10 * math.log10(j) for j in tones_suppressed]

# Build demux full spectrum

    demux_spectrum = demux_tone_y_dB
    demux_x = tone_span

    for i in range(nb_tones):

        if(i < demux_set_tone):
            demux_spectrum = numpy.append(tones_suppressed_dB, demux_spectrum)
            x1 = tone_span + (i + 1) * spacing_nm
            demux_x = numpy.append(demux_x, x1)

        elif (i >= demux_set_tone):
            demux_spectrum = numpy.append(demux_spectrum, tones_suppressed_dB)
            x1 = tone_span + (i + 1) * spacing_nm
            demux_x = numpy.append(demux_x, x1)

    # shift whole spectrum to central_wavelength
    demux_x = [j + central_wavelength -
               (nb_tones - 1) * spacing_nm / 2 for j in demux_x]

    x_values = numpy.linspace(
        demux_x[0], demux_x[len(demux_x) - 1], len(demux_x))
    Gaussian = gaussian(x_values, central_wavelength - (nb_tones - 1)
                        * spacing_nm / 2 + demux_set_tone * spacing_nm, 1)
    # in dB
    Gaussian_dB = [10 * math.log10(j) for j in Gaussian]
    demux_spectrum_shaped = [a + 15 * b for a,
                             b in zip(demux_spectrum, Gaussian_dB)]

# filter values above -50 dB

    ind = [i for i in range(len(demux_spectrum_shaped))
           if demux_spectrum_shaped[i] > -50]
    demux_spectrum_shaped = [demux_spectrum_shaped[i] for i in ind]
    demux_x = [demux_x[i] for i in ind]

# Saves the data to a .csv file

    data = [demux_x, demux_spectrum_shaped]
    data = pd.DataFrame(data).T
    data.to_csv(demux_full_path, index=False, header=False)

    print((json.JSONEncoder().encode(
        {"status": "success", "description": "Successfully Created"})))


############################################################################################################################
# Defining form_getvalue()
############################################################################################################################

def form_getvalue(val):

    # Allows the user to enter a value for different components

    if val == "central_wavelength":
        central_wavelength = int(
            eval(input("Enter the central wavelength value in nm: ")))
        return central_wavelength

    if val == "FSR":
        FSR = int(eval(input("Enter the FSR value in GHz: ")))
        return FSR

    if val == "demux_set_tone":
        demux_set_tone = int(
            eval(input("Enter the Set Tone " + str(count) + " value: ")))
        return demux_set_tone


############################################################################################################################
# Calling the relevant function
############################################################################################################################


# Values are called / chosen depending on if GUI == true

if(request_Type == 'create_csv'):
    if(GUI == true):  # Not sure how to interface with GUI
        k = 1
        #central_wavelength = form.getvalue("central_wavelength")
        #FSR = form.getvalue("FSR")
        #nb_tones = int(round((200 / (k * FSR))))
        id = form.getvalue("id")
        central_wavelength = form.getvalue("demo_wavelength")
        FSR = int(form.getvalue("demo_FSR"))
        if FSR != 0:
            nb_tones = int(round((200 / (k * FSR))))
        else:
            nb_tones = 0

        demuxMapId = form.getvalue("id")
        demo_demux_power = form.getvalue("set_power")
        # demux_set_tone = form.getvalue("set_tone")### Sandhya This must be list of TONES for each demux what we select we demo mode

        demux_set_tone1 = form.getvalue("demux_set_tone1")
        demux_set_tone2 = form.getvalue("demux_set_tone2")
        demux_set_tone3 = form.getvalue("demux_set_tone3")
        demux_set_tone4 = form.getvalue("demux_set_tone4")
        demux_set_tone_list = [demux_set_tone1,
                               demux_set_tone2, demux_set_tone3, demux_set_tone4]
    else:
        k = 1
        central_wavelength = form_getvalue("central_wavelength")
        FSR = form_getvalue("FSR")
        if FSR != 0:
            nb_tones = int(round((200 / (k * FSR))))
        else:
            nb_tones = 0

        demux_set_tone_list = []
        count = 1

        for i in range(1, 5):
            demux_set_tone = form_getvalue("demux_set_tone")
            demux_set_tone_list.append(demux_set_tone)
            count += 1

# Call demo_mode_comb

    # print("\n")
    #print("Comb (demo_mode)")
    demo_mode_comb(int(central_wavelength), FSR, nb_tones)

# Call demo_mode_demux four times

    for i in demux_set_tone_list:
        # print("\n")
        index = demux_set_tone_list.index(i) + 1
        #print("Demux " + str(index) + " (demo_mode)")
        demo_mode_demux(int(central_wavelength), FSR, nb_tones, int(i), index)
