class ConcordanceQueryBuilder {

  constructor() {


    this.elements = {
      
      counter: 0,
      yourQueryContent: [],
      queryContent:[],
      concordanceQueryBuilder: document.querySelector('#concordance-query-builder'),
      concordanceQueryBuilderButton: document.querySelector('#concordance-query-builder-button'),
      closeQueryBuilder: document.querySelector('#close-query-builder'),
      queryBuilderTutorialModal: document.querySelector('#query-builder-tutorial-modal'),
      valueValidator: true,


      //#region QueryBuilder Elements
      
      positionalAttrButton: document.querySelector('#positional-attr-button'),
      positionalAttrArea: document.querySelector('#positional-attr'),
      positionalAttr: document.querySelector('#token-attr'),
      structuralAttrButton: document.querySelector('#structural-attr-button'),
      structuralAttrArea: document.querySelector('#structural-attr'),
      queryContainer: document.querySelector('#query-container'),
      buttonPreparer: document.querySelector('#button-preparer'),
      yourQuery: document.querySelector('#your-query'),
      insertQueryButton: document.querySelector('#insert-query-button'),
      queryPreview: document.querySelector('#query-preview'),
      tokenQuery: document.querySelector('#token-query'),
      tokenBuilderContent: document.querySelector('#token-builder-content'),
      tokenSubmitButton: document.querySelector('#token-submit'),
      extFormQuery: document.querySelector('#concordance-extension-form-query'),
      dropButton: '',
      
      queryBuilderTutorialInfoIcon: document.querySelector('#query-builder-tutorial-info-icon'),
      tokenTutorialInfoIcon: document.querySelector('#token-tutorial-info-icon'),
      editTokenTutorialInfoIcon: document.querySelector('#edit-options-tutorial-info-icon'),
      structuralAttributeTutorialInfoIcon: document.querySelector('#add-structural-attribute-tutorial-info-icon'),
      generalOptionsQueryBuilderTutorialInfoIcon: document.querySelector('#general-options-query-builder-tutorial-info-icon'),
      
      
      //#endregion QueryBuilder Elements

      //#region Strucutral Attributes
      
      sentence:document.querySelector('#sentence'),
      entity: document.querySelector('#entity'),
      textAnnotation: document.querySelector('#text-annotation'),

      entityBuilder: document.querySelector('#entity-builder'),
      englishEntType: document.querySelector('#english-ent-type'),
      germanEntType: document.querySelector('#german-ent-type'),
      emptyEntity: document.querySelector('#empty-entity'),
      entityAnyType: false,

      textAnnotationBuilder: document.querySelector('#text-annotation-builder'),
      textAnnotationOptions: document.querySelector('#text-annotation-options'),
      textAnnotationInput: document.querySelector('#text-annotation-input'),
      textAnnotationSubmit: document.querySelector('#text-annotation-submit'),
      noValueMetadataMessage: document.querySelector('#no-value-metadata-message'),
      //#endregion Structural Attributes

      //#region Token Attributes
      tokenQueryFilled: false,

      lemma: document.querySelector('#lemma'),
      emptyToken: document.querySelector('#empty-token'),
      word: document.querySelector('#word'),
      lemma: document.querySelector('#lemma'),
      pos: document.querySelector('#pos'),
      simplePosButton: document.querySelector('#simple-pos-button'),
      incidenceModifiers: document.querySelector('[data-target="incidence-modifiers"]'),
      or: document.querySelector('#or'),
      and: document.querySelector('#and'),

      //#region Word and Lemma Elements
      wordBuilder: document.querySelector('#word-builder'),
      lemmaBuilder: document.querySelector('#lemma-builder'),
      inputOptions: document.querySelector('#input-options'),
      incidenceModifiersButton: document.querySelector('#incidence-modifiers-button'),
      conditionContainer: document.querySelector('#condition-container'),
      wordInput: document.querySelector('#word-input'),
      lemmaInput: document.querySelector('#lemma-input'),
      ignoreCaseCheckbox : document.querySelector('#ignore-case-checkbox'),
      ignoreCase: document.querySelector('input[type="checkbox"]'),
      wildcardChar: document.querySelector('#wildcard-char'),
      optionGroup: document.querySelector('#option-group'),
      //#endregion Word and Lemma Elements

      //#region posBuilder Elements
      englishPosBuilder: document.querySelector('#english-pos-builder'),
      englishPos: document.querySelector('#english-pos'),
      germanPosBuilder: document.querySelector('#german-pos-builder'),
      germanPos: document.querySelector('#german-pos'),
      //#endregion posBuilder Elements

      //#region simple_posBuilder Elements
      simplePosBuilder: document.querySelector('#simplepos-builder'),
      simplePos: document.querySelector('#simple-pos'),
      //#endregion simple_posBuilder Elements

      //#region incidence modifiers
      oneOrMore: document.querySelector('#one-or-more'),
      zeroOrMore: document.querySelector('#zero-or-more'),
      zeroOrOne: document.querySelector('#zero-or-one'),
      exactlyN: document.querySelector('#exactlyN'),
      betweenNM: document.querySelector('#betweenNM'),
      nInput: document.querySelector('#n-input'),
      nSubmit: document.querySelector('#n-submit'),
      nmInput: document.querySelector('#n-m-input'),
      mInput: document.querySelector('#m-input'),
      nmSubmit: document.querySelector('#n-m-submit'),
      //#endregion incidence modifiers

      cancelBool: false,
      noValueMessage: document.querySelector('#no-value-message'),
      //#endregion Token Attributes
    }
    
    this.elements.closeQueryBuilder.addEventListener('click', () => {this.closeQueryBuilderModal(this.elements.concordanceQueryBuilder);});
    this.elements.concordanceQueryBuilderButton.addEventListener('click', () => {this.clearAll();});
    this.elements.insertQueryButton.addEventListener('click', () => {this.insertQuery();});
    this.elements.positionalAttrButton.addEventListener('click', () => {this.showPositionalAttrArea();});
    this.elements.structuralAttrButton.addEventListener('click', () => {this.showStructuralAttrArea();});

    //#region Structural Attribute Event Listeners
    this.elements.sentence.addEventListener('click', () => {this.addSentence();});
    this.elements.entity.addEventListener('click', () => {this.addEntity();});
    this.elements.textAnnotation.addEventListener('click', () => {this.addTextAnnotation();});

    this.elements.englishEntType.addEventListener('change', () => {this.englishEntTypeHandler();});
    this.elements.germanEntType.addEventListener('change', () => {this.germanEntTypeHandler();});
    this.elements.emptyEntity.addEventListener('click', () => {this.emptyEntityButton();});
    
    this.elements.textAnnotationSubmit.addEventListener('click', () => {this.textAnnotationSubmitHandler();});

    //#endregion
    
    //#region Token Attribute Event Listeners
    this.elements.queryBuilderTutorialInfoIcon.addEventListener('click', () => {this.tutorialIconHandler('#query-builder-tutorial-start');});
    this.elements.tokenTutorialInfoIcon.addEventListener('click', () => {this.tutorialIconHandler('#add-new-token-tutorial');});
    this.elements.editTokenTutorialInfoIcon.addEventListener('click', () => {this.tutorialIconHandler('#edit-options-tutorial');});
    this.elements.structuralAttributeTutorialInfoIcon.addEventListener('click', () => {this.tutorialIconHandler('#add-structural-attribute-tutorial');});
    this.elements.generalOptionsQueryBuilderTutorialInfoIcon.addEventListener('click', () => {this.tutorialIconHandler('#general-options-query-builder');});

    this.elements.positionalAttr.addEventListener('change', () => {this.tokenTypeSelector();});
    this.elements.tokenSubmitButton.addEventListener('click', () => {this.addTokenToQuery();});


    this.elements.ignoreCase.addEventListener('change', () => {this.inputOptionHandler(this.elements.ignoreCase);});
    this.elements.wildcardChar.addEventListener('click', () => {this.inputOptionHandler(this.elements.wildcardChar);});
    this.elements.optionGroup.addEventListener('click', () => {this.inputOptionHandler(this.elements.optionGroup);});

    this.elements.oneOrMore.addEventListener('click', () => {this.incidenceModifiersHandler(this.elements.oneOrMore);});
    this.elements.zeroOrMore.addEventListener('click', () => {this.incidenceModifiersHandler(this.elements.zeroOrMore);});
    this.elements.zeroOrOne.addEventListener('click', () => {this.incidenceModifiersHandler(this.elements.zeroOrOne);});
    this.elements.nSubmit.addEventListener('click', () => {this.nSubmitHandler();});
    this.elements.nmSubmit.addEventListener('click', () => {this.nmSubmitHandler();});

    this.elements.or.addEventListener('click', () => {this.orHandler();});
    this.elements.and.addEventListener('click', () => {this.andHandler();});
  
  
    //#endregion Token Attribute Event Listeners

  }


