import java.io.IOException;
import java.io.Serializable;
import jdbm.PrimaryStoreMap;
import jdbm.RecordManager;
import jdbm.RecordManagerFactory;
import jdbm.SecondaryKeyExtractor;
import jdbm.SecondaryTreeMap;
/**
 * More advanced example to demonstrate Map usage.
 * 
 * @author Jan Kotek
 *
 */
public class HelloWorld2 {
  static class Person implements Serializable{
    
    /** never forget this, very important for serialization*/
    private static final long serialVersionUID = -3321252970661193623L;
    final String name;    
    final String town;
    final String country;
    
    /** some data to object class bigger */
    final byte[] balast = new byte[1024];
    public Person(String name, String town, String country) {
      this.name = name;
      this.town = town;
      this.country = country;      
    }
    @Override
    public String toString() {
      return "Person [name=" + name + ", town=" + town + ", country=" + country + "]";
    }
        
    /** snip getters and setters*/
    
  }
  
  
  public static void main(String[] args) throws IOException {
    RecordManager recman = RecordManagerFactory.
        createRecordManager("HelloWorld2");
    /**
     * Create primary map which is used to store records.  
     * Data can be also stored in PrimaryTreeMap and PrimaryHashMap,
     * but this is more efficient for large objects. 
     */
    PrimaryStoreMap<Long,Person> main = recman.storeMap("recman");
    
    /**
     * Create secondary index which points to Person name.
     * SecondaryMap is readonly, it is updated by PrimaryMap.
     *  
     * Secondary map have three types, 
     * first is type of secondary index (string),
     * second and third are copied from primary map.
     */
    SecondaryTreeMap<String, Long, Person> nameIndex = main.secondaryTreeMap("nameIndex",
            new SecondaryKeyExtractor<String, Long, Person>() {
              public String extractSecondaryKey(Long key, Person value) {
                return value.name;
              }          
            });
    
    /**
     * Another secondary map which points to town and country
     */
    SecondaryTreeMap<String, Long, Person> townIndex = main.secondaryTreeMap("townIndex",
        new SecondaryKeyExtractor<String, Long, Person>() {
          public String extractSecondaryKey(Long key, Person value) {
            /**
             * Note format of map key
             */
            return value.country+"/"+value.town;
          }          
        });
    
    /**
     * And very simple index of Evil family members
     */
    SecondaryTreeMap<Boolean, Long, Person> evilIndex = main.secondaryTreeMap("evilIndex",
        new SecondaryKeyExtractor<Boolean, Long, Person>() {
          public Boolean extractSecondaryKey(Long key, Person value) {
            return value.name.contains("Evil");
          }          
        });
    
    /**
     * Clean up, if this example was run more times.
     * All secondary indexes are updated automatically. 
     */
    main.clear();
    
    
    /** 
     * Add some data. 
     * StoreMap does not have usuall 'put' method.
     * Key is generated by Store, so use 'putValue' instead 
     */
    main.putValue(new Person("James Bond","London","UK"));
    main.putValue(new Person("Austin Powers","London","UK"));
    main.putValue(new Person("Dr Evil","Vulcano Island","Ocean"));
    main.putValue(new Person("Scott Evil","Vulcano Island","Ocean"));    
    main.putValue(new Person("Vanessa Kensington","London","UK"));
    main.putValue(new Person("Alotta Fagina","Las Vegas","USA"));
        
    /**
     * Persists inserted values
     */
    recman.commit();
    
    /**
     * Get persons with name Austin Powers
     */
    System.out.println();
    System.out.println("Austin Powers: ");
    for(Person person:nameIndex.getPrimaryValues("Austin Powers")){
      System.out.println("  "+person);
    }
    
    /**
     * Print all Persons who lives on Vulcano Island.
     * First we must obtain key from primary map,
     * then 
     */
    System.out.println();
    System.out.println("Persons on Vulcano Island: ");
    for(Person person:townIndex.getPrimaryValues("Ocean/Vulcano Island")){
      System.out.println("  "+person);
    }
    
    /**
     * Get everyone who is Evil
     */
    System.out.println();
    System.out.println("Evil family: ");
    for(Person person:evilIndex.getPrimaryValues(true)){
      System.out.println("  "+person);
    }    
    
    recman.close();
  }
}