#!/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
import csv
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 = demoGraphs
#path = "/var/www/pilot/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 = zip(x, y)
    # data = pd.DataFrame(data).T
    # data.to_csv(comb_full_path, index=False, header=False)
    with open(comb_full_path, 'w', newline='') as csvfile:
        writer = csv.writer(csvfile)
        for row in data:
            writer.writerow(row)

    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)
    data = zip(demux_x, demux_spectrum_shaped)
    with open(demux_full_path, 'w', newline='') as csvfile:
        writer = csv.writer(csvfile)
        for row in data:
            writer.writerow(row)
    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)