  // ##########################################################################
  // #################### General Functions ###################################
  // ##########################################################################

  //#region General Functions

  closeQueryBuilderModal(closeInstance) {
    let instance = M.Modal.getInstance(closeInstance);
    instance.close();

  }
  
  showPositionalAttrArea() {
    this.elements.positionalAttrArea.classList.remove('hide');
    this.elements.wordBuilder.classList.remove('hide');
    this.elements.inputOptions.classList.remove('hide');
    this.elements.incidenceModifiersButton.classList.remove('hide');
    this.elements.conditionContainer.classList.remove('hide');
    this.elements.ignoreCaseCheckbox.classList.remove('hide');
    this.elements.structuralAttrArea.classList.add('hide');
    this.elements.lemmaBuilder.classList.add('hide');
    this.elements.englishPosBuilder.classList.add('hide');
    this.elements.germanPosBuilder.classList.add('hide');
    this.elements.simplePosBuilder.classList.add('hide');

    this.elements.tokenQueryFilled = false;

    window.location.href = '#token-builder-content';

    // Resets materialize select field to default value 
    let SelectInstance = M.FormSelect.getInstance(this.elements.positionalAttr);
    SelectInstance.input.value = 'word';
    this.elements.positionalAttr.value = 'word';
  }

  showStructuralAttrArea() {
    this.elements.positionalAttrArea.classList.add('hide');
    this.elements.structuralAttrArea.classList.remove('hide');
  }

