From 6ad1b015aa6fbc9ca51b5cc766dc44adc55a6867 Mon Sep 17 00:00:00 2001
From: Tor-Einar Skog <tor-einar.skog@nibio.no>
Date: Wed, 20 Sep 2023 13:53:21 +0200
Subject: [PATCH] Feature: FireBlight map: First draft of nursery/apiary site
 layer

---
 pom.xml                                       |   2 +-
 .../session/PointOfInterestBean.java          |   1 +
 .../vips/logic/entity/PointOfInterest.java    |   3 +
 .../entity/PointOfInterestTypeApiarySite.java |  36 +
 .../entity/PointOfInterestTypeNursery.java    |  36 +
 .../nibio/vips/logic/service/POIService.java  |  24 +
 .../db/migration/V14__POI_type_added.sql      |  38 +
 .../vips/logic/i18n/vipslogictexts.properties |   2 +
 .../logic/i18n/vipslogictexts_bs.properties   |   2 +
 .../logic/i18n/vipslogictexts_hr.properties   |   2 +
 .../logic/i18n/vipslogictexts_nb.properties   |   2 +
 .../logic/i18n/vipslogictexts_sr.properties   |   2 +
 .../i18n/vipslogictexts_zh_CN.properties      |   2 +
 .../map_applications/fireblight/js/map.js     | 912 ++++++++++--------
 src/main/webapp/templates/poiForm.ftl         |   2 +-
 15 files changed, 665 insertions(+), 401 deletions(-)
 create mode 100644 src/main/java/no/nibio/vips/logic/entity/PointOfInterestTypeApiarySite.java
 create mode 100644 src/main/java/no/nibio/vips/logic/entity/PointOfInterestTypeNursery.java
 create mode 100644 src/main/resources/db/migration/V14__POI_type_added.sql

diff --git a/pom.xml b/pom.xml
index f0953827..3b94a9fa 100755
--- a/pom.xml
+++ b/pom.xml
@@ -217,7 +217,7 @@
         <dependency>
             <groupId>no.nibio.vips</groupId>
             <artifactId>VIPSCommon</artifactId>
-            <version>2022.1</version>
+            <version>2.0.8-SNAPSHOT</version>
         </dependency>
         <dependency>
             <groupId>javax</groupId>
