iMapsBuilder = {
  searchInput: {},
  autocomplete: {},
  geocoder: {},
  regionData: {},
  regionsUsed: {},
  imageSaved: false,
  needsUpdate: false,
  previewBlocked: false,
  advanced: false,
  form: document.querySelector('form#post'),
};

iMapsBuilder.editControls = function () {
  // Basic
  let addMarker = document.createElement('div');
  addMarker.setAttribute('id', 'map_click_add_marker');
  addMarker.innerHTML =
    '<span class="dashicons dashicons-plus-alt"></span><span class="map_action_label">Add Marker There</span>';

  let coordinatesBox = document.getElementById('map_clicked_coordinates_box');
  coordinatesBox.appendChild(addMarker);
  coordinatesBox.style.display = 'block';

  // Advanced
  if (!iMapsBuilder.advanced) {
    return;
  }

  let setCenter = document.createElement('div');
  setCenter.setAttribute('id', 'map_set_center');
  setCenter.setAttribute('title', 'Set as initial zoom and center');
  setCenter.innerHTML =
    '<span class="dashicons dashicons-admin-post"></span><span class="map_action_label"></span>';

  setCenter.addEventListener('click', function (ev) {
    let centerData = document.getElementById('map_visual_info').dataset.visual;
    centerData = JSON.parse(centerData);
    iMapsBuilder.setInitialCenter(centerData);
    let icon = ev.target;
    icon.classList.remove('dashicons-admin-post');
    icon.classList.add('dashicons-yes-alt');
    setTimeout(function () {
      icon.classList.remove('dashicons-yes-alt');
      icon.classList.add('dashicons-admin-post');
    }, 2500);
  });

  let visualBox = document.getElementById('map_visual_info_box');
  visualBox.appendChild(setCenter);
  visualBox.style.display = 'block';
};

iMapsBuilder.setInitialCenter = function (centerData) {
  let zoomField = document.getElementsByName('map_info[viewport][zoomLevel]')[0];
  let latitudeField = document.getElementsByName('map_info[viewport][homeGeoPoint][latitude]')[0];
  let longitudeField = document.getElementsByName('map_info[viewport][homeGeoPoint][longitude]')[0];
  zoomField.value = centerData.zoom;
  latitudeField.value = centerData.lat;
  longitudeField.value = centerData.long;

  // rebuildPreview
  const event = new Event('change');
  longitudeField.dispatchEvent(event);
};

iMapsBuilder.listenToClicks = function (mapID) {
  console.log(iMapsData.data[0].container);
  document
    .getElementById(iMapsData.data[0].container)
    .addEventListener('mapEntryClicked', function (ev) {
      let data = iMapsManager.maps[mapID].map.lastClickedEntry.dataItem.dataContext;
      iMapsBuilder.populateClickInfo(data);
    });
};

iMapsBuilder.populateClickInfo = function (data) {
  var container = document.getElementById('map_click_events_info'),
    info = '';
  controls = false;

  if (container && data) {
    info += 'ID: ' + data.id + '<br>';

    if (data.name) {
      info += 'Name: ' + data.name + '<br>';
    }

    if (data.madeFromGeoData) {
      controls = iMapsBuilder.addRegionButton(data.id, data.name);
      controls.addEventListener('click', function (ev) {
        ev.target.classList.remove('dashicons-plus-alt');
        ev.target.classList.add('dashicons-yes-alt');
        ev.target.style.pointerEvents = 'none';
      });
    }

    if (data.latitude) {
      info += 'LAT: ' + Number(data.latitude).toFixed(6) + '<br>';
      info += 'LONG: ' + Number(data.longitude).toFixed(6) + '<br>';
    }

    if (data.action) {
      info += 'Action: ' + data.action.replace('igm_', '') + '<br>';
    }
    container.parentElement.style.display = 'block';
    container.innerHTML = info;

    if (controls) {
      container.appendChild(controls);
    }
  }
};

iMapsBuilder.checkMaxInputVars = function () {
  var numNormInputs = document.getElementsByTagName('input').length;
  var numTextarea = document.getElementsByTagName('textarea').length;
  var numInputs = numNormInputs + numTextarea;
  var warning = '';
  var firstBox = document.getElementById('titlediv');
  var reqBox = document.getElementById('map_min_req');
  var icon = '<span class="dashicons dashicons-yes-alt"></span>';

  console.log('Number of inputs: ', numInputs + numTextarea);
  console.log('Max Input Vars: ', iMapsOptions.max_input_vars);

  if (parseInt(numInputs) > parseInt(iMapsOptions.max_input_vars * 0.75)) {
    warning = document.createElement('div');
    warning.setAttribute('class', 'notice notice-error is-dismissible');
    warning.innerHTML = '<h1>' + iMapsOptions.messages.maxInputError + '</h1>';
    icon = firstBox.insertBefore(warning, firstBox.childNodes[0]);

    icon = '<span class="dashicons dashicons-warning"></span>';
  }

  reqBox.innerHTML =
    'max_input_vars: ' + numInputs + '/' + iMapsOptions.max_input_vars + ' ' + icon;
};