  queryChipFactory(dataType, prettyQueryText, queryText) {
    window.location.href = '#query-container';
    queryText = Utils.escape(queryText);
    prettyQueryText = Utils.escape(prettyQueryText);
    let queryChipElement = Utils.HTMLToElement(
      `
        <span class="chip query-component" data-type="${dataType}" data-query="${queryText}" draggable="true">
          ${prettyQueryText}
          <i class="material-icons close">close</i>
        </span>
      `
    );
    queryChipElement.addEventListener('click', () => {this.deleteAttr(queryChipElement);});
    queryChipElement.addEventListener('dragstart', (event) => {
      // selects all nodes without target class
      let queryChips = this.elements.yourQuery.querySelectorAll('.query-component');

      // Adds a target chip in front of all draggable childnodes
      setTimeout(() => {
        let targetChipElement = Utils.HTMLToElement('<span class="chip drop-target">Drop here</span>');
        for (let element of queryChips) {
          if (element === queryChipElement.nextSibling) {continue;}
          let targetChipClone = targetChipElement.cloneNode(true);
          if (element === queryChipElement) {
            // If the dragged element is not at the very end, a target chip is also inserted at the end
            if (queryChips[queryChips.length - 1] !== element) {
              queryChips[queryChips.length - 1].insertAdjacentElement('afterend', targetChipClone);
            }
          } else {
            element.insertAdjacentElement('beforebegin', targetChipClone);
          }
          targetChipClone.addEventListener('dragover', (event) => {
            event.preventDefault();
          });
          targetChipClone.addEventListener('dragenter', (event) => {
            event.preventDefault();
            event.target.style.borderStyle = 'solid dotted';
          });
          targetChipClone.addEventListener('dragleave', (event) => {
            event.preventDefault();
            event.target.style.borderStyle = 'hidden';
          });
          targetChipClone.addEventListener('drop', (event) => {
            let dropzone = event.target;
            dropzone.parentElement.replaceChild(queryChipElement, dropzone);
            this.queryPreviewBuilder();
          });
        }
      }, 0);
    });

    queryChipElement.addEventListener('dragend', (event) => {
      let targets = document.querySelectorAll('.drop-target');
      for (let target of targets) {
        target.remove();
      }
    });

    // Ensures that metadata is always at the end of the query:
    if (this.elements.yourQuery.lastChild === null || this.elements.yourQuery.lastChild.dataset.type !== 'text-annotation') {
      this.elements.yourQuery.appendChild(queryChipElement);
    } else if (this.elements.yourQuery.lastChild.dataset.type === 'text-annotation') {
      this.elements.yourQuery.insertBefore(queryChipElement, this.elements.yourQuery.lastChild);
    }
    this.elements.queryContainer.classList.remove('hide');
    this.queryPreviewBuilder();

    // Shows a hint about possible functions for editing the query at the first added element in the query
    if (this.elements.yourQuery.childNodes.length === 1) {
      app.flash('You can edit your query by deleting individual elements or moving them via drag and drop.');
    }
  }

  queryPreviewBuilder() {
    this.elements.yourQueryContent = [];
    for (let element of this.elements.yourQuery.childNodes) {
      let queryElement = decodeURI(element.dataset.query);
      queryElement = Utils.escape(queryElement);
      if (queryElement !== 'undefined') {
        this.elements.yourQueryContent.push(queryElement);
      }
    }

    let queryString = this.elements.yourQueryContent.join(' ');
    queryString += ';';
    this.elements.queryPreview.innerHTML = queryString;
  }


  deleteAttr(attr) {
    this.elements.yourQuery.removeChild(attr);
    if (attr.dataset.type === "start-sentence") {
      this.elements.sentence.innerHTML = 'Sentence';
    } else if (attr.dataset.type === "start-entity" || attr.dataset.type === "start-empty-entity") {
      this.elements.entity.innerHTML = 'Entity';
    }
    this.elements.counter -= 1;
    if (this.elements.counter === 0) {
      this.elements.queryContainer.classList.add('hide');
    }
    this.queryPreviewBuilder();
  }

  insertQuery() {
    this.elements.yourQueryContent = [];
    this.validateValue();
    if (this.elements.valueValidator === true) {
      for (let element of this.elements.yourQuery.childNodes) {
        let queryElement = decodeURI(element.dataset.query);
        if (queryElement !== 'undefined') {
          this.elements.yourQueryContent.push(queryElement);
        }
      }

      let queryString = this.elements.yourQueryContent.join(' ');
      queryString += ';';

      this.elements.concordanceQueryBuilder.classList.add('modal-close');
      this.elements.extFormQuery.value = queryString;
    }
  }

