package org.oskari.log;

import fi.nls.oskari.domain.User;
import fi.nls.oskari.log.LogFactory;
import fi.nls.oskari.log.Logger;
import fi.nls.oskari.util.JSONHelper;
import org.json.JSONObject;

import java.util.LinkedHashMap;
import java.util.Map;

// AuditLog.user("127.0.0.1", "me@my.com")
//  .withParam("id", 123)
//  .deleted(AuditLog.ResourceType.MYPLACES)
public class AuditLog {

    public enum ResourceType {
        GENERIC,
        MAPLAYER,
        MAPLAYER_GROUP,
        MAPLAYER_PERMISSION,
        DATAPROVIDER,
        MYPLACES,
        MYPLACES_LAYER,
        USERLAYER,
        ANALYSIS,
        SYSTEM_VIEW,
        USER_VIEW,
        EMBEDDED_VIEW,
        TERMS_OF_USE,
        SEARCH,
        USER,
        STATISTICAL_DATA
    }

    enum Op {
        ERROR,
        INVALID_PARAMS,
        UNAUTHORIZED,
        ADDED,
        UPDATED,
        DELETED
    }

    enum Level {
        INFO,
        WARN
    }

    private static final Logger LOGGER = LogFactory.getLogger("AUDIT");
    private final String ip;
    private final String email;
    private String message;
    private Map<String, Object> params;

    private AuditLog(String remote, String email) {
        ip = remote;
        this.email = email;
    }

    public static AuditLog guest(String remote) {
        return user(remote, "");
    }

    public static AuditLog user(String remote, User user) {
        String email = null;
        if (!user.isGuest()) {
            email = user.getEmail();
        }
        return user(remote, email);
    }

    public static AuditLog user(String remote, String email) {
        return new AuditLog(remote, email);
    }

    public AuditLog withParams(Map<String, String[]> params) {
        if (params == null) {
            return this;
        }
        params.entrySet().stream()
                .forEach(p -> withParam(p.getKey(), p.getValue()));
        return this;
    }

    public AuditLog withParam(String key, Object value) {
        if (params == null) {
            params = new LinkedHashMap();
        }
        params.put(key, value);
        return this;
    }

    public AuditLog withMsg(String msg) {
        message = msg;
        return this;
    }

    /*
     * Actual logging. Probably write out JSON so it can be parsed easily
     */
    public void wasDenied(ResourceType type) {
        wasDenied(type.name());
    }
    public void wasDenied(String msg) {
        send(Level.WARN, getJSON(msg, Op.UNAUTHORIZED));
    }

    public void errored(ResourceType type) {
        errored(type.name());
    }

    public void errored(String msg) {
        send(Level.WARN, getJSON(msg, Op.ERROR));
    }

    public void usedInvalidParams(ResourceType type) {
        usedInvalidParams(type.name());
    }
    public void usedInvalidParams(String msg) {
        send(Level.INFO, getJSON(msg, Op.INVALID_PARAMS));
    }

    public void added(ResourceType type) {
        added(type.name());
    }

    public void added(String msg) {
        send(Level.INFO, getJSON(msg, Op.ADDED));
    }

    public void updated(ResourceType type) {
        updated(type.name());
    }

    public void updated(String msg) {
        send(Level.INFO, getJSON(msg, Op.UPDATED));
    }

    public void deleted(ResourceType type) {
        deleted(type.name());
    }

    public void deleted(String msg) {
        send(Level.INFO, getJSON(msg, Op.DELETED));
    }

    private String getJSON(String resource, Op operation) {
        JSONObject json = JSONHelper.createJSONObject("ip", ip);
        if (email != null && !email.isEmpty()) {
            JSONHelper.putValue(json, "user", email);
        }
        JSONHelper.putValue(json, "resource", resource);
        JSONHelper.putValue(json, "op", operation.name());
        if (params != null) {
            JSONHelper.putValue(json, "params", params);
        }
        if (message != null) {
            JSONHelper.putValue(json, "msg", message);
        }
        return json.toString();
    }

    private void send(Level lvl, String json) {
        switch (lvl) {
            case INFO:
                LOGGER.info(json);
                break;
            case WARN:
                LOGGER.warn(json);
                break;
            default:
                LOGGER.debug(json);
        }
    }
}

@@ -156,24 +156,64 @@
 JSONHelper;%0A
+import fi.nls.oskari.util.PropertyUtil;%0A
 import org.j
@@ -1097,21 +1097,20 @@
  String 
-email
+user
 ;%0A    pr
@@ -1172,16 +1172,148 @@
 arams;%0A%0A
+    private enum Ident %7B%0A        UNSET,%0A        EMAIL,%0A        NICK%0A    %7D%0A    private static Ident userIdentityType = Ident.UNSET;%0A%0A
     priv
@@ -1339,37 +1339,36 @@
  remote, String 
-email
+user
 ) %7B%0A        ip =
@@ -1393,21 +1393,19 @@
 his.
-email = email
+user = user
 ;%0A  
@@ -1571,140 +1571,49 @@
     
-String email = null;%0A        if (!user.isGuest()) %7B%0A            email = user.getEmail();%0A        %7D%0A        return user(remote, email
+return user(remote, getUserIdentity(user)
 );%0A 
@@ -1672,21 +1672,20 @@
  String 
-email
+user
 ) %7B%0A    
@@ -1716,21 +1716,20 @@
 remote, 
-email
+user
 );%0A    %7D
@@ -3473,32 +3473,638 @@
 LETED));%0A    %7D%0A%0A
+    private static String getUserIdentity(User user) %7B%0A        // guest always null%0A        if (user.isGuest()) %7B%0A            return null;%0A        %7D%0A        // setup for future calls%0A        if (Ident.UNSET == userIdentityType) %7B%0A            if (PropertyUtil.getOptional(%22audit.user.email%22, false)) %7B%0A                userIdentityType = Ident.EMAIL;%0A            %7D else %7B%0A                userIdentityType = Ident.NICK;%0A            %7D%0A        %7D%0A        // email or username%0A        if(Ident.EMAIL == userIdentityType) %7B%0A            return user.getEmail();%0A        %7D%0A        return user.getScreenname();%0A    %7D%0A%0A
     private Stri
@@ -4224,21 +4224,20 @@
     if (
-email
+user
  != null
@@ -4241,21 +4241,20 @@
 ull && !
-email
+user
 .isEmpty
@@ -4305,21 +4305,20 @@
 %22user%22, 
-email
+user
 );%0A     

Use username by default, allow email for user ident