<commit_before>// @flow weak

// Components
import { FiltersMenu } from './FiltersMenu';
import { LineChart } from './LineChart';
import { TrendsAPI } from './TrendsAPI';

// Types
import type { Term, Geo, Filter } from './types'

// Data
import { dummyData, terms, countries } from './util.js';

// Libraries
import * as d3 from 'd3';
import selectize from 'selectize';
import $ from 'jquery'; 

//Styles
import 'selectize/dist/css/selectize.css';

export class Explore {

  data: {
    prevDiseases: Term[],
    diseases: Term[],
    prevGeo: Geo,
    geo: Geo,
    seasonal: {date: Date, value: number}[],
    trend: {date: Date, value: number}[],
    total: {date: Date, value: number}[],
    isMerged: boolean,
    isLoading: boolean
  };

  keepShinyAlive: () => {};
  
  diseaseSelect: HTMLElement;
  geoSelect: HTMLElement;
  loaderContainer: HTMLElement;
  confirmNav: HTMLElement;
  mergeButton: HTMLElement;

  seasonalChart: LineChart;
  trendChart: LineChart;
  trendsAPI: TrendsAPI;

  constructor(parentContainer: HTMLElement, data) {
    if (data) {
      this.data = data;
    } else {
      this.data = {
        prevDiseases: [],
        diseases: [],
        prevGeo: countries[0],
        geo: countries[0],
        seasonal: [],
        trend: [],
        total: [],
        isMerged: false,
        isLoading: false
      }
    }
    this.trendsAPI = new TrendsAPI();
    this.addShinyListeners();
    this.createElements(parentContainer);
  }

  addShinyListeners() {
    const self = this;

    $(document).on('shiny:connected', function(event) {
      console.log('Connected to Shiny server');
    });

    $(document).on('shiny:sessioninitialized', function(event) {
      console.log('Shiny session initialized');

      // Create a loop to ping the Shiny server and keep the websocket connection on
      clearInterval(self.keepShinyAlive);
      self.keepShinyAlive = setInterval(pingShiny, 10000);
      function pingShiny() {
        const timestamp = Date.now();
        Shiny.onInputChange("ping", timestamp);      
      }

      // Add listener for stl data
      Shiny.addCustomMessageHandler("stl", function(dataFromR) {
        console.log('From R: ', dataFromR);
        self.parseRData(dataFromR);
      });      
    });

    $(document).on('shiny:idle', function(event) {
      console.log('Shiny session idle');
    });

    $(document).on('shiny:disconnected', function(event) {
      console.log('Disconnected from Shiny server');
      location.reload();
    });
  }

  handleSelectDiseaseChange(value: string[], self) {
    const diseases = value.map(v => self.getDiseaseByEntity(v));
    this.updateData({diseases: diseases});
    self.confirmNav.classList.remove('hidden');
  }

  handleSelectGeoChange(event, self) {
    const { value } = event.target;
    const name = this.getSelectedText(event.target);
    this.updateData({geo: {iso: value, name: name}});
    self.confirmNav.classList.remove('hidden');
  }

  getDiseaseByEntity(entity: string): Term {
    return terms.find(t => t.entity === entity);
  }

  getSelectedText(el) {
    if (el.selectedIndex == -1)
      return null;
    return el.options[el.selectedIndex].text;
  }

  cancelFilters(event, self) {
    const { prevDiseases, prevGeo } = self.data;
    self.confirmNav.classList.add('hidden');
    self.updateData({ diseases: prevDiseases, geo: prevGeo });
  }

  confirmFilters(event, self) {
    const { diseases, geo } = self.data;
    self.confirmNav.classList.add('hidden');
    self.updateData({ prevDiseases: diseases, prevGeo: geo });
    self.callTrendsApi();
    this.updateData({ isLoading: true });
  }

  toggleChartMerge(event, self) {
    let { isMerged } = self.data;
    isMerged = isMerged ? false : true;
    this.seasonalChart.hide();
    this.updateData({ isMerged: isMerged });
  }

  loadCurated(filter: Filter) {
    const { terms, geo } = filter;
    this.updateData({ prevDiseases: terms, diseases: terms, prevGeo: geo, geo: geo });
    this.confirmNav.classList.add('hidden');
    this.callTrendsApi();
  }

