/*
 *  Database with possible unifications/queries
 *
 *  2004 - 2011 Frantisek Zboril jr.
 *  Faculty of Information Technology
 *  zborilf@fit.vutbr.cz
 *  http://www.fit.vutbr.cz/~zborilf
 *
 * (C) Brno University of Technology
 * Freeware licence VUT v Brně
 * https://wis.fit.vutbr.cz/FIT/db/dir.php/dr/VZ2007/externiInformace/softwareNaWebu/Priloha2_rozh23.pdf

 */

package jTMass.core.jALLL.jTObjects;
import jTMass.*;

import java.util.HashMap;
import java.util.LinkedList;
import java.util.Collection;
import java.util.Iterator;
import java.util.Set;


public class TStorageBox extends HashMap{

    // ===== CONTENT ACCESS =====

    public int getSize(){
        int size=0;
        TObject value;
	Set keys=keySet();
        for(Object key:keys){
            value=(TObject)this.get(key);
            size=size+value.getContent().length();
        }
        return(size);
    }

    public String getContent(boolean values){
        String content=new String();
        TObject value;
	Set keys=keySet();

        for(Object key:keys){
            if(!content.isEmpty())
                content=content+'\n';
            value=(TObject)this.get(key);
            if((values)&& !(value instanceof TPlan))
                content+=key.toString()+'>'+value.getContent();
            else
		content+=key.toString()+" : "+value.getContent();
	}
        return(content);
    }

    public String getBeliefs(){
        String content=new String();
        TObject value;
	Set keys=keySet();

        for(Object key:keys){
            value=(TObject)this.get(key);
            if(!(value instanceof TPlan)){
                if(!content.isEmpty())
                    content=content+'\n';
                    content+=value.getContent();
                }
             }
             content=content+'\n';
             return(content);
        }

    public String getPlans(){
        String content=new String();
        TObject value;
	Set keys=keySet();

        for(Object key:keys){
            value=(TObject)this.get(key);
            if(value instanceof TPlan){
                if(!content.isEmpty())
                    content=content+'\n';
                content+=key+":"+value.getContent();
            }
        }
        return(content);
    }

    // ===== TERMINAL OUTPUT =====

    public void printBox(boolean values){
        TMass._Terminal.printlnSystemInfo(getContent(values));
    }

    // ====== DATABASE ACCESS, READERS & WRITERS =====
	
    public TObject get(String key){
	return((TObject)super.get(key));
    }
		
    public TObject put(String key, TObject object){
    	TObject previous=(TObject)super.put(key,object);
	return(previous);
    }
	
    public TObject put(TObject object){
	String key;
	key=object.getContent(); // the hash is the list transcription
	TObject previous=(TObject)super.put(key,object);
	return(previous);
    }
	
    public TObject remove(String key){
	return((TObject)super.remove(key));
    }
		
    public void clearBox(){
	super.clear();
    	return;
    }
	
    // === UNIFICATIONS, TESTING =====
	
    public boolean testList(TList list, boolean goThrough){

	// Testing existence of a list in DB
        // list does not contain anonymous variables

        if(get(list.getContent())!=null){
            return(true);
	}
        else
	if(goThrough){
            TList item;
            Collection values=this.values();
            Iterator iterator=values.iterator();
            while(iterator.hasNext()){
                item=(TList)iterator.next();
		if(unifiable(item,list))
                    return(true);
            }
	}
	return(false);
    }
	
	
    public void unifyRemove(TList query){

        // first it tries to delete a grounded list
	// then it goes through the base and deletes every unifiable knowledge

        if(query.getType()==TConstants._GeneralList){
            remove(query.getContent()); //general list is grounded
            return;
	}

	TList item;
	Collection values=this.values(); 	
	Iterator iterator=values.iterator();

	while(iterator.hasNext()){  
            item=(TList)iterator.next();
            if(unifiable(item,query))
                iterator.remove();
        }
	return;
    }
	
	
    public TList unifyToList(TList query){

        // returns a list of lists which are unifiable with the query

        TList result=new TList();
	TStorageBuffer buffer=unify(query);

        if(!buffer.hasNext())
            return(null);
	while(buffer.hasNext())
            result.add((TObject)buffer.next());
	return(result);
    }

    private boolean unifiable2(TList list,TList query,int index){

        // tests equality of two elements of the list
        // the .equal method repspect possible anonymous variables

        TObject object1,object2;

        object1=list.get(index);
        object2=query.get(index);
        if((object1 instanceof TList)&&(object2 instanceof TAtom))
            if(object2.getType()==TConstants._AnonymousVariable){
                index++;
		if(index<list.size())
                    return(unifiable2(list,query,index));
		else
                    return(true);
            }

        if((object1 instanceof TList)&&(object2 instanceof TList))
            return(unifiable((TList)object1,(TList)object2));
        else
        if((object1 instanceof TAtom)&&(object2 instanceof TAtom))
            if(TObject.equals(list.get(index),query.get(index))){
                index++;
                if(index<list.size())
                    return(unifiable2(list,query,index));
                else
                    return(true);
            }

        return(false);
    }

    private boolean unifiable(TList list,TList query){

    // only two lists of the same lenght may be unifiable

        if(list.size()==query.size())
            return(unifiable2(list,query,0));
	else
            return(false);
    }
	
    public TStorageBuffer unify(TList query){

        LinkedList list=new LinkedList();
	TList item;
	Collection values=this.values(); 
	Iterator iterator=values.iterator();

	while(iterator.hasNext()){ 
            item=(TList)iterator.next();
            if(unifiable(item,query))
                list.add(item);
	}
	return(new TStorageBuffer(list));
    }

    // ===== CONSTRUCTORS =====
	
    public TStorageBox(){
    	super();
    }
	
    public TStorageBox(int initialCapacity){
	super(initialCapacity);
    }
		
    public TStorageBox(int initialCapacity, float loadFactor){
	super(initialCapacity, loadFactor);
    }

}