/*
 * Copyright 2016 CREATE-NET.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.createnet.raptor.db.mapdb;

import com.fasterxml.jackson.databind.JsonNode;
import java.io.File;
import java.util.List;
import org.createnet.raptor.db.Storage;
import org.createnet.raptor.db.config.StorageConfiguration;
import org.createnet.raptor.db.AbstractConnection;
import org.createnet.raptor.db.query.ListQuery;
import org.mapdb.BTreeMap;
import org.mapdb.DB;
import org.mapdb.DBMaker;
import org.mapdb.HTreeMap;
import org.mapdb.Serializer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 *
 * @author Luca Capra <luca.capra@gmail.com>
 */
class MapDBConnection extends AbstractConnection {

  private final Logger logger = LoggerFactory.getLogger(MapDBConnection.class);

  private StorageConfiguration config;
  
  private DB db;
  private HTreeMap<String, String> map;
  private  BTreeMap<Long, String> ttl;

  static public class Record {
    
    public long ttl;
    public String content;
    public String id;
    
    public JsonNode toJsonNode() {
      return Storage.mapper.convertValue(this, JsonNode.class);
    }
    
    @Override
    public String toString() {
      return toJsonNode().toString();
    }
    
  }
  
  public MapDBConnection(Storage.ConnectionId connId) {
    this.id = connId.name();
  }

  @Override
  public void setup(boolean forceSetup) throws Storage.StorageException {

    if (config.mapdb.storage.equals("memory")) {
      db = DBMaker.memoryDB().make();
      return;
    }

    File file = new File(config.mapdb.storePath + File.separator + this.id);

    if (forceSetup && file.exists()) {
      file.delete();
    }

    db = DBMaker.fileDB(file).make();

    logger.debug("Created store for {} at {}", this.id, file.getPath());
    
    map = db.hashMap(this.id + "_dataset")
            .keySerializer(Serializer.STRING)
            .valueSerializer(Serializer.STRING)
            .createOrOpen();

    ttl = db.treeMap(this.id + "_ttl")
            .keySerializer(Serializer.LONG)
            .valueSerializer(Serializer.STRING)
            .createOrOpen();    
    
  }

  @Override
  public void connect() throws Storage.StorageException {
  }

  @Override
  public void disconnect() {
  }

  @Override
  public void set(String id, JsonNode data, int ttlDays) throws Storage.StorageException {
    ttl.put((long)ttlDays, id);
    map.put(id, data.toString());
  }

  @Override
  public JsonNode get(String id) throws Storage.StorageException {
//    return Storage.mapper.convertValue(map.get(id), JsonNode.class);
  }

  @Override
  public List<JsonNode> list(ListQuery query) throws Storage.StorageException {
    throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
  }

  @Override
  public void delete(String id) throws Storage.StorageException {
    map.remove(id);
  }
  
  protected Record parseRecord(String raw) {
    return Storage.mapper.convertValue(raw, Record.class);
  }
  
}

@@ -698,16 +698,44 @@
 o.File;%0A
+import java.util.ArrayList;%0A
 import j
@@ -1434,17 +1434,16 @@
 private 
- 
 BTreeMap
@@ -1531,22 +1531,24 @@
  public 
-String
+JsonNode
  content
@@ -1572,24 +1572,167 @@
 ng id;%0A    %0A
+    private Record(String id, JsonNode content, long ttl) %7B%0A      this.id = id;%0A      this.content = content;%0A      this.ttl = ttl;%0A    %7D%0A    %0A
     public J
@@ -3050,31 +3050,77 @@
     
-ttl.put((long)ttlDays, 
+Record r = new Record(id, data, (long)ttlDays);%0A    ttl.put(r.ttl, r.
 id);
@@ -3132,24 +3132,31 @@
 map.put(
+r.
 id, 
-data
+r.content
 .toStrin
@@ -3245,18 +3245,16 @@
 ption %7B%0A
-//
     retu
@@ -3260,294 +3260,352 @@
 urn 
-Storage.mapper.convertValue(map.get(id), JsonNode.class);%0A  %7D%0A%0A  @Override%0A  public List%3CJsonNode%3E list(ListQuery query) throws Storage.StorageException %7B%0A    throw new UnsupportedOperationException(%22Not supported yet.%22); //To change body of generated methods, choose Tools %7C Templates.
+getRecord(id).content;%0A  %7D%0A  %0A  public Record getRecord(String id) throws Storage.StorageException %7B%0A    return parseRecord(map.get(id));%0A  %7D%0A%0A  @Override%0A  public List%3CJsonNode%3E list(ListQuery query) throws Storage.StorageException %7B%0A    List%3CJsonNode%3E results = new ArrayList();%0A    logger.warn(%22NOT IMPLEMENTED: list()%22);%0A    return results;
 %0A  %7D
@@ -3692,30 +3692,81 @@
     
-map.remove(id
+Record r = getRecord(id);%0A    map.remove(id);%0A    ttl.remove(r.ttl
 );%0A  %7D%0A
-  
 %0A  p

use Record to store data