package project;

import java.util.*;

public class AuxiliaryBuffer {
    private HashMap fileHitHash;
    private HashMap fileTimeHash;    
    private long freeObject;// num for object
    private long lowestObjectLimit; //lowest limit of number of object

    public AuxiliaryBuffer() {
        freeObject = 1000;	//Dump value for initilize, will adjust soon
        lowestObjectLimit = 100; //Dump value for initilize, will adjust soon
        fileHitHash = new HashMap((int)freeObject);
        fileTimeHash = new HashMap((int)freeObject);        
    }
    
    public HashMap getHitStatic() {
	return fileHitHash;
    }
    
    public void addRecord(String fileName)throws IllegalArgumentException {
	freeObject--;
	if(freeObject < 0) {
	    throw new IllegalStateException("Aux Buffer overflow!!");
	}
        if(!containFile(fileName))
            internAddRecord(fileName);
	else	//The case that add a file in Aux field should not happen
	    throw new IllegalArgumentException("Error in adding file, Aux contain: "+fileName);
    }

    private void internAddRecord(String fileName) {
	    Long currentTime = new Long(System.currentTimeMillis());
        int hit = getHitCount(fileName);
        fileHitHash.put(fileName, new Integer(hit+1));
        fileTimeHash.put(fileName, currentTime);        
    }

    public int getHitCount(String fileName) {
	Integer hit = (Integer)fileHitHash.get(fileName);
	if(hit == null)	//if there is no that file then mean hit == 0
	    return 0;
	else
	    return hit.intValue();
    }
    
    //Don't remove Hit count as this need to remember thoughout the session
    public void removeRecord(String fileName) throws NoSuchFieldException{
        if(containFile(fileName))
	{
	    Object timeStamp = fileTimeHash.get(fileName);
            fileHitHash.remove(fileName);
            fileTimeHash.remove(fileName);
	    freeObject++;
	}
	else	//The case that remove a file not in Aux field should not happen
	    throw new NoSuchFieldException("Error in Removing file, Aux don't contain: "+fileName);
    }

    public void updateRecord(String fileName) throws NoSuchFieldException{
        
        internAddRecord(fileName);	//We don't not remove other field because HashMap will displace them
    }

    public void resetSize(MainBuffer main) throws NoSuchFieldException{

        long newAuxObjectCount = 2 * main.objectCount();
        freeObject = newAuxObjectCount - fileTimeHash.size();	//set aux size = 2*object in main
        
        while(freeObject < 0) {	    
            String delFileName = getLRUfile("");
            main.removeRecord(delFileName);
            removeRecord(delFileName);

            // still have question in the formula
            freeObject = newAuxObjectCount - fileTimeHash.size();	//set aux size = 2*object in main
        }
        
        if ( (freeObject + fileTimeHash.size()) < lowestObjectLimit) {
            freeObject = lowestObjectLimit - fileTimeHash.size();
        }
        
    }

    public boolean containFile(String fileName) throws IllegalStateException {
        if(fileName == null)
            throw new NullPointerException("The passing fileName should not be null");
	    
        boolean timeHash = fileTimeHash.containsKey(fileName);        
        boolean hitHash = fileHitHash.containsKey(fileName);
        
        
        if (timeHash != hitHash)            
            throw new IllegalStateException ("TimeHashs don't sync,  " + fileName + " timeHash: " + timeHash + " hitHash: "+ hitHash);

        
        return timeHash;
    }
    
    public boolean isAvaliable() {
	    return freeObject > 0? true:false;
    }

    public String getLRUfile(String fileName) throws NoSuchFieldException{        
        Long oldestTime = (Long)Collections.min(fileTimeHash.values());
        Object fileNameLRU = null;
        
        System.out.println("getLRUfile() method, fileName argument = " + fileName); //test message

        Set keySet = fileTimeHash.keySet();
        Iterator iterator = keySet.iterator();
        while (iterator.hasNext()) {
            Object fileObject = iterator.next();
            if ( ( (Long)(fileTimeHash.get(fileObject)) ).equals(oldestTime) ) {
                System.out.println("The oldest time got from the fileTimeHash: " + (Long)(fileTimeHash.get(fileObject)));
                fileNameLRU = fileObject;
            }
        }        

        System.out.println("OldestTime: " + oldestTime); //test message
        System.out.println("File Name LRU: " + fileNameLRU); // test message

        containFile((String)fileNameLRU);
            
        if( fileNameLRU.equals(fileName) ) {	//don't return the parameter file
            updateRecord(fileName);
            return getLRUfile(fileName);
        }
        else
            return (String)fileNameLRU;
    }
}