iMapsBuilder.init = function () {
  var saveBtn = document.getElementById('publish'),
    mapID = document.getElementById('post_ID').value;

  // add listener to accordions and clone buttons for maxInputVars
  iMapsBuilder.addRepeatFieldsListener();

  //check if advanced
  if (document.body.classList.contains('igm-pro')) {
    iMapsBuilder.advanced = true;
  }

  // click action warning
  iMapsBuilder.clickActionWarnings();

  // add preview
  if (typeof iMapsData !== 'undefined') {
    iMapsBuilder.buildPreview();
    iMapsBuilder.initAvailableRegions();
    iMapsBuilder.addPreviewImage();
    iMapsBuilder.listenToClicks(mapID);
  }

  // save button
  saveBtn.addEventListener('click', function (ev) {
    var mapImageField = document.getElementsByName('map_image[mapImage]')[0],
      mapId = document.getElementById('post_ID').value;

    if (typeof mapImageField === 'undefined') {
      return;
    }

    if (!iMapsBuilder.imageSaved) {
      if (iMaps.maps && iMaps.maps[mapId] && iMaps.maps[mapId].map) {
        ev.preventDefault();

        var zoomLevel = iMaps.maps[mapId].map.zoomLevel;
        if (zoomLevel !== 1) {
          iMaps.maps[mapId].map.goHome(0);
        }

        iMaps.maps[mapId].map.exporting.getImage('svg').then(function (imgData) {
          mapImageField.value = imgData;
          iMapsBuilder.imageSaved = true;
          ev.target.click();
        });
      }
    }
  });

  // check for overlay and make sortable
  iMapsBuilder.sortableOverlay();

  // check for auto labels clear link
  iMapsBuilder.autoLabelsReset();

  // geocoding fields
  if (iMapsOptions.googleApiKey && iMapsOptions.googleApiKey !== '') {
    var geocodingFields = document.getElementsByClassName('geocoding');
    for (var i = 0; i < geocodingFields.length; i++) {
      geocodingFields.item(i).classList.remove('geocoding-hide');
    }

    // enable google autocomplete
    if (iMapsOptions.googleAutocomplete && iMapsOptions.googleAutocomplete === '1') {
      iMapsBuilder.initGoogleAutocomplete();
    } else {
      iMapsBuilder.initGeocoding();
    }
  }

  iMapsBuilder.editControls();
  iMapsBuilder.prepareAddMarkerActions();

  // check number of inputs
  setTimeout(function () {
    iMapsBuilder.checkMaxInputVars();
  }, 1000);
};

iMapsBuilder.addRepeatFieldsListener = function () {
  var cloneBts = document.getElementsByClassName('csf-cloneable-add');

  for (var i = 0; i < cloneBts.length; i++) {
    cloneBts[i].addEventListener('click', iMapsBuilder.checkMaxInputVars, false);
  }
};

iMapsBuilder.clickActionWarnings = function () {
  var clickActionBts = document.getElementsByName('map_info[regionDefaults][action]')[0];
  var clickActionMarkerBts = document.getElementsByName('map_info[markerDefaults][action]')[0];
  var mainContainer = document.getElementById('map_info');

  clickActionBts.addEventListener('change', function (ev) {
    if (this.value !== 'none') {
      mainContainer.classList.add('igm_region_click_check');
    } else {
      mainContainer.classList.remove('igm_region_click_check');
    }
  });

  clickActionMarkerBts.addEventListener('change', function (ev) {
    if (this.value !== 'none') {
      mainContainer.classList.add('igm_marker_click_check');
    } else {
      mainContainer.classList.remove('igm_marker_click_check');
    }
  });

  // on initial load, check them
  if (clickActionBts && clickActionBts.value !== 'none') {
    mainContainer.classList.add('igm_region_click_check');
  }

  if (clickActionMarkerBts && clickActionMarkerBts.value !== 'none') {
    mainContainer.classList.add('igm_marker_click_check');
  }
};

/**
 * Set up click event to reset auto labels custom coordinates
 */
iMapsBuilder.autoLabelsReset = function () {
  var clearLink = document.getElementById('igm-reset-auto-labels');
  if (clearLink) {
    clearLink.addEventListener('click', function (ev) {
      if (confirm(iMapsOptions.messages.resetAutoLabels)) {
        var regionLabelsCustomCoordinates = document.getElementsByName(
          'map_info[regionLabels][regionLabelCustomCoordinates]'
        )[0];
        regionLabelsCustomCoordinates.value = '';
        regionLabelsCustomCoordinates.dispatchEvent(new Event('change'));
      }
    });
  }
};