  validateValue() {
    this.elements.valueValidator = true;
    let sentenceCounter = 0;
    let sentenceEndCounter = 0;
    let entityCounter = 0;
    let entityEndCounter = 0;
    for (let element of this.elements.yourQuery.childNodes) {
      if (element.dataset.type === 'start-sentence') {
        sentenceCounter += 1;
      }else if (element.dataset.type === 'end-sentence') {
        sentenceEndCounter += 1;
      }else if (element.dataset.type === 'start-entity' || element.dataset.type === 'start-empty-entity') {
        entityCounter += 1;
      }else if (element.dataset.type === 'end-entity') {
        entityEndCounter += 1;
      }
    }
    // Checks if the same number of opening and closing tags (entity and sentence) are present. Depending on what is missing, the corresponding error message is ejected
    if (sentenceCounter > sentenceEndCounter) {
      app.flash('Please add the closing sentence tag', 'error');
      this.elements.valueValidator = false;
    } else if (sentenceCounter < sentenceEndCounter) {
      app.flash('Please remove the closing sentence tag', 'error');
      this.elements.valueValidator = false;
    }
    if (entityCounter > entityEndCounter) {
      app.flash('Please add the closing entity tag', 'error');
      this.elements.valueValidator = false;
    } else if (entityCounter < entityEndCounter) {
      app.flash('Please remove the closing entity tag', 'error');
      this.elements.valueValidator = false;
    }
  }

  clearAll() {
    // Everything is reset.
    let instance = M.Tooltip.getInstance(this.elements.queryBuilderTutorialInfoIcon);

    this.hideEverything();
    this.elements.counter = 0;
    this.elements.concordanceQueryBuilder.classList.remove('modal-close');
    this.elements.positionalAttrArea.classList.add('hide');
    this.elements.structuralAttrArea.classList.add('hide');
    this.elements.yourQuery.innerHTML = '';
    this.elements.queryContainer.classList.add('hide');
    this.elements.entity.innerHTML = 'Entity';
    this.elements.sentence.innerHTML = 'Sentence';
    
    // If the Modal is open after 5 seconds for 5 seconds (with 'instance'), a message is displayed indicating that further information can be obtained via the question mark icon
    instance.tooltipEl.style.background = '#98ACD2';
    instance.tooltipEl.style.borderTop = 'solid 4px #0064A3';
    instance.tooltipEl.style.padding = '10px';
    instance.tooltipEl.style.color = 'black';

    setTimeout(() => {
      let modalInstance = M.Modal.getInstance(this.elements.concordanceQueryBuilder);
      if (modalInstance.isOpen) {
        instance.open();
        setTimeout(() => {
          instance.close();
        }, 5000);
      }
    }, 5000);

  }

  tutorialIconHandler(id) {
    setTimeout(() => {
      window.location.href= id;
    }, 0);

  }

  //#endregion General Functions


  // ##########################################################################
  // ############## Token Attribute Builder Functions #########################
  // ##########################################################################

  //#region Token Attribute Builder Functions

  //#region General functions of the Token Builder
  tokenTypeSelector() {
    this.hideEverything();
    switch (this.elements.positionalAttr.value) {
      case 'word':
        this.wordBuilder();
        break;
      case 'lemma':
        this.lemmaBuilder();
        break;
      case 'english-pos':
        this.englishPosHandler();
        break;
      case 'german-pos':
        this.germanPosHandler();
        break;    
      case 'simple-pos-button':
        this.simplePosBuilder();
        break;
      case 'empty-token':
        this.emptyTokenHandler();
        break;
      default:
        this.wordBuilder();
        break;
    }
  }

  hideEverything() {

    this.elements.wordBuilder.classList.add('hide');
    this.elements.lemmaBuilder.classList.add('hide');
    this.elements.ignoreCaseCheckbox.classList.add('hide');
    this.elements.inputOptions.classList.add('hide');
    this.elements.incidenceModifiersButton.classList.add('hide');
    this.elements.conditionContainer.classList.add('hide');
    this.elements.englishPosBuilder.classList.add('hide');
    this.elements.germanPosBuilder.classList.add('hide');
    this.elements.simplePosBuilder.classList.add('hide');
    this.elements.entityBuilder.classList.add('hide');
    this.elements.textAnnotationBuilder.classList.add('hide');

  }

  tokenChipFactory(prettyQueryText, tokenText) {
    tokenText = encodeURI(tokenText);
    let builderElement;
    let queryChipElement;
    builderElement = document.createElement('div');
    builderElement.innerHTML = `
    <div class='chip col s2 l2' style='margin-top:20px;' data-tokentext='${tokenText}'>
      ${prettyQueryText}
      <i class='material-icons close'>close</i>
    </div>`;
    queryChipElement = builderElement.firstElementChild;
    queryChipElement.addEventListener('click', () => {this.deleteTokenAttr(queryChipElement);});
    this.elements.tokenQuery.appendChild(queryChipElement);
  }

