package page.tools.entity;

import java.util.Collection;

import org.wikiwebserver.core.WareHouse;
import org.wikiwebserver.core.WikiMap;

abstract class Storable {
    
    private static final int MAX_STORABLE_ITEMS = 10000;    
    
    private String id;     
    
    protected abstract String getType();
    
    Storable() {
        this.id = allocateId(getType());   
    }
    
    Storable(String id) {
        this.id = id;
    }
    
    public String getId() {
        return id;
    }    
    
    public boolean equals(Object obj) {
        if (obj != null && obj instanceof Storable) {
            return this.getId().equals(((Storable)obj).getId());
        }
        return false;
    }        
    
    long getLastAllocatedIdNumber() {
        return WareHouse.lastIdentity(getType() + "ID");
    }
    
    static Collection<String> listIds(String type) {
        return getStore(type).keySet();
    } 
    
    static String allocateId(String type) {
        return WareHouse.newIdentity(type + "ID");
    }
    
    public boolean hasAllocatedId() {
        if (getId() == null) return false; 
        if (getId().length() != 12) return false;         
        try {
            long lastID = getLastAllocatedIdNumber();
            Long thisID = Long.parseLong(getId(), 16); 
            if (thisID.longValue() > lastID) return false;
        } catch (Exception ex) {
            // No store, invalid
            return false;
        }
        
        return true;
    }      
    
    public Object get(String key, String... hierarchy) {
        return getEntityStore(hierarchy).get(key);
    }     
    
    public Object remove(String key, String... hierarchy) {
        return getEntityStore(hierarchy).remove(key);
    }     
    
    public Object put(String key, Object value, String... hierarchy) {
        return getEntityStore(hierarchy).put(key, value);
    }       
    
    public long incrementValue(String key, long amount, String... hierarchy) {
        return getEntityStore(hierarchy).incrementLongValue(key, amount);
    }  
 
    public double recalculateAverage(String key, long amount, String... hierarchy) {
        return getEntityStore(hierarchy).recalculateAverage(key, amount);
    }      
    
    public void clear() {
        getEntityStore().clear();
        getStore().remove(getId());
    }
    
    public boolean isValid() {
        return ((WikiMap) getStore().get(getId()) != null);
    }    
    
    private WikiMap getStore() {
        return getStore(getType());
    }
    
    public static WikiMap getStore(String type) {
        WikiMap map = WareHouse.getWikiMap(type);
        if (map == null) {
            map = WareHouse.initWikiMap(MAX_STORABLE_ITEMS, Storable.class.getName(), type);
        }
        return map;        
    }
    
    private WikiMap getEntityStore(String... heirarchy) {
        WikiMap entityStore = (WikiMap) getStore().get(getId());
        if (entityStore == null) {
            entityStore = WareHouse.initWikiMap(getStore(), getId());
        }
        if (heirarchy == null || heirarchy.length == 0) return entityStore;
        WikiMap map = WareHouse.getWikiMap(entityStore, heirarchy); 
        if (map == null) map = WareHouse.initWikiMap(entityStore, 100, null, heirarchy);
        return map; 
    }    
    
    private static WikiMap getIndexStore(String type, String index) {
        WikiMap map = WareHouse.getWikiMap(type, "Index", index); 
        if (map == null) map = WareHouse.initWikiMap(type, "Index", index);
        return map;
    }      
    
    static String putInIndex(String type, String index, String key, String value) {
        return (String) getIndexStore(type, index).put(key, value);
    }    
    
    static String getFromIndex(String type, String index, String key) {
        return (String) getIndexStore(type, index).get(key);
    }
    
    static String removeFromIndex(String type, String index, String key) {
        return (String) getIndexStore(type, index).remove(key);
    }
}

