diff --git a/src/main/java/no/bioforsk/vips/logic/controller/servlet/ObservationController.java b/src/main/java/no/bioforsk/vips/logic/controller/servlet/ObservationController.java
index e9071ecd2c8e3a9053de6552a5dbb5872f8a7454..2bc1d865518c6e07d7ee2bd5a8c5e192b093d97f 100644
--- a/src/main/java/no/bioforsk/vips/logic/controller/servlet/ObservationController.java
+++ b/src/main/java/no/bioforsk/vips/logic/controller/servlet/ObservationController.java
@@ -80,6 +80,8 @@ public class ObservationController extends HttpServlet {
                 {
                     Observation observation = new Observation();
                     request.setAttribute("observation", observation);
+                    request.setAttribute("defaultMapCenter",user.getOrganizationId().getDefaultMapCenter());
+                    request.setAttribute("defaultMapZoom", user.getOrganizationId().getDefaultMapZoom());
                     List<Organism> allOrganisms = em.createNamedQuery("Organism.findAll").getResultList();
                     request.setAttribute("allOrganisms", allOrganisms);
                     // Hierarchy categories
@@ -152,7 +154,6 @@ public class ObservationController extends HttpServlet {
                         observation.setLocation(formValidation.getFormField("location").getValueAsPointWGS84());
                         observation = SessionControllerGetter.getObservationBean().storeObservation(observation);
                         
-                        // Redirecting to form
                         // Redirect to form
                         response.sendRedirect(new StringBuilder("http://")
                                 .append(ServletUtil.getServerName(request))
diff --git a/src/main/java/no/bioforsk/vips/logic/controller/servlet/PointOfInterestController.java b/src/main/java/no/bioforsk/vips/logic/controller/servlet/PointOfInterestController.java
index 2a8bc7cc24e46cf2c2f2ceacfa9572ab31310503..e996fbe40dfec86e8152eff3288e4b17679aed4f 100644
--- a/src/main/java/no/bioforsk/vips/logic/controller/servlet/PointOfInterestController.java
+++ b/src/main/java/no/bioforsk/vips/logic/controller/servlet/PointOfInterestController.java
@@ -22,14 +22,26 @@ package no.bioforsk.vips.logic.controller.servlet;
 import java.io.IOException;
 import java.util.List;
 import java.util.TimeZone;
+import javax.persistence.EntityManager;
+import javax.persistence.PersistenceContext;
 import javax.servlet.ServletException;
 import javax.servlet.http.HttpServlet;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
+import no.bioforsk.vips.logic.entity.Country;
 import no.bioforsk.vips.logic.entity.PointOfInterest;
+import no.bioforsk.vips.logic.entity.PointOfInterestType;
 import no.bioforsk.vips.logic.entity.PointOfInterestWeatherStation;
+import no.bioforsk.vips.logic.entity.VipsLogicRole;
 import no.bioforsk.vips.logic.entity.VipsLogicUser;
+import no.bioforsk.vips.logic.entity.WeatherStationDataSource;
+import no.bioforsk.vips.logic.util.Globals;
 import no.bioforsk.vips.logic.util.SessionControllerGetter;
+import no.bioforsk.vips.util.ExceptionUtil;
+import no.bioforsk.vips.util.ServletUtil;
+import no.bioforsk.web.forms.FormValidation;
+import no.bioforsk.web.forms.FormValidationException;
+import no.bioforsk.web.forms.FormValidator;
 
 /**
  * Handles transactions for POIs
@@ -37,7 +49,8 @@ import no.bioforsk.vips.logic.util.SessionControllerGetter;
  * @author Tor-Einar Skog <tor-einar.skog@bioforsk.no>
  */
 public class PointOfInterestController extends HttpServlet {
-
+    @PersistenceContext(unitName="VIPSLogic-PU")
+    EntityManager em;
     /**
      * Processes requests for both HTTP
      * <code>GET</code> and
@@ -53,7 +66,7 @@ public class PointOfInterestController extends HttpServlet {
         
         request.getSession().removeAttribute("weatherStations");
         request.getSession().removeAttribute("weatherStation");
-        
+        String action = request.getParameter("action");
         VipsLogicUser user = (VipsLogicUser) request.getSession().getAttribute("user");
         
         /*
@@ -66,46 +79,182 @@ public class PointOfInterestController extends HttpServlet {
         
         if(request.getServletPath().equals("/weatherStation"))
         {
-            // Decide if requsted view is list view or single view
-            String pointOfInterestId = request.getParameter("pointOfInterestId");
-            // List view
-            if(pointOfInterestId == null)
+            if(action == null)
             {
-                List<PointOfInterestWeatherStation> weatherStations;
-                if(user.isSuperUser()){
-                    weatherStations = SessionControllerGetter.getPointOfInterestBean().getAllWeatherStations();
+                // Decide if requested view is list view or single view
+                String pointOfInterestId = request.getParameter("pointOfInterestId");
+                // List view
+                if(pointOfInterestId == null)
+                {
+                    List<PointOfInterestWeatherStation> weatherStations;
+                    if(user.isSuperUser()){
+                        weatherStations = SessionControllerGetter.getPointOfInterestBean().getAllWeatherStations();
+                    }
+                    else
+                    {
+                        weatherStations = SessionControllerGetter.getPointOfInterestBean().getWeatherstationsForOrganization(user.getOrganizationId());
+                    }
+                    request.setAttribute("defaultMapCenter",user.getOrganizationId().getDefaultMapCenter());
+                    request.setAttribute("defaultMapZoom", user.getOrganizationId().getDefaultMapZoom());
+                    request.getSession().setAttribute("weatherStations", weatherStations);
+                    request.getRequestDispatcher("/weatherstationList.ftl").forward(request, response);
                 }
+                // Single view
                 else
                 {
-                    weatherStations = SessionControllerGetter.getPointOfInterestBean().getWeatherstationsForUser(user.getUserId());
+                    PointOfInterest weatherStation = SessionControllerGetter.getPointOfInterestBean().getPointOfInterest(Integer.valueOf(pointOfInterestId));
+                    if(weatherStation instanceof PointOfInterestWeatherStation)
+                    {
+                        PointOfInterestWeatherStation stationWithDataSource = (PointOfInterestWeatherStation) weatherStation;
+                        request.getSession().setAttribute("weatherStation", stationWithDataSource);
+                    }
+                    else
+                    {
+                        request.getSession().setAttribute("weatherStation", weatherStation);
+                    }
+                    request.getSession().setAttribute("availableTimeZones", TimeZone.getAvailableIDs());
+                    request.getSession().setAttribute("defaultTimeZoneId", user.getOrganizationId().getDefaultTimeZone());
+                    request.setAttribute("defaultMapCenter",user.getOrganizationId().getDefaultMapCenter());
+                    request.setAttribute("defaultMapZoom", user.getOrganizationId().getDefaultMapZoom());
+
+                    request.getRequestDispatcher("/weatherstationView.ftl").forward(request, response);
+
                 }
-                request.getSession().setAttribute("weatherStations", weatherStations);
-                request.getRequestDispatcher("/weatherstationlist.ftl").forward(request, response);
             }
-            // Single view
-            else
+            else if(action.equals("newWeatherStationForm"))
             {
-                PointOfInterest weatherStation = SessionControllerGetter.getPointOfInterestBean().getPointOfInterest(Integer.valueOf(pointOfInterestId));
-                if(weatherStation instanceof PointOfInterestWeatherStation)
+                if(SessionControllerGetter.getUserBean().authorizeUser(user, VipsLogicRole.ORGANIZATION_ADMINISTRATOR, VipsLogicRole.SUPERUSER))
                 {
-                    PointOfInterestWeatherStation stationWithDataSource = (PointOfInterestWeatherStation) weatherStation;
-                    request.getSession().setAttribute("weatherStation", stationWithDataSource);
+                    try
+                    {
+                        PointOfInterest weatherStation = new PointOfInterestWeatherStation();  
+                        request.getSession().setAttribute("weatherStation", weatherStation);
+                        request.setAttribute("defaultMapCenter",user.getOrganizationId().getDefaultMapCenter());
+                        request.setAttribute("defaultMapZoom", user.getOrganizationId().getDefaultMapZoom());
+                        request.getSession().setAttribute("dataSources", SessionControllerGetter.getPointOfInterestBean().getWeatherStationDataSources());
+                        request.getSession().setAttribute("availableTimeZones", TimeZone.getAvailableIDs());
+                        request.getSession().setAttribute("defaultTimeZoneId", user.getOrganizationId().getDefaultTimeZone());
+                        request.getSession().setAttribute("availableCountries", em.createNamedQuery("Country.findAll").getResultList());
+                        request.getSession().setAttribute("defaultCountryCode", user.getOrganizationId().getCountryCode().getCountryCode());
+                        if(user.isSuperUser())
+                        {
+                            request.getSession().setAttribute("users", em.createNamedQuery("VipsLogicUser.findAll", VipsLogicUser.class).getResultList());
+                        }
+                        request.getRequestDispatcher("/weatherstationForm.ftl").forward(request, response);
+                    }
+                    catch(NullPointerException | NumberFormatException ex)
+                    {
+                        response.sendError(500, ExceptionUtil.getStackTrace(ex));
+                    }
                 }
                 else
                 {
-                    request.getSession().setAttribute("weatherStation", weatherStation);
+                    response.sendError(403,"Access not authorized"); // HTTP Forbidden
                 }
-                request.getSession().setAttribute("availableTimeZones", TimeZone.getAvailableIDs());
-                request.getSession().setAttribute("defaultTimeZoneId", TimeZone.getDefault().getID());
-                
-                // Dispatch to read or write view?
-                if(request.getPathInfo() != null && request.getPathInfo().equals("/edit"))
+            }
+            // Authorization: ORGANIZATION ADMIN or SUPERUSER
+            else if(action.equals("editWeatherStationForm"))
+            {
+                if(SessionControllerGetter.getUserBean().authorizeUser(user, VipsLogicRole.ORGANIZATION_ADMINISTRATOR, VipsLogicRole.SUPERUSER))
                 {
-                    request.getRequestDispatcher("/weatherstationForm.ftl").forward(request, response);
+                    try
+                    {
+                        Integer pointOfInterestId = Integer.valueOf(request.getParameter("pointOfInterestId"));
+                        PointOfInterest weatherStation = em.find(PointOfInterest.class, pointOfInterestId);
+                        request.getSession().setAttribute("weatherStation", weatherStation);
+                        request.setAttribute("defaultMapCenter",user.getOrganizationId().getDefaultMapCenter());
+                        request.setAttribute("defaultMapZoom", user.getOrganizationId().getDefaultMapZoom());
+                        request.getSession().setAttribute("dataSources", SessionControllerGetter.getPointOfInterestBean().getWeatherStationDataSources());
+                        request.getSession().setAttribute("availableTimeZones", TimeZone.getAvailableIDs());
+                        request.getSession().setAttribute("defaultTimeZoneId", user.getOrganizationId().getDefaultTimeZone());
+                        request.getSession().setAttribute("availableCountries", em.createNamedQuery("Country.findAll").getResultList());
+                        request.getSession().setAttribute("defaultCountryCode", user.getOrganizationId().getCountryCode().getCountryCode());
+                        if(user.isSuperUser())
+                        {
+                            request.getSession().setAttribute("users", em.createNamedQuery("VipsLogicUser.findAll", VipsLogicUser.class).getResultList());
+                        }
+                        request.getRequestDispatcher("/weatherstationForm.ftl").forward(request, response);
+                    }
+                    catch(NullPointerException | NumberFormatException ex)
+                    {
+                        response.sendError(500, ExceptionUtil.getStackTrace(ex));
+                    }
+                }
+                else
+                {
+                    response.sendError(403,"Access not authorized"); // HTTP Forbidden
+                }
+            }
+            // Authorization: ORGANIZATION ADMIN or SUPERUSER
+            else if(action.equals("weatherStationFormSubmit"))
+            {
+                if(SessionControllerGetter.getUserBean().authorizeUser(user, VipsLogicRole.ORGANIZATION_ADMINISTRATOR, VipsLogicRole.SUPERUSER))
+                {
+                    try
+                    {
+                        Integer pointOfInterestId = Integer.valueOf(request.getParameter("pointOfInterestId"));
+                        PointOfInterestWeatherStation weatherStation = pointOfInterestId > 0 ? 
+                                                                        em.find(PointOfInterestWeatherStation.class, pointOfInterestId) 
+                                                                        : new PointOfInterestWeatherStation();
+                        FormValidation formValidation = FormValidator.validateForm("weatherStationForm", request, getServletContext());
+                        if(formValidation.isValid())
+                        {
+                            // Set values
+                            weatherStation.setName(formValidation.getFormField("name").getWebValue());
+                            weatherStation.setAltitude(formValidation.getFormField("altitude").getValueAsDouble());
+                            weatherStation.setLongitude(formValidation.getFormField("location").getValueAsPointWGS84().getX());
+                            weatherStation.setLatitude(formValidation.getFormField("location").getValueAsPointWGS84().getY());
+                            weatherStation.setWeatherStationDataSourceId(em.find(WeatherStationDataSource.class, formValidation.getFormField("weatherStationDataSourceId").getValueAsInteger()));
+                            weatherStation.setWeatherStationRemoteId(formValidation.getFormField("weatherStationRemoteId").getWebValue());
+                            weatherStation.setTimeZone(formValidation.getFormField("timeZone").getWebValue());
+                            weatherStation.setCountryCode(em.find(Country.class, formValidation.getFormField("countryCode").getWebValue()));
+                            if(weatherStation.getPointOfInterestType() == null)
+                            {
+                                weatherStation.setPointOfInterestType(em.find(PointOfInterestType.class, Globals.POI_TYPE_WEATHERSTATION));
+                            }
+                            // If userId is set from form, always update
+                            if(user.isSuperUser() && !formValidation.getFormField("userId").isEmpty())
+                            {
+                                weatherStation.setUserId(em.find(VipsLogicUser.class, formValidation.getFormField("userId").getValueAsInteger()));
+                            }
+                            // If user is not set, use current user
+                            else if(weatherStation.getUserId() == null)
+                            {
+                                weatherStation.setUserId(user);
+                            }
+                            // Store
+                            weatherStation = SessionControllerGetter.getPointOfInterestBean().storeWeatherStation(weatherStation);
+                            
+                            // Redirect to form
+                            response.sendRedirect(new StringBuilder("http://")
+                                .append(ServletUtil.getServerName(request))
+                                .append("/weatherStation?action=editWeatherStationForm&pointOfInterestId=").append(weatherStation.getPointOfInterestId())
+                                .append("&messageKey=").append("weatherStationStored").toString()
+
+                            );
+                        }
+                        else
+                        {
+                            request.setAttribute("formValidation", formValidation);
+                            request.setAttribute("weatherStation", weatherStation);
+                            request.setAttribute("defaultMapCenter",user.getOrganizationId().getDefaultMapCenter());
+                            request.setAttribute("defaultMapZoom", user.getOrganizationId().getDefaultMapZoom());
+                            request.getSession().setAttribute("dataSources", SessionControllerGetter.getPointOfInterestBean().getWeatherStationDataSources());
+                            request.getSession().setAttribute("availableTimeZones", TimeZone.getAvailableIDs());
+                            request.getSession().setAttribute("defaultTimeZoneId", user.getOrganizationId().getDefaultTimeZone());
+                            request.getSession().setAttribute("availableCountries", em.createNamedQuery("Country.findAll").getResultList());
+                            request.getSession().setAttribute("defaultCountryCode", user.getOrganizationId().getCountryCode().getCountryCode());
+                            request.getRequestDispatcher("/weatherstationForm.ftl").forward(request, response);
+                        }
+                    }
+                    catch(NullPointerException | NumberFormatException | FormValidationException ex)
+                    {
+                        response.sendError(500, ExceptionUtil.getStackTrace(ex));
+                    }
                 }
                 else
                 {
-                    request.getRequestDispatcher("/weatherstation.ftl").forward(request, response);
+                    response.sendError(403,"Access not authorized"); // HTTP Forbidden
                 }
             }
         }
diff --git a/src/main/java/no/bioforsk/vips/logic/controller/session/PointOfInterestBean.java b/src/main/java/no/bioforsk/vips/logic/controller/session/PointOfInterestBean.java
index 5887d6f9b91ccddeab7282fa1299d91eeb3e682d..c09d6d831f5d28e7ddd7d5086addc484ddc7e5c4 100644
--- a/src/main/java/no/bioforsk/vips/logic/controller/session/PointOfInterestBean.java
+++ b/src/main/java/no/bioforsk/vips/logic/controller/session/PointOfInterestBean.java
@@ -19,14 +19,28 @@
 
 package no.bioforsk.vips.logic.controller.session;
 
+import de.micromata.opengis.kml.v_2_2_0.Coordinate;
+import de.micromata.opengis.kml.v_2_2_0.Document;
+import de.micromata.opengis.kml.v_2_2_0.Kml;
+import de.micromata.opengis.kml.v_2_2_0.KmlFactory;
+import de.micromata.opengis.kml.v_2_2_0.Placemark;
+import de.micromata.opengis.kml.v_2_2_0.Point;
+import java.util.HashSet;
 import java.util.List;
+import java.util.ResourceBundle;
+import java.util.Set;
 import javax.ejb.LocalBean;
 import javax.ejb.Stateless;
 import javax.persistence.EntityManager;
 import javax.persistence.PersistenceContext;
 import javax.persistence.Query;
+import no.bioforsk.vips.logic.entity.Organization;
 import no.bioforsk.vips.logic.entity.PointOfInterest;
 import no.bioforsk.vips.logic.entity.PointOfInterestWeatherStation;
+import no.bioforsk.vips.logic.entity.UserPointOfInterest;
+import no.bioforsk.vips.logic.entity.UserPointOfInterestPK;
+import no.bioforsk.vips.logic.entity.VipsLogicUser;
+import no.bioforsk.vips.logic.entity.WeatherStationDataSource;
 import no.bioforsk.vips.logic.util.Globals;
 
 
@@ -79,4 +93,78 @@ public class PointOfInterestBean {
         return (PointOfInterest) q.getSingleResult();
         
     }
+
+    public Kml getWeatherstationsForOrganization(Integer organizationId, Integer excludeWeatherStationId, Integer highlightWeatherStationId, String serverName, ResourceBundle i18nBundle) {
+        String iconPath = "http://" + serverName + "/public/images/";
+        Organization organization = em.find(Organization.class, organizationId);
+        // Initialization
+        final Kml kml = KmlFactory.createKml();
+        final Document document = kml.createAndSetDocument()
+        .withName("Weather stations").withDescription("Weather stations for ");
+        
+        document.createAndAddStyle()
+            .withId("weatherstation_icon")
+        .createAndSetIconStyle()
+                .withScale(0.55)
+                .createAndSetIcon()
+                    .withHref(iconPath + "dot_blue.png");
+        
+        document.createAndAddStyle()
+            .withId("weatherstation_icon_highlighted")
+        .createAndSetIconStyle()
+                .withScale(0.55)
+                .createAndSetIcon()
+                    .withHref(iconPath + "anemometer_mono.png");
+        
+        List<PointOfInterestWeatherStation> weatherStations = this.getWeatherstationsForOrganization(organization);
+        String description = "";
+        for(PointOfInterestWeatherStation weatherStation:weatherStations)
+        {
+            if(excludeWeatherStationId != null && excludeWeatherStationId.equals(weatherStation.getPointOfInterestId()))
+            {
+                continue;
+            }
+            
+            String styleUrl = "#weatherstation_icon"
+                            +   (highlightWeatherStationId != null && highlightWeatherStationId.equals(weatherStation.getPointOfInterestId()) ? "_highlighted" :"");
+            
+            if(weatherStation instanceof PointOfInterestWeatherStation)
+            {
+                description = i18nBundle.getString("dataSourceName") + 
+                                ": <a href=\"" + weatherStation.getWeatherStationDataSourceId().getUri() + "\" target=\"new\">" 
+                                +  weatherStation.getWeatherStationDataSourceId().getName() 
+                                + "</a>";
+            }
+            final Placemark placemark = document.createAndAddPlacemark()
+            .withName(weatherStation.getName())
+            .withDescription(description)
+            .withStyleUrl(styleUrl)
+             .withId(weatherStation.getPointOfInterestId().toString());
+            
+            
+            final Point point = placemark.createAndSetPoint();
+            List<Coordinate> coord = point.createAndSetCoordinates();
+            coord.add(new Coordinate(
+                    weatherStation.getLongitude(),
+                    weatherStation.getLatitude(),
+                    weatherStation.getAltitude() != null ? weatherStation.getAltitude() : 0
+            ));
+        }
+        return kml;
+    }
+
+    public List<WeatherStationDataSource> getWeatherStationDataSources() {
+        return em.createNamedQuery("WeatherStationDataSource.findAll").getResultList();
+    }
+
+    public PointOfInterestWeatherStation storeWeatherStation(PointOfInterestWeatherStation weatherStation) {
+        weatherStation = em.merge(weatherStation);
+        return weatherStation;
+    }
+
+    public List<PointOfInterestWeatherStation> getWeatherstationsForOrganization(Organization organization) {
+        return em.createNamedQuery("PointOfInterestWeatherStation.findByOrganizationId", PointOfInterestWeatherStation.class)
+                                                .setParameter("organizationId", organization)
+                                                .getResultList();
+    }
 }
diff --git a/src/main/java/no/bioforsk/vips/logic/entity/Country.java b/src/main/java/no/bioforsk/vips/logic/entity/Country.java
index 07cdc5e4c395082d48daef92b6887802f6a9632c..1ed4cf116c4ef05df183671418960c5f183015d2 100644
--- a/src/main/java/no/bioforsk/vips/logic/entity/Country.java
+++ b/src/main/java/no/bioforsk/vips/logic/entity/Country.java
@@ -20,6 +20,7 @@
 package no.bioforsk.vips.logic.entity;
 
 import java.io.Serializable;
+import java.util.Locale;
 import java.util.Set;
 import javax.persistence.Basic;
 import javax.persistence.Column;
@@ -32,6 +33,7 @@ import javax.persistence.NamedQueries;
 import javax.persistence.NamedQuery;
 import javax.persistence.OneToMany;
 import javax.persistence.Table;
+import javax.persistence.Transient;
 import javax.validation.constraints.NotNull;
 import javax.validation.constraints.Size;
 import javax.xml.bind.annotation.XmlRootElement;
@@ -50,19 +52,11 @@ import org.codehaus.jackson.annotate.JsonIgnore;
     @NamedQuery(name = "Country.findByCountryCode", query = "SELECT c FROM Country c WHERE c.countryCode = :countryCode")})
 public class Country implements Serializable {
     private static final long serialVersionUID = 1L;
-    @Id
-    @Basic(optional = false)
     @NotNull
     @Size(min = 1, max = 2)
-    @Column(name = "country_code")
     private String countryCode;
-    @JoinTable(name = "external_resource_validity", joinColumns = {
-        @JoinColumn(name = "country_code", referencedColumnName = "country_code")}, inverseJoinColumns = {
-        @JoinColumn(name = "external_resource_id", referencedColumnName = "external_resource_id")})
-    @ManyToMany
-    private Set<ExternalResource> externalResourceSet;
-    @OneToMany(mappedBy = "countryCode")
-    private Set<PointOfInterest> pointOfInterestSet;
+        private Set<ExternalResource> externalResourceSet;
+        private Set<PointOfInterest> pointOfInterestSet;
 
     public Country() {
     }
@@ -71,6 +65,9 @@ public class Country implements Serializable {
         this.countryCode = countryCode;
     }
 
+@Id
+    @Basic(optional = false)
+    @Column(name = "country_code")
     public String getCountryCode() {
         return countryCode;
     }
@@ -79,6 +76,10 @@ public class Country implements Serializable {
         this.countryCode = countryCode;
     }
 
+@JoinTable(name = "external_resource_validity", joinColumns = {
+        @JoinColumn(name = "country_code", referencedColumnName = "country_code")}, inverseJoinColumns = {
+            @JoinColumn(name = "external_resource_id", referencedColumnName = "external_resource_id")})
+    @ManyToMany
     @XmlTransient
     @JsonIgnore
     public Set<ExternalResource> getExternalResourceSet() {
@@ -89,6 +90,7 @@ public class Country implements Serializable {
         this.externalResourceSet = externalResourceSet;
     }
 
+@OneToMany(mappedBy = "countryCode")
     @XmlTransient
     @JsonIgnore
     public Set<PointOfInterest> getPointOfInterestSet() {
@@ -124,4 +126,10 @@ public class Country implements Serializable {
         return "no.bioforsk.vips.logic.entity.Country[ countryCode=" + countryCode + " ]";
     }
 
+    
+    public String getCountryName(String language)
+    {
+        Locale locale = new Locale(language, this.countryCode);
+        return locale.getDisplayCountry();
+    }
 }
diff --git a/src/main/java/no/bioforsk/vips/logic/entity/Organization.java b/src/main/java/no/bioforsk/vips/logic/entity/Organization.java
index 46a5ebec5d3f3e55ec31e43cde65756d916238d7..4020ab91ac0980bea4bda20d9fcf071675b67fce 100644
--- a/src/main/java/no/bioforsk/vips/logic/entity/Organization.java
+++ b/src/main/java/no/bioforsk/vips/logic/entity/Organization.java
@@ -19,6 +19,7 @@
 
 package no.bioforsk.vips.logic.entity;
 
+import com.vividsolutions.jts.geom.Point;
 import java.io.Serializable;
 import java.util.Set;
 import javax.persistence.Basic;
@@ -37,6 +38,7 @@ import javax.validation.constraints.Size;
 import javax.xml.bind.annotation.XmlRootElement;
 import javax.xml.bind.annotation.XmlTransient;
 import org.codehaus.jackson.annotate.JsonIgnore;
+import org.hibernate.annotations.Type;
 
 /**
  * @copyright 2013 <a href="http://www.bioforsk.no/">Bioforsk</a>
@@ -71,6 +73,14 @@ public class Organization implements Serializable {
     @Size(max = 63)
     @Column(name = "postal_code")
     private String postalCode;
+    @Column(name = "default_map_zoom")
+    private Integer defaultMapZoom;
+    @Column(name = "default_time_zone")
+    private String defaultTimeZone;
+    @JsonIgnore
+    @Type(type = "org.hibernate.spatial.GeometryType")
+    @Column(name = "default_map_center", columnDefinition = "Geometry")
+    private Point defaultMapCenter;
     @OneToMany(mappedBy = "parentOrganizationId")
     private Set<Organization> organizationSet;
     @JoinColumn(name = "parent_organization_id", referencedColumnName = "organization_id")
@@ -207,4 +217,46 @@ public class Organization implements Serializable {
         this.defaultLocale = defaultLocale;
     }
 
+    /**
+     * @return the defaultMapZoom
+     */
+    public Integer getDefaultMapZoom() {
+        return defaultMapZoom;
+    }
+
+    /**
+     * @param defaultMapZoom the defaultMapZoom to set
+     */
+    public void setDefaultMapZoom(Integer defaultMapZoom) {
+        this.defaultMapZoom = defaultMapZoom;
+    }
+
+    /**
+     * @return the defaultMapCenter
+     */
+    public Point getDefaultMapCenter() {
+        return defaultMapCenter;
+    }
+
+    /**
+     * @param defaultMapCenter the defaultMapCenter to set
+     */
+    public void setDefaultMapCenter(Point defaultMapCenter) {
+        this.defaultMapCenter = defaultMapCenter;
+    }
+
+    /**
+     * @return the defaultTimeZone
+     */
+    public String getDefaultTimeZone() {
+        return defaultTimeZone;
+    }
+
+    /**
+     * @param defaultTimeZone the defaultTimeZone to set
+     */
+    public void setDefaultTimeZone(String defaultTimeZone) {
+        this.defaultTimeZone = defaultTimeZone;
+    }
+
 }
diff --git a/src/main/java/no/bioforsk/vips/logic/entity/PointOfInterest.java b/src/main/java/no/bioforsk/vips/logic/entity/PointOfInterest.java
index 1c06c6009e7716bae0fa0217ea7e25275d80c525..672ccfcd20ed0044205cfabe33322e2d7a08db55 100644
--- a/src/main/java/no/bioforsk/vips/logic/entity/PointOfInterest.java
+++ b/src/main/java/no/bioforsk/vips/logic/entity/PointOfInterest.java
@@ -21,9 +21,7 @@ package no.bioforsk.vips.logic.entity;
 import java.io.Serializable;
 import java.util.HashMap;
 import java.util.Map;
-import java.util.Set;
 import javax.persistence.Basic;
-import javax.persistence.CascadeType;
 import javax.persistence.Column;
 import javax.persistence.DiscriminatorColumn;
 import javax.persistence.Entity;
@@ -36,12 +34,10 @@ import javax.persistence.JoinColumn;
 import javax.persistence.ManyToOne;
 import javax.persistence.NamedQueries;
 import javax.persistence.NamedQuery;
-import javax.persistence.OneToMany;
 import javax.persistence.Table;
 import javax.persistence.Transient;
 import javax.validation.constraints.Size;
 import javax.xml.bind.annotation.XmlRootElement;
-import javax.xml.bind.annotation.XmlTransient;
 import org.codehaus.jackson.annotate.JsonIgnore;
 
 /**
@@ -60,7 +56,8 @@ import org.codehaus.jackson.annotate.JsonIgnore;
     @NamedQuery(name = "PointOfInterest.findByName", query = "SELECT p FROM PointOfInterest p WHERE p.name = :name"),
     @NamedQuery(name = "PointOfInterest.findByLongitude", query = "SELECT p FROM PointOfInterest p WHERE p.longitude = :longitude"),
     @NamedQuery(name = "PointOfInterest.findByLatitude", query = "SELECT p FROM PointOfInterest p WHERE p.latitude = :latitude"),
-    @NamedQuery(name = "PointOfInterest.findByAltitude", query = "SELECT p FROM PointOfInterest p WHERE p.altitude = :altitude")
+    @NamedQuery(name = "PointOfInterest.findByAltitude", query = "SELECT p FROM PointOfInterest p WHERE p.altitude = :altitude"),
+    @NamedQuery(name = "PointOfInterest.findByUserId", query = "SELECT p FROM PointOfInterest p WHERE p.userId = :userId")
 })
 public class PointOfInterest implements Serializable, Comparable {
 
@@ -83,8 +80,9 @@ public class PointOfInterest implements Serializable, Comparable {
     private Double latitude;
     @Column(name = "altitude")
     private Double altitude;
-    @OneToMany(cascade = CascadeType.ALL, mappedBy = "pointOfInterest")
-    private Set<UserPointOfInterest> userPointOfInterestSet;
+    @JoinColumn(name = "user_id", referencedColumnName = "user_id")
+    @ManyToOne
+    private VipsLogicUser userId;
     @JoinColumn(name = "country_code", referencedColumnName = "country_code")
     @ManyToOne
     private Country countryCode;
@@ -144,16 +142,7 @@ public class PointOfInterest implements Serializable, Comparable {
         this.altitude = altitude;
     }
 
-    @XmlTransient
-    @JsonIgnore
-    public Set<UserPointOfInterest> getUserPointOfInterestSet() {
-        return userPointOfInterestSet;
-    }
-
-    public void setUserPointOfInterestSet(Set<UserPointOfInterest> userPointOfInterestSet) {
-        this.userPointOfInterestSet = userPointOfInterestSet;
-    }
-
+    
     public Country getCountryCode() {
         return countryCode;
     }
@@ -249,4 +238,19 @@ public class PointOfInterest implements Serializable, Comparable {
     public void setProperties(Map<String,Object> properties) {
         this.properties = properties;
     }
+
+    /**
+     * @return the userId
+     */
+    @JsonIgnore
+    public VipsLogicUser getUserId() {
+        return userId;
+    }
+
+    /**
+     * @param userId the userId to set
+     */
+    public void setUserId(VipsLogicUser userId) {
+        this.userId = userId;
+    }
 }
diff --git a/src/main/java/no/bioforsk/vips/logic/entity/PointOfInterestWeatherStation.java b/src/main/java/no/bioforsk/vips/logic/entity/PointOfInterestWeatherStation.java
index 5c275e7099202e465312442462c700a456f97eb9..7254b146a42bfb7dd4416fecd5c224d0eb12572f 100644
--- a/src/main/java/no/bioforsk/vips/logic/entity/PointOfInterestWeatherStation.java
+++ b/src/main/java/no/bioforsk/vips/logic/entity/PointOfInterestWeatherStation.java
@@ -45,7 +45,8 @@ import org.codehaus.jackson.annotate.JsonIgnore;
 @NamedQueries({
     @NamedQuery(name = "PointOfInterestWeatherStation.findAll", query = "SELECT p FROM PointOfInterest p WHERE p.pointOfInterestType.pointOfInterestTypeId=1"),
     @NamedQuery(name = "PointOfInterestWeatherStation.findByPointOfInterestId", query = "SELECT p FROM PointOfInterest p WHERE p.pointOfInterestId = :pointOfInterestId AND p.pointOfInterestType.pointOfInterestTypeId=1"),
-    @NamedQuery(name = "PointOfInterestWeatherStation.findByUserId", query = "SELECT p FROM PointOfInterest p WHERE p.pointOfInterestType.pointOfInterestTypeId=1 AND p.pointOfInterestId IN(SELECT up.pointOfInterest.pointOfInterestId FROM UserPointOfInterest up WHERE up.userPointOfInterestPK.userId = :userId)")
+    @NamedQuery(name = "PointOfInterestWeatherStation.findByOrganizationId", query = "SELECT p FROM PointOfInterestWeatherStation p WHERE p.pointOfInterestType.pointOfInterestTypeId=1 AND p.userId IN(SELECT u.userId FROM VipsLogicUser u WHERE u.organizationId=:organizationId)"),
+    @NamedQuery(name = "PointOfInterestWeatherStation.findByUserId", query = "SELECT p FROM PointOfInterestWeatherStation p WHERE p.pointOfInterestType.pointOfInterestTypeId=1 AND p.userId = :userId")
 })
 public class PointOfInterestWeatherStation extends PointOfInterest implements Serializable {
     @Size(max = 255)
diff --git a/src/main/java/no/bioforsk/vips/logic/service/LogicService.java b/src/main/java/no/bioforsk/vips/logic/service/LogicService.java
index a26880a16d69d8c131a6696e5dc6517acce34796..5a4f0b002c86cdf321d94b046b297fe5d97fe6c6 100644
--- a/src/main/java/no/bioforsk/vips/logic/service/LogicService.java
+++ b/src/main/java/no/bioforsk/vips/logic/service/LogicService.java
@@ -170,6 +170,15 @@ public class LogicService {
         return Response.ok().entity(latestResults).build();
     }
     
+    @GET
+    @Path("weatherstations/kml/{organizationId}")
+    @Produces("application/vnd.google-earth.kml+xml;charset=utf-8")
+    public Response getWeatherStations(@QueryParam("excludeWeatherStationId") Integer excludeWeatherStationId, @QueryParam("highlightWeatherStationId") Integer highlightWeatherStationId, @PathParam("organizationId") Integer organizationId)
+    {
+        Kml retVal = SessionControllerGetter.getPointOfInterestBean().getWeatherstationsForOrganization(organizationId, excludeWeatherStationId, highlightWeatherStationId, ServletUtil.getServerName(httpServletRequest), SessionLocaleUtil.getI18nBundle(httpServletRequest));
+        return Response.ok().entity(retVal).build();
+    }
+    
     @GET
     @Path("organism/list")
     @Produces("application/json;charset=UTF-8")
diff --git a/src/main/resources/no/bioforsk/vips/logic/i18n/vipslogictexts.properties b/src/main/resources/no/bioforsk/vips/logic/i18n/vipslogictexts.properties
index 82a5d0bd1bd95c69e896ff36d1e25e0b0c179f91..5f4b9ac0e9694d6f15857ba476f8588ec0e0b47d 100644
--- a/src/main/resources/no/bioforsk/vips/logic/i18n/vipslogictexts.properties
+++ b/src/main/resources/no/bioforsk/vips/logic/i18n/vipslogictexts.properties
@@ -210,3 +210,9 @@ informAdminOfConfirmedEmailSubject=New user has confirmed email and is now ready
 informAdminOfConfirmedEmailBody=The user''s last name is {0}. Follow this link to edit this user: {1}
 sendUserApprovalConfirmationSubject=Your user account has been approved
 sendUserApprovalConfirmationBody=We are happy to confirm that your user account for VIPSLogic has been approved. Please log in here: {0}
+dataSourceName=Data source name
+newWeatherStation=New weather station
+meter=Meter
+country=Country
+editWeatherStation=Edit weather station
+toTheTop=To the top
diff --git a/src/main/resources/no/bioforsk/vips/logic/i18n/vipslogictexts_no.properties b/src/main/resources/no/bioforsk/vips/logic/i18n/vipslogictexts_no.properties
index 17627de0c749b0b5888e70a153c867afb2eec989..75ae7830fd86c3478c83621c824f461f112b3b88 100644
--- a/src/main/resources/no/bioforsk/vips/logic/i18n/vipslogictexts_no.properties
+++ b/src/main/resources/no/bioforsk/vips/logic/i18n/vipslogictexts_no.properties
@@ -210,3 +210,9 @@ informAdminOfConfirmedEmailSubject=Ny bruker har bekreftet sin e-postadresse og
 informAdminOfConfirmedEmailBody=Brukerens etternavn er {0}. F\u00f8lg denne lenken for \u00e5 redigere/godkjenne: {1}
 sendUserApprovalConfirmationSubject=Din brukerkonto har blitt godkjent
 sendUserApprovalConfirmationBody=Vi har gleden av \u00e5 bekrefte at din brukerkonto hos VIPSLogic er blitt godkjent. Vennligst logg in her: {0}
+dataSourceName=Datakildenavn
+newWeatherStation=Ny m\u00e5lestasjon
+meter=Meter
+country=Land
+editWeatherStation=Rediger m\u00e5lestasjon
+toTheTop=Helt til topps
diff --git a/src/main/webapp/css/vipslogic.css b/src/main/webapp/css/vipslogic.css
index c0e4006547349da3ecbbdf95de51d571f2970214..72d6f03c3d79ea2f116e2490a022225fc2987366 100644
--- a/src/main/webapp/css/vipslogic.css
+++ b/src/main/webapp/css/vipslogic.css
@@ -70,7 +70,7 @@ legend {
     display: block;
 }
 
-#observationFormMap{
+#observationFormMap, #weatherStationListMap, #weatherStationFormMap, #weatherStationViewMap{
     height: 400px;
     width: 100%;
 }
\ No newline at end of file
diff --git a/src/main/webapp/formdefinitions/weatherStationForm.json b/src/main/webapp/formdefinitions/weatherStationForm.json
new file mode 100644
index 0000000000000000000000000000000000000000..449fa851a359ee29a5a0e74494186bf861e121e1
--- /dev/null
+++ b/src/main/webapp/formdefinitions/weatherStationForm.json
@@ -0,0 +1,72 @@
+{
+    "_licenseNote": [
+        "Copyright (c) 2014 Bioforsk <http://www.bioforsk.no/>.",
+        "", 
+        "This file is part of VIPSLogic.",
+        "VIPSLogic 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.",
+        "", 
+        "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",
+        "GNU Affero General Public License for more details.",
+        "", 
+        "You should have received a copy of the GNU Affero General Public License",
+        "along with VIPSLogic.  If not, see <http://www.gnu.org/licenses/>."
+    ],
+    "_comment" : "Structure of the weatherStationForm and how to validate it",
+    "fields": [
+        {
+            "name" : "pointOfInterestId",
+            "dataType" : "INTEGER",
+            "required" : true
+        },
+        {
+            "name" : "name",
+            "dataType" : "STRING",
+            "required" : true
+        },
+        {
+            "name" : "weatherStationDataSourceId",
+            "dataType" : "INTEGER",
+            "fieldType" : "SELECT_SINGLE",
+            "required" : true,
+            "nullValue" : "-1"
+        },
+        {
+            "name" : "weatherStationRemoteId",
+            "dataType" : "STRING",
+            "required" : true
+        },
+        {
+            "name" : "location",
+            "dataType" : "POINT_WGS84",
+            "required" : true
+        },
+        {
+            "name" : "altitude",
+            "dataType" : "DOUBLE",
+            "required" : false
+        },
+        {
+            "name" : "timeZone",
+            "dataType" : "STRING",
+            "fieldType" : "SELECT_SINGLE",
+            "required" : true
+        },
+        {
+            "name" : "countryCode",
+            "dataType" : "STRING",
+            "fieldType" : "SELECT_SINGLE",
+            "required" : true
+        },
+        {
+            "name" : "userId",
+            "dataType" : "INTEGER",
+            "required" : false
+        }
+        
+    ]
+}
diff --git a/src/main/webapp/js/constants.js b/src/main/webapp/js/constants.js
new file mode 100644
index 0000000000000000000000000000000000000000..7d7a94fca0490b3c3ffdd412e7aced8193bae691
--- /dev/null
+++ b/src/main/webapp/js/constants.js
@@ -0,0 +1,27 @@
+/* 
+ * Copyright (c) 2014 Bioforsk <http://www.bioforsk.no/>. 
+ * 
+ * This file is part of VIPSLogic.
+ * VIPSLogic 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.
+ * 
+ * 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
+ * GNU Affero General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Affero General Public License
+ * along with VIPSLogic.  If not, see <http://www.gnu.org/licenses/>.
+ * 
+ */
+
+
+/*
+ * Constants for maps
+ */
+var mapConstants = {
+    // The attribution shown in the corner of the map 
+    MAP_ATTRIBUTION : "&copy; <a href='http://www.openstreetmap.org'>OpenStreetMap</a> contributors"
+};
\ No newline at end of file
diff --git a/src/main/webapp/js/observationFormMap.js b/src/main/webapp/js/observationFormMap.js
index 616ec67848f69b4166e7bf3263a85bdf77addea8..53a843e44e0c56ce606ea8917667d5dbf40e2407 100644
--- a/src/main/webapp/js/observationFormMap.js
+++ b/src/main/webapp/js/observationFormMap.js
@@ -32,7 +32,13 @@ function initMap(center, zoomLevel, displayMarker)
 {
     // Background layer is OpenStreetMap
     var backgroundLayer = new ol.layer.Tile({
-                    source: new ol.source.OSM()
+                    source: new ol.source.OSM({
+                        attributions: [
+                            new ol.Attribution({
+                              html: mapConstants.MAP_ATTRIBUTION
+                            })
+                          ]
+                    })
     });
     
     
diff --git a/src/main/webapp/js/validateForm.js b/src/main/webapp/js/validateForm.js
index 1cc79f8e4b38a14f3b1619036c3bfcc331faba72..066d7603a85dc335466fab829b1290f1216aa94f 100644
--- a/src/main/webapp/js/validateForm.js
+++ b/src/main/webapp/js/validateForm.js
@@ -188,12 +188,12 @@ function validateField(fieldEl, formDefinitionKey)
         $.getJSON( "/formdefinitions/" + theForm.id + ".json")
         .done(function(json){
             formDefinitions[theForm.id] = json;
-            validateFieldActual(fieldEl, theForm, formDefinitionKey);
+            return validateFieldActual(fieldEl, theForm, formDefinitionKey);
         });
     }
     else
     {
-        validateFieldActual(fieldEl, theForm, formDefinitionKey);
+        return validateFieldActual(fieldEl, theForm, formDefinitionKey);
     }
 }
 
@@ -231,7 +231,7 @@ function getValidationOutputEl(fieldEl, theForm)
  * @param {Element} fieldEl the form element to be validated
  * @param {Element} theForm the form
  * @param {String} formDefinitionKey optional key to a formdefinition for a part of the form that has been dynamically added to the main form
- * @returns {void}
+ * @returns {boolean}
  */
 function validateFieldActual(fieldEl, theForm, formDefinitionKey)
 {
diff --git a/src/main/webapp/js/weatherStationFormMap.js b/src/main/webapp/js/weatherStationFormMap.js
new file mode 100644
index 0000000000000000000000000000000000000000..38b71cce713af4c21ffbc138edea77d3863f137e
--- /dev/null
+++ b/src/main/webapp/js/weatherStationFormMap.js
@@ -0,0 +1,148 @@
+/* 
+ * Copyright (c) 2014 Bioforsk <http://www.bioforsk.no/>. 
+ * 
+ * This file is part of VIPSLogic.
+ * VIPSLogic 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.
+ * 
+ * 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
+ * GNU Affero General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Affero General Public License
+ * along with VIPSLogic.  If not, see <http://www.gnu.org/licenses/>.
+ * 
+ */
+
+/*
+ * KML layer map with weather station information
+ * @author Tor-Einar Skog <tor-einar.skog@bioforsk.no>
+ */
+
+// Keeping the map and station marker globally available
+var map;
+var stationMarker;
+
+/**
+ * 
+ * @param {ol.Coordinate} center - coordinates for the map's center (WGS84)
+ * @param {int} zoomLevel - the zoom level (1-15, 1 is world wide view, 15 is greatest zoom)
+ * * @param {int} currentWeatherStationId - the current weather station id
+ * @returns {void}
+ */
+function initMap(center, zoomLevel, currentWeatherStationId)
+{
+    // Background layer is OpenStreetMap
+    var backgroundLayer = new ol.layer.Tile({
+                    source: new ol.source.OSM({
+                        attributions: [
+                            new ol.Attribution({
+                              html: mapConstants.MAP_ATTRIBUTION
+                            })
+                          ]
+                    })
+    });
+    
+    // The weather station layer
+    var weatherStationLayer = new ol.layer.Vector({
+    source: new ol.source.KML({
+        url: "/rest/weatherstations/kml/2" + (currentWeatherStationId > 0 ? "?excludeWeatherStationId=" + currentWeatherStationId : ""),
+            projection: "EPSG:3857"
+      })
+    });
+    
+   
+    // Layer for popup
+    var popOverlay = new ol.Overlay({
+      element: document.getElementById("popover")
+    });
+    
+    // Creating the map
+    map = new ol.Map({
+                    target: 'weatherStationFormMap',
+                    layers: [backgroundLayer,weatherStationLayer],
+                    overlays: [popOverlay],
+                    renderer: 'canvas'
+    });
+
+    var centerPosition = ol.proj.transform(center, 'EPSG:4326', map.getView().getProjection().getCode());
+    
+    
+
+    // Setting zoom and center for the map (need to do this after creating map. so that we kan transform our
+    // center to correct map projection)
+    var view = new ol.View2D({
+            center: centerPosition,
+            zoom:zoomLevel
+    });
+    map.setView(view);
+    
+    // Marker overlay
+    stationMarker = new ol.Overlay({
+      position: currentWeatherStationId !== null ? centerPosition : undefined,
+      positioning: 'bottom-center',
+      element: document.getElementById('stationMarker'),
+      stopEvent: false
+    });
+    
+    map.addOverlay(stationMarker);
+    
+    
+    // Listening for single clicks, position observation pin and updating form element
+    map.on(['singleclick'], function(evt) {
+        updateLocationPosition(evt.coordinate);
+    });
+    
+    
+    
+    
+    
+    
+   
+   
+}
+
+function updateLocationPosition(coordinate)
+{
+    var locationPosition = ol.coordinate.toStringXY(ol.proj.transform(coordinate, map.getView().getProjection().getCode(), 'EPSG:4326'),4);
+    // Set/move location pin
+    stationMarker.setPosition(coordinate);
+    // Update form field "location"
+    var locationEl = document.getElementById("location");
+    //console.log(locationEl);
+    locationEl.value=locationPosition;
+
+    // Adding a little animation
+    $("#location").animate({borderWidth: "4"},500, function(){
+        $("#location").animate({borderWidth: "1"},500, function(){});
+    });
+}
+
+/**
+ * Places the station marker on the coordinates given in Location input field,
+ * and centers the map around these coordinates
+ */
+function updateMarkerPosition()
+{
+    var locationEl = document.getElementById("location");
+   
+   var coordinate = locationEl.value.split(",");
+   coordinate[0] = parseFloat(coordinate[0]);
+   coordinate[1] = parseFloat(coordinate[1]);
+   //console.log(coordinate);
+   var centerPosition = ol.proj.transform(coordinate, 'EPSG:4326', map.getView().getProjection().getCode());
+   
+   stationMarker.setPosition(centerPosition);
+
+   // Setting zoom and center for the map (need to do this after creating map. so that we kan transform our
+   // center to correct map projection)
+   var view = new ol.View2D({
+           center: centerPosition,
+           zoom:10
+   });
+   map.setView(view);
+}
+
diff --git a/src/main/webapp/js/weatherStationListMap.js b/src/main/webapp/js/weatherStationListMap.js
new file mode 100644
index 0000000000000000000000000000000000000000..f3ad172fdff9c810ce06ccde714379d0ad017c34
--- /dev/null
+++ b/src/main/webapp/js/weatherStationListMap.js
@@ -0,0 +1,119 @@
+/* 
+ * Copyright (c) 2014 Bioforsk <http://www.bioforsk.no/>. 
+ * 
+ * This file is part of VIPSLogic.
+ * VIPSLogic 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.
+ * 
+ * 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
+ * GNU Affero General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Affero General Public License
+ * along with VIPSLogic.  If not, see <http://www.gnu.org/licenses/>.
+ * 
+ */
+
+/*
+ * KML layer map with weather station information
+ * @author Tor-Einar Skog <tor-einar.skog@bioforsk.no>
+ */
+
+/**
+ * 
+ * @param {ol.Coordinate} center - coordinates for the map's center (WGS84)
+ * @param {int} zoomLevel - the zoom level (1-15, 1 is world wide view, 15 is greatest zoom)
+ * @returns {void}
+ */
+function initMap(center, zoomLevel)
+{
+    // Background layer is OpenStreetMap
+    var backgroundLayer = new ol.layer.Tile({
+                    source: new ol.source.OSM({
+                        attributions: [
+                            new ol.Attribution({
+                              html: mapConstants.MAP_ATTRIBUTION
+                            })
+                          ]
+                    })
+    });
+    
+    // The weather station layer
+    var weatherStationLayer = new ol.layer.Vector({
+    source: new ol.source.KML({
+        url: "/rest/weatherstations/kml/2",
+            projection: "EPSG:3857"
+      })
+    });
+    
+    // Layer for popup
+    var popOverlay = new ol.Overlay({
+      element: document.getElementById("popover")
+    });
+    
+    // Creating the map
+    var map = new ol.Map({
+                    target: 'weatherStationListMap',
+                    layers: [backgroundLayer,weatherStationLayer],
+                    overlays: [popOverlay],
+                    renderer: 'canvas'
+    });
+    
+    var centerPosition = ol.proj.transform(center, 'EPSG:4326', map.getView().getProjection().getCode());
+
+    // Setting zoom and center for the map (need to do this after creating map. so that we kan transform our
+    // center to correct map projection)
+    var view = new ol.View2D({
+            center: centerPosition,
+            zoom:zoomLevel
+    });
+    map.setView(view);
+    
+    // Using Bootstrap's popover plugin. See http://getbootstrap.com/javascript/#popovers
+    var poiDetails = $("#popover");
+    
+    
+    
+    // Displays popup with forecasts for a given station
+    // (if there is a station where the click event is fired)
+    var displayFeatureDetails = function(pixel, coordinate) {
+          var feature = map.forEachFeatureAtPixel(pixel, function(feature,layer){
+             return feature; 
+          });
+
+          if (feature) {
+              // Position the popup, and hiding it
+              // Resetting information from (possible) former popups
+              var geometry = feature.getGeometry();
+              popOverlay.setPosition(geometry.getCoordinates());
+              poiDetails.popover('destroy');
+              // Create the popup, showing it
+            poiDetails.popover({
+                    animation: true,
+                    trigger: 'manual',
+                    html: true,
+                    placement: "auto top",
+                    title: "<a href='/weatherStation?pointOfInterestId=" + feature.getId() + "'>" + feature.get("name") + "</a>",
+                    content: feature.get("description")
+            });
+
+            poiDetails.popover('show');
+
+
+          } else {
+              poiDetails.popover('destroy');
+          }
+
+    };
+    
+
+    // On click, display forecasts in popup
+    map.on('singleclick', function(evt) {
+            var pixel = map.getEventPixel(evt.originalEvent);
+              displayFeatureDetails(pixel);
+            });
+}
+
diff --git a/src/main/webapp/js/weatherStationViewMap.js b/src/main/webapp/js/weatherStationViewMap.js
new file mode 100644
index 0000000000000000000000000000000000000000..1b0b741e0b52dc9985e5bd9a8644d7b8ae16a36f
--- /dev/null
+++ b/src/main/webapp/js/weatherStationViewMap.js
@@ -0,0 +1,119 @@
+/* 
+ * Copyright (c) 2014 Bioforsk <http://www.bioforsk.no/>. 
+ * 
+ * This file is part of VIPSLogic.
+ * VIPSLogic 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.
+ * 
+ * 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
+ * GNU Affero General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Affero General Public License
+ * along with VIPSLogic.  If not, see <http://www.gnu.org/licenses/>.
+ * 
+ */
+
+/*
+ * KML layer map with weather station information
+ * @author Tor-Einar Skog <tor-einar.skog@bioforsk.no>
+ */
+
+/**
+ * 
+ * @param {ol.Coordinate} center - coordinates for the map's center (WGS84)
+ * @param {int} zoomLevel - the zoom level (1-15, 1 is world wide view, 15 is greatest zoom)
+ * @returns {void}
+ */
+function initMap(center, zoomLevel, highlightWeatherStationId)
+{
+    // Background layer is OpenStreetMap
+    var backgroundLayer = new ol.layer.Tile({
+                    source: new ol.source.OSM({
+                        attributions: [
+                            new ol.Attribution({
+                              html: mapConstants.MAP_ATTRIBUTION
+                            })
+                          ]
+                    })
+    });
+    
+    // The weather station layer
+    var weatherStationLayer = new ol.layer.Vector({
+    source: new ol.source.KML({
+        url: "/rest/weatherstations/kml/2" + (highlightWeatherStationId !== null ? "?highlightWeatherStationId=" + highlightWeatherStationId : ""),
+            projection: "EPSG:3857"
+      })
+    });
+    
+    // Layer for popup
+    var popOverlay = new ol.Overlay({
+      element: document.getElementById("popover")
+    });
+    
+    // Creating the map
+    var map = new ol.Map({
+                    target: 'weatherStationViewMap',
+                    layers: [backgroundLayer,weatherStationLayer],
+                    overlays: [popOverlay],
+                    renderer: 'canvas'
+    });
+    
+    var centerPosition = ol.proj.transform(center, 'EPSG:4326', map.getView().getProjection().getCode());
+
+    // Setting zoom and center for the map (need to do this after creating map. so that we kan transform our
+    // center to correct map projection)
+    var view = new ol.View2D({
+            center: centerPosition,
+            zoom:zoomLevel
+    });
+    map.setView(view);
+    
+    // Using Bootstrap's popover plugin. See http://getbootstrap.com/javascript/#popovers
+    var poiDetails = $("#popover");
+    
+    
+    
+    // Displays popup with forecasts for a given station
+    // (if there is a station where the click event is fired)
+    var displayFeatureDetails = function(pixel, coordinate) {
+          var feature = map.forEachFeatureAtPixel(pixel, function(feature,layer){
+             return feature; 
+          });
+
+          if (feature) {
+              // Position the popup, and hiding it
+              // Resetting information from (possible) former popups
+              var geometry = feature.getGeometry();
+              popOverlay.setPosition(geometry.getCoordinates());
+              poiDetails.popover('destroy');
+              // Create the popup, showing it
+            poiDetails.popover({
+                    animation: true,
+                    trigger: 'manual',
+                    html: true,
+                    placement: "auto top",
+                    title: "<a href='/weatherStation?pointOfInterestId=" + feature.getId() + "'>" + feature.get("name") + "</a>",
+                    content: feature.get("description")
+            });
+
+            poiDetails.popover('show');
+
+
+          } else {
+              poiDetails.popover('destroy');
+          }
+
+    };
+    
+
+    // On click, display forecasts in popup
+    map.on('singleclick', function(evt) {
+            var pixel = map.getEventPixel(evt.originalEvent);
+              displayFeatureDetails(pixel);
+            });
+}
+
diff --git a/src/main/webapp/public/images/anemometer_mono.png b/src/main/webapp/public/images/anemometer_mono.png
new file mode 100644
index 0000000000000000000000000000000000000000..8056a3e729d8e9a3221289774d627a8286f71f55
Binary files /dev/null and b/src/main/webapp/public/images/anemometer_mono.png differ
diff --git a/src/main/webapp/templates/forecastConfigurationForm.ftl b/src/main/webapp/templates/forecastConfigurationForm.ftl
index eab8c5863801ff08e6f32b0b52f9f12a1b3d8216..82c2f10adbb08586c312d4623593fd42fafcc804 100644
--- a/src/main/webapp/templates/forecastConfigurationForm.ftl
+++ b/src/main/webapp/templates/forecastConfigurationForm.ftl
@@ -44,6 +44,7 @@
 	</script>
 </#macro>
 <#macro page_contents>
+	<p><a href="/forecastConfiguration" class="btn btn-default back" role="button">${i18nBundle.back}</a></p>
         <h1>${i18nBundle.viewForecastConfiguration}</h1>
         <div id="errorMsgEl" class="alert alert-danger" <#if !formValidation?has_content> style="display:none;"</#if>>
 		<#if formValidation?has_content>${formValidation.validationMessages?replace("\n", "<br>")}</#if>
diff --git a/src/main/webapp/templates/messageForm.ftl b/src/main/webapp/templates/messageForm.ftl
index c753179027f633ff1af9c823f52b26fdc4a3c8e5..98a1516fbbb7888985945b8d5f1cd732ee779d62 100644
--- a/src/main/webapp/templates/messageForm.ftl
+++ b/src/main/webapp/templates/messageForm.ftl
@@ -80,6 +80,7 @@
 
 </#macro>
 <#macro page_contents>
+	<p><a href="/message" class="btn btn-default back" role="button">${i18nBundle.back}</a></p>
 	<#if message.messageId?has_content>
 	<h1>${i18nBundle.editMessage}</h1>
 	<#else>
diff --git a/src/main/webapp/templates/observationForm.ftl b/src/main/webapp/templates/observationForm.ftl
index 5dcd1321148801018a7d5809a7df974d05e8d659..8b50245a5973833d6c9d9ae310e061c5e7b3ad00 100644
--- a/src/main/webapp/templates/observationForm.ftl
+++ b/src/main/webapp/templates/observationForm.ftl
@@ -27,6 +27,7 @@
 	<script type="text/javascript" src="/js/3rdparty/modernizr_custom.js"></script>
 	<script type="text/javascript" src="/js/3rdparty/moment.min.js"></script>
 	<script type="text/javascript" src="/js/3rdparty/ol.js"></script>
+	<script type="text/javascript" src="/js/constants.js"></script>
 	<script type="text/javascript" src="/js/resourcebundle.js"></script>
 	<script type="text/javascript" src="/js/validateForm.js"></script>
 	<script type="text/javascript" src="/js/observationFormMap.js"></script>
@@ -51,12 +52,13 @@
 			<#if observation.location?has_content>
 			initMap([${(observation.location.x?c)!""},${(observation.location.y?c)!""}],10,true);
 			<#else>
-			initMap([14.1,65.4],4,false);
+			initMap([${defaultMapCenter.x?c},${defaultMapCenter.y?c}],${defaultMapZoom},false);
 			</#if>
 		});
 	</script>
 </#macro>
 <#macro page_contents>
+	<p><a href="/observation" class="btn btn-default back" role="button">${i18nBundle.back}</a></p>
         <h1><#if observation.observationId?has_content>${i18nBundle.editObservation}<#else>${i18nBundle.newObservation}</#if></h1>
         <div id="errorMsgEl" class="alert alert-danger" <#if !formValidation?has_content> style="display:none;"</#if>>
 		<#if formValidation?has_content>${formValidation.validationMessages?replace("\n", "<br>")}</#if>
diff --git a/src/main/webapp/templates/organismList.ftl b/src/main/webapp/templates/organismList.ftl
index 4dde4687083c0a7dd29d7ffcab0eafcdfb8ebcc0..ecfbc28370b567f327fc4d4a199de3a2de8c46a1 100644
--- a/src/main/webapp/templates/organismList.ftl
+++ b/src/main/webapp/templates/organismList.ftl
@@ -32,6 +32,7 @@
 	</#if>
 	<#if organism.organismId?has_content>
 	<a href="/organism?action=listChildOrganisms&organismId=${organism.parentOrganismId!""}" class="btn btn-default" role="button">${i18nBundle.up}</a>
+	<a href="/organism" class="btn btn-default" role="button">${i18nBundle.toTheTop}</a>
 	</#if>
         <div class="table-responsive">
 	<table class="table table-striped">
diff --git a/src/main/webapp/templates/userForm.ftl b/src/main/webapp/templates/userForm.ftl
index cbeb2bd76113e7b80a2be79f18e6a860bd1a6942..9add085f9eb3f671fc456024ae3c026a347db5c9 100644
--- a/src/main/webapp/templates/userForm.ftl
+++ b/src/main/webapp/templates/userForm.ftl
@@ -27,6 +27,7 @@
 	</script>
 </#macro>
 <#macro page_contents>
+	<p><a href="/user" class="btn btn-default back" role="button">${i18nBundle.back}</a></p>
         <h1>${viewUser.firstName} ${viewUser.lastName}</h1>
         <div id="errorMsgEl" class="alert alert-danger" <#if !formValidation?has_content> style="display:none;"</#if>>
 		<#if formValidation?has_content>${formValidation.validationMessages?replace("\n", "<br>")}</#if>
diff --git a/src/main/webapp/templates/weatherstation.ftl b/src/main/webapp/templates/weatherstation.ftl
deleted file mode 100644
index c28749f5f0426aaec48e12c66659c203181e26c1..0000000000000000000000000000000000000000
--- a/src/main/webapp/templates/weatherstation.ftl
+++ /dev/null
@@ -1,126 +0,0 @@
-<#-- 
-  Copyright (c) 2014 Bioforsk <http://www.bioforsk.no/>. 
-
-  This file is part of VIPSLogic.
-  VIPSLogic 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.
- 
-  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
-  GNU Affero General Public License for more details.
- 
-  You should have received a copy of the GNU Affero General Public License
-  along with VIPSLogic.  If not, see <http://www.gnu.org/licenses/>.
---><#include "master.ftl">
-<#macro page_head>
-        <title>${weatherStation.name}</title>
-        
-</#macro>
-
-<#macro custom_js>
-<script src="http://code.jquery.com/ui/1.10.3/jquery-ui.min.js"></script>
-<link href="http://code.jquery.com/ui/1.10.3/themes/redmond/jquery-ui.css" rel="stylesheet" />
-<script type="text/javascript" src="/js/3rdparty/modernizr_custom.js"></script>
-<script type="text/javascript">
-	// Make sure that there is a date picker present for HTML5 
-	// date input fields
-	if (!Modernizr.inputtypes.date) {
-	    $('input[type=date]').datepicker({ dateFormat: 'yy-mm-dd' });
-	}
-</script>
-</#macro>
-
-<#macro page_contents>
-        <h1>${weatherStation.name}</h1>
-        <h2>${i18nBundle.position}</h2>
-	<ul>
-		<li>${i18nBundle.latitude}: ${weatherStation.latitude!i18nBundle.missing}</li>
-		<li>${i18nBundle.longitude}: ${weatherStation.longitude!i18nBundle.missing}</li>
-		<li>${i18nBundle.altitude}: ${weatherStation.altitude!i18nBundle.missing}</li>
-	</ul>
-	<iframe width="300" height="200" frameborder="0" scrolling="no" marginheight="0" marginwidth="0" 
-	src="http://www.openstreetmap.org/export/embed.html?bbox=${(weatherStation.longitude-0.037722588)?c}%2C${(weatherStation.latitude-0.016374048)?c}%2C${(weatherStation.longitude+0.037722588)?c}%2C${(weatherStation.latitude+0.016374048)?c}&amp;layer=mapnik&amp;marker=${weatherStation.latitude?c}%2C${weatherStation.longitude?c}" 
-	style="border: 1px solid black"></iframe><br/>
-	<a href="http://www.openstreetmap.org/?mlat=${weatherStation.latitude?c}&amp;mlon=${weatherStation.longitude?c}#map=14/${weatherStation.latitude?c}/${weatherStation.longitude?c}&amp;layers=N" target="new">${i18nBundle.viewFullScreen}</a>
-	<h2>${i18nBundle.dataSource}</h2>
-	<#if weatherStation.weatherStationDataSourceId??>
-	<ul>
-		<li>${i18nBundle.name}: ${weatherStation.weatherStationDataSourceId.name}</li>
-		<li>URI: <a href="${weatherStation.weatherStationDataSourceId.uri}" target="new">${weatherStation.weatherStationDataSourceId.uri}</a></li>
-		<li>${i18nBundle.weatherStationRemoteId}: ${weatherStation.weatherStationRemoteId!i18nBundle.weatherStationRemoteIdMissing}</li>
-	</ul>
-	<h3>${i18nBundle.test} ${i18nBundle.dataSource?lower_case}</h3>
-	<form action="${weatherStation.dataFetchUri}" method="POST" target="new" class="form-horizontal" role="form">
-		<div class="form-group">
-			<label class="col-lg-4 control-label" for="elementMeasurementTypes[]">${i18nBundle.elementMeasurementTypes}</label>
-			<div class="col-lg-8">
-				<select name="elementMeasurementTypes[]" multiple="multiple" cols="10" size="5">
-					<option value="TM">TM</option>
-					<option value="RR">RR</option>
-					<option value="BT">BT</option>
-					<option value="Q0">Q0</option>
-					<option value="UM">UM</option>
-				</select>
-			</div>
-		</div>
-		<div class="form-group">
-			<label class="col-lg-4 control-label" for="logInterval">${i18nBundle.logInterval}</label>
-			<div class="col-lg-8">
-				<select name="logInterval">
-					<option value="1h" selected="selected">${i18nBundle.logInterval1h}</option>
-					<option value="1d">${i18nBundle.logInterval1d}</option>
-				</select>
-			</div>
-		</div>
-		<div class="form-group">
-			<label class="col-lg-4 control-label" for="startDate">${i18nBundle.startTime}</label>
-			<div class="col-lg-8">
-				<input type="date" name="startDate" size="15"/>
-				<select name="startTime">
-				<#list 0..23 as hour>
-					<option value="${hour?string("00")}"<#if hour == 0> selected="selected"</#if>>${hour?string("00")}</option>
-				</#list>
-				</select>
-			</div>
-		</div>
-		<div class="form-group">
-			<label class="col-lg-4 control-label" for="endDate">${i18nBundle.endTime}</label>
-			<div class="col-lg-8">
-				<input type="date" name="endDate" size="15"/>
-				<select name="endTime">
-				<#list 0..23 as hour>
-					<option value="${hour?string("00")}"<#if hour == 0> selected="selected"</#if>>${hour?string("00")}</option>
-				</#list>
-				</select>
-			</div>
-		</div>
-		<div class="form-group">
-			<label class="col-lg-4 control-label" for="endDate">${i18nBundle.timeZone}</label>
-			<div class="col-lg-8">
-				<select name="timeZone">
-				<!--
-				<#list -12..12 as offset>
-					<option value="<#if (offset >= 0)>+</#if>${offset?string("00")}"<#if offset == 0> selected="selected"</#if>><#if (offset >= 0)>+</#if>${offset?string("00")}</option>
-				</#list>
-				-->
-				<#list availableTimeZones as timeZoneId>
-				<option value="${timeZoneId}"<#if timeZoneId == weatherStation.timeZone> selected="selected"</#if>>${timeZoneId}</option>
-				</#list>
-				</select>
-			</div>
-		</div>
-		<div class="form-group">
-			<div class="col-lg-offset-4 col-lg-8">
-				<button type="submit" class="btn btn-default">Test</button>
-			</div>
-		</div>
-	
-	</form>
-	<#else>
-	<p>${i18nBundle.dataSourceMissing}</p>
-	</#if>
-</#macro>
-<@page_html/>
diff --git a/src/main/webapp/templates/weatherstationForm.ftl b/src/main/webapp/templates/weatherstationForm.ftl
new file mode 100644
index 0000000000000000000000000000000000000000..e3a4ee7120e7f4724fc62d182b32ead845a5af1c
--- /dev/null
+++ b/src/main/webapp/templates/weatherstationForm.ftl
@@ -0,0 +1,143 @@
+<#-- 
+  Copyright (c) 2014 Bioforsk <http://www.bioforsk.no/>. 
+
+  This file is part of VIPSLogic.
+  VIPSLogic 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.
+ 
+  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
+  GNU Affero General Public License for more details.
+ 
+  You should have received a copy of the GNU Affero General Public License
+  along with VIPSLogic.  If not, see <http://www.gnu.org/licenses/>.
+--><#include "master.ftl">
+<#macro page_head>
+        <title><#if weatherStation.pointOfInterestId?has_content>${i18nBundle.editWeatherStation}<#else>${i18nBundle.newWeatherStation}</#if></title>
+</#macro>
+<#macro custom_css>
+	<link rel="stylesheet" type="text/css" href="/css/3rdparty/ol.css"/ >
+</#macro>
+<#macro custom_js>
+	<script type="text/javascript" src="/js/3rdparty/ol.js"></script>
+	<script type="text/javascript" src="/js/constants.js"></script>
+	<script type="text/javascript" src="/js/resourcebundle.js"></script>
+	<script type="text/javascript" src="/js/validateForm.js"></script>
+	<script type="text/javascript" src="/js/weatherStationFormMap.js"></script>
+	<script type="text/javascript">
+		$(document).ready(function() {
+			// Load main form definition (for validation)
+			loadFormDefinition("weatherStationForm");
+			
+			// Initialize the map
+			// If weather station already registered, center on location
+			// Otherwise, center and zoom to organizations's default
+			<#if weatherStation.longitude?has_content && weatherStation.latitude?has_content>
+			initMap([${(weatherStation.longitude?c)!""},${(weatherStation.latitude?c)!""}],10,${weatherStation.pointOfInterestId!"null"});
+			<#else>
+			initMap([${defaultMapCenter.x?c},${defaultMapCenter.y?c}],${defaultMapZoom},${weatherStation.pointOfInterestId!"null"});
+			</#if>
+		});
+	</script>
+</#macro>
+<#macro page_contents>
+	<p><a href="/weatherStation" class="btn btn-default back" role="button">${i18nBundle.back}</a></p>
+        <h1><#if weatherStation.pointOfInterestId?has_content>${i18nBundle.editWeatherStation}<#else>${i18nBundle.newWeatherStation}</#if></h1>
+        <div id="errorMsgEl" class="alert alert-danger" <#if !formValidation?has_content> style="display:none;"</#if>>
+		<#if formValidation?has_content>${formValidation.validationMessages?replace("\n", "<br>")}</#if>
+	</div>
+	<#if messageKey?has_content>
+		<div class="alert alert-success">${i18nBundle(messageKey)}</div>
+	</#if>
+	<div class="row">
+		<div class="col-md-6">
+			<#assign formId = "weatherStationForm">
+			<form id="${formId}" role="form" action="/weatherStation?action=weatherStationFormSubmit" method="POST" onsubmit="return validateForm(this);">
+			  <input type="hidden" name="pointOfInterestId" value="${weatherStation.pointOfInterestId!"-1"}"/>
+			  <div class="form-group">
+			    <label for="name">${i18nBundle.name}</label>
+			    <input type="text" class="form-control" name="name" placeholder="${i18nBundle.name}" value="${(weatherStation.name)!""}" onblur="validateField(this);"/>
+			    <span class="help-block" id="${formId}_name_validation"></span>
+			  </div>
+			  <div class="form-group">
+			    <label for="location">${i18nBundle.location} (<a href="http://en.wikipedia.org/wiki/World_Geodetic_System#A_new_World_Geodetic_System:_WGS_84" target="new">WGS84</a>: ${i18nBundle.longitude},${i18nBundle.latitude})</label>
+			    <input type="text" class="form-control" id="location" name="location" placeholder="${i18nBundle.location}" value="${(weatherStation.longitude?c)!""},${(weatherStation.latitude?c)!""}" onblur="validateField(this);" onchange="if(validateField(this)){updateMarkerPosition();}" />
+			    <span class="help-block" id="${formId}_location_validation"></span>
+			  </div>
+			  <div class="form-group">
+			    <label for="altitude">${i18nBundle.altitude} (${i18nBundle.meter})</label>
+			    <input type="number" class="form-control" name="altitude" placeholder="${i18nBundle.altitude}" value="${(weatherStation.altitude?c)!""}" onblur="validateField(this);"/>
+			    <span class="help-block" id="${formId}_altitude_validation"></span>
+			  </div>
+			  <div class="form-group">
+			    <label for="weatherStationDataSourceId">${i18nBundle.dataSource}</label>
+			    <select class="form-control" name="weatherStationDataSourceId" onblur="validateField(this);">
+			    	<option value="-1">${i18nBundle.pleaseSelect} ${i18nBundle.dataSource?lower_case}
+				<#list dataSources as dataSource>
+					<option value="${dataSource.weatherStationDataSourceId}"
+						<#if weatherStation.weatherStationDataSourceId?has_content && weatherStation.weatherStationDataSourceId.weatherStationDataSourceId == dataSource.weatherStationDataSourceId>selected="selected"</#if>
+					>${dataSource.name}</option>
+				</#list>
+			     </select>
+			     <span class="help-block" id="${formId}_weatherStationDataSourceId_validation"></span>
+			  </div>
+			  <div class="form-group">
+			    <label for="weatherStationRemoteId">${i18nBundle.weatherStationRemoteId}</label>
+			    <input type="text" class="form-control" name="weatherStationRemoteId" placeholder="${i18nBundle.weatherStationRemoteId}" value="${(weatherStation.weatherStationRemoteId)!""}" onblur="validateField(this);"/>
+			    <span class="help-block" id="${formId}_weatherStationRemoteId_validation"></span>
+			  </div>
+			   <div class="form-group">
+			    <label for="timeZone">${i18nBundle.timeZone}</label>
+			    <select class="form-control" name="timeZone" onblur="validateField(this);">
+				<#list availableTimeZones as timeZoneId>
+					<option value="${timeZoneId}"<#if 
+								(weatherStation.timeZone?has_content && timeZoneId == weatherStation.timeZone)
+								|| (!weatherStation.timeZone?has_content && timeZoneId == defaultTimeZoneId)
+								> selected="selected"</#if>>${timeZoneId}</option>
+				</#list>
+			     </select>
+			     <span class="help-block" id="${formId}_timeZone_validation"></span>
+			  </div>
+			  <div class="form-group">
+			    <label for="countryCode">${i18nBundle.country}</label>
+			    <select class="form-control" name="countryCode" onblur="validateField(this);">
+				<#list availableCountries as country>
+					<option value="${country.countryCode}"<#if 
+								(weatherStation.countryCode?has_content && country.countryCode == weatherStation.countryCode.countryCode)
+								|| (!weatherStation.countryCode?has_content && country.countryCode == defaultCountryCode)
+								> selected="selected"</#if>>${country.getCountryName(currentLocale)}</option>
+				</#list>
+			     </select>
+			     <span class="help-block" id="${formId}_countryCode_validation"></span>
+			  </div>
+			  <#if user.isSuperUser()>
+			  <div class="form-group">
+			    <label for="userId">${i18nBundle.vipsLogicUserId}</label>
+			    <select class="form-control" name="userId" onblur="validateField(this);">
+			    	<option value="-1">${i18nBundle.pleaseSelect} ${i18nBundle.vipsLogicUserId?lower_case}</option>
+				<#list users as user>
+					<option value="${user.userId}"<#if weatherStation.userId?has_content && user.userId == weatherStation.userId.userId
+								> selected="selected"</#if>>${user.lastName}, ${user.firstName} (${user.organizationId.organizationName})</option>
+				</#list>
+			     </select>
+			     <span class="help-block" id="${formId}_userId_validation"></span>
+			  </div>
+			  </#if>
+			  <button type="submit" class="btn btn-default">${i18nBundle.submit}</button>
+			  <#if weatherStation.pointOfInterestId?has_content>
+			  <!--button type="button" class="btn btn-danger" onclick="if(confirm('${i18nBundle.confirmDelete}')){window.location.href='/weatherStation?action=deleteWeatherStation&pointOfInterestId=${weatherStation.pointOfInterestId}';}">${i18nBundle.delete}</button-->
+			  </#if>
+			</form>
+		</div>
+		<div class="col-md-6">
+			<div id="weatherStationFormMap" class="map">
+				<div id="popover"></div>
+			</div>
+		</div>
+	</div>
+	<div style="display: none;"><div id="stationMarker" title="Marker"><img src="/public/images/anemometer_mono.png"/></div></div>
+</#macro>
+<@page_html/>
diff --git a/src/main/webapp/templates/weatherstationList.ftl b/src/main/webapp/templates/weatherstationList.ftl
new file mode 100644
index 0000000000000000000000000000000000000000..9c01debb6045fd33f492a06a9ac260bc8c97b7ce
--- /dev/null
+++ b/src/main/webapp/templates/weatherstationList.ftl
@@ -0,0 +1,79 @@
+<#-- 
+  Copyright (c) 2014 Bioforsk <http://www.bioforsk.no/>. 
+
+  This file is part of VIPSLogic.
+  VIPSLogic 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.
+ 
+  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
+  GNU Affero General Public License for more details.
+ 
+  You should have received a copy of the GNU Affero General Public License
+  along with VIPSLogic.  If not, see <http://www.gnu.org/licenses/>.
+--><#include "master.ftl">
+<#macro page_head>
+        <title>${i18nBundle.weatherStations}</title>
+</#macro>
+<#macro custom_css>
+	<link rel="stylesheet" type="text/css" href="/css/3rdparty/ol.css"/ >
+</#macro>
+<#macro custom_js>
+	<script type="text/javascript" src="/js/3rdparty/ol.js"></script>
+	<script type="text/javascript" src="/js/constants.js"></script>
+	<script type="text/javascript" src="/js/weatherStationListMap.js"></script>
+	<script type="text/javascript">
+		$(document).ready(function() {
+			initMap([${defaultMapCenter.x?c},${defaultMapCenter.y?c}],${defaultMapZoom});
+		});
+	</script>
+</#macro>
+<#macro page_contents>
+<h1>${i18nBundle.weatherStations}</h1>
+<p>
+	<a href="/weatherStation?action=newWeatherStationForm" class="btn btn-default" role="button">${i18nBundle.addNew}</a>
+</p>
+<div class="row">
+	<div class="col-md-8">
+		<div id="weatherStationListMap" class="map">
+			<div id="popover"></div>
+		</div>
+	</div>
+	<div class="col-md-4">
+		 <div class="table-responsive">
+			 <table class="table table-striped">
+				<thead>
+					<th>${i18nBundle.name}</th>
+					<#if user.isOrganizationAdmin() || user.isSuperUser() >
+					<th></th>
+					</#if>
+					<th>${i18nBundle.dataSourceName}</th>
+				</thead>
+				<tbody>
+				<#list weatherStations?sort_by("name") as weatherStation>
+				    <tr>
+					<td>
+						<a href="weatherStation?pointOfInterestId=${weatherStation.pointOfInterestId}">${weatherStation.name!""}</a>
+					</td>
+					<#if user.isOrganizationAdmin() || user.isSuperUser() >
+					<td>
+						<a href="/weatherStation?action=editWeatherStationForm&pointOfInterestId=${weatherStation.pointOfInterestId}" class="btn btn-default" role="button">${i18nBundle.edit}</a>
+					</td>
+					</#if>
+					<td>
+					<#if weatherStation.weatherStationDataSourceId?has_content>
+						<a href="${weatherStation.weatherStationDataSourceId.uri}">${weatherStation.weatherStationDataSourceId.name}</a>
+					</#if>
+					</td>
+				    </tr>
+				</#list>
+				</tbody>
+			</table>
+		</div>
+	</div>
+</div>
+</#macro>
+<@page_html/>
diff --git a/src/main/webapp/templates/weatherstationView.ftl b/src/main/webapp/templates/weatherstationView.ftl
new file mode 100644
index 0000000000000000000000000000000000000000..028fb7f33f20d70578fb103a446ead5685ecfd6f
--- /dev/null
+++ b/src/main/webapp/templates/weatherstationView.ftl
@@ -0,0 +1,165 @@
+<#-- 
+  Copyright (c) 2014 Bioforsk <http://www.bioforsk.no/>. 
+
+  This file is part of VIPSLogic.
+  VIPSLogic 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.
+ 
+  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
+  GNU Affero General Public License for more details.
+ 
+  You should have received a copy of the GNU Affero General Public License
+  along with VIPSLogic.  If not, see <http://www.gnu.org/licenses/>.
+--><#include "master.ftl">
+<#macro page_head>
+        <title>${weatherStation.name}</title>
+        
+</#macro>
+<#macro custom_css>
+	<link rel="stylesheet" type="text/css" href="/css/3rdparty/ol.css"/ >
+</#macro>
+<#macro custom_js>
+<script type="text/javascript" src="/js/3rdparty/ol.js"></script>
+<script type="text/javascript" src="/js/constants.js"></script>
+<script src="http://code.jquery.com/ui/1.10.3/jquery-ui.min.js"></script>
+<link href="http://code.jquery.com/ui/1.10.3/themes/redmond/jquery-ui.css" rel="stylesheet" />
+<script type="text/javascript" src="/js/3rdparty/modernizr_custom.js"></script>
+<script type="text/javascript" src="/js/weatherStationViewMap.js"></script>
+<script type="text/javascript">
+	$(document).ready(function() {
+		
+		// Initialize the map
+		// If weather station already registered, center on location
+		// Otherwise, center and zoom to organizations's default
+		<#if weatherStation.longitude?has_content && weatherStation.latitude?has_content>
+		initMap([${(weatherStation.longitude?c)!""},${(weatherStation.latitude?c)!""}],10,${weatherStation.pointOfInterestId!"null"});
+		<#else>
+		initMap([${defaultMapCenter.x?c},${defaultMapCenter.y?c}],${defaultMapZoom},${weatherStation.pointOfInterestId!"null"});
+		</#if>
+	});
+	// Make sure that there is a date picker present for HTML5 
+	// date input fields
+	if (!Modernizr.inputtypes.date) {
+	    $('input[type=date]').datepicker({ dateFormat: 'yy-mm-dd' });
+	}
+</script>
+</#macro>
+
+<#macro page_contents>
+	<p><a href="/weatherStation" class="btn btn-default back" role="button">${i18nBundle.back}</a></p>
+        <h1>${weatherStation.name}</h1>
+        <div class="row">
+		<div class="col-md-6">
+			<dl class="dl-horizontal">
+				<dt>${i18nBundle.location}</dt>
+				<dd>${(weatherStation.longitude?c)!""},${(weatherStation.latitude?c)!""}</dd>
+				
+				<dt>${i18nBundle.altitude} (${i18nBundle.meter})</dt>
+				<dd>${(weatherStation.altitude?c)!""}</dd>
+				
+				<dt>${i18nBundle.dataSource}</dt>
+				<dd>
+					<#if weatherStation.weatherStationDataSourceId?has_content> 
+						<a href="${weatherStation.weatherStationDataSourceId.uri}">${weatherStation.weatherStationDataSourceId.name}</a>
+					<#else>
+						${i18nBundle.dataSourceMissing}
+					</#if>
+				</dd>
+				
+				<dt>${i18nBundle.weatherStationRemoteId}</dt>
+				<dd>${(weatherStation.weatherStationRemoteId)!i18nBundle.missing}</dd>
+				
+				<dt>${i18nBundle.timeZone}</dt>
+				<dd>${(weatherStation.timeZone)!""}</dd>
+				
+				<dt>${i18nBundle.country}</dt>
+				<dd>${weatherStation.countryCode.getCountryName(currentLocale)}</dd>
+				
+				<dt>${i18nBundle.vipsLogicUserId}</dt>
+				<dd>${user.lastName}, ${user.firstName} (${user.organizationId.organizationName})</dd>
+				
+			</dl>
+			<#if weatherStation.weatherStationDataSourceId?has_content>
+			<h3>${i18nBundle.test} ${i18nBundle.dataSource?lower_case}</h3>
+			<form action="${weatherStation.dataFetchUri}" method="POST" target="new" class="form-horizontal" role="form">
+				<div class="form-group">
+					<label class="col-lg-4 control-label" for="elementMeasurementTypes[]">${i18nBundle.elementMeasurementTypes}</label>
+					<div class="col-lg-8">
+						<select name="elementMeasurementTypes[]" multiple="multiple" cols="10" size="5">
+							<option value="TM">TM</option>
+							<option value="RR">RR</option>
+							<option value="BT">BT</option>
+							<option value="Q0">Q0</option>
+							<option value="UM">UM</option>
+						</select>
+					</div>
+				</div>
+				<div class="form-group">
+					<label class="col-lg-4 control-label" for="logInterval">${i18nBundle.logInterval}</label>
+					<div class="col-lg-8">
+						<select name="logInterval">
+							<option value="1h" selected="selected">${i18nBundle.logInterval1h}</option>
+							<option value="1d">${i18nBundle.logInterval1d}</option>
+						</select>
+					</div>
+				</div>
+				<div class="form-group">
+					<label class="col-lg-4 control-label" for="startDate">${i18nBundle.startTime}</label>
+					<div class="col-lg-8">
+						<input type="date" name="startDate" size="15"/>
+						<select name="startTime">
+						<#list 0..23 as hour>
+							<option value="${hour?string("00")}"<#if hour == 0> selected="selected"</#if>>${hour?string("00")}</option>
+						</#list>
+						</select>
+					</div>
+				</div>
+				<div class="form-group">
+					<label class="col-lg-4 control-label" for="endDate">${i18nBundle.endTime}</label>
+					<div class="col-lg-8">
+						<input type="date" name="endDate" size="15"/>
+						<select name="endTime">
+						<#list 0..23 as hour>
+							<option value="${hour?string("00")}"<#if hour == 0> selected="selected"</#if>>${hour?string("00")}</option>
+						</#list>
+						</select>
+					</div>
+				</div>
+				<div class="form-group">
+					<label class="col-lg-4 control-label" for="endDate">${i18nBundle.timeZone}</label>
+					<div class="col-lg-8">
+						<select name="timeZone">
+						<!--
+						<#list -12..12 as offset>
+							<option value="<#if (offset >= 0)>+</#if>${offset?string("00")}"<#if offset == 0> selected="selected"</#if>><#if (offset >= 0)>+</#if>${offset?string("00")}</option>
+						</#list>
+						-->
+						<#list availableTimeZones as timeZoneId>
+						<option value="${timeZoneId}"<#if timeZoneId == weatherStation.timeZone> selected="selected"</#if>>${timeZoneId}</option>
+						</#list>
+						</select>
+					</div>
+				</div>
+				<div class="form-group">
+					<div class="col-lg-offset-4 col-lg-8">
+						<button type="submit" class="btn btn-default">Test</button>
+					</div>
+				</div>
+			
+			</form>
+			</#if>
+		</div>
+		<div class="col-md-6">
+			<div id="weatherStationViewMap" class="map">
+			</div>
+		</div>
+	</div>
+        
+	
+	
+</#macro>
+<@page_html/>
diff --git a/src/main/webapp/templates/weatherstationform.ftl b/src/main/webapp/templates/weatherstationform.ftl
deleted file mode 100644
index 51884a95bef7ac6c436719e5ca795db5318338bd..0000000000000000000000000000000000000000
--- a/src/main/webapp/templates/weatherstationform.ftl
+++ /dev/null
@@ -1,27 +0,0 @@
-<#-- 
-  Copyright (c) 2014 Bioforsk <http://www.bioforsk.no/>. 
-
-  This file is part of VIPSLogic.
-  VIPSLogic 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.
- 
-  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
-  GNU Affero General Public License for more details.
- 
-  You should have received a copy of the GNU Affero General Public License
-  along with VIPSLogic.  If not, see <http://www.gnu.org/licenses/>.
---><#include "master.ftl">
-<#macro page_head>
-        <title>${i18nBundle.edit} ${weatherStation.name}</title>
-        
-</#macro>
-
-<#macro page_contents>
-        <h1>${i18nBundle.edit} ${weatherStation.name}</h1>
-        
-</#macro>
-<@page_html/>
diff --git a/src/main/webapp/templates/weatherstationlist.ftl b/src/main/webapp/templates/weatherstationlist.ftl
deleted file mode 100644
index bd466d3a95550c0920b4e1327f8ccef766d6cd0d..0000000000000000000000000000000000000000
--- a/src/main/webapp/templates/weatherstationlist.ftl
+++ /dev/null
@@ -1,29 +0,0 @@
-<#-- 
-  Copyright (c) 2014 Bioforsk <http://www.bioforsk.no/>. 
-
-  This file is part of VIPSLogic.
-  VIPSLogic 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.
- 
-  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
-  GNU Affero General Public License for more details.
- 
-  You should have received a copy of the GNU Affero General Public License
-  along with VIPSLogic.  If not, see <http://www.gnu.org/licenses/>.
---><#include "master.ftl">
-<#macro page_head>
-        <title>${i18nBundle.weatherStations}</title>
-</#macro>
-<#macro page_contents>
-        <h1>${i18nBundle.weatherStations}</h1>
-	<ul>
-	<#list weatherStations?sort_by("name") as weatherStation>
-	    <li><a href="weatherStation?pointOfInterestId=${weatherStation.pointOfInterestId}">${weatherStation.name}</a><#if weatherStation.weatherStationDataSourceId??>, ${weatherStation.weatherStationDataSourceId.uri!}<#else></#if></li>
-	</#list>
-        </ul>
-</#macro>
-<@page_html/>