  deleteTokenAttr(attr) {
    if (this.elements.tokenQuery.childNodes.length < 2) {
      this.elements.tokenQuery.removeChild(attr);
      this.wordBuilder();
    } else {
      this.elements.tokenQuery.removeChild(attr);
    }

  }

  addTokenToQuery() {
    let c;
    let tokenQueryContent = ''; //for ButtonFactory(prettyQueryText)
    let tokenQueryText = ''; //for ButtonFactory(queryText)
    this.elements.cancelBool = false;
    let tokenIsEmpty = false;

    if (this.elements.ignoreCase.checked) {
      c = ' %c';
    } else {
      c = '';
    }


    for (let element of this.elements.tokenQuery.childNodes) {
      tokenQueryContent += ' ' + element.firstChild.data + ' ';
      tokenQueryText += decodeURI(element.dataset.tokentext);
      if (element.innerText.indexOf('empty token') !== -1) {
        tokenIsEmpty = true;
      }
    }

    if (this.elements.tokenQueryFilled === false) {
      switch (this.elements.positionalAttr.value) {
        case 'word':
          if (this.elements.wordInput.value === '') {
            this.disableTokenSubmit();
          } else {
            tokenQueryContent += `word=${this.elements.wordInput.value}${c}`;
            tokenQueryText += `word="${this.elements.wordInput.value}"${c}`;
            this.elements.wordInput.value = '';
          }
          break;
        case 'lemma':
          if (this.elements.lemmaInput.value === '') {
            this.disableTokenSubmit();
          } else {
            tokenQueryContent += `lemma=${this.elements.lemmaInput.value}${c}`;
            tokenQueryText += `lemma="${this.elements.lemmaInput.value}"${c}`;
            this.elements.lemmaInput.value = '';
          }
          break;
        case 'english-pos':
          if (this.elements.englishPos.value === 'default') {
            this.disableTokenSubmit();
          } else {
            tokenQueryContent += `pos=${this.elements.englishPos.value}`;
            tokenQueryText += `pos="${this.elements.englishPos.value}"`;
            this.elements.englishPos.value = '';
          }
          break;
        case 'german-pos':
          if (this.elements.germanPos.value === 'default') {
            this.disableTokenSubmit();
          } else {
            tokenQueryContent += `pos=${this.elements.germanPos.value}`;
            tokenQueryText += `pos="${this.elements.germanPos.value}"`;
            this.elements.germanPos.value = '';
          }
          break;
        case 'simple-pos-button':
          if (this.elements.simplePos.value === 'default') {
            this.disableTokenSubmit();
          } else {
            tokenQueryContent += `simple_pos=${this.elements.simplePos.value}`;
            tokenQueryText += `simple_pos="${this.elements.simplePos.value}"`;
            this.elements.simplePos.value = '';
          }
          break;
        default:
          this.wordBuilder();
          break;
      }
    }

    // cancelBool looks in disableTokenSubmit() whether a value is passed. If the input fields/dropdowns are empty (cancelBool === true), no token is added.
    if (this.elements.cancelBool === false) {
      // Square brackets are added only if it is not an empty token (where they are already present).
      if (tokenIsEmpty === false) {
        tokenQueryText = '[' + tokenQueryText + ']';
        }
      console.log(tokenQueryText);
      this.queryChipFactory('token', tokenQueryContent, tokenQueryText);
      this.hideEverything();
      this.elements.positionalAttrArea.classList.add('hide');
      this.elements.tokenQuery.innerHTML = '';
    }

  }

  disableTokenSubmit() {
    this.elements.cancelBool = true;
    this.elements.tokenSubmitButton.classList.add('red');
    this.elements.noValueMessage.classList.remove('hide');
    setTimeout(() => {
      this.elements.tokenSubmitButton.classList.remove('red');
    }, 500);
    setTimeout(() => {
      this.elements.noValueMessage.classList.add('hide');
    }, 3000);
  }

    //#endregion General functions of the Token Builder

    //#region Dropdown Select Handler
  wordBuilder() {
    this.hideEverything();
    this.elements.wordInput.value = '';
    this.elements.wordBuilder.classList.remove('hide');
    this.elements.inputOptions.classList.remove('hide');
    this.elements.incidenceModifiersButton.classList.remove('hide');
    this.elements.conditionContainer.classList.remove('hide');
    this.elements.ignoreCaseCheckbox.classList.remove('hide');

    // Resets materialize select field to default value 
    let SelectInstance = M.FormSelect.getInstance(this.elements.positionalAttr);
    SelectInstance.input.value = 'word';
    this.elements.positionalAttr.value = 'word';

  }

