/*
 * ICESOFT COMMERCIAL SOURCE CODE LICENSE V 1.1
 *
 * The contents of this file are subject to the ICEsoft Commercial Source
 * Code License Agreement V1.1 (the "License"); you may not use this file
 * except in compliance with the License. You may obtain a copy of the
 * License at
 * http://www.icesoft.com/license/commercial-source-v1.1.html
 *
 * Software distributed under the License is distributed on an "AS IS"
 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
 * License for the specific language governing rights and limitations under
 * the License.
 *
 * Copyright 2009-2015 ICEsoft Technologies Canada, Corp. All Rights Reserved.
 */
package com.icesoft.faces.facelets.component.progress;

import java.io.Serializable;
import java.util.Map;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.logging.Logger;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
import javax.faces.context.FacesContext;
import javax.faces.event.ActionEvent;

import org.icefaces.application.PortableRenderer;
import org.icefaces.application.PushRenderer;

@ManagedBean
@ViewScoped
public class ProgressAsyncBean implements Serializable {
    
	private String groupId;
	private transient ProgressState progressState;
    private boolean disableButton = false;
    private Runnable runnable;
    private static final Logger LOG = Logger.getLogger(ProgressAsyncBean.class.getName());
    
    @PostConstruct
    public void init(){
    	PushRenderer.addCurrentSession(getGroupId());
    }
    
    @PreDestroy
    public void predestroy(){
    	PushRenderer.removeCurrentSession(getGroupId());
    }
    
    public int getProgress(){
    	return getState().getProgress();
    }
    
    public void setProgress(int progress){
    	getState().setProgress(progress);
    }
    
    public ProgressState getState(){
    	/*
    	 * if ProgressState instance has not been provided try
    	 * to create one using the Session Map
    	 */
    	if( progressState == null ){
    		final Map<String,Object> sessionMap = FacesContext.getCurrentInstance()
    				.getExternalContext().getApplicationMap();
    		progressState = new ProgressState(){
    			public void setProgress(int progress) {
    				sessionMap.put(getGroupId(), Integer.valueOf(progress));
				}

				public int getProgress() {
					int result = 0;
					if( sessionMap != null ){
						Object obj = sessionMap.get(getGroupId());
						if( obj != null ){
							result = ((Integer)obj).intValue();
						}
					}
					return result;
				}
    			
    		};
    	}
    	return progressState;
    }
    
    public void setState(ProgressState state){
    	this.progressState = state;
    }

    public Runnable getRunnable() {
        return runnable;
    }

    public void setRunnable(Runnable runnable) {
        this.runnable = runnable;
    }

    public boolean isDisableButton() {
        return disableButton;
    }

    public void setDisableButton(boolean disableButton) {
        this.disableButton = disableButton;
    }

    public void start(ActionEvent actionEvent) {
    	LOG.info("start()");
    	final PortableRenderer renderer = PushRenderer.getPortableRenderer();
    	final ThreadPoolExecutor executor = new ThreadPoolExecutor(1, 1, 0, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(1), new ThreadPoolExecutor.DiscardPolicy()){
    		 protected void afterExecute(Runnable r, Throwable t) {
    			LOG.info("afterExecute()");
		        super.afterExecute(r, t);
		        getState().setProgress(100);
		        disableButton = false;
		        renderer.render(getGroupId());
		    }
    	};
        getState().setProgress(1);
        disableButton = true;
        LOG.info("execute()");
        executor.execute(runnable);
    }
    
    private String getGroupId(){
    	if( groupId == null ){
    		groupId = "progressAsyncPushGroup:" + System.nanoTime();
    		LOG.info("created group id="+groupId);
    	}
    	return groupId;
    }


   
}