  callTrendsApi(){
    const { diseases, geo } = this.data;
    const self = this;

    self.trendsAPI.getTrends({terms: diseases, geo: geo}, function(val){
      console.log(val);
      const parseTime = d3.timeParse('%Y-%m-%d');
      self.updateData({
        total: val.lines[0].points.map((p, i) => {
          return{ date: parseTime(p.date), value: p.value}
        })
      });

      // self.sendDataToR(val);
    });
  }

  sendDataToR(data) {
    console.log('From Google Trends: ', data);

    const dataToR = data.lines[0].points.map((p, i) => p.date+','+p.value);
    this.parseRData(dummyData);
    // Shiny.onInputChange("mydata", dataToR);
  }

  parseRData(dataFromR) {
    const { total } = this.data;

    const seasonalString = dataFromR.substring(dataFromR.indexOf('seasonal:') + 'seasonal:'.length + 1, dataFromR.indexOf('trend:'));
    const seasonal = (seasonalString.split(',')).slice(0, 13).map((n, i) => {
      return{ date: total[i].date, value: Number(n.trim())}
    });
    
    const trendString = dataFromR.substring(dataFromR.indexOf('trend:') + 'trend:'.length + 1, dataFromR.length);
    const trend = (trendString.split(',')).map((n, i) => {
      return{ date: total[i].date, value: Number(n.trim())}
    });
    this.updateData({seasonal: seasonal, trend: trend});
  }

