{% load i18n static %}

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>IOP4</title>

    <link rel="shortcut icon" type="image/png" href="{% static 'favicon.ico' %}"/>
    
    <link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined" rel="stylesheet" />

    <!-- Vue.js -->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/3.4.9/vue.global.prod.min.js" integrity="sha512-CP6yhSirAJn9qCZWv/TQSa6oZ+sgOZ95I5HmFTxStR/n/8NAmyKoqstZEZPlQ/aPmRJNOvvF3omnxuPn1g4aew==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>    <!-- QUASAR - vue.js (stylesheets) -->
    <link href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900|Material+Icons|Material+Icons+Outlined" rel="stylesheet" type="text/css">
    <script src="https://cdn.jsdelivr.net/npm/quasar@2.12.5/dist/icon-set/material-icons-outlined.umd.prod.js"></script>
    <link href="https://cdn.jsdelivr.net/npm/quasar@2.12.5/dist/quasar.prod.css" rel="stylesheet" type="text/css"> 

    <!-- Tabulator -->
    <link href="https://unpkg.com/tabulator-tables@5.4.2/dist/css/tabulator.min.css" rel="stylesheet">
    <script type="text/javascript" src="https://unpkg.com/tabulator-tables@5.4.2/dist/js/tabulator.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.5.1/jspdf.umd.min.js" integrity="sha512-qZvrmS2ekKPF2mSznTQsxqPgnpkI4DNTlrdUmTzrDgektczlKNRRhy5X5AAOnx5S09ydFYWWNSfcEqDTTHgtNA==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf-autotable/3.5.25/jspdf.plugin.autotable.min.js" integrity="sha512-SgWewGM3r8xXm8LNXt4ZHqKVKu/7eKrJ1aBCbMaX44xXXaCcIvCAvD2kj9qnC1lhyjAu04mcPiTzcc/CaACnUQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>

    <!-- jquery gui required for bokeh datatable reorder -->
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script> 
    <link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/jqueryui/1.13.2/themes/smoothness/jquery-ui.css"> 
    <script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.13.2/jquery-ui.min.js"></script> 

    <!-- Bokeh -->
    <script src="https://cdn.bokeh.org/bokeh/release/bokeh-3.2.2.min.js"></script>
    <script src="https://cdn.bokeh.org/bokeh/release/bokeh-widgets-3.2.2.min.js"></script>
    <script src="https://cdn.bokeh.org/bokeh/release/bokeh-tables-3.2.2.min.js"></script>
    <script src="https://cdn.bokeh.org/bokeh/release/bokeh-api-3.2.2.min.js"></script>
    <script src="https://cdn.bokeh.org/bokeh/release/bokeh-gl-3.2.2.min.js"></script>
    <script src="https://cdn.bokeh.org/bokeh/release/bokeh-mathjax-3.2.2.min.js"></script>

    <!-- CSS styles and JS -->
    <link rel="stylesheet" href="{% static "iop4api/base.css" %}?datetime={% now "Y-m-d-Hi" %}">
    <script src="{% static "iop4api/gui.js" %}?datetime={% now "Y-m-d-Hi" %}"></script>
</head>