  lemmaBuilder() {
    this.hideEverything();
    this.elements.lemmaBuilder.classList.remove('hide');
    this.elements.inputOptions.classList.remove('hide');
    this.elements.incidenceModifiersButton.classList.remove('hide');
    this.elements.conditionContainer.classList.remove('hide');
    this.elements.ignoreCaseCheckbox.classList.remove('hide');
  }

  englishPosHandler() {
    this.hideEverything();
    this.elements.englishPosBuilder.classList.remove('hide');
    this.elements.incidenceModifiersButton.classList.remove('hide');
    this.elements.conditionContainer.classList.remove('hide');
    
    // Resets materialize select dropdown
    let selectInstance = M.FormSelect.getInstance(this.elements.englishPos);
    selectInstance.input.value = 'English pos tagset';
    this.elements.englishPos.value = 'default';
  }
  
  germanPosHandler() {
    this.hideEverything();
    this.elements.germanPosBuilder.classList.remove('hide');
    this.elements.incidenceModifiersButton.classList.remove('hide');
    this.elements.conditionContainer.classList.remove('hide');

    // Resets materialize select dropdown
    let selectInstance = M.FormSelect.getInstance(this.elements.germanPos);
    selectInstance.input.value = 'German pos tagset';
    this.elements.germanPos.value = 'default';
  }

  simplePosBuilder() {
  this.hideEverything();
  this.elements.simplePosBuilder.classList.remove('hide');
  this.elements.incidenceModifiersButton.classList.remove('hide');
  this.elements.conditionContainer.classList.remove('hide');
  this.elements.simplePos.selectedIndex = 0;
  
  // Resets materialize select dropdown
  let selectInstance = M.FormSelect.getInstance(this.elements.simplePos);
  selectInstance.input.value = 'simple_pos tagset';
  this.elements.simplePos.value = 'default';
  }

  emptyTokenHandler() {
    this.tokenChipFactory('empty token', '[]');
    this.elements.tokenQueryFilled = true;
    this.hideEverything();
    this.elements.incidenceModifiersButton.classList.remove('hide');
  }
  //#endregion Dropdown Select Handler
  
    //#region Options to edit your token - Wildcard Charakter, Option Group, Incidence Modifiers, Ignore Case, 'and', 'or'

  inputOptionHandler(elem) {
    let input;

    if (this.elements.wordBuilder.classList.contains('hide') === false) {
      input = this.elements.wordInput;
    } else {
      input =  this.elements.lemmaInput;
    }

    if (elem === this.elements.optionGroup) {
      input.value  += '( option1 | option2 )';
      let firstIndex = input.value.indexOf('option1');
      let lastIndex = firstIndex + 'option1'.length;
      input.focus();
      input.setSelectionRange(firstIndex, lastIndex);
    } else if (elem === this.elements.wildcardChar) {
      input.value  += '.';
    }
  }

  nSubmitHandler() {
    let instance = M.Modal.getInstance(this.elements.exactlyN);
    instance.close();
    
    switch (this.elements.positionalAttr.value) {
      case 'word':
        this.elements.wordInput.value += ' {' + this.elements.nInput.value + '}';
        break;
      case 'lemma':
        this.elements.lemmaInput.value += ' {' + this.elements.nInput.value + '}';
        break;
      case 'english-pos':
        this.elements.tokenQueryFilled = true;
        this.tokenChipFactory(`pos=${this.elements.englishPos.value}`, `pos="${this.elements.englishPos.value}"`);
        this.tokenChipFactory('{' + this.elements.nInput.value + '}', '{' + this.elements.nInput.value + '}');
        this.elements.englishPosBuilder.classList.add('hide');
        this.elements.incidenceModifiersButton.classList.add('hide');
        break;
      case 'german-pos':
        this.elements.tokenQueryFilled = true;
        this.tokenChipFactory(`pos=${this.elements.germanPos.value}`, `pos="${this.elements.germanPos.value}"`);
        this.tokenChipFactory('{' + this.elements.nInput.value + '}', '{' + this.elements.nInput.value + '}');
        this.elements.germanPosBuilder.classList.add('hide');
        this.elements.incidenceModifiersButton.classList.add('hide');
        break;
      case 'simple-pos-button':
        this.elements.tokenQueryFilled = true;
        this.tokenChipFactory(`simple_pos=${this.elements.simplePos.value}`, `simple_pos="${this.elements.simplePos.value}"`);
        this.tokenChipFactory('{' + this.elements.nInput.value + '}', '{' + this.elements.nInput.value + '}');
        this.elements.simplePosBuilder.classList.add('hide');
        this.elements.incidenceModifiersButton.classList.add('hide');
        break;
      case 'empty-token':
        this.tokenChipFactory('{' + this.elements.nInput.value + '}', '{' + this.elements.nInput.value + '}');
        break;
      default:
        break;
    }

  }