iMapsBuilder.sortableOverlay = function () {
  // Using jQuery since we'll use jquery-ui for sortable anyway
  var overlayParent = jQuery('[data-depend-id=overlay]');
  var overlaySortable;

  if (overlayParent) {
    overlaySortable = overlayParent.first().closest('ul');

    // take advantage of this function to also set the title attribute for the li with the map id
    overlaySortable.find('li').each(function () {
      jQuery(this).attr('title', 'Map ID: ' + jQuery(this).find('input').attr('value'));
    });
  }

  // update order when we select a new overlay
  overlayParent.on('change', function () {
    iMapsBuilder.updateOrderOverlay();
  });

  // if there's an order
  var overlayOrder = document.querySelector('[data-depend-id=overlayOrder]');
  if (overlayOrder && overlayOrder.value !== '' && overlaySortable) {
    var orderValues = JSON.parse(overlayOrder.value);
    if (Array.isArray(orderValues)) {
      orderValues.reverse();
      orderValues.forEach(function (val) {
        var thisOrder = overlaySortable.find('input[value=' + val + ']').closest('li');
        if (thisOrder) {
          overlaySortable.prepend(thisOrder);
        }
      });
    }
  }

  // set sortable behaviour
  if (overlayParent) {
    overlaySortable.sortable({
      placeholder: 'ui-state-highlight',
      stop: function (event, ui) {
        iMapsBuilder.previewBlocked = true;
        iMapsBuilder.blockPreview();
        iMapsBuilder.updateOrderOverlay();
      },
    });
    overlayParent.disableSelection();
  }
};

iMapsBuilder.updateOrderOverlay = function () {
  var overlayOrder = document.querySelector('[data-depend-id=overlayOrder]');
  var overlaySelected = document.querySelectorAll('input[data-depend-id=overlay]:checked');
  var order = [];

  if (overlaySelected) {
    overlaySelected.forEach(function (el) {
      order.push(el.value);
    });
  }
  order = JSON.stringify(order);
  overlayOrder.value = order;
};

iMapsBuilder.prepareAddMarkerActions = function () {
  var addMarkerButton = document.getElementById('map_click_add_marker');
  var addMarkerButtonIcon = addMarkerButton.querySelector('.dashicons');
  var addMarkerButtonLabel = addMarkerButton.querySelector('.map_action_label');

  // listen to clicked point event
  document.addEventListener('mapPointClicked', function (e) {
    // set coordinates in button
    addMarkerButton.setAttribute('data-latitude', e.detail.latitude);
    addMarkerButton.setAttribute('data-longitude', e.detail.longitude);
    addMarkerButtonIcon.classList.remove('dashicons-yes-alt');
    addMarkerButtonIcon.classList.add('dashicons-plus-alt');
    addMarkerButtonLabel.innerHTML = 'Add Marker Here';
  });

  addMarkerButton.addEventListener(
    'click',
    function (e) {
      e.stopPropagation();

      var lat = addMarkerButton.getAttribute('data-latitude');
      var long = addMarkerButton.getAttribute('data-longitude');

      iMapsBuilder.addMarker(lat, long);

      addMarkerButtonIcon.classList.remove('dashicons-plus-alt');
      addMarkerButtonIcon.classList.add('dashicons-yes-alt');
      addMarkerButtonLabel.innerHTML = 'Marker Added';
    },
    false
  );
};

iMapsBuilder.updateRegionsUsed = function () {
  var regionFields = document.querySelectorAll('.region-code-autocomplete');
  var result = [].map.call(regionFields, function (e) {
    return e.value;
  });

  iMapsBuilder.regionsUsed = result;
  return result;
};

iMapsBuilder.addPreviewImage = function () {
  var mapImage = document.getElementById('map_image_preview'),
    mapImageField = document.getElementsByName('map_image[mapImage]')[0];

  if (mapImageField && mapImageField.value !== '') {
    mapImage.innerHTML = '<img class="igm_map_image_preview" src="' + mapImageField.value + '">';
  }
};

iMapsBuilder.initAvailableRegions = function () {
  var data = iMapsData.data[0],
    regionCodes;

  if (data.disabled) {
    return;
  }

  if (data.map === 'custom' || data.map.startsWith('http')) {
    fetch(data.mapURL)
      .then(function (res) {
        res.json().then(function (out) {
          regionCodes = iMapsBuilder.extractGeojson(out);
          iMapsBuilder.updateRegionsUsed();
          iMapsBuilder.populateAvailableRegions(regionCodes);
        });
      })
      .catch(function (err) {
        console.error(err);
      });
  } else {
    mapVar = iMapsRouter.getVarByName(data.map);

    if (typeof window[mapVar] !== 'undefined') {
      regionCodes = iMapsBuilder.extractGeojson(window[mapVar]);
      iMapsBuilder.updateRegionsUsed();
      iMapsBuilder.populateAvailableRegions(regionCodes);
    } else {
      return;
    }
  }
};