diff --git a/src/main/java/no/nibio/vips/logic/controller/session/PointOfInterestBean.java b/src/main/java/no/nibio/vips/logic/controller/session/PointOfInterestBean.java
index 8516bd86..fbe1d3e7 100755
--- a/src/main/java/no/nibio/vips/logic/controller/session/PointOfInterestBean.java
+++ b/src/main/java/no/nibio/vips/logic/controller/session/PointOfInterestBean.java
@@ -395,6 +395,7 @@ public class PointOfInterestBean {
         {
             GISUtil gisUtil = new GISUtil();
             poi.addProperty("pointOfInterestId", poi.getPointOfInterestId());
+            poi.addProperty("pointOfInterestTypeId", poi.getPointOfInterestTypeId());
             if(poi.getGisGeom() != null)
             {
                 
diff --git a/src/main/java/no/nibio/vips/logic/entity/PointOfInterest.java b/src/main/java/no/nibio/vips/logic/entity/PointOfInterest.java
index 2c22c7db..796d7816 100755
--- a/src/main/java/no/nibio/vips/logic/entity/PointOfInterest.java
+++ b/src/main/java/no/nibio/vips/logic/entity/PointOfInterest.java
@@ -48,6 +48,7 @@ import javax.persistence.DiscriminatorValue;
 import javax.persistence.FetchType;
 import javax.persistence.OneToMany;
 import no.nibio.vips.gis.GISUtil;
+import org.wololo.geojson.Feature;
 
 /**
  * @copyright 2017 <a href="http://www.nibio.no/">NIBIO</a>
@@ -64,6 +65,7 @@ import no.nibio.vips.gis.GISUtil;
     @NamedQuery(name = "PointOfInterest.findByPointOfInterestId", query = "SELECT p FROM PointOfInterest p WHERE p.pointOfInterestId = :pointOfInterestId"),
     @NamedQuery(name = "PointOfInterest.findByPointOfInterestIds", query = "SELECT p FROM PointOfInterest p WHERE p.pointOfInterestId IN :pointOfInterestIds"),
     @NamedQuery(name = "PointOfInterest.findByOrganizationId", query = "SELECT p FROM PointOfInterest p WHERE p.user IN(SELECT u.userId FROM VipsLogicUser u WHERE u.organizationId=:organizationId OR u.organizationId IN (SELECT o.organizationId FROM Organization o WHERE o.parentOrganizationId = :organizationId))  ORDER BY p.name ASC"),
+    @NamedQuery(name = "PointOfInterest.findByOrganizationIdAndPoiTypes", query = "SELECT p FROM PointOfInterest p WHERE p.pointOfInterestTypeId in :pointOfInterestTypes AND p.user IN(SELECT u.userId FROM VipsLogicUser u WHERE u.organizationId=:organizationId OR u.organizationId IN (SELECT o.organizationId FROM Organization o WHERE o.parentOrganizationId = :organizationId))  ORDER BY p.name ASC"),
     @NamedQuery(name = "PointOfInterest.findForecastLocationsByOrganizationId", query = "SELECT p FROM PointOfInterest p WHERE p.isForecastLocation IS TRUE AND p.user IN(SELECT u.userId FROM VipsLogicUser u WHERE u.organizationId=:organizationId OR u.organizationId IN (SELECT o.organizationId FROM Organization o WHERE o.parentOrganizationId = :organizationId))  ORDER BY p.name ASC"),
     @NamedQuery(name = "PointOfInterest.findByName", query = "SELECT p FROM PointOfInterest p WHERE p.name = :name"),
     @NamedQuery(name = "PointOfInterest.findByNameCaseInsensitive", query = "SELECT p FROM PointOfInterest p WHERE lower(p.name) = lower(:name)"),
@@ -357,6 +359,7 @@ public class PointOfInterest implements Serializable, Comparable {
     public String getGeoJSON()
     {
         this.addProperty("pointOfInterestId", this.getPointOfInterestId());
+        this.addProperty("pointOfInterestTypeId", this.getPointOfInterestTypeId());
         return this.gisUtil.getGeoJSONFromGeometry(this.getGisGeom(), this.getProperties());
     }
     
diff --git a/src/main/java/no/nibio/vips/logic/entity/PointOfInterestTypeApiarySite.java b/src/main/java/no/nibio/vips/logic/entity/PointOfInterestTypeApiarySite.java
new file mode 100644
index 00000000..58e0e462
--- /dev/null
+++ b/src/main/java/no/nibio/vips/logic/entity/PointOfInterestTypeApiarySite.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2020 NIBIO <http://www.nibio.no/>. 
+ * 
+ * This file is part of VIPSLogic.
+ * VIPSLogic is free software: you can redistribute it and/or modify
+ * it under the terms of the NIBIO Open Source License as published by 
+ * NIBIO, either version 1 of the License, or (at your option) any
+ * later version.
+ * 
+ * VIPSLogic is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * NIBIO Open Source License for more details.
+ * 
+ * You should have received a copy of the NIBIO Open Source License
+ * along with VIPSLogic.  If not, see <http://www.nibio.no/licenses/>.
+ * 
+ */
+
+package no.nibio.vips.logic.entity;
+
+import java.io.Serializable;
+import javax.persistence.DiscriminatorValue;
+import javax.persistence.Entity;
+import javax.persistence.Table;
+
+/**
+ * @copyright 2023 <a href="http://www.nibio.no/">NIBIO</a>
+ * @author Tor-Einar Skog <tor-einar.skog@nibio.no>
+ */
+@Entity
+@DiscriminatorValue("6")
+@Table(name = "point_of_interest_apiary_site")
+public class PointOfInterestTypeApiarySite extends PointOfInterest implements Serializable {
+
+}
diff --git a/src/main/java/no/nibio/vips/logic/entity/PointOfInterestTypeNursery.java b/src/main/java/no/nibio/vips/logic/entity/PointOfInterestTypeNursery.java
new file mode 100644
index 00000000..18565569
--- /dev/null
+++ b/src/main/java/no/nibio/vips/logic/entity/PointOfInterestTypeNursery.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2020 NIBIO <http://www.nibio.no/>. 
+ * 
+ * This file is part of VIPSLogic.
+ * VIPSLogic is free software: you can redistribute it and/or modify
+ * it under the terms of the NIBIO Open Source License as published by 
+ * NIBIO, either version 1 of the License, or (at your option) any
+ * later version.
+ * 
+ * VIPSLogic is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * NIBIO Open Source License for more details.
+ * 
+ * You should have received a copy of the NIBIO Open Source License
+ * along with VIPSLogic.  If not, see <http://www.nibio.no/licenses/>.
+ * 
+ */
+
+package no.nibio.vips.logic.entity;
+
+import java.io.Serializable;
+import javax.persistence.DiscriminatorValue;
+import javax.persistence.Entity;
+import javax.persistence.Table;
+
+/**
+ * @copyright 2023 <a href="http://www.nibio.no/">NIBIO</a>
+ * @author Tor-Einar Skog <tor-einar.skog@nibio.no>
+ */
+@Entity
+@DiscriminatorValue("7")
+@Table(name = "point_of_interest_nursery")
+public class PointOfInterestTypeNursery extends PointOfInterest implements Serializable {
+
+}
diff --git a/src/main/java/no/nibio/vips/logic/service/POIService.java b/src/main/java/no/nibio/vips/logic/service/POIService.java
index 7ef5783d..32839ba2 100644
--- a/src/main/java/no/nibio/vips/logic/service/POIService.java
+++ b/src/main/java/no/nibio/vips/logic/service/POIService.java
@@ -46,6 +46,9 @@ import com.fasterxml.jackson.core.type.TypeReference;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import com.webcohesion.enunciate.metadata.Facet;
 import com.webcohesion.enunciate.metadata.rs.TypeHint;
+import java.util.Arrays;
+import java.util.stream.Collectors;
+import javax.ws.rs.QueryParam;
 
 import no.nibio.vips.gis.GISUtil;
 import no.nibio.vips.logic.entity.Country;
@@ -97,6 +100,27 @@ public class POIService {
         PointOfInterest retVal = SessionControllerGetter.getPointOfInterestBean().getPointOfInterest(pointOfInterestId);
         return Response.ok().entity(retVal).build();
     }
+    
+    /**
+     * @param organizationId Id of the organization in question
+     * @param poiTypesStr Comma separated list of poiTypes
+     * @return GeoJson with pois filtered by organization and type
+     */
+    @GET
+    @Path("organization/{organizationId}/type/geojson")
+    @Produces("application/json;charset=UTF-8")
+    @TypeHint(PointOfInterest.class)
+    public Response getPoisByPoiTypesAsGeoJson(
+            @PathParam("organizationId") Integer organizationId,
+            @QueryParam("poiTypes") String poiTypesStr
+    )
+    {
+        List<Integer> poiTypes = Arrays.asList(poiTypesStr.split(",")).stream().map(str->Integer.valueOf(str)).collect(Collectors.toList());
+        Organization organization = SessionControllerGetter.getUserBean().getOrganization(organizationId);
+        List<PointOfInterest> pois = SessionControllerGetter.getPointOfInterestBean().getPoisForOrganizationAndOfTypes(organization, poiTypes); 
+        
+        return Response.ok().entity(SessionControllerGetter.getPointOfInterestBean().getPoisAsGeoJson(pois)).build();
+    }
 
     /**
      * Find a POI (Point of interest) by name
diff --git a/src/main/resources/db/migration/V14__POI_type_added.sql b/src/main/resources/db/migration/V14__POI_type_added.sql
new file mode 100644
index 00000000..2fcdf8bb
--- /dev/null
+++ b/src/main/resources/db/migration/V14__POI_type_added.sql
@@ -0,0 +1,38 @@
+/* 
+ * Copyright (c) 2020 NIBIO <http://www.nibio.no/>. 
+ * 
+ * This file is part of VIPSLogic.
+ *  This program is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU Affero General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU Affero General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Affero General Public License
+ *  along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ * 
+ */
+/**
+ * Author:  Tor-Einar Skog <tor-einar.skog@nibio.no>
+ * Created: September 18th, 2023
+ */
+
+-- Create POI type apiary site (birøkterplass) as entity
+CREATE TABLE public.point_of_interest_apiary_site (
+    point_of_interest_id INTEGER REFERENCES public.point_of_interest(point_of_interest_id) PRIMARY KEY REFERENCES public.point_of_interest(point_of_interest_id)
+);
+
+INSERT INTO public.point_of_interest_type (point_of_interest_type_id, default_name)
+VALUES (6, 'Apiary site');
+
+-- Create POI type nursery as entity
+CREATE TABLE public.point_of_interest_nursery (
+    point_of_interest_id INTEGER REFERENCES public.point_of_interest(point_of_interest_id) PRIMARY KEY REFERENCES public.point_of_interest(point_of_interest_id)
+);
+
+INSERT INTO public.point_of_interest_type (point_of_interest_type_id, default_name)
+VALUES (7, 'Nursery');
\ No newline at end of file
diff --git a/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts.properties b/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts.properties
index a2c3609a..947d27d1 100755
--- a/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts.properties
+++ b/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts.properties
@@ -1044,3 +1044,5 @@ LEAFBLOTCH=Leaf blotch model
 universalMessageSettingsLink_tpl=To edit your notification subscriptions, please use this link: {0}
 pointOfInterestType_5=Trap
 sowingDate=Sowing date
+pointOfInterestType_6=Apiary site
+pointOfInterestType_7=Nursery
diff --git a/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts_bs.properties b/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts_bs.properties
index 9789f83e..fe09b88c 100755
--- a/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts_bs.properties
+++ b/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts_bs.properties
@@ -1038,3 +1038,5 @@ LEAFBLOTCH=Leaf blotch model
 universalMessageSettingsLink_tpl=To edit your VIPS notification subscriptions, please use this link: {0}
 pointOfInterestType_5=Trap
 sowingDate=Sowing date
+pointOfInterestType_6=Apiary site
+pointOfInterestType_7=Nursery
diff --git a/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts_hr.properties b/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts_hr.properties
index 59e50597..ebcccfcd 100755
--- a/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts_hr.properties
+++ b/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts_hr.properties
@@ -1036,3 +1036,5 @@ LEAFBLOTCH=Leaf blotch model
 universalMessageSettingsLink_tpl=To edit your notification subscriptions, please use this link: {0}
 pointOfInterestType_5=Trap
 sowingDate=Sowing date
+pointOfInterestType_6=Apiary site
+pointOfInterestType_7=Nursery
diff --git a/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts_nb.properties b/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts_nb.properties
index 0eeeb052..2e80c64e 100755
--- a/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts_nb.properties
+++ b/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts_nb.properties
@@ -1044,3 +1044,5 @@ LEAFBLOTCH=Bladflekksjukdomsmodell
 universalMessageSettingsLink_tpl=For \u00e5 endre dine abonnement p\u00e5 push-varsler fra VIPS, bruk denne lenken: {0}
 pointOfInterestType_5=Felle
 sowingDate=S\u00e5dato
+pointOfInterestType_6=Big\u00e5rdsplass
+pointOfInterestType_7=Planteskole
diff --git a/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts_sr.properties b/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts_sr.properties
index d8b6a735..a431e5ec 100755
--- a/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts_sr.properties
+++ b/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts_sr.properties
@@ -1038,3 +1038,5 @@ LEAFBLOTCH=Leaf blotch model
 universalMessageSettingsLink_tpl=To edit your notification subscriptions, please use this link: {0}
 pointOfInterestType_5=Trap
 sowingDate=Sowing date
+pointOfInterestType_6=Apiary site
+pointOfInterestType_7=Nursery
diff --git a/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts_zh_CN.properties b/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts_zh_CN.properties
index 7f748c1d..27b71513 100755
--- a/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts_zh_CN.properties
+++ b/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts_zh_CN.properties
@@ -1032,3 +1032,5 @@ LEAFBLOTCH=Leaf blotch model
 universalMessageSettingsLink_tpl=To edit your notification subscriptions, please use this link: {0}
 pointOfInterestType_5=Trap
 sowingDate=Sowing date
+pointOfInterestType_6=Apiary site
+pointOfInterestType_7=Nursery
diff --git a/src/main/webapp/map_applications/fireblight/js/map.js b/src/main/webapp/map_applications/fireblight/js/map.js
index a6b0f098..b9671d45 100755
--- a/src/main/webapp/map_applications/fireblight/js/map.js
+++ b/src/main/webapp/map_applications/fireblight/js/map.js
@@ -1,5 +1,5 @@
-// The globally available map object
-var map, featureOverlay, newFeatureOverlay; 
+// The globally available map objects
+var map, featureOverlay, newFeatureOverlay, diseaseSpreadingPoisOverlay;
 
 // Override localization settings for this particular web page
 var hardcodedLanguage = "nb";
@@ -7,235 +7,354 @@ var hardcodedLanguage = "nb";
 // If false, touching map will not create a new item
 var registration = false;
 var geolocation;
-function initMap()
+async function initMap()
 {
-    
+
     var features = new ol.Collection();
 
-var iconRadius = 10;
-    
-var styles = {
-    // Bulkemispel = rød
-    'cotoneaster bullatus': [new ol.style.Style({
-        image: new ol.style.Circle({
-            fill: new ol.style.Fill({ color: [255,0,0,1] }),
-            stroke: new ol.style.Stroke({width: 1,  color: [0,0,0,1] }),
-            radius: iconRadius
-        })
-    })],
-    // Sprikemispel = dyp oransje
-    'cotoneaster divaricata': [new ol.style.Style({
-        image: new ol.style.Circle({
-            fill: new ol.style.Fill({ color: [239,133,19,1] }),
-            stroke: new ol.style.Stroke({width: 1,  color: [0,0,0,1] }),
-            radius: iconRadius
-        })
-    })],
-    // Pilemispel = gul
-    'cotoneaster salicifolia': [new ol.style.Style({
-        image: new ol.style.Circle({
-            fill: new ol.style.Fill({ color: [239,236,19,1] }),
-            stroke: new ol.style.Stroke({width: 1,  color: [0,0,0,1] }),
-            radius: iconRadius
-        })
-    })],
-    // Eple = grønn
-    'malus domestica': [new ol.style.Style({
-        image: new ol.style.Circle({
-            fill: new ol.style.Fill({ color: [0,255,0,1] }),
-            stroke: new ol.style.Stroke({ width: 1, color: [0,0,0,1] }),
-            radius: iconRadius
-        })
-    })],
-    // Pære = grågrønn
-    'pyrus communis': [new ol.style.Style({
-        image: new ol.style.Circle({
-            fill: new ol.style.Fill({ color: [122,175,131,1] }),
-            stroke: new ol.style.Stroke({width: 1,  color: [0,0,0,1] }),
-            radius: iconRadius
-        })
-    })],
-    // Planteriket = blå 
-    'plantae': [new ol.style.Style({
-	        image: new ol.style.Circle({
-	            fill: new ol.style.Fill({ color: [0,0,255,1] }),
-	            stroke: new ol.style.Stroke({ width: 1, color: [0,0,0,1] }),
-	            radius: iconRadius
-	        })
-    	})
-	]
-};
-  
-  featureOverlay = new ol.layer.Vector({
-    source: new ol.source.Vector({
-      features: features
-    }),
-    style: function(feature, resolution){
-        // Site that has been cleared is all black
-        var observationData = JSON.parse(feature.get("observationData"));
-        if(observationData["tiltak"] == "Ryddet" && observationData["symptom"] == "Ikke symptom")
-        {
-                return [new ol.style.Style({
+    var iconRadius = 10;
+
+    var styles = {
+        // Bulkemispel = rød
+        'cotoneaster bullatus': [new ol.style.Style({
                 image: new ol.style.Circle({
-                    fill: new ol.style.Fill({ color: [0,0,0,1] }),
-                    stroke: new ol.style.Stroke({ color: [0,0,0,1] }),
+                    fill: new ol.style.Fill({color: [255, 0, 0, 1]}),
+                    stroke: new ol.style.Stroke({width: 1, color: [0, 0, 0, 1]}),
                     radius: iconRadius
                 })
-            })];
-        }
-        else if(observationData["tiltak"] == "Ryddet" && observationData["symptom"] == "Symptom")
-        {
-                return [new ol.style.Style({
+            })],
+        // Sprikemispel = dyp oransje
+        'cotoneaster divaricata': [new ol.style.Style({
                 image: new ol.style.Circle({
-                    fill: new ol.style.Fill({ color: [255,255,255,1] }),
-                    stroke: new ol.style.Stroke({ width: 8, color: [0,0,0,1] }),
+                    fill: new ol.style.Fill({color: [239, 133, 19, 1]}),
+                    stroke: new ol.style.Stroke({width: 1, color: [0, 0, 0, 1]}),
                     radius: iconRadius
                 })
-            })];
-        }
+            })],
+        // Pilemispel = gul
+        'cotoneaster salicifolia': [new ol.style.Style({
+                image: new ol.style.Circle({
+                    fill: new ol.style.Fill({color: [239, 236, 19, 1]}),
+                    stroke: new ol.style.Stroke({width: 1, color: [0, 0, 0, 1]}),
+                    radius: iconRadius
+                })
+            })],
+        // Eple = grønn
+        'malus domestica': [new ol.style.Style({
+                image: new ol.style.Circle({
+                    fill: new ol.style.Fill({color: [0, 255, 0, 1]}),
+                    stroke: new ol.style.Stroke({width: 1, color: [0, 0, 0, 1]}),
+                    radius: iconRadius
+                })
+            })],
+        // Pære = grågrønn
+        'pyrus communis': [new ol.style.Style({
+                image: new ol.style.Circle({
+                    fill: new ol.style.Fill({color: [122, 175, 131, 1]}),
+                    stroke: new ol.style.Stroke({width: 1, color: [0, 0, 0, 1]}),
+                    radius: iconRadius
+                })
+            })],
+        // Planteriket = blå 
+        'plantae': [new ol.style.Style({
+                image: new ol.style.Circle({
+                    fill: new ol.style.Fill({color: [0, 0, 255, 1]}),
+                    stroke: new ol.style.Stroke({width: 1, color: [0, 0, 0, 1]}),
+                    radius: iconRadius
+                })
+            })
+        ]
+    };
+
+    featureOverlay = new ol.layer.Vector({
+        source: new ol.source.Vector({
+            features: features
+        }),
+        style: function (feature, resolution) {
+            // Site that has been cleared is all black
+            var observationData = JSON.parse(feature.get("observationData"));
+            if (observationData["tiltak"] == "Ryddet" && observationData["symptom"] == "Ikke symptom")
+            {
+                return [new ol.style.Style({
+                        image: new ol.style.Circle({
+                            fill: new ol.style.Fill({color: [0, 0, 0, 1]}),
+                            stroke: new ol.style.Stroke({color: [0, 0, 0, 1]}),
+                            radius: iconRadius
+                        })
+                    })];
+            } else if (observationData["tiltak"] == "Ryddet" && observationData["symptom"] == "Symptom")
+            {
+                return [new ol.style.Style({
+                        image: new ol.style.Circle({
+                            fill: new ol.style.Fill({color: [255, 255, 255, 1]}),
+                            stroke: new ol.style.Stroke({width: 8, color: [0, 0, 0, 1]}),
+                            radius: iconRadius
+                        })
+                    })];
+            }
 
-        var retVal = null;
-        if(feature.get("cropOrganism") != null && feature.get("cropOrganism")["latinName"] != null)
-        {
-            retVal = styles[feature.get("cropOrganism")["latinName"].toLowerCase()];
-        }
-        else 
-        {
-            retVal = styles["plantae"];
-        }
-        //console.info(retVal[0].getImage().getStroke().getWidth());
-        // If symptom has been registered, mark with inner black dot
-        if(observationData["symptom"] == "Symptom")
-        {
+            var retVal = null;
+            if (feature.get("cropOrganism") != null && feature.get("cropOrganism")["latinName"] != null)
+            {
+                retVal = styles[feature.get("cropOrganism")["latinName"].toLowerCase()];
+            } else
+            {
+                retVal = styles["plantae"];
+            }
+            //console.info(retVal[0].getImage().getStroke().getWidth());
+            // If symptom has been registered, mark with inner black dot
+            if (observationData["symptom"] == "Symptom")
+            {
                 retVal = [
-                        new ol.style.Style({
-                                image: new ol.style.Circle({
-                                    fill: new ol.style.Fill({ color: [0,0,0,1]  }),
-                                    stroke: new ol.style.Stroke({ width: 8, color: retVal[0].getImage().getFill().getColor() }),
-                                    radius: iconRadius
-                                })
+                    new ol.style.Style({
+                        image: new ol.style.Circle({
+                            fill: new ol.style.Fill({color: [0, 0, 0, 1]}),
+                            stroke: new ol.style.Stroke({width: 8, color: retVal[0].getImage().getFill().getColor()}),
+                            radius: iconRadius
                         })
+                    })
                 ];
+            }
+            return retVal;
         }
-        return retVal;
-    }
-            
-  });
-  
-  newFeatureOverlay = new ol.layer.Vector({
-    source: new ol.source.Vector({
-      features: new ol.Collection()
-    }),
-    style: [new ol.style.Style({
-        image: new ol.style.Circle({
-            fill: new ol.style.Fill({ color: [255,255,255,1] }),
-            stroke: new ol.style.Stroke({ color: [0,0,0,1], width: 3, lineDash: [2,2] }),
-            radius: 10
-        })
-    })]
-            
-  });
-  
-  
-  var parser = new ol.format.WMTSCapabilities();
-  fetch('https://opencache.statkart.no/gatekeeper/gk/gk.open_wmts?Version=1.0.0&service=wmts&request=getcapabilities').then(function(response) {
+
+    });
+
+    newFeatureOverlay = new ol.layer.Vector({
+        source: new ol.source.Vector({
+            features: new ol.Collection()
+        }),
+        style: [new ol.style.Style({
+                image: new ol.style.Circle({
+                    fill: new ol.style.Fill({color: [255, 255, 255, 1]}),
+                    stroke: new ol.style.Stroke({color: [0, 0, 0, 1], width: 3, lineDash: [2, 2]}),
+                    radius: 10
+                })
+            })]
+
+    });
+    
+    
+    
+    
+    /*
+    
+    new ol.style.Style({
+                   image: new ol.style.Circle({
+                        stroke: new Stroke({color: '#7c8692'}),
+                        radius: 200 / (resolution / viewProjection.getMetersPerUnit() * Math.cos(latitude_rad)),
+                      }),
+                    });
+     [new ol.style.Style({
+                image: new ol.style.Circle({
+                    fill: new ol.style.Fill({color: [255, 87, 222, 1]}),
+                    stroke: new ol.style.Stroke({color: [0, 0, 0, 1], width: 3, lineDash: [2, 2]}),
+                    radius: 10
+                })
+            })]
+    */
+
+
+    var parser = new ol.format.WMTSCapabilities();
+    fetch('https://opencache.statkart.no/gatekeeper/gk/gk.open_wmts?Version=1.0.0&service=wmts&request=getcapabilities').then(function (response) {
         return response.text();
-      }).then(function(text) {
+    }).then(function (text) {
         var result = parser.read(text);
         var options = ol.source.WMTS.optionsFromCapabilities(result, {
-          layer: 'topo4',
-          matrixSet: 'EPSG:3857'
+            layer: 'topo4',
+            matrixSet: 'EPSG:3857'
+        });
+        var topo4 =
+                new ol.layer.Tile({
+                    opacity: 1,
+                    source: new ol.source.WMTS(/** @type {!olx.source.WMTSOptions} */ (options))
+                });
+
+
+        diseaseSpreadingPoisOverlay = new ol.layer.Vector({
+            source: new ol.source.Vector({
+                features: new ol.Collection()
+            }),
+            style: diseaseSpreadingPoiStyle
         });
-        var topo4 = 
-          new ol.layer.Tile({
-            opacity: 1,
-            source: new ol.source.WMTS(/** @type {!olx.source.WMTSOptions} */ (options))
-          });
-          
-  
+
         map = new ol.Map({
-              target: 'map',
-              layers: [
+            target: 'map',
+            layers: [
                 //topo2graatone, 
                 topo4,
                 //osm,
+                diseaseSpreadingPoisOverlay,
                 featureOverlay,
                 newFeatureOverlay
-              ],
-              view: new ol.View({
+            ],
+            view: new ol.View({
                 center: ol.proj.fromLonLat([8.5, 60.8]),
                 zoom: 6
-              })
-            });
+            })
+        });
+        
+        
+        
+        //map.addOverlay(diseaseSpreadingPoisOverlay);
+
+        // Configure geolocation tracker
+        geolocation = new ol.Geolocation({
+            trackingOptions: {
+                enableHighAccuracy: true
+            },
+            projection: map.getView().getProjection()
+        });
+        var positionFeature = new ol.Feature();
+        positionFeature.setStyle(
+                new ol.style.Style({
+                    image: new ol.style.Circle({
+                        radius: 6,
+                        fill: new ol.style.Fill({
+                            color: '#3399CC',
+                        }),
+                        stroke: new ol.style.Stroke({
+                            color: '#fff',
+                            width: 2,
+                        }),
+                    }),
+                })
+                );
 
-		// Configure geolocation tracker
-		geolocation = new ol.Geolocation({
-			trackingOptions: {
-				enableHighAccuracy: true
-			},
-			projection: map.getView().getProjection()
-		});
-		var positionFeature = new ol.Feature();
-		positionFeature.setStyle(
-		  new ol.style.Style({
-		    image: new ol.style.Circle({
-		      radius: 6,
-		      fill: new ol.style.Fill({
-		        color: '#3399CC',
-		      }),
-		      stroke: new ol.style.Stroke({
-		        color: '#fff',
-		        width: 2,
-		      }),
-		    }),
-		  })
-		);
-		
-		geolocation.on('change:position', function () {
-		  var coordinates = geolocation.getPosition();
-		  positionFeature.setGeometry(coordinates ? new ol.geom.Point(coordinates) : null);
-		});
-		
-		new ol.layer.Vector({
-		  map: map,
-		  source: new ol.source.Vector({
-		    features: [positionFeature],
-		  }),
-		});
+        geolocation.on('change:position', function () {
+            var coordinates = geolocation.getPosition();
+            positionFeature.setGeometry(coordinates ? new ol.geom.Point(coordinates) : null);
+        });
 
+        new ol.layer.Vector({
+            map: map,
+            source: new ol.source.Vector({
+                features: [positionFeature]
+            })
+        });
+        
         // TODO feature properties must be synchronized
         var lastYear = new Date().getFullYear() - 1;
         // Population the season select list, setting last year as default selected
         initSeasonSelectList(lastYear);
+        getAndRenderDiseaseSpreadingPois();
         getAndRenderObservations(lastYear);
 
 
-        map.on('click', function(evt){
-                //features = []
-                var feature = map.forEachFeatureAtPixel(
-                    evt.pixel, function(ft, l) { return ft; }
-                );
+        map.on('click', function (evt) {
+            //features = []
+            var feature = map.forEachFeatureAtPixel(
+                    evt.pixel, function (ft, l) {
+                        return ft;
+                    }
+            );
 
-                var vectorSource = newFeatureOverlay.getSource();
-                // Remove any new features already created
-                vectorSource.clear();
+            var vectorSource = newFeatureOverlay.getSource();
+            // Remove any new features already created
+            vectorSource.clear();
 
-                if (feature && feature.getProperties()["observationId"] != undefined) {
-                    // Create a fake icon for highlighting
-                    var fakeFeature = createFeature(feature.getGeometry().getCoordinates());
-                    vectorSource.addFeature(fakeFeature);
-                    displayFeature(feature);   
-                }
-                else if(registration)
-                {
-                    var newFeature = createFeature(map.getCoordinateFromPixel(evt.pixel));
-                    vectorSource.addFeature(newFeature);
-                    editFeature(newFeature.getId());
-                }
+            if (feature && feature.getProperties()["observationId"] != undefined) {
+                // Create a fake icon for highlighting
+                var fakeFeature = createFeature(feature.getGeometry().getCoordinates());
+                vectorSource.addFeature(fakeFeature);
+                displayFeature(feature);
+            } else if (registration)
+            {
+                var newFeature = createFeature(map.getCoordinateFromPixel(evt.pixel));
+                vectorSource.addFeature(newFeature);
+                editFeature(newFeature.getId());
+            }
         });
-    
+
     }); // END FETCH
+
+}
+
+let openLayersDefaultStyle = undefined;
+
+function getOpenLayersDefaultStyle()
+{
+    if(openLayersDefaultStyle == undefined)
+    {
+        var fill = new ol.style.Fill({
+        color: 'rgba(255,255,255,0.4)'
+      });
+      var stroke = new ol.style.Stroke({
+        color: '#3399CC',
+        width: 1.25
+      });
+      openLayersDefaultStyle = [
+        new ol.style.Style({
+          image: new ol.style.Circle({
+            fill: fill,
+            stroke: stroke,
+            radius: 5
+          }),
+          fill: fill,
+          stroke: stroke
+        })
+      ];
+    }
     
+    return openLayersDefaultStyle;
+}
+
+/**
+ * Styling the different disease spreading pois
+ * @param {ol.Feature} feature
+ * @param {Number} resolution
+ * @returns {Array}
+ */
+function diseaseSpreadingPoiStyle(feature, resolution) 
+{
+    if(feature.getGeometry().getType() == "Point")
+    {
+        const radiusInMeters = feature.getProperties()["pointOfInterestTypeId"] == "6" ? 5000 
+            : feature.getProperties()["pointOfInterestTypeId"] == "7" ? 10000
+            : 500;
+        const fillColor = feature.getProperties()["pointOfInterestTypeId"] == "6" ? [255,0, 0, 0.5] 
+            : feature.getProperties()["pointOfInterestTypeId"] == "7" ? [255, 127,127 , 0.5]
+            : [255, 255, 255, 0.0];
+        const viewProjection = map.getView().getProjection();      
+        const coordsInViewProjection = feature.getGeometry().getCoordinates();
+        const longLat = ol.proj.toLonLat(coordsInViewProjection, viewProjection);
+        const latitude_rad = longLat[1] * Math.PI / 180;
+        const circle = new ol.style.Style({
+            image: new ol.style.Circle({
+                fill: new ol.style.Fill({color: fillColor}),
+                stroke: new ol.style.Stroke({color: [0, 0, 0, 1], width: 5, lineDash: [5, 10], lineCap:"square"}),
+                radius: radiusInMeters / (resolution / viewProjection.getMetersPerUnit() * Math.cos(latitude_rad))
+            })
+        });
+
+        return [circle];
+    }
+    
+    return getOpenLayersDefaultStyle();
+}
+
+
+function getAndRenderDiseaseSpreadingPois()
+{
+    fetch("/rest/poi/organization/1/type/geojson?poiTypes=6,7")
+            .then(response => response.json())
+            .then(data => {
+                let olFeatures = (new ol.format.GeoJSON()).readFeatures(
+                    data, 
+                    {
+                        dataProjection: "EPSG:4326",
+                        featureProjection: map.getView().getProjection().getCode()
+                    }
+                );
+
+            //sconsole.info(olFeatures);
+            //console.info(diseaseSpreadingPoisOverlay.getSource());
+            diseaseSpreadingPoisOverlay.getSource().clear();
+            diseaseSpreadingPoisOverlay.getSource().addFeatures(olFeatures);
+                
+            });
+            
+
 }
 
 /**
@@ -246,14 +365,14 @@ var styles = {
 function getAndRenderObservations(fromSeason)
 {
     //console.info("getAndRenderObservations(" + season + ")");
-    $.getJSON("/rest/observation/filter/1/geoJSON?from=" + fromSeason + "-01-01&pestId=" + paerebrann.organismId, function(geoData){
+    $.getJSON("/rest/observation/filter/1/geoJSON?from=" + fromSeason + "-01-01&pestId=" + paerebrann.organismId, function (geoData) {
         //console.info(geoData)
         var format = new ol.format.GeoJSON();
 
         var drawnfeatures = format.readFeatures(geoData, {
-          //dataProjection: "EPSG:32633",
-          dataProjection: "EPSG:4326",
-          featureProjection: map.getView().getProjection().getCode()
+            //dataProjection: "EPSG:32633",
+            dataProjection: "EPSG:4326",
+            featureProjection: map.getView().getProjection().getCode()
         });
         featureOverlay.getSource().clear();
         featureOverlay.getSource().addFeatures(drawnfeatures);
@@ -264,73 +383,72 @@ function getAndRenderObservations(fromSeason)
 /**
  * 
  * @param {type} fromSeason
-*  @param {type} countyNo
+ *  @param {type} countyNo
  * @returns {undefined}
  */
 function getAndRenderObservationsForReport(fromSeason, countyNo = "-1")
 {
     //console.info("getAndRenderObservations(" + season + ")");
-    $.getJSON("/rest/observation/filter/1/geoJSON?from=" + fromSeason + "-01-01&pestId=" + paerebrann.organismId, function(geoData){
+    $.getJSON("/rest/observation/filter/1/geoJSON?from=" + fromSeason + "-01-01&pestId=" + paerebrann.organismId, function (geoData) {
         //console.info(geoData)
-		// Filter by county
-		$.getJSON("/corsproxy/https://ws.geonorge.no/kommuneinfo/v1/fylker/" + countyNo + "/omrade")
-		.always(function(serviceResponse){
-			//console.info(geoData);
-			//console.info(serviceResponse);
-			
-			if(parseInt(countyNo) > 0)
-			{
-				var filteredFeatures = [];
-				for(var i=0;i < geoData.features.length;i++)
-				{
-					var featureToBeFiltered = geoData.features[i];
-					coordinate = proj4("EPSG:4326","EPSG:4258",[featureToBeFiltered.geometry.coordinates[0],featureToBeFiltered.geometry.coordinates[1]]);
-					// For some weird reason, d3 returns NOT contains in our case
-					if(!d3.geoContains(serviceResponse.omrade, coordinate))
-					{
-						//console.info(featureToBeFiltered);
-						filteredFeatures.push(featureToBeFiltered);
-					}
-					//console.info(featureToBeFiltered);
-				}
-				//console.info(filteredFeatures);
-				geoData.features = filteredFeatures;
-			}
-			
-	        var format = new ol.format.GeoJSON();
-	
-	        var drawnfeatures = format.readFeatures(geoData, {
-	          //dataProjection: "EPSG:32633",
-	          dataProjection: "EPSG:4326",
-	          featureProjection: map.getView().getProjection().getCode()
-	        });
-	        featureOverlay.getSource().clear();
-	        featureOverlay.getSource().addFeatures(drawnfeatures);
-			}
-		);
-		});
+        // Filter by county
+        $.getJSON("/corsproxy/https://ws.geonorge.no/kommuneinfo/v1/fylker/" + countyNo + "/omrade")
+                .always(function (serviceResponse) {
+                    //console.info(geoData);
+                    //console.info(serviceResponse);
+
+                    if (parseInt(countyNo) > 0)
+                    {
+                        var filteredFeatures = [];
+                        for (var i = 0; i < geoData.features.length; i++)
+                        {
+                            var featureToBeFiltered = geoData.features[i];
+                            coordinate = proj4("EPSG:4326", "EPSG:4258", [featureToBeFiltered.geometry.coordinates[0], featureToBeFiltered.geometry.coordinates[1]]);
+                            // For some weird reason, d3 returns NOT contains in our case
+                            if (!d3.geoContains(serviceResponse.omrade, coordinate))
+                            {
+                                //console.info(featureToBeFiltered);
+                                filteredFeatures.push(featureToBeFiltered);
+                            }
+                            //console.info(featureToBeFiltered);
+                        }
+                        //console.info(filteredFeatures);
+                        geoData.features = filteredFeatures;
+                    }
+
+                    var format = new ol.format.GeoJSON();
+
+                    var drawnfeatures = format.readFeatures(geoData, {
+                        //dataProjection: "EPSG:32633",
+                        dataProjection: "EPSG:4326",
+                        featureProjection: map.getView().getProjection().getCode()
+                    });
+                    featureOverlay.getSource().clear();
+                    featureOverlay.getSource().addFeatures(drawnfeatures);
+                }
+                );
+    });
 }
 
 function toggleRegistration(theButton)
 {
-    if(registration)
+    if (registration)
     {
         theButton.title = "Registrering er AV";
-        theButton.style.color="white";
-    }
-    else
+        theButton.style.color = "white";
+    } else
     {
         theButton.title = "Registrering er PÅ";
-        theButton.style.color="red";
+        theButton.style.color = "red";
     }
-    registration = ! registration;
+    registration = !registration;
 }
 
 function toggleTracking(theButton)
 {
-	geolocation.setTracking(!geolocation.getTracking());
-	theButton.style.backgroundColor = geolocation.getTracking() ? "green" : "rgba(0,60,136,.5)";
-	theButton.title = geolocation.getTracking() ? "Vis min posisjon er PÅ" : "Vis min posisjon er AV";
+    geolocation.setTracking(!geolocation.getTracking());
+    theButton.style.backgroundColor = geolocation.getTracking() ? "green" : "rgba(0,60,136,.5)";
+    theButton.title = geolocation.getTracking() ? "Vis min posisjon er PÅ" : "Vis min posisjon er AV";
 }
 
 /**
@@ -338,11 +456,11 @@ function toggleTracking(theButton)
  * @param {type} coordinate
  * @returns {createFeature.newFeature|ol.Feature}
  */
-var createFeature = function(coordinate)
+var createFeature = function (coordinate)
 {
-    if(coordinate.length == 2)
+    if (coordinate.length == 2)
     {
-        coordinate = [coordinate[0],coordinate[1],0];
+        coordinate = [coordinate[0], coordinate[1], 0];
     }
     var point = new ol.geom.Point(coordinate);
     var newFeature = new ol.Feature({
@@ -351,34 +469,34 @@ var createFeature = function(coordinate)
     });
     newFeature.setId(-1);
     newFeature.setProperties({
-            "observationId": -1,
-            "observationData": "{\"symptom\":\"\",\"tiltak\":\"\",\"forekomststorrelse\":\"\"}",
-            "cropOrganism": {},
-            "observationText" : "",
-            "timeOfObservation": moment().valueOf()
-        });
-    
+        "observationId": -1,
+        "observationData": "{\"symptom\":\"\",\"tiltak\":\"\",\"forekomststorrelse\":\"\"}",
+        "cropOrganism": {},
+        "observationText": "",
+        "timeOfObservation": moment().valueOf()
+    });
+
     return newFeature;
 }
 
-var displayFeature = function(feature)
+var displayFeature = function (feature)
 {
     var featureForm = document.getElementById("featureForm");
-    
+
     var observationData = JSON.parse(feature.get("observationData"));
     var timeOfObservation = new moment(feature.get("timeOfObservation"));
     var html = [
         '<button type="button" onclick="unFocusForm()">X</button>',
-        '<button type="button" onclick="editFeature(\'', feature.getId() ,'\');">Rediger</button>',
+        '<button type="button" onclick="editFeature(\'', feature.getId(), '\');">Rediger</button>',
         '<button type="button" onclick="deleteFeature(' + feature.getId() + ')">Slett</button>',
         '<h3>Registrering</h3>',
         '<table>',
-        '<tr><td>Type</td><td>',getLocalizedOrganismName(feature.get("cropOrganism"),hardcodedLanguage),'</td></tr>',
-        '<tr><td>Størrelse</td><td>',observationData["forekomststorrelse"],'</td></tr>',
-        '<tr><td>Symptom</td><td>',observationData["symptom"],'</td></tr>',
-        '<tr><td>Tiltak</td><td>',observationData["tiltak"],'</td></tr>',
-        '<tr><td>Beskrivelse</td><td>',feature.get("observationText"),'</td></tr>',
-        '<tr><td>Dato</td><td>',timeOfObservation.format("DD.MM.YYYY"),'</td></tr>',
+        '<tr><td>Type</td><td>', getLocalizedOrganismName(feature.get("cropOrganism"), hardcodedLanguage), '</td></tr>',
+        '<tr><td>Størrelse</td><td>', observationData["forekomststorrelse"], '</td></tr>',
+        '<tr><td>Symptom</td><td>', observationData["symptom"], '</td></tr>',
+        '<tr><td>Tiltak</td><td>', observationData["tiltak"], '</td></tr>',
+        '<tr><td>Beskrivelse</td><td>', feature.get("observationText"), '</td></tr>',
+        '<tr><td>Dato</td><td>', timeOfObservation.format("DD.MM.YYYY"), '</td></tr>',
         '</table>'
     ];
     featureForm.innerHTML = html.join("");
@@ -399,26 +517,26 @@ var paerebrann = {};
 
 function initForekomsttyper()
 {
-    $.getJSON("/rest/organism/search/latinnames?keywords=" + forekomsttypeLatinskeNavn.join(","), function(data){
-       forekomsttyper = data; 
+    $.getJSON("/rest/organism/search/latinnames?keywords=" + forekomsttypeLatinskeNavn.join(","), function (data) {
+        forekomsttyper = data;
     });
 }
 
-function initPaerebrann(){
-    $.getJSON("/rest/organism/search/latinnames?keywords=Erwinia amylovora", function(data){
-       if(data.length == 1)
-       {
-           paerebrann = data[0];
-           initMap();
-       }
+function initPaerebrann() {
+    $.getJSON("/rest/organism/search/latinnames?keywords=Erwinia amylovora", function (data) {
+        if (data.length == 1)
+        {
+            paerebrann = data[0];
+            initMap();
+        }
     });
 }
 
-var getCropOrganism = function(organismId)
+var getCropOrganism = function (organismId)
 {
-    for(var i=0;i<forekomsttyper.length;i++)
+    for (var i = 0; i < forekomsttyper.length; i++)
     {
-        if(forekomsttyper[i].organismId == organismId)
+        if (forekomsttyper[i].organismId == organismId)
         {
             return forekomsttyper[i];
         }
@@ -430,54 +548,54 @@ var symptoms = ["Ikke symptom", "Symptom"];
 var tiltaks = ["Ikke ryddet", "Ryddet"];
 
 
-var editFeature = function(featureId)
+var editFeature = function (featureId)
 {
     var feature = featureId > 0 ? featureOverlay.getSource().getFeatureById(featureId)
-                                    : newFeatureOverlay.getSource().getFeatureById(featureId);
+            : newFeatureOverlay.getSource().getFeatureById(featureId);
     var observationData = JSON.parse(feature.get("observationData"));
     var timeOfObservation = new moment(feature.get("timeOfObservation"));
     var featureForm = document.getElementById("featureForm");
-    var html = 
-        '<button type="button" onclick="unFocusForm()" title="Avbryt">X</button>' +
-        (featureId > 0 ? '<button type="button" onclick="deleteFeature(' + featureId + ')">Delete</button>' : '') +
-        '<h3>' + (featureId > 0 ? "R" : "Ny r") + 'egistrering</h3>' +
-        '<table>' +
-        '<tr><td>Type</td><td>' +
-        generateCropSelect("forekomsttype", forekomsttyper, feature.get("cropOrganism")["organismId"]) +           
-        '</td></tr>' +
-        '<tr><td>Størrelse</td><td>' +
-        generateSelect("forekomststorrelse", forekomststorrelses, observationData["forekomststorrelse"]) +           
-        '</td></tr>' +
-        '<tr><td>Symptom</td><td>' +
-        generateSelect("symptom", symptoms, observationData["symptom"]) + 
-        '</td></tr>' +
-        '<tr><td>Tiltak</td><td>' + 
-        generateSelect ("tiltak", tiltaks, observationData["tiltak"]) + 
-        '</td></tr>' +
-        '<tr><td>Beskrivelse</td><td>' + 
-        '<textarea id="beskrivelse" name="beskrivelse">' + (feature.get("observationText") != null ? feature.get("observationText") : "")  + '</textarea>' +
-        '</td></tr>' +
-        '<tr><td>Dato</td><td>' +
-        '<input type="text" id="dato" name="dato" size="10" value="'+ timeOfObservation.format("DD.MM.YYYY") + '"/></td></tr>' +
-        '<tr><td></td><td>' +
-        '<input type="submit" value="Lagre" onclick="storeFeature(' + feature.getId() + ');"/></td></tr>' +
-        '</table>';
-        
-    
+    var html =
+            '<button type="button" onclick="unFocusForm()" title="Avbryt">X</button>' +
+            (featureId > 0 ? '<button type="button" onclick="deleteFeature(' + featureId + ')">Delete</button>' : '') +
+            '<h3>' + (featureId > 0 ? "R" : "Ny r") + 'egistrering</h3>' +
+            '<table>' +
+            '<tr><td>Type</td><td>' +
+            generateCropSelect("forekomsttype", forekomsttyper, feature.get("cropOrganism")["organismId"]) +
+            '</td></tr>' +
+            '<tr><td>Størrelse</td><td>' +
+            generateSelect("forekomststorrelse", forekomststorrelses, observationData["forekomststorrelse"]) +
+            '</td></tr>' +
+            '<tr><td>Symptom</td><td>' +
+            generateSelect("symptom", symptoms, observationData["symptom"]) +
+            '</td></tr>' +
+            '<tr><td>Tiltak</td><td>' +
+            generateSelect("tiltak", tiltaks, observationData["tiltak"]) +
+            '</td></tr>' +
+            '<tr><td>Beskrivelse</td><td>' +
+            '<textarea id="beskrivelse" name="beskrivelse">' + (feature.get("observationText") != null ? feature.get("observationText") : "") + '</textarea>' +
+            '</td></tr>' +
+            '<tr><td>Dato</td><td>' +
+            '<input type="text" id="dato" name="dato" size="10" value="' + timeOfObservation.format("DD.MM.YYYY") + '"/></td></tr>' +
+            '<tr><td></td><td>' +
+            '<input type="submit" value="Lagre" onclick="storeFeature(' + feature.getId() + ');"/></td></tr>' +
+            '</table>';
+
+
     featureForm.innerHTML = html;
     focusForm();
     //console.info(feature);
 };
 
-var storeFeature = function(featureId)
+var storeFeature = function (featureId)
 {
     var feature = featureId > 0 ? featureOverlay.getSource().getFeatureById(featureId)
-                                    : newFeatureOverlay.getSource().getFeatureById(featureId);
-    
+            : newFeatureOverlay.getSource().getFeatureById(featureId);
+
     // Store, clear newFeature layer
     // Need to add feature as payload
     var format = new ol.format.GeoJSON();
-    
+
     // Add the form data
     var cropOrganism = getCropOrganism(document.getElementById("forekomsttype").options[document.getElementById("forekomsttype").options.selectedIndex].value);
     //console.info(cropOrganism);
@@ -486,32 +604,32 @@ var storeFeature = function(featureId)
     var tiltak = document.getElementById("tiltak").options[document.getElementById("tiltak").options.selectedIndex].value;
     var observationText = document.getElementById("beskrivelse").value;
     var observationHeading = "Registrering av pærebrann";
-    var timeOfObservation = moment(document.getElementById("dato").value + "+0200","DD.MM.YYYYZ");
-    if(timeOfObservation.year() < 2000)
+    var timeOfObservation = moment(document.getElementById("dato").value + "+0200", "DD.MM.YYYYZ");
+    if (timeOfObservation.year() < 2000)
     {
         alert("Feil dato (før år 2000). Datoformat er DD.MM.ÅÅÅÅ");
         return;
     }
-    
+
     feature.setProperties({
-       timeOfObservation: timeOfObservation.valueOf(),
-       cropOrganism: cropOrganism,
-       organism: paerebrann,
-       observationHeading: observationHeading,
-       observationText: observationText,
-       observationData: "{\"symptom\":\"" + symptom + "\",\"tiltak\":\"" + tiltak + "\",\"forekomststorrelse\":\"" + forekomststorrelse + "\"}",
-       statusTypeId: 3,
-       statusRemarks: "Registrert via pærebrannovervåkningskartet",
-       isQuantified: true,
-       broadcastMessage: false
+        timeOfObservation: timeOfObservation.valueOf(),
+        cropOrganism: cropOrganism,
+        organism: paerebrann,
+        observationHeading: observationHeading,
+        observationText: observationText,
+        observationData: "{\"symptom\":\"" + symptom + "\",\"tiltak\":\"" + tiltak + "\",\"forekomststorrelse\":\"" + forekomststorrelse + "\"}",
+        statusTypeId: 3,
+        statusRemarks: "Registrert via pærebrannovervåkningskartet",
+        isQuantified: true,
+        broadcastMessage: false
     });
     var result = format.writeFeatures([feature], {
         dataProjection: 'EPSG:4326',
         featureProjection: map.getView().getProjection().getCode()
-      });
-    
+    });
+
     //console.log(feature);
-    
+
     $.ajax({
         type: "POST",
         url: "/rest/observation/gisobservation",
@@ -519,41 +637,40 @@ var storeFeature = function(featureId)
         data: result,
         contentType: "application/json; charset=utf-8",
         dataType: "json",
-        success: function(geoData){
+        success: function (geoData) {
             //console.info(geoData)
             var format = new ol.format.GeoJSON();
 
             var drawnfeatures = format.readFeatures(geoData, {
-              dataProjection: "EPSG:4326",
-              featureProjection: map.getView().getProjection().getCode()
+                dataProjection: "EPSG:4326",
+                featureProjection: map.getView().getProjection().getCode()
             });
             newFeatureOverlay.getSource().clear(true);
             // If storing an existing feature, remove the one
             // that was there before storing, since the returned
             // one has a new gisId (featureId)
-            if(featureId > 0)
+            if (featureId > 0)
             {
                 featureOverlay.getSource().removeFeature(feature);
             }
             featureOverlay.getSource().addFeatures(drawnfeatures);
             unFocusForm();
         },
-        error: function( jqXHR, textStatus, errorThrown) {
-            if(jqXHR.status == 401)
+        error: function (jqXHR, textStatus, errorThrown) {
+            if (jqXHR.status == 401)
             {
-                if(confirm("Kan ikke lagre fordi du er logget ut av applikasjonen. Klikk OK for å logge inn."))
+                if (confirm("Kan ikke lagre fordi du er logget ut av applikasjonen. Klikk OK for å logge inn."))
                 {
                     window.location.reload();
                 }
-            }
-            else
+            } else
             {
                 alert("Beklager, en feil oppsto. Status = " + jqXHR.status + ", eventuell feilmelding: " + textStatus);
             }
         }
     });
-    
-    
+
+
 }
 
 /**
@@ -561,38 +678,37 @@ var storeFeature = function(featureId)
  * @param {type} featureId
  * @returns {undefined}
  */
-var deleteFeature = function(featureId)
+var deleteFeature = function (featureId)
 {
-    if(!confirm("Er du sikker på at du vil slette?"))
+    if (!confirm("Er du sikker på at du vil slette?"))
     {
         return;
     }
-    
+
     var feature = featureOverlay.getSource().getFeatureById(featureId);
-    
+
     $.ajax({
         type: "DELETE",
         url: "/rest/observation/gisobservation/" + feature.getId(),
-        success: function(response){
-            console.info(response);
+        success: function (response) {
+            //console.info(response);
             // If storing an existing feature, remove the one
             // that was there before storing, since the returned
             // one has a new gisId (featureId)
-            if(featureId > 0)
+            if (featureId > 0)
             {
                 featureOverlay.getSource().removeFeature(feature);
             }
             unFocusForm();
         },
-        error: function( jqXHR, textStatus, errorThrown) {
-            if(jqXHR.status == 401)
+        error: function (jqXHR, textStatus, errorThrown) {
+            if (jqXHR.status == 401)
             {
-                if(confirm("Kan ikke slette fordi du er logget ut av applikasjonen. Klikk OK for å logge inn."))
+                if (confirm("Kan ikke slette fordi du er logget ut av applikasjonen. Klikk OK for å logge inn."))
                 {
                     window.location.reload();
                 }
-            }
-            else
+            } else
             {
                 alert("Beklager, en feil oppsto. Status = " + jqXHR.status + ", eventuell feilmelding: " + textStatus);
             }
@@ -600,29 +716,29 @@ var deleteFeature = function(featureId)
     });
 }
 
-var generateSelect = function(selectName, options, preselect)
+var generateSelect = function (selectName, options, preselect)
 {
     var retVal = '<select id="' + selectName + '" name="' + selectName + '">';
-    for(var i=0; i< options.length; i++)
+    for (var i = 0; i < options.length; i++)
     {
-        retVal += '<option value="' + options[i] + '"' + (options[i] == preselect ? " selected=\"selected\"" : "") + '">' + options[i]  + '</option>';
+        retVal += '<option value="' + options[i] + '"' + (options[i] == preselect ? " selected=\"selected\"" : "") + '">' + options[i] + '</option>';
     }
     retVal += '</select>';
     return retVal;
 }
 
-var generateCropSelect = function(selectName, cropOrganisms, preselect)
+var generateCropSelect = function (selectName, cropOrganisms, preselect)
 {
     var retVal = '<select id="' + selectName + '" name="' + selectName + '">';
-    for(var c=0; c < forekomsttypeLatinskeNavn.length; c++)
+    for (var c = 0; c < forekomsttypeLatinskeNavn.length; c++)
     {
         currentLatinName = forekomsttypeLatinskeNavn[c];
-        for(var i=0; i< cropOrganisms.length; i++)
+        for (var i = 0; i < cropOrganisms.length; i++)
         {
-            if(cropOrganisms[i].latinName == currentLatinName)
+            if (cropOrganisms[i].latinName == currentLatinName)
             {
-                retVal += '<option value="' + cropOrganisms[i].organismId + '"' + (cropOrganisms[i].organismId == preselect ? " selected=\"selected\"" : "") + '">' + 
-                        (currentLatinName == "Plantae" ? "Annet" : getLocalizedOrganismName(cropOrganisms[i], hardcodedLanguage))  
+                retVal += '<option value="' + cropOrganisms[i].organismId + '"' + (cropOrganisms[i].organismId == preselect ? " selected=\"selected\"" : "") + '">' +
+                        (currentLatinName == "Plantae" ? "Annet" : getLocalizedOrganismName(cropOrganisms[i], hardcodedLanguage))
                         + '</option>';
             }
         }
@@ -631,13 +747,13 @@ var generateCropSelect = function(selectName, cropOrganisms, preselect)
     return retVal;
 }
 
-var focusForm = function()
+var focusForm = function ()
 {
     var featureForm = document.getElementById("featureForm");
     featureForm.style.display = "block";
 }
 
-var unFocusForm = function()
+var unFocusForm = function ()
 {
     var featureForm = document.getElementById("featureForm");
     featureForm.style.display = "none";
@@ -645,63 +761,61 @@ var unFocusForm = function()
     newFeatureOverlay.getSource().clear();
 }
 
-var navigateTo = function(center)
+var navigateTo = function (center)
 {
     var centerPosition = ol.proj.transform(center, 'EPSG:4326', 'EPSG:3857');
-        view = new ol.View({
+    view = new ol.View({
         center: centerPosition,
         zoom: 18
-      });
+    });
+
+    map.setView(view);
 
-      map.setView(view);
-   
     var searchResultsEl = document.getElementById("searchResults");
     searchResultsEl.innerHTML = "";
-    searchResultsEl.style.display="none";
+    searchResultsEl.style.display = "none";
 };
 
 /**
  * Uses the client's geolocation information - displays it on the map
  */
 function showLocation() {
-	if (navigator.geolocation) {
-        if(window.location.protocol === "http:")
+    if (navigator.geolocation) {
+        if (window.location.protocol === "http:")
         {
-            navigator.geolocation.getCurrentPosition(function(geopositionObj){
+            navigator.geolocation.getCurrentPosition(function (geopositionObj) {
                 // TODO: position and display location icon
-                }
+            }
             );
-        }
-        else
+        } else
         {
-            if(confirm("Lokalisering fungerer bare over https (sikker tilkobling mellom nettleser og tjener). Klikk OK for å gå til sikker tilkobling."))
+            if (confirm("Lokalisering fungerer bare over https (sikker tilkobling mellom nettleser og tjener). Klikk OK for å gå til sikker tilkobling."))
             {
                 window.location = "https:" + window.location.href.substring(window.location.protocol.length);
             }
         }
     } else {
-        alert( "Lokaliseringsfunksjonen er ikke tilgjengelig i denne nettleseren.");
+        alert("Lokaliseringsfunksjonen er ikke tilgjengelig i denne nettleseren.");
     }
 }
 
 function navToLocation() {
     if (navigator.geolocation) {
-        if(window.location.protocol === "https:")
+        if (window.location.protocol === "https:")
         {
-            navigator.geolocation.getCurrentPosition(function(geopositionObj){
+            navigator.geolocation.getCurrentPosition(function (geopositionObj) {
                 navigateTo([geopositionObj.coords.longitude, geopositionObj.coords.latitude]);
-                }
+            }
             );
-        }
-        else
+        } else
         {
-            if(confirm("Lokalisering fungerer bare over https (sikker tilkobling mellom nettleser og tjener). Klikk OK for å gå til sikker tilkobling."))
+            if (confirm("Lokalisering fungerer bare over https (sikker tilkobling mellom nettleser og tjener). Klikk OK for å gå til sikker tilkobling."))
             {
                 window.location = "https:" + window.location.href.substring(window.location.protocol.length);
             }
         }
     } else {
-        alert( "Lokaliseringsfunksjonen er ikke tilgjengelig i denne nettleseren.");
+        alert("Lokaliseringsfunksjonen er ikke tilgjengelig i denne nettleseren.");
     }
 }
 
@@ -717,26 +831,26 @@ function initSeasonSelectList(selectedSeason)
     // How many years do we go back?
     $.ajax({
         url: "/rest/observation/first/" + paerebrann.organismId
-        })
-    .done(function(data){
-       var time = moment(data);
-       var firstYear = time.toDate().getFullYear();
-       // Loop gjennom år, lag valgliste :-)
-       var startSeasonList = document.getElementById("startSeason");
-       for(var i=firstYear;i<=thisYear;i++)
-       {
-           var yearOpt = new Option("",i);
-           yearOpt.innerHTML = i + " &rarr;"
-           if(i==selectedSeason)
-           {
-               yearOpt.selected=true;
-           }
-           startSeasonList.options[startSeasonList.options.length] = yearOpt;
-       }
     })
-    .fail(function(jqXHR, textStatus, errorThrown){
-        alert(textStatus);
-    });
-    
+            .done(function (data) {
+                var time = moment(data);
+                var firstYear = time.toDate().getFullYear();
+                // Loop gjennom år, lag valgliste :-)
+                var startSeasonList = document.getElementById("startSeason");
+                for (var i = firstYear; i <= thisYear; i++)
+                {
+                    var yearOpt = new Option("", i);
+                    yearOpt.innerHTML = i + " &rarr;"
+                    if (i == selectedSeason)
+                    {
+                        yearOpt.selected = true;
+                    }
+                    startSeasonList.options[startSeasonList.options.length] = yearOpt;
+                }
+            })
+            .fail(function (jqXHR, textStatus, errorThrown) {
+                alert(textStatus);
+            });
+
 }
-    
+
diff --git a/src/main/webapp/templates/poiForm.ftl b/src/main/webapp/templates/poiForm.ftl
index b2d0274b..64127dda 100755
--- a/src/main/webapp/templates/poiForm.ftl
+++ b/src/main/webapp/templates/poiForm.ftl
@@ -84,7 +84,7 @@
 			  <div class="form-group">
 			    <label for="pointOfInterestTypeId">${i18nBundle.pointOfInterestType}</label>
 			    <select class="form-control" name="pointOfInterestTypeId" onblur="validateField(this);">
-				<#list [0,1,2,3,5] as pointOfInterestTypeId>
+				<#list [0,1,2,3,5,6,7] as pointOfInterestTypeId>
                                     <#if pointOfInterestTypeId != 1>
 					<option value="${pointOfInterestTypeId}"<#if 
 								poi.pointOfInterestTypeId?has_content && pointOfInterestTypeId == poi.pointOfInterestTypeId
-- 
GitLab