  nmSubmitHandler() {
    let instance = M.Modal.getInstance(this.elements.betweenNM);
    instance.close();

    switch (this.elements.positionalAttr.value) {
      case 'word':
        this.elements.wordInput.value += `{${this.elements.nmInput.value}, ${this.elements.mInput.value}}`;
        break;
      case 'lemma':
        this.elements.lemmaInput.value += `{${this.elements.nmInput.value}, ${this.elements.mInput.value}}`;
        break;
      case 'english-pos':
        this.elements.tokenQueryFilled = true;
        this.tokenChipFactory(`pos=${this.elements.englishPos.value}`, `pos="${this.elements.englishPos.value}"`);
        this.tokenChipFactory(`{${this.elements.nmInput.value}, ${this.elements.mInput.value}}`, `{${this.elements.nmInput.value}, ${this.elements.mInput.value}}`);
        this.elements.englishPosBuilder.classList.add('hide');
        this.elements.incidenceModifiersButton.classList.add('hide');
        break;
      case 'german-pos':
        this.elements.tokenQueryFilled = true;
        this.tokenChipFactory(`pos=${this.elements.germanPos.value}`, `pos="${this.elements.germanPos.value}"`);
        this.tokenChipFactory(`{${this.elements.nmInput.value}, ${this.elements.mInput.value}}`, `{${this.elements.nmInput.value}, ${this.elements.mInput.value}}`);
        this.elements.germanPosBuilder.classList.add('hide');
        this.elements.incidenceModifiersButton.classList.add('hide');
        break;
      case 'simple-pos-button':
        this.elements.tokenQueryFilled = true;
        this.tokenChipFactory(`simple_pos=${this.elements.simplePos.value}`, `simple_pos="${this.elements.simplePos.value}"`);
        this.tokenChipFactory(`{${this.elements.nmInput.value}, ${this.elements.mInput.value}}`, `{${this.elements.nmInput.value}, ${this.elements.mInput.value}}`);
        this.elements.simplePosBuilder.classList.add('hide');
        this.elements.incidenceModifiersButton.classList.add('hide');
        break;
      case 'empty-token':
        this.tokenChipFactory(`{${this.elements.nmInput.value}, ${this.elements.mInput.value}}`, `{${this.elements.nmInput.value}, ${this.elements.mInput.value}}`);
        break;
      default:
        break;
    }
  }

  incidenceModifiersHandler(elem) {
    // For word and lemma, the incidence modifiers are inserted in the input field. For the others, one or two chips are created which contain the respective value of the token and the incidence modifier.
    if (this.elements.positionalAttr.value === 'empty-token') {
      this.tokenChipFactory(elem.innerText, elem.dataset.token);
    } else if (this.elements.positionalAttr.value === 'english-pos') {
      this.tokenChipFactory(`pos=${this.elements.englishPos.value}`, `pos="${this.elements.englishPos.value}"`);
      this.tokenChipFactory(elem.innerText, elem.dataset.token);
      this.elements.englishPosBuilder.classList.add('hide');
      this.elements.incidenceModifiersButton.classList.add('hide');
      this.elements.tokenQueryFilled = true;
    } else if (this.elements.positionalAttr.value === 'german-pos') {
      this.tokenChipFactory(`pos=${this.elements.germanPos.value}`, `pos="${this.elements.germanPos.value}"`);
      this.tokenChipFactory(elem.innerText, elem.dataset.token);
      this.elements.germanPosBuilder.classList.add('hide');
      this.elements.incidenceModifiersButton.classList.add('hide');
      this.elements.tokenQueryFilled = true;
    } else if (this.elements.positionalAttr.value === 'simple-pos-button') {
      this.tokenChipFactory(`simple_pos=${this.elements.simplePos.value}`, `simple_pos="${this.elements.simplePos.value}"`);
      this.tokenChipFactory(elem.innerText, elem.dataset.token);
      this.elements.simplePosBuilder.classList.add('hide');
      this.elements.incidenceModifiersButton.classList.add('hide');
      this.elements.tokenQueryFilled = true;
    } else {
      let input;

      if (this.elements.wordBuilder.classList.contains('hide') === false) {
        input = this.elements.wordInput;
      } else {
        input =  this.elements.lemmaInput;
      }

      input.value += ' ' + elem.dataset.token;
    }

  }

  orHandler() {
    this.conditionHandler('or', ' | ');
  }

  andHandler() {
    this.conditionHandler('and', ' & ');
  }