iMapsBuilder.populateAvailableRegions = function (regionCodes) {
  var data = iMapsData.data[0],
    regionDataContainer = document.getElementsByName('map_regions_info[regionData]')[0],
    container = document.getElementById('map_region_data'),
    currentMap = document.getElementsByName('map_info[map]')[0].selectedOptions[0].text,
    jsonContainer,
    containerContent,
    tree,
    regionData = {},
    populateButton,
    regionDataArray = [],
    mainContainer = document.getElementById('map_info'),
    html = document.createElement('div'),
    used = iMapsBuilder.regionsUsed;

  if (typeof regionCodes === 'undefined') {
    regionCodes = iMapsBuilder.regionCodes;
  } else {
    iMapsBuilder.regionCodes = regionCodes;
  }

  if (container) {
    var currentMapEl = document.createElement('p');
    currentMapEl.innerHTML = currentMap;
    html.appendChild(currentMapEl);

    // add button to autopopulate map
    /*
		populateButton = document.createElement("button");
		populateButton.innerHTML = "Populate Map with all regions";
		populateButton.setAttribute("class", "button button-secondary");
		populateButton.onclick = function (e) {
			e.preventDefault();

			Object.keys(regionCodes).forEach(function (region) {
				iMapsBuilder.addRegion(
					regionCodes[region].id,
					regionCodes[region].name
				);
			});

			// trigger form change event
			document
				.getElementsByName("map_info[map]")[0]
				.dispatchEvent(new Event("change"));
		};
		html.appendChild(populateButton);
		*/
    var regionCodeEl = document.createElement('code');
    regionCodeEl.innerHTML = iMapsOptions.messages.regionCode;
    html.appendChild(regionCodeEl);

    var regionNameEl = document.createElement('span');
    regionNameEl.innerHTML =
      iMapsOptions.messages.regionName +
      '<br> <small>' +
      iMapsOptions.messages.regionCodeInfo +
      '</small>';
    html.appendChild(regionNameEl);

    html.appendChild(document.createElement('br'));
    html.appendChild(document.createElement('br'));

    Object.keys(regionCodes)
      .sort()
      .forEach(function (region) {
        regionData[regionCodes[region].name] = region;

        regionDataArray.push({
          label: regionCodes[region].name + ' ' + '(' + region + ')',
          value: region,
        });

        // if there's no name property, try NAME or id
        if (typeof regionCodes[region].name === 'undefined') {
          if (typeof regionCodes[region].NAME !== 'undefined') {
            regionCodes[region].name = regionCodes[region].NAME;
          } else {
            regionCodes[region].name = region;
          }
        }

        html.appendChild(iMapsBuilder.addRegionButton(region, regionCodes[region].name));

        var regionCodeId = document.createElement('code');
        regionCodeId.innerHTML = region;
        html.appendChild(regionCodeId);

        // append space to separate elements
        html.appendChild(document.createTextNode(' '));

        var regionNameLoop = document.createElement('span');
        regionNameLoop.innerHTML = regionCodes[region].name;
        html.appendChild(regionNameLoop);
        html.appendChild(document.createElement('br'));
      });

    var fullDataEl = document.createElement('p');
    fullDataEl.innerHTML = iMapsOptions.messages.fullData;
    html.appendChild(fullDataEl);

    containerContent = document.createElement('div');
    containerContent.appendChild(html);

    container.innerHTML = '';
    container.appendChild(containerContent);

    jsonContainer = document.createElement('DIV');
    container.appendChild(jsonContainer);

    // Create json-tree
    tree = jsonTree.create(
      {
        full: regionCodes,
      },
      jsonContainer
    );

    // set regionData to hidden field to be saved
    regionDataContainer.value = JSON.stringify(regionData);
    iMapsBuilder.regionData = regionDataArray;

    // set region code fields to autocomplete
    mainContainer.addEventListener('click', iMapsBuilder.clickEvents);

    // for the region autocomplete
    mainContainer.addEventListener('focus', iMapsBuilder.eventRegionCodeAutocomplete, true);
  }
};

iMapsBuilder.addRegionButton = function (id, name) {
  var icon = document.createElement('span'),
    form;

  if (!iMapsBuilder.regionsUsed.includes(id.toString())) {
    icon.classList.add('igm_add_region_btn', 'dashicons', 'dashicons-plus-alt');
  } else {
    icon.classList.add('dashicons', 'dashicons-yes-alt');
    return icon;
  }

  icon.setAttribute('title', iMapsOptions.messages.addToMap);

  icon.onclick = function (e) {
    e.preventDefault();

    iMapsBuilder.addRegion(id, name);

    // trigger form change event
    previewContainer = document.querySelector('.map_wrapper');

    if (!previewContainer) {
      return;
    }

    iMapsBuilder.needsUpdate = true;
    previewContainer.classList.add('map_updating');

    if (!iMapsBuilder.isInViewport(previewContainer)) {
      return;
    }

    form = iMapsBuilder.form;
    iMapsBuilder.updatePreview(form, false);
    return;
  };

  return icon;
};

iMapsBuilder.clickEvents = function (e) {
  var previewContainer;

  if (e.target && e.target.classList.contains('csf-cloneable-remove')) {
    previewContainer = document.querySelector('.map_wrapper');
    previewContainer.classList.add('map_updating');

    // update region list? Only when regions.. should be improved
    iMapsBuilder.updateRegionsUsed();
    iMapsBuilder.populateAvailableRegions();

    if (previewContainer && !iMapsBuilder.isInViewport(previewContainer)) {
      iMapsBuilder.needsUpdate = true;
      return;
    }
  }
};

iMapsBuilder.eventRegionCodeAutocomplete = function (e) {
  if (e.target && e.target.classList.contains('region-code-autocomplete')) {
    autocomplete({
      input: e.target,
      preventSubmit: true,
      fetch: function (text, update) {
        text = text.toLowerCase();
        // you can also use AJAX requests instead of preloaded data
        var suggestions = iMapsBuilder.regionData.filter(function (n) {
          return n.label.toLowerCase().includes(text);
        });
        update(suggestions);
      },
      onSelect: function (item) {
        e.target.value = item.value;
      },
    });
  }
};

