package examples;

import org.mapdb.DB;
import org.mapdb.DBMaker;
import org.mapdb.Serializer;

import java.io.*;
import java.util.Map;

/*
 *	Demonstrates HashMaps with non-standard types of objects as key or value.
 */
public class Custom_Value {


    /**
     * MapDB uses custom serialization which stores class metadata at single place.
     * Thanks to it is 10x more efficient than standard Java serialization.
     *
     * Using custom values in MapDB has three conditions:
     *
     *   1)  classes should be immutable. There is instance cache, background serialization etc
     *         Modifing your classes after they were inserted into MapDB may leed to unexpected things.
     *
     *   2) You should implement `Serializable` marker interface. MapDB tries to stay compatible
     *         with standard Java serialization.
     *
     *   3) Even your values should implement equalsTo method for CAS (compare-and-swap) operations.
     *
     */
    public static class Person implements Serializable{
        final String name;
        final String city;

        public Person(String n, String c){
            super();
            this.name = n;
            this.city = c;
        }

        public String getName() {
            return name;
        }

        public String getCity() {
            return city;
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;

            Person person = (Person) o;

            if (city != null ? !city.equals(person.city) : person.city != null) return false;
            if (name != null ? !name.equals(person.name) : person.name != null) return false;

            return true;
        }

    }

    public static void main(String[] args) throws IOException {

        // Open db in temp directory
        File f = File.createTempFile("mapdb","temp");
		DB db = DBMaker.newFileDB(f)
				.make();
		
		// Open or create table
		Map<String,Person> dbMap = db.getTreeMap("personAndCity");
		
		// Add data
		Person bilbo = new Person("Bilbo","The Shire");
		Person sauron = new Person("Sauron","Mordor");
		Person radagast = new Person("Radagast","Crazy Farm");
		
		dbMap.put("west",bilbo);
		dbMap.put("south",sauron);
		dbMap.put("mid",radagast);

		// Commit and close
		db.commit();
		db.close();


        //
        // Second option for using cystom values is to use your own serializer.
        // This usually leads to better performance as MapDB does not have to
        // analyze the class structure.
        //

        class CustomSerializer extends Serializer<Person> implements Serializable{

            @Override
            public void serialize(DataOutput out, Person value) throws IOException {
                out.writeUTF(value.getName());
                out.writeUTF(value.getCity());
            }

            @Override
            public Person deserialize(DataInput in, int available) throws IOException {
                return new Person(in.readUTF(), in.readUTF());
            }

            @Override
            public int fixedSize() {
                return -1;
            }

        }

        Serializer<Person> serializer = new CustomSerializer();

        DB db2 = DBMaker.newTempFileDB().make();

        Map<String,Person> map2 = db2.createHashMap("map").valueSerializer(serializer).make();

        map2.put("North", new Person("Yet another dwarf","Somewhere"));

        db2.commit();
        db2.close();


	}


}
	

	