  createElements(parentContainer: HTMLElement) {

    const elementsContainer = document.createElement('div');
    elementsContainer.id = 'explore';
    parentContainer.appendChild(elementsContainer);


    // Loader<commit_msg>Storing total as array of lines<commit_after>// @flow weak

// Components
import { FiltersMenu } from './FiltersMenu';
import { LineChart } from './LineChart';
import { TrendsAPI } from './TrendsAPI';

// Types
import type { Term, Geo, Filter } from './types'

// Data
import { dummyData, terms, countries } from './util.js';

// Libraries
import * as d3 from 'd3';
import selectize from 'selectize';
import $ from 'jquery'; 

//Styles
import 'selectize/dist/css/selectize.css';

export class Explore {

  data: {
    prevDiseases: Term[],
    diseases: Term[],
    prevGeo: Geo,
    geo: Geo,
    seasonal: {date: Date, value: number}[],
    trend: {date: Date, value: number}[],
    total: {date: Date, value: number}[],
    rIndex: number,
    isMerged: boolean,
    isLoading: boolean
  };

  keepShinyAlive: () => {};
  
  diseaseSelect: HTMLElement;
  geoSelect: HTMLElement;
  loaderContainer: HTMLElement;
  confirmNav: HTMLElement;
  mergeButton: HTMLElement;

  seasonalChart: LineChart;
  trendChart: LineChart;
  trendsAPI: TrendsAPI;

  constructor(parentContainer: HTMLElement, data) {
    if (data) {
      this.data = data;
    } else {
      this.data = {
        prevDiseases: [],
        diseases: [],
        prevGeo: countries[0],
        geo: countries[0],
        seasonal: [],
        trend: [],
        total: [],
        rIndex: 0,
        isMerged: false,
        isLoading: false
      }
    }
    this.trendsAPI = new TrendsAPI();
    this.addShinyListeners();
    this.createElements(parentContainer);
  }

  addShinyListeners() {
    const self = this;

    $(document).on('shiny:connected', function(event) {
      console.log('Connected to Shiny server');
    });

    $(document).on('shiny:sessioninitialized', function(event) {
      console.log('Shiny session initialized');

      // Create a loop to ping the Shiny server and keep the websocket connection on
      clearInterval(self.keepShinyAlive);
      self.keepShinyAlive = setInterval(pingShiny, 10000);
      function pingShiny() {
        const timestamp = Date.now();
        Shiny.onInputChange("ping", timestamp);      
      }

      // Add listener for stl data
      Shiny.addCustomMessageHandler("stl", function(dataFromR) {
        console.log('From R: ', dataFromR);
        self.parseRData(dataFromR);
      });
    });

    $(document).on('shiny:idle', function(event) {
      console.log('Shiny session idle');
    });

    $(document).on('shiny:disconnected', function(event) {
      console.log('Disconnected from Shiny server');
      location.reload();
    });
  }

  handleSelectDiseaseChange(value: string[], self) {
    const diseases = value.map(v => self.getDiseaseByEntity(v));
    this.updateData({diseases: diseases});
    self.confirmNav.classList.remove('hidden');
  }

  handleSelectGeoChange(event, self) {
    const { value } = event.target;
    const name = this.getSelectedText(event.target);
    this.updateData({geo: {iso: value, name: name}});
    self.confirmNav.classList.remove('hidden');
  }

  getDiseaseByEntity(entity: string): Term {
    return terms.find(t => t.entity === entity);
  }

  getSelectedText(el) {
    if (el.selectedIndex == -1)
      return null;
    return el.options[el.selectedIndex].text;
  }

  cancelFilters(event, self) {
    const { prevDiseases, prevGeo } = self.data;
    self.confirmNav.classList.add('hidden');
    self.updateData({ diseases: prevDiseases, geo: prevGeo });
  }

  confirmFilters(event, self) {
    const { diseases, geo } = self.data;
    self.confirmNav.classList.add('hidden');
    self.updateData({ prevDiseases: diseases, prevGeo: geo });
    self.callTrendsApi();
    this.updateData({ isLoading: true });
  }

  toggleChartMerge(event, self) {
    let { isMerged } = self.data;
    isMerged = isMerged ? false : true;
    this.seasonalChart.hide();
    this.updateData({ isMerged: isMerged });
  }

  loadCurated(filter: Filter) {
    const { terms, geo } = filter;
    this.updateData({ prevDiseases: terms, diseases: terms, prevGeo: geo, geo: geo });
    this.confirmNav.classList.add('hidden');
    this.callTrendsApi();
  }

  callTrendsApi(){
    const { diseases, geo } = this.data;
    let total = [];
    const self = this;

    self.trendsAPI.getTrends({terms: diseases, geo: geo}, function(val){
      console.log('From Google Trends: ', val);

      const parseTime = d3.timeParse('%Y-%m-%d');
      for (const l of val.lines) {
        total.push(
          val.lines[0].points.map((p, i) => {
            return{ date: parseTime(p.date), value: p.value}
          })
        );
      }
      self.updateData({ total: total });
      self.sendDataToR(val);
    });
  }

  sendDataToR(data) {
    const { rIndex } = this.data;

    const dataToR = data.lines[rIndex].points.map((p, i) => p.date+','+p.value);
    // this.parseRData(dummyData);
    Shiny.onInputChange("mydata", dataToR);
  }

  parseRData(dataFromR) {
    const { diseases, total } = this.data;
    let { rIndex } = this.data;

    const seasonalString = dataFromR.substring(dataFromR.indexOf('seasonal:') + 'seasonal:'.length + 1, dataFromR.indexOf('trend:'));
    const seasonal = (seasonalString.split(',')).slice(0, 13).map((n, i) => {
      return{ date: total[i].date, value: Number(n.trim())}
    });
    
    const trendString = dataFromR.substring(dataFromR.indexOf('trend:') + 'trend:'.length + 1, dataFromR.length);
    const trend = (trendString.split(',')).map((n, i) => {
      return{ date: total[i].date, value: Number(n.trim())}
    });


    if (rIndex < diseases.length) {
      rIndex ++;
      sendDataToR()
    }
    this.updateData({rIndex: rIndex, seasonal: seasonal, trend: trend});

  }

  createElements(parentContainer: HTMLElement) {

    const elementsContainer = document.createElement('div');
    elementsContainer.id = 'explore';
    parentContainer.appendChild(elementsContainer);


    // Loader
{'fraction_non_alphanumeric': 0.15308964316797216, 'fraction_numerical': 0.003133159268929504, 'mean_word_length': 3.1053947838513754, 'pattern_counts': {'":': 0, '<': 4, '<?xml version=': 0, '>': 17, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3346839', 'n_tokens_mistral': 3805, 'n_tokens_neox': 3729, 'n_words': 770}