iMapsBuilder.extractGeojson = function (geojson) {
  if (typeof geojson === 'undefined') {
    return {
      error: iMapsOptions.messages.jsonError,
    };
  }

  var extracted = {},
    features = geojson.features ? geojson.features : geojson;

  Object.keys(features).forEach(function (key) {
    extracted[features[key].id] = features[key].properties
      ? features[key].properties
      : features[key];
  });

  return extracted;
};

iMapsBuilder.buildPreview = function () {
  var previewContainer = document.getElementById('map_preview'),
    form = iMapsBuilder.form,
    mapId,
    mapContainer,
    mapData,
    onChangeFunction,
    inputsSelector,
    inputs,
    switchInputs;

  window.addEventListener(
    'scroll',
    function (e) {
      if (iMapsBuilder.isInViewport(previewContainer)) {
        if (iMapsBuilder.needsUpdate) {
          iMapsBuilder.updatePreview(form, false);
        }
      }
    },
    false
  );

  // set listener for input fields of form
  onChangeFunction = iMapsBuilder.eventThrottle(function (e) {
    // create exceptions
    if (
      e.target.classList.contains('chosen-search-input') ||
      e.target.classList.contains('skip-preview') ||
      e.target.name == 'map_info[description]'
    ) {
      return;
    }
    //form = document.querySelector("form#post"),
    iMapsBuilder.updatePreview(form, e);
  }, 3000);

  //form.addEventListener("change", onChangeFunction);
  inputsSelector = '#map_info input, #map_info select, #map_info textarea';
  inputs = document.querySelectorAll(inputsSelector);

  inputs.forEach(function (input) {
    input.onchange = onChangeFunction;
  });

  // when a clone button is clicked, we remove event listener from form and add it again to include new inputs
  document.querySelectorAll('.csf-cloneable-add').forEach(function (button) {
    button.addEventListener('click', function (e) {
      inputs.forEach(function (input) {
        input.onchange = null;
      });
      setTimeout(function () {
        inputs = document.querySelectorAll(inputsSelector);
        inputs.forEach(function (input) {
          input.onchange = onChangeFunction;
        });
      }, 500);
    });
  });

  // onclick events to trigger change on some fields
  switchInputs = document.querySelectorAll('#map_info .csf--switcher');
  switchInputs.forEach(function (inp) {
    // inp.addEventListener("click", onChangeFunction);
  });

  if (previewContainer) {
    mapContainer = previewContainer.querySelector('.map_render');
    mapId = document.getElementById('post_ID').value;
    mapContainer.id = 'map_' + mapId;

    // trigger map preview if first time
    if (iMapsData.data[0].disabled) {
      document.getElementsByName('map_info[map]')[0].dispatchEvent(new Event('change'));
    }
  }
};

iMapsBuilder.restartMap = function () {
  var data;
  var previewContainer = document.querySelector('.map_wrapper');

  if (iMaps.maps) {
    Object.keys(iMaps.maps).forEach(function (id) {
      iMaps.maps[id].map.dispose();
    });

    data = iMapsModel.prepareData(iMapsData.data);
    data.forEach(function (tdata, index) {
      if (tdata.disabled) {
        return;
      }
      iMapsManager.init(index);
    });
    iMapsBuilder.needsUpdate = false;
  }

  previewContainer.classList.remove('map_updating');
};