  conditionHandler(conditionText, conditionQueryContent) {
    this.hideEverything();
    let tokenQueryContent;
    let tokenQueryText;
    let c;

    if (this.elements.ignoreCase.checked) {
      c = ' %c';
    } else {
      c = '';
    }

    switch (this.elements.positionalAttr.value) {
      case 'word':
        tokenQueryContent = `word=${this.elements.wordInput.value}${c}`;
        tokenQueryText = `word="${this.elements.wordInput.value}"${c}`;
        this.elements.wordInput.value = '';
        break;
      case 'lemma':
        tokenQueryContent = `lemma=${this.elements.lemmaInput.value}${c}`;
        tokenQueryText = `lemma="${this.elements.lemmaInput.value}"${c}`;
        this.elements.lemmaInput.value = '';
        break;
      case 'english-pos':
        tokenQueryContent = `pos=${this.elements.englishPos.value}`;
        tokenQueryText = `pos="${this.elements.englishPos.value}"`;
        this.elements.englishPos.value = '';
        break;
      case 'german-pos':
        tokenQueryContent = `pos=${this.elements.germanPos.value}`;
        tokenQueryText = `pos="${this.elements.germanPos.value}"`;
        this.elements.germanPos.value = '';
        break;
      case 'simple-pos-button':
        tokenQueryContent = `simple_pos=${this.elements.simplePos.value}`;
        tokenQueryText = `simple_pos="${this.elements.simplePos.value}"`;
        this.elements.simplePos.value = '';
        break;
      default:
        this.wordBuilder();
        break;
    }

    this.tokenChipFactory(tokenQueryContent, tokenQueryText);
    this.tokenChipFactory(conditionText, conditionQueryContent);
    this.wordBuilder();
  }

  //#endregion Options to edit your token - Wildcard Charakter, Option Group, Incidence Modifiers, Ignore Case, 'and', 'or'

  //#endregion Token Attribute Builder Functions


  // ##########################################################################
  // ############ Structural Attribute Builder Functions ######################
  // ##########################################################################

  //#region Structural Attribute Builder Functions
  addSentence() {
    this.hideEverything();
    if (this.elements.sentence.text === 'End Sentence') {
      this.queryChipFactory('end-sentence', 'Sentence End', '</s>');
      this.elements.sentence.innerHTML = 'Sentence';
    } else {
      this.queryChipFactory('start-sentence', 'Sentence Start', '<s>');
      this.elements.queryContent.push('sentence');
      this.elements.sentence.innerHTML = 'End Sentence';
    }
  }

  addEntity() {
    if (this.elements.entity.text === 'End Entity') {
      let queryText;
      if (this.elements.entityAnyType === false) {
        queryText = '</ent_type>'; 
      } else {
        queryText = '</ent>';
      }
      this.queryChipFactory('end-entity', 'Entity End', queryText);
      this.elements.entity.innerHTML = 'Entity';
    } else {
      this.hideEverything();
      this.elements.entityBuilder.classList.remove('hide');
      window.location.href = '#entity-builder';
    }
  }

  englishEntTypeHandler() {
    this.queryChipFactory('start-entity', 'Entity Type=' + this.elements.englishEntType.value, '<ent_type="' + this.elements.englishEntType.value + '">');
    this.elements.entity.innerHTML = 'End Entity';
    this.hideEverything();
    this.elements.entityAnyType = false;
    
    // Resets materialize select dropdown
    let SelectInstance = M.FormSelect.getInstance(this.elements.englishEntType);
    SelectInstance.input.value = 'English ent_type';
    this.elements.englishEntType.value = 'default';
  }   

  germanEntTypeHandler() {
    this.queryChipFactory('start-entity', 'Entity Type=' + this.elements.germanEntType.value, '<ent_type="' + this.elements.germanEntType.value + '">');
    this.elements.entity.innerHTML = 'End Entity';
    this.hideEverything();
    this.elements.entityAnyType = false;

    // Resets materialize select dropdown
    let SelectInstance = M.FormSelect.getInstance(this.elements.germanEntType);
    SelectInstance.input.value = 'German ent_type';
    this.elements.germanEntType.value = 'default';
  }

  emptyEntityButton() {
    this.queryChipFactory('start-empty-entity', 'Entity Start', '<ent>');
    this.elements.entity.innerHTML = 'End Entity';
    this.hideEverything();
    this.elements.entityAnyType = true;
  }

  addTextAnnotation() {
    this.hideEverything();
    this.elements.textAnnotationBuilder.classList.remove('hide');
    window.location.href = '#text-annotation-builder';

    // Resets materialize select dropdown
    let SelectInstance = M.FormSelect.getInstance(this.elements.textAnnotationOptions);
    SelectInstance.input.value = 'address';
    this.elements.textAnnotationOptions.value = 'address';
    this.elements.textAnnotationInput.value= '';
  }

  textAnnotationSubmitHandler() {
    if (this.elements.textAnnotationInput.value === '') {
      this.elements.textAnnotationSubmit.classList.add('red');
      this.elements.noValueMetadataMessage.classList.remove('hide');
      setTimeout(() => {
        this.elements.textAnnotationSubmit.classList.remove('red');
      }, 500);
      setTimeout(() => {
        this.elements.noValueMetadataMessage.classList.add('hide');
      }, 3000);
    } else {
      let queryText = `:: match.text_${this.elements.textAnnotationOptions.value}="${this.elements.textAnnotationInput.value}"`;
      this.queryChipFactory('text-annotation', `${this.elements.textAnnotationOptions.value}=${this.elements.textAnnotationInput.value}`, queryText);
      this.hideEverything();
    }
  }
  //#endregion Structural Attribute Builder Functions
  
}
