/* 

	Purpose:
		
	Description:
		
	History:
		2014/4/21, Dennis

Copyright (C) 2010 Potix Corporation. All Rights Reserved.

*/
package org.zkoss.zss.jsf.ui.impl;

import java.io.Serializable;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;

import javax.servlet.http.HttpSession;

/**
 * the object holder to hold object for a while, and remove timeout object when someone {@link #kick()} it.
 * @author Dennis
 *
 */
public class ObjectHolder extends ObjectHolderContext implements Serializable {
	private static final long serialVersionUID = 4832818033988336706L;

	private final static String key = "$zss.jsf.objectHolder$";
	
	private HttpSession session;
	private int millisecondToKick;
	
	public ObjectHolder(HttpSession session,int millisecondToKick){
		this.session = session;
		this.millisecondToKick = millisecondToKick;
	}
	
	static class ObjectWrapper implements Serializable{
		private static final long serialVersionUID = 1L;
		long timeToKick;
		transient Object object;
		public ObjectWrapper(Object object, long timeToKick) {
			super();
			this.object = object;
			this.timeToKick = timeToKick;
		}
		public long getTimeToKick() {
			return timeToKick;
		}
		public Object getObject() {
			return object;
		}
	}
	/**
	 * Kick this holder to remove timeout object
	 */
	public void kick(){
		Map<String,ObjectWrapper> objects = (Map<String, ObjectWrapper>) session.getAttribute(key);
		if(objects!=null){
			long now = System.currentTimeMillis();
			synchronized(objects){
				for(Iterator<Entry<String, ObjectWrapper>> iter = objects.entrySet().iterator();iter.hasNext();){
					Entry<String, ObjectWrapper> entry = iter.next();
					if(entry.getValue().getTimeToKick()<=now){
						iter.remove();
					}
				}
				if(objects.size()==0){
					session.removeAttribute(key);
				}
			}
		}
	}	

	/**
	 * Gets the object with given id
	 */
	public Object get(String objectId) {
		Map<String,ObjectWrapper> objects = (Map<String, ObjectWrapper>) session.getAttribute(key);
		Object object = null;
		if(objects!=null){
			synchronized(objects){
				ObjectWrapper dd = objects.get(objectId);
				object = dd==null?null:dd.getObject();
			}
		}
		return object;
	}

	/**
	 * Puts the object with given id
	 */
	public void put(String objectId, Object object) {
		Map<String,ObjectWrapper> objects = getOrCreateObjectMap(session);
		synchronized(objects){
			objects.put(objectId, new ObjectWrapper(object,System.currentTimeMillis()+(millisecondToKick)));
		}
	}

	private synchronized Map<String, ObjectWrapper> getOrCreateObjectMap(HttpSession session) {
		Map<String,ObjectWrapper> objects = (Map<String, ObjectWrapper>) session.getAttribute(key);
		if(objects==null){
			objects = new HashMap<String,ObjectWrapper>();
		}
		session.setAttribute(key,objects);
		return objects;
	}
	
	
}