iMapsBuilder.updatePreview = function (form, ev) {
  var formData = new FormData(form),
    mapContainer,
    mapData,
    mapWrapper,
    paddingTop,
    maxWidth,
    baseRegionSeries,
    previewContainer,
    map = false;

  // if we're just scrolling and we don't need to update
  if (!ev && !iMapsBuilder.needsUpdate) {
    return;
  }

  // if the preview is blocked - because of overlay preview
  if (iMapsBuilder.previewBlocked) {
    return;
  }

  // if the change event was not from the map_info collection
  if (ev && !ev.target.name.includes('map_info')) {
    return;
  }

  if (iMaps.maps) {
    Object.keys(iMaps.maps).forEach(function (id) {
      mapData = iMaps.maps[id];
      map = iMaps.maps[id].map;
      baseRegionSeries = iMaps.maps[id].baseRegionSeries;
    });
  }

  // if we only changed visual stuff
  if (
    ev &&
    (ev.target.name == 'map_info[visual][paddingTop]' ||
      ev.target.name == 'map_info[visual][maxWidth]')
  ) {
    maxWidth = document.getElementsByName('map_info[visual][maxWidth]')[0];
    paddingTop = document.getElementsByName('map_info[visual][paddingTop]')[0];
    mapWrapper = document.querySelector('.map_wrapper .map_box');
    mapContainer = document.querySelector('.map_aspect_ratio');
    mapContainer.style.paddingTop = String(paddingTop.value) + '%';

    if (maxWidth !== '' && maxWidth !== '0') {
      mapWrapper.style.maxWidth = String(maxWidth.value) + 'px';
    }

    return;
  }
  // change fontFamily
  if (ev && ev.target.name == 'map_info[visual][fontFamily]') {
    mapWrapper = document.querySelector('.map_wrapper .map_box');
    mapWrapper.style.fontFamily = ev.target.value;
    return;
  }

  // change projections
  /*
	if (ev && ev.target.name == "map_info[projection]" && map) {

		if ("Orthographic" !== ev.target.value && ev.target.value !== "Albers" ) {
			map.projection = new am4maps.projections[ev.target.value]();
			console.log(ev.target.value);

			return;
		}
	}*/

  // background color
  if (ev && ev.target.name == 'map_info[visual][backgroundColor]' && map) {
    if (ev.target.value === 'transparent') {
      map.background.fill = am4core.color('#f00', 0);
    } else {
      map.background.fill = am4core.color(ev.target.value);
    }

    return;
  }

  // borders width
  if (ev && ev.target.name == 'map_info[visual][borderWidth]' && map) {
    baseRegionSeries.mapPolygons.each(function (polygon) {
      polygon.animate(
        {
          property: 'strokeWidth',
          to: ev.target.value,
        },
        250
      );
    });

    return;
  }

  // inactive color
  if (ev && ev.target.name == 'map_info[visual][inactiveColor]' && map) {
    baseRegionSeries.mapPolygons.each(function (polygon) {
      if (polygon.dataItem.dataContext.madeFromGeoData) {
        return;
      }

      polygon.animate(
        {
          property: 'inactiveColor',
          to: ev.target.value,
        },
        250
      );
    });

    return;
  }

  // border color
  if (ev && ev.target.name == 'map_info[visual][borderColor]' && map) {
    baseRegionSeries.mapPolygons.each(function (polygon) {
      polygon.animate(
        {
          property: 'stroke',
          to: am4core.color(ev.target.value),
        },
        250
      );
    });

    return;
  }

  if (ev && ev.target.name == 'map_info[overlay][]' && map) {
    iMapsBuilder.previewBlocked = true;
    iMapsBuilder.blockPreview();

    return;
  }

  // if map changes and is set to 'custom' maybe we block it to make sure everything else works?
  if (
    ev &&
    ev.target.name == 'map_info[map]' &&
    ev.target.value === 'custom' &&
    ev.target.value === '' &&
    map
  ) {
    iMapsBuilder.previewBlocked = true;
    iMapsBuilder.blockPreview();
    return;
  }

  if (ev && ev.target.name == 'map_info[mapURL]' && ev.target.value !== '' && map) {
    iMapsBuilder.previewBlocked = true;
    iMapsBuilder.blockPreview();
    return;
  }

  if (iMapsOptions.preview && iMapsOptions.preview !== '1') {
    iMapsBuilder.previewBlocked = true;
    iMapsBuilder.blockPreview();

    return;
  }

  // to block preview after custom js change
  if (ev && ev.target.name == 'map_info[custom_js]' && map) {
    iMapsBuilder.previewBlocked = true;
    iMapsBuilder.blockPreview();

    return;
  }

  // if preview container is not visible, only update when it becomes visible
  // but only if the change was not in the map option
  previewContainer = document.querySelector('.map_wrapper');
  if (
    ev &&
    ev.target.name != 'map_info[map]' &&
    previewContainer &&
    !iMapsBuilder.isInViewport(previewContainer)
  ) {
    previewContainer.classList.add('map_updating');
    iMapsBuilder.needsUpdate = true;

    return;
  }

  formData.append('action', 'map_form_data');
  formData.append('security', iMapsOptions.ajax_nonce);

  previewContainer.classList.add('map_updating');

  jQuery.ajaxSetup({
    async: true,
  });

  console.log(formData);

  jQuery.ajax({
    url: iMapsOptions.ajax_url,
    type: 'POST',
    data: formData,
    contentType: false,
    processData: false,
    async: false,
    success: function (response) {
      var decode = [JSON.parse(response)];

      //handle entries with json that might lost formatting
      if (
        typeof decode[0].regionLabels === 'object' &&
        decode[0].regionLabels.hasOwnProperty('regionLabelCustomCoordinates')
      ) {
        decode[0].regionLabels.regionLabelCustomCoordinates =
          decode[0].regionLabels.regionLabelCustomCoordinates.replace(/\\/g, '');
      }

      iMapsData.data = decode;

      // merge with global options
      if (typeof iMapsOptions !== 'undefined') {
        iMapsData.data[0] = Object.assign(iMapsData.data[0], iMapsOptions);
      }

      if (ev && ev.target.name === 'map_info[map]') {
        // we changed map, so we need to attach it to the page
        iMapsBuilder.addGeoFileSeries(decode[0].mapURL, iMapsBuilder.restartMap);
      } else {
        // rebuild map
        iMapsBuilder.restartMap();
        //iMapsBuilder.checkMaxInputVars();
        console.log('map updated');
      }
    },
    error: function (error) {
      console.log(error);
    },
  });

  // check number of inputs
  // iMapsBuilder.checkMaxInputVars();
};

iMapsBuilder.blockPreview = function () {
  previewContainer = document.querySelector('.map_wrapper .map_blocked_preview');
  previewContainer.classList.remove('map_block_hidden');
  iMapsBuilder.needsUpdate = false;
  return;
};

/**
 * Adds a new script to the page
 *
 * @return false
 */