<body>
    <div id="app">

        <div id="navbar">
            <div id="site-header">
                <h1><a href="https://vhega.iaa.es/iop4">IOP4</a></h1>
                <div>
                    <h2><a href="https://vhega.iaa.es/">VHEGA@IAA-CSIC</a></h2>
                    {% if debug and request.user.is_authenticated %}
                        <span style="color: red;">DEBUG*</span>
                    {% endif %}
                </div>
            </div>
            
            <q-tabs v-model="selectedTabs[0]" class="tab-navigator" id="site-nav" inline-label outside-arrows >

                <q-tab name="about" label="about" icon="rocket_launch"></q-tab>

                {% if request.user.is_authenticated %}
                    <q-tab name="explore" label="explore" icon="search" ></q-tab>
                {% endif %}

                {% if not request.user.is_authenticated %} 
                    <q-tab name="login" label="login" icon="login" ></q-tab>
                {% else %}
                    <a href="{% url 'iop4admin:index' %}"><q-tab label="admin" icon="admin_panel_settings" ></q-tab></a>
                    <a href="{% url 'iop4api:logout_view' %}"><q-tab label="logout" icon="logout" ></q-tab></a>
                {% endif %}

            </q-tabs>
        </div>

        <div id="appBody" class="tab-container">
            
            <div v-show="selectedTabs[0] == 'about'" class="tab-content" id="about-tab"> 
                {% include 'iop4api/about.html' %}
            </div>

            <div v-show="selectedTabs[0] == 'login'" class="tab-content" id="login-tab"> 
                {% include 'iop4api/login.html' %}
            </div>

            {% if request.user.is_authenticated %}
                <div v-show="selectedTabs[0] == 'explore'" class="tab-content" id="explore-tab">
                    {% include 'iop4api/explore.html' %}
                </div>
            {% endif %}
            
        </div>
    </div>

    <!-- QUASAR - vue.js -->

    <script src="https://cdn.jsdelivr.net/npm/quasar@2.12.5/dist/quasar.umd.prod.js"></script>
    
    <script>
        const log_files = JSON.parse('{{ log_files | escapejs }}');
        const tab_tree = JSON.parse('{{ tab_tree | escapejs }}');
        const { ref } = Vue
        
        C1selectedTab_0 = {% if 'C1selectedTab' in tabs %} "{{ tabs.C1selectedTab }}" {% else %} "about" {% endif %};
        C2selectedTab_0 = {% if 'C2selectedTab' in tabs %} "{{ tabs.C2selectedTab }}" {% else %} "plot" {% endif %};

        vueApp = Vue.createApp({
            delimiters: ['[[', ']]'],
            data() {
                return {
                    //tabs 
                    selectedTabs: [C1selectedTab_0, C2selectedTab_0],
                    // log
                    logEntries: [],
                    // plot
                    showPlot: false,
                    plot_config_fast: true,
                    enable_full_lc: false,
                    enable_crosscheckpts: false,
                    enable_errorbars: false,
                    use_hostcorrected: false,
                    plot_config_band: 'R',
                    plot_config_band_options: ['R', 'V', 'B', 'U', 'I'],
                    // plot (flagging)
                    selected_plot_idx: [],
                    show_selected_plot_pts: false,
                    selected_refresh: 0,
                    flag_gui_popup: false,
                    // data
                    showDataTable: false,
                    showDataTableFilters: false,
                    DataTableFilters: [],
                    tableData: null,
                    // catalog
                    catalog: null,
                    // query
                    input_astrosource: '',
                    // logs
                    pipeline_log: {'isLoaded': false, 'items': null, 'items_filtered': null, 'filter_in_progress': false},
                    pipeline_log_options: {'errors':true, 
                                           'warnings':true, 
                                           'info':true, 
                                           'debug':false, 
                                           'filter_text': null,},
                    log_file: 'iop4.log',
                    log_files: log_files,
                }
            },
            computed: {
                bokeh_document() {
                    return Bokeh.documents.slice(-1)[0];
                },
                bokeh_source: {
                    get() {
                        if (this.bokeh_document == null) {
                            return null;
                        } else {
                            return this.bokeh_document.get_model_by_name('source').data;
                        }
                    },
                    set(newValue) {
                        new Error('bokeh_source is read-only');
                    }
                },
                selected_plot_pts() {

                    console.log("Computing selected_plot_pts");

                    console.log("this.selected_refresh", this.selected_refresh++);

                    // Ensure that selected_plot_idx is reactive and triggers this computed property
                    const newIndices = this.selected_plot_idx;

                    // Get the last document in the Bokeh documents array
                    const bokehDocument = Bokeh.documents.slice(-1)[0];
                    if (!bokehDocument) {
                        console.log("no bokeh document");
                        return [];
                    }

                    // Get the data source from the Bokeh document by its name
                    const dataSource = bokehDocument.get_model_by_name('source').data;
                    if (!dataSource) {
                        console.log("no data source");
                        return [];
                    }

                    // If the flag GUI is activated, show the popup table
                    if (this.flag_gui_popup) {
                        this.show_selected_plot_pts = true;
                    }

                    // Use map to transform the indices into an array of point data
                    return newIndices.map(index => {
                        let pointData = {};
                        for (let field in dataSource) {
                            if (dataSource.hasOwnProperty(field)) {
                                pointData[field] = dataSource[field][index];
                            }
                        }

                        // add fake but useful flag str representation field
                        pointData['flagsstr'] = flags_to_str(pointData['flags']);

                        // to make it easier
                        pointData['has_flag_bad_photometry'] = (pointData['flags'] & (1<<1));
                        pointData['has_flag_bad_polarimetry'] = (pointData['flags'] & (1<<2));

                        return pointData;
                    });
                },
                selected_plot_pts_flagsummary() {
                    if (this.selected_plot_pts.length == 0) {
                        notset = null;
                        bad_photometry = null;
                        bad_polarimetry = null;
                    } else {
                        if (this.selected_plot_pts.every(pt => (pt['flags'] === 0))) {
                            notset = true;
                        } else if (this.selected_plot_pts.some(pt => (pt['flags'] === 0))) {
                            notset = null;
                        } else {
                            notset = false;
                        }

                        if (this.selected_plot_pts.every(pt => (pt['flags'] & (1<<1)))) {
                            bad_photometry = true;
                        } else if (this.selected_plot_pts.some(pt => (pt['flags'] & (1<<1)))) {
                            bad_photometry = null;
                        } else {
                            bad_photometry = false;
                        }

                        if (this.selected_plot_pts.every(pt => (pt['flags'] & (1<<2)))) {
                            bad_polarimetry = true;
                        } else if (this.selected_plot_pts.some(pt => (pt['flags'] & (1<<2)))) {
                            bad_polarimetry = null;
                        } else {
                            bad_polarimetry = false;
                        }
                    }

                    return {notset:notset, bad_photometry:bad_photometry, bad_polarimetry:bad_polarimetry};
                }
            },
            watch: {
                // Watch for changes in selectedTabs
                selectedTabs: {
                    handler(newTabs, oldTabs) {
                        this.updateURL();

                        // Handling specific cases based on the new tab selections
                        if (newTabs.length > 0) {
                            // first level tab
                        }
                        if (newTabs.length > 1) {
                            const newVal = newTabs[1]; // second level tab

                            if (this.catalog == null && newVal === 'catalog') {
                                load_catalog();
                            }
                            if (this.pipeline_log.items == null && newVal === 'logs') {
                                this.pipeline_log.items = [];
                                this.pipeline_log.items_filtered = [];
                                load_pipeline_log.bind(this)();
                            }
                        }
                    },
                    deep: true,
                    immediate: true,
                },
                // log viewer gui
                pipeline_log_options: {
                    handler(newValue, oldValue) {
                        format_pipeline_logs();
                    },
                    deep: true
                },
                log_file: {
                    handler(newValue, oldValue) {
                        console.log('log_file changed to ' + newValue);
                        this.pipeline_log.items = [];
                        this.pipeline_log.items_filtered = [];
                        load_pipeline_log.bind(this)();
                    },
                },
                // data table filters
                DataTableFilters: {
                    handler(newValue, oldValue) {
                        // get only filters with non empty field and type
                        let filter_array = newValue.filter(function (el) {
                            return el.field != '' && el.type != '';
                        });

                        // interpret some filters
                        filter_array = Array.from(filter_array).map(function (e) { 
                            let field = e.field;
                            let type = e.type;
                            let value = e.value;

                            // debug 
                            console.log('input [field, type, value] = ' + [field, type, value]); // debug
            
                            if (value === '') { // if empty, null (works with = or != default filters)
                                value = null;
                            } else if (type != 'after') { // if values can be numbers, fix type
                                if (!isNaN(value) && !isNaN(Number(value))) {
                                    value = Number(value);
                                }
                            }

                            // debug
                            console.log(`was interpreted as [${field}, ${type}, ${value}] = [${field}, ${type}, ${value}] (${typeof value})`); // debug

                            return {'field':field, 'type':type, 'value':value};
                });

                        // get tabulator table
                        let table = Tabulator.findTable('#tableDiv')[0];

                        // set new filters or clear them if there are none
                        if (filter_array.length == 0) {
                            table.clearFilter();
                        } else {
                            table.setFilter(filter_array);
                        }

                    },
                    deep: true
                },
            },
            methods: {
                updateURL() {
                    // Start forming the new URL based on the selected tabs
                    let newURL = '/iop4/';

                    let currentTabTree = tab_tree;
                    
                    for (let i = 0; i < this.selectedTabs.length; i++) {
                            const tab = this.selectedTabs[i];
                            if (tab in currentTabTree) {
                            newURL += `${tab}/`;
                            currentTabTree = currentTabTree[tab];
                        } else {
                            // Set to the first key in the object as default if not matching
                            if (Object.keys(currentTabTree).length > 0) {
                                const defaultTab = Object.keys(currentTabTree)[0];
                                newURL += `${defaultTab}/`;
                                currentTabTree = currentTabTree[defaultTab];
                                this.selectedTabs[i] = defaultTab;
                            } else {
                                // No sub-levels, so don't set anything
                            }
                        }
                    }

                    window.history.pushState({}, '', newURL);
                },
                updateSelectedTabFromPath() { 
                    // Called when the URL changes (e.g. back/forward button)
                    const path = window.location.pathname;
                    const segments = path.split('/').filter(Boolean);
                    
                    let currentTabTree = tab_tree;

                    // Skip the first segment if it's "iop4"
                    const startIndex = segments[0] === 'iop4' ? 1 : 0;

                    for (let index = startIndex; index < segments.length; index++) {
                        const segment = segments[index];
                        if (segment in currentTabTree) {
                        this.selectedTabs[index - startIndex] = segment;
                        currentTabTree = currentTabTree[segment];
                        }
                    }
                },
                // Add a new entry to the log
                addLogEntry(title, content, log_title=null) {
                    if (title != null) {
                        Quasar.Notify.create(title);
                    }
                    this.logEntries.push({
                        title: (log_title != null)? log_title : title,
                        dateTime: getCurrentDateTime(),
                        content: content,
                    });
                },
                // catalog
                catalog_row_clicked(evt,row) {
                    this.input_astrosource = row.name;
                },
                // also make some gui.js available inside vue
                // flagging
                toggle_flag,
                set_flag,
                // logs,
                load_pipeline_log,
                is_log_visible,
                format_pipeline_logs,
                // to format floats to give precision or return nan
                formatFloat(value, precision) {
                    if (value === null || isNaN(Number(value))) {
                        return 'NaN';
                    }
                    return Number(value).toFixed(precision);
                },
            },
            beforeMount() {
                this.updateSelectedTabFromPath();
            },
            mounted() {
                window.addEventListener('popstate', () => {
                    this.updateSelectedTabFromPath();
                });
            }
        }).use(Quasar).mount('#app')

    </script>

</body>
</html>
