/**
 * 
 */
package org.forkalsrud.album.db;

import java.io.IOException;
import java.io.StringReader;
import java.io.StringWriter;
import java.nio.charset.Charset;

import com.sleepycat.bind.tuple.TupleBinding;
import com.sleepycat.bind.tuple.TupleInput;
import com.sleepycat.bind.tuple.TupleOutput;
import com.sleepycat.je.Database;
import com.sleepycat.je.DatabaseConfig;
import com.sleepycat.je.DatabaseEntry;
import com.sleepycat.je.Environment;
import com.sleepycat.je.OperationStatus;
import com.sleepycat.je.Transaction;

/**
 * @author knut
 * 
 */
public class DirectoryDatabase extends TupleBinding<DirectoryProps> {

    private static Charset UTF8 = Charset.forName("utf-8");
    
    private Environment environment;
    private Database db;

    public DirectoryDatabase(Environment environment) {

        this.environment = environment;

        String dbname = "directories";

        DatabaseConfig databaseConfig = new DatabaseConfig();
        databaseConfig.setAllowCreate(true);
        databaseConfig.setTransactional(true);
        // perform other database configurations
        this.db = environment.openDatabase(null, dbname, databaseConfig);
    }

    public void close() {
        db.close();
    }
    
    public long size() {
        return db.count();
    }

    public DirectoryProps load(String key) {

        DatabaseEntry data = new DatabaseEntry();
        Transaction txn = environment.beginTransaction(null, null);
        OperationStatus status = db.get(txn, key(key), data, null);
        txn.commitNoSync();
        if (OperationStatus.SUCCESS.equals(status)) {
            return entryToObject(data);
        } else {
            return null;
        }
    }

    public void store(String key, DirectoryProps img) {

        DatabaseEntry data = new DatabaseEntry();
        objectToEntry(img, data);
        DatabaseEntry binKey = key(key);
        Transaction txn = environment.beginTransaction(null, null);
        db.delete(txn, binKey);
        db.put(txn, binKey, data);
        txn.commitSync();
    }


    private DatabaseEntry key(String key) {
        DatabaseEntry returnValue = new DatabaseEntry();
        returnValue.setData(key.getBytes(UTF8));
        return returnValue;
    }


    @Override
    public DirectoryProps entryToObject(TupleInput in) {

        DirectoryProps props = new DirectoryProps();
        int version = in.readInt();
        if (version != 1) {
            throw new RuntimeException("I only understand version 1");
        }
        props.setTimestamp(in.readLong());
        String val = in.readString();
        try {
            props.load(new StringReader(val));
        } catch (IOException e) {
            e.printStackTrace();
        }
        return props;
    }


    @Override
    public void objectToEntry(DirectoryProps props, TupleOutput out) {

        out.writeInt(1);  // version 1
        out.writeLong(props.getTimestamp());
        StringWriter writer = new StringWriter();
        try {
            props.store(writer, "");
        } catch (IOException e) {
            e.printStackTrace();
        }
        out.writeString(writer.toString());
    }

}