iMapsBuilder.addGeoFileSeries = function (src, clback) {
  if (!src) {
    return false;
  }

  var scriptPromise = new Promise(function (resolve, reject) {
    var script = document.createElement('script');
    document.body.appendChild(script);
    script.onload = resolve;
    script.onerror = reject;
    script.async = true;
    script.src = src;
  });

  scriptPromise.then(function () {
    clback();
    iMapsBuilder.initAvailableRegions();
  });

  return true;
};

iMapsBuilder.eventGeocoding = function (e) {
  // e.target is the clicked element!
  // If it was a list item
  if (e.target && e.target.classList.contains('geocoding-input')) {
    iMapsBuilder.geocoder = new google.maps.Geocoder();
    iMapsBuilder.searchInput = e.target;

    // key enter press
    iMapsBuilder.searchInput.addEventListener('keypress', function (e) {
      var key = e.which || e.keyCode;
      if (key === 13) {
        e.preventDefault();
        iMapsBuilder.geocodeAddress();
      }
    });

    // blur (remove focus) event
    iMapsBuilder.searchInput.addEventListener('blur', function (e) {
      iMapsBuilder.geocodeAddress();
    });
  }
};

iMapsBuilder.initGeocoding = function () {
  // Get the element, add a click listener...
  var container = document.getElementById('map_info');
  container.addEventListener('click', iMapsBuilder.eventGeocoding);
  container.addEventListener('focus', iMapsBuilder.eventGeocoding, true);
};

iMapsBuilder.eventGoogleAutocomplete = function (e) {
  // e.target is the clicked element!
  // If it was a list item
  if (e.target && e.target.classList.contains('geocoding-input')) {
    // Create the autocomplete object, restricting the search predictions to
    // geographical location types.
    iMapsBuilder.autocomplete = new google.maps.places.Autocomplete(e.target, {
      types: ['geocode'],
    });

    iMapsBuilder.searchInput = e.target;

    // Avoid paying for data that you don't need by restricting the set of
    // place fields that are returned to just the address components.
    iMapsBuilder.autocomplete.setFields(['geometry']);

    // When the user selects an address from the drop-down, populate the
    // address fields in the form.
    iMapsBuilder.autocomplete.addListener('place_changed', iMapsBuilder.fillInAddress);
  }
};

iMapsBuilder.initGoogleAutocomplete = function () {
  // Get the element, add a click listener...
  var container = document.getElementById('map_info');
  container.addEventListener('click', iMapsBuilder.eventGoogleAutocomplete);
  container.addEventListener('focus', iMapsBuilder.eventGoogleAutocomplete, true);

  return;
};

iMapsBuilder.fillInAddress = function (i) {
  var autocomplete = iMapsBuilder.autocomplete;
  var input = iMapsBuilder.searchInput;
  var parent = iMapsBuilder.getClosest(input, '.csf-fieldset-content');
  var changeEvent = new Event('change');

  console.log(iMapsBuilder.autocomplete);

  // Get the place details from the autocomplete object.
  var place = autocomplete.getPlace();
  var latfield = parent.querySelector('[data-depend-id="latitude"]');
  var lonfield = parent.querySelector('[data-depend-id="longitude"]');

  if (place) {
    latfield.value = place.geometry.location.lat();
    lonfield.value = place.geometry.location.lng();
    latfield.dispatchEvent(changeEvent);
  }
};

iMapsBuilder.geocodeAddress = function () {
  var addressInput = iMapsBuilder.searchInput,
    address = addressInput.value,
    geocoder = iMapsBuilder.geocoder,
    parent = iMapsBuilder.getClosest(iMapsBuilder.searchInput, '.csf-fieldset-content'),
    latfield = parent.querySelector('[data-depend-id="latitude"]'),
    lonfield = parent.querySelector('[data-depend-id="longitude"]'),
    place,
    changeEvent = new Event('change');

  addressInput.setAttribute('readonly', 'readonly');

  geocoder.geocode(
    {
      address: address,
    },
    function (results, status) {
      if (status === 'OK') {
        place = results[0];
        latfield.value = place.geometry.location.lat();
        lonfield.value = place.geometry.location.lng();
        latfield.dispatchEvent(changeEvent);
      } else {
        console.log('geocode error: ' + status);
      }

      addressInput.removeAttribute('readonly');
    }
  );
};

iMapsBuilder.getClosest = function (elem, selector) {
  // Element.matches() polyfill
  if (!Element.prototype.matches) {
    Element.prototype.matches =
      Element.prototype.matchesSelector ||
      Element.prototype.mozMatchesSelector ||
      Element.prototype.msMatchesSelector ||
      Element.prototype.oMatchesSelector ||
      Element.prototype.webkitMatchesSelector ||
      function (s) {
        var matches = (this.document || this.ownerDocument).querySelectorAll(s),
          i = matches.length;
        while (--i >= 0 && matches.item(i) !== this) {}
        return i > -1;
      };
  }

  // Get the closest matching element
  for (; elem && elem !== document; elem = elem.parentNode) {
    if (elem.matches(selector)) return elem;
  }
  return null;
};

iMapsBuilder.swap = function (json) {
  var ret = {};
  for (var key in json) {
    ret[json[key]] = key;
  }
  return ret;
};

