import { Element, ElementBase, ElementStatus, PostalAddress } from '../../classes/classes';
import { capitalize, slugify, splitLongText } from '../../utils/string-helpers';
import { App } from '../../gogocarto';
declare let $, L, moment;

export class ElementJsonParserModule {
  // contains the ontology of the compact Json. This mapping must be provided in the elements ajax response
  compactMapping = ['id', ['name'], 'latitude', 'longitude', 'status', 'moderationState'];

  load(elementJson: any, element: Element | ElementBase) {
    // when we get the compact json representation of the element from the server
    // the elementJson is a simple array with the more important element attribute
    if ($.isArray(elementJson) && elementJson.length >= 5) this.loadFromCompactJson(elementJson, element);
    else this.loadFromFullJson(elementJson, element);
    if (App.config.infobar.displayDateField)
      element.dateToDisplay = moment(element.data[App.config.infobar.displayDateField]);
  }

  private loadFromCompactJson(elementJson: any, element: Element | ElementBase) {
    element.id = elementJson.id; // the element has been modified before to fixs bad ids
    for (let i = 0; i < this.compactMapping[1].length; ++i) {
      const attrName = this.compactMapping[1][i];
      let value = elementJson[1][i];
      if (attrName == 'images') element.images = value;
      else if (attrName == 'name') element.name = capitalize(value);
      else if (attrName == 'address') {
        if (typeof value == 'string') value = JSON.parse(value);
        element.address = new PostalAddress(value);
      } else element.data[attrName] = value;
    }
    element.position = L.latLng(elementJson[2], elementJson[3]);
    App.elementOptionValuesModule.createOptionValues(elementJson[4], element);
    element.status = elementJson.length >= 6 ? elementJson[5] : 1;
    element.moderationState = elementJson.length >= 7 ? elementJson[6] : 0;
  }

  private loadFromFullJson(elementJson: any, element: Element | ElementBase) {
    // MANDATORY DATA
    element.id = elementJson.id || elementJson['@id'];
    element.position = L.latLng(
      elementJson.latitude || elementJson.lat || (elementJson.geo && elementJson.geo.latitude),
      elementJson.longitude || elementJson.lng || elementJson.long || (elementJson.geo && elementJson.geo.longitude)
    );
    element.name = capitalize(elementJson.name || elementJson.title);
    element.address = new PostalAddress(elementJson.address);
    App.elementOptionValuesModule.createOptionValues(
      elementJson.categoriesFull || elementJson.categories || elementJson.taxonomy,
      element
    );

    // OPTIONAL DATA
    element.status = elementJson.status == undefined ? 1 : elementJson.status;
    element.moderationState = elementJson.moderationState || 0;
    element.searchScore = elementJson.searchScore;

    // SPECIFIC DATA
    element.openHours = elementJson.openHours;
    App.elementFormaterModule.calculateFormatedOpenHours(element);
    element.stamps = elementJson.stamps || [];
    element.geoJSONFeature = elementJson.geoJSONFeature;

    element.images = [];
    if (elementJson.image) element.images.push(elementJson.image);
    else if (elementJson.images) element.images = [].concat(elementJson.images);
    element.images = element.images.filter((imageUrl) => imageUrl.length > 5);

    element.files = [];
    if (elementJson.file) element.files.push(elementJson.file);
    else if (elementJson.files) element.files = [].concat(elementJson.files);
    element.files = element.files.filter((url) => url.length > 5);

    // CUSTOM DATA
    element.data = { ...element.data, ...elementJson }

    // ADMIN HISTORY DATA
    element.reports = elementJson.reports;
    element.contributions = elementJson.contributions;
    element.pendingContribution = elementJson.pendingContribution;
    element.votes = elementJson.votes;

    // PENDING ELEMENTS
    if (elementJson.modifiedElement && element.status != -5) {
      const modifiedElement = new ElementBase(elementJson.modifiedElement);

      // calcul and store diff optionsValues in modified element
      App.elementOptionValuesModule.createOptionValues(
        elementJson.categoriesFull || elementJson.categories || elementJson.taxonomy,
        element
      );
      const diffOptionValues = App.elementDiffModule.getDiffOptionValues(
        element.optionsValues,
        modifiedElement.optionsValues
      );
      modifiedElement.optionsValues = diffOptionValues;

      element.modifiedElement = modifiedElement;
    }
    
    // AGGREGATE ELEMENTS
    if (element.status == ElementStatus.Aggregate && elementJson.aggregatedElements) {
      elementJson.aggregatedElements.forEach(aggregatedElementJson => {
        let aggregatedElement = aggregatedElementJson
        if (typeof(aggregatedElementJson) == 'object') {
          aggregatedElement = new Element(aggregatedElementJson);
          aggregatedElement.initialize()
          aggregatedElement.data.aggregate = element

          // calcul and store optionsValues in aggregated element
          App.elementOptionValuesModule.createOptionValues(
            aggregatedElementJson.categoriesFull || aggregatedElementJson.categories || aggregatedElementJson.taxonomy,
            aggregatedElement
          );
        }
        element.aggregatedElements.push(aggregatedElement);
      })
      App.elementsModule.addElements(element.aggregatedElements);
      for(let aggregated of element.aggregatedElements) {
        aggregated.aggregatedElements = element.aggregatedElements
      }
    }

    element.isFullyLoaded = true;
  }
}
