/**
 *  Accounting
 *  Copyright 24.05.2016 by Michael Peter Christen, @0rb1t3r
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License as published by the Free Software Foundation; either
 *  version 2.1 of the License, or (at your option) any later version.
 *  
 *  This library 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
 *  Lesser General Public License for more details.
 *  
 *  You should have received a copy of the GNU Lesser General Public License
 *  along with this program in the file lgpl21.txt
 *  If not, see <http://www.gnu.org/licenses/>.
 */

package org.loklak.server;

import java.util.TreeMap;

import org.json.JSONObject;

/**
 * Accounting asks: what has the user done. This class holds user activities.
 */
public class Accounting extends JSONObject {

    private static final TreeMap<Long, String> EMPTY_MAP = new TreeMap<>();
    private static final long ONE_HOUR_MILLIS = 1000 * 60 * 60;

    private static long uc = 0;
    
    public Accounting() {
        super();
    }
    
    /**
     * cleanup deletes all old entries and frees up the memory.
     * some outside process muss call this frequently
     * @return self
     */
    public Accounting cleanup() {
        if (!this.has("requests")) return this;
        JSONObject requests = this.getJSONObject("requests");
        for (String path: requests.keySet()) {
            TreeMap<Long, String> events = (TreeMap<Long, String>) requests.get(path);
            // shrink that map and delete everything which is older than now minus one hour
            long pivotTime = System.currentTimeMillis() - ONE_HOUR_MILLIS;
            while (events.size() > 0 && events.firstKey().longValue() < pivotTime) events.remove(events.firstKey());
            if (events.size() == 0) requests.remove(path);
        }
        return this;
    }
    
    public synchronized Accounting addRequest(String path, String query) {
        if (!this.has("requests")) this.put("requests", new JSONObject());
        JSONObject requests = this.getJSONObject("requests");
        if (!requests.has(path)) requests.put(path, new TreeMap<Long, String>());
        TreeMap<Long, String> events = (TreeMap<Long, String>) requests.get(path);
        events.put(System.currentTimeMillis() + ((uc ++) % 1000), query); // the counter is used to distinguish very fast concurrent requests
        return this;
    }
    
    public synchronized TreeMap<Long, String> getRequests(String path) {
        if (!this.has("requests")) return EMPTY_MAP;
        JSONObject requests = this.getJSONObject("requests");
        if (!requests.has(path)) return EMPTY_MAP;
        TreeMap<Long, String> events = (TreeMap<Long, String>) requests.get(path);
        return events;
    }
    
}

@@ -1034,57 +1034,76 @@
 nal 
-TreeMap%3CLong, String%3E EMPTY_MAP = new TreeMap%3C
+JSONObject EMPTY_MAP = new JSONObject(new TreeMap%3CString, String
 %3E()
+)
 ;%0A  
@@ -1617,62 +1617,27 @@
     
-TreeMap%3CLong, String%3E events = (TreeMap%3CLong, String%3E)
+JSONObject events =
  req
@@ -1637,32 +1637,42 @@
 s = requests.get
+JSONObject
 (path);%0A        
@@ -1856,20 +1856,22 @@
 (events.
-size
+length
 () %3E 0 &
@@ -1876,36 +1876,43 @@
  && 
+Long.parseLong(
 events.
-firstK
+k
 ey
+s
 ().
-longValue(
+next()
 ) %3C 
@@ -1947,16 +1947,19 @@
 nts.
-firstKey
+keys().next
 ());
@@ -1986,12 +1986,14 @@
 nts.
-size
+length
 () =
@@ -2330,34 +2330,36 @@
 th, new TreeMap%3C
-Lo
+Stri
 ng, String%3E());%0A
@@ -2370,62 +2370,27 @@
     
-TreeMap%3CLong, String%3E events = (TreeMap%3CLong, String%3E)
+JSONObject events =
  req
@@ -2390,32 +2390,42 @@
 s = requests.get
+JSONObject
 (path);%0A        
@@ -2435,16 +2435,30 @@
 nts.put(
+Long.toString(
 System.c
@@ -2494,16 +2494,17 @@
  %25 1000)
+)
 , query)
@@ -2629,37 +2629,26 @@
 ronized 
-TreeMap%3CLong, String%3E
+JSONObject
  getRequ
@@ -2845,104 +2845,324 @@
     
-TreeMap%3CLong, String%3E events = (TreeMap%3CLong, String%3E) requests.get(path);%0A        return events
+JSONObject events = requests.getJSONObject(path);%0A        return events;%0A    %7D%0A    %0A    public static void main(String%5B%5D args) %7B%0A        Accounting a = new Accounting();%0A        a.addRequest(%22/api/test.json%22, %22q=test%22);%0A        JSONObject r = a.getRequests(%22/api/test.json%22);%0A        System.out.println(r.toString())
 ;%0A  

fix for accounting