iMapsBuilder.eventThrottle = function (fn, threshold, scope) {
  threshold = typeof threshold !== 'undefined' ? threshold : 250;
  var last, deferTimer;
  return function () {
    var context = scope || this;

    var now = +new Date(),
      args = arguments;
    if (last && now < last + threshold) {
      // hold on to it
      clearTimeout(deferTimer);
      deferTimer = setTimeout(function () {
        last = now;
        fn.apply(context, args);
      }, threshold);
    } else {
      last = now;
      fn.apply(context, args);
    }
  };
};

iMapsBuilder.addRegion = function (regionCode, regionName) {
  var newEntry,
    titleField,
    regionCodeField,
    tooltipField,
    regionCollection,
    regionCheck = false,
    regionTab,
    addButton = document.querySelector('.regions_tab .csf-cloneable-add');

  regionTab = document.querySelector('#map_info .csf-nav-metabox ul li:nth-of-type(3)');
  if (!regionTab.classList.contains('csf-section-active')) {
    regionTab.querySelector('a').click();
  }

  // check if region already exists
  regionCollection = document.querySelector('.region-code-autocomplete');

  if (regionCollection.length > 0) {
    regionCollection.forEach(function (field) {
      if (field.value === regionCode) {
        regionCheck = true;
      }
    });
  }

  // if it doesn't exist yet
  if (!regionCheck) {
    addButton.click();

    newEntry = document.querySelector(
      'div[data-field-id="[regions]"] .csf-cloneable-item:last-of-type'
    );

    // set title
    titleField = newEntry.querySelector('[data-depend-id="name"]');
    titleField.value = regionName;
    titleField.dispatchEvent(new Event('keyup'));

    // set regionCode
    regionCodeField = newEntry.querySelector('[data-depend-id="id"]');
    regionCodeField.value = regionCode;

    // set Tooltip
    tooltipField = newEntry.querySelector('[data-depend-id="tooltipContent"]');
    tooltipField.value = regionName;
  }

  iMapsBuilder.updateRegionsUsed();
  iMapsBuilder.populateAvailableRegions();
};

iMapsBuilder.addMarker = function (latitude, longitude) {
  var newEntry,
    titleField,
    latitudeField,
    longitudeField,
    tooltipField,
    markersTab,
    form,
    previewContainer = document.querySelector('.map_wrapper'),
    addButton = document.querySelector('.markers_tab .csf-cloneable-add');

  markersTab = document.querySelector('#map_info .csf-nav-metabox ul li:nth-of-type(4)');

  if (!markersTab.classList.contains('csf-section-active')) {
    markersTab.querySelector('a').click();
  }

  addButton.click();

  newEntry = document.querySelector(
    'div[data-field-id="[roundMarkers]"] .csf-cloneable-item:last-of-type'
  );

  if (newEntry) {
    // set title
    titleField = newEntry.querySelector('[data-depend-id="id"]');

    thisID = titleField.getAttribute('name');
    thisID = thisID.replace('map_info[roundMarkers]', '');
    thisID = thisID.replace('[id]', '');

    titleField.value = 'Custom Marker ' + thisID;
    titleField.dispatchEvent(new Event('keyup'));

    // set Tooltip
    tooltipField = newEntry.querySelector('[data-depend-id="tooltipContent"]');
    tooltipField.value = 'Custom Marker ' + thisID;

    // set lat and long
    latitudeField = newEntry.querySelector('[data-depend-id="latitude"]');
    longitudeField = newEntry.querySelector('[data-depend-id="longitude"]');

    if (latitudeField && longitudeField) {
      latitudeField.value = latitude;
      longitudeField.value = longitude;
    }
    // probably using openstreetmap
    else {
      latitudeField = newEntry.querySelector('.csf--latitude');
      longitudeField = newEntry.querySelector('.csf--longitude');
      latitudeField.value = latitude;
      longitudeField.value = longitude;
      latitudeField.dispatchEvent(new Event('change'));
    }

    iMapsBuilder.needsUpdate = true;
    previewContainer.classList.add('map_updating');

    if (!iMapsBuilder.isInViewport(previewContainer)) {
      return;
    }

    form = iMapsBuilder.form;
    iMapsBuilder.updatePreview(form, false);
    return;
  }
};

/*!
 * Determine if an element is in the viewport
 * (c) 2017 Chris Ferdinandi, MIT License, https://gomakethings.com
 * @param  {Node}    elem The element
 * @return {Boolean}      Returns true if element is in the viewport
 */
iMapsBuilder.isInViewport = function (elem) {
  var distance = elem.getBoundingClientRect();
  return (
    distance.bottom >= 250 &&
    distance.bottom <= (window.innerHeight || document.documentElement.clientHeight)
  );
};

// code for geolocate metabox
iMapsBuilder.geoLocateInit = function () {
  // fix map field not rendering properly when initially hidden
  let trigger = document.querySelector('[data-depend-id="enabled"]').closest('.csf--switcher');
  trigger.addEventListener('click', function () {
    window.dispatchEvent(new Event('resize'));
  });
};

// if we have the options available, we're in the edit map screen
if (typeof iMapsOptions !== 'undefined') {
  iMapsBuilder.init();
} else {
  iMapsBuilder.geoLocateInit();
}
