/**
 * License Agreement.
 *
 * Rich Faces - Natural Ajax for Java Server Faces (JSF)
 *
 * Copyright (C) 2007 Exadel, Inc.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License version 2.1 as published by the Free Software Foundation.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
 */
/*

 * Created on 25.09.2004

 *

 * Copyright 1999-2004 The Apache Software Foundation.

 * 

 * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0

 * 

 * Unless required by applicable law or agreed to in writing, software

 * distributed under the License is distributed on an "AS IS" BASIS,

 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

 * See the License for the specific language governing permissions and

 * limitations under the License.

 */
package org.ajax4jsf.portlet.context;

import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.security.Principal;
import java.util.Collections;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import javax.faces.FacesException;
import javax.faces.context.ExternalContext;
import javax.servlet.RequestDispatcher;
import javax.servlet.Servlet;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletResponse;

/**
 * 
 * @author shura
 * 
 * 
 * 
 * Cocoon specific implementation of <code>ExternalContext</code> Use cocoon
 * 
 * <code>Context</code> for Implement JSF Servlet specific functions Do not
 * 
 * perform redirect - but tell <code>Action</code> for internal pipeline
 * 
 * redirect ? or do normal Cocoon redirect Via Http Environment do not dispanch -
 * 
 * use Cocoon generator source parametr, but perform generation Full
 * 
 * Cocoon-specific realization ;
 * 
 * 
 * 
 */
public abstract class AbstractExternalContext extends ExternalContext {
    
    /**
     * Request parameter to store current View Id.
     */
    public static final String VIEW_ID_PARAMETER ="org.ajax4jsf.portlet.VIEWID";
    /**
     * Name of request parameter to store namsepace of the current portlet instance. 
     */
    public static final String NAMESPACE_PARAMETER ="org.ajax4jsf.portlet.NAMESPACE";
    public static final String ACTION__PARAMETER = "org.ajax4jsf.portlet.ACTION_URL";
    public static final Object PORTLET_MODE_PARAMETER = "org.ajax4jsf.portlet.MODE";
    
    protected static final String[] EMPTY_STRING_ARRAY = new String[0];
    // TODO - optimization.
    private Map applicationMap;

    private Map initParameterMap;

    private Map requestHeaderMap = null;

    private Map requestHeaderValues;

    private Map requestMap;

    private Map requestParameterMap;

    private Map requestParameterValuesMap;

    private Map sessionMap;

    private Object request;

    private Object response;

    private boolean http;

    private Map actionSettings;

    private Object context;
    

    /**
         * 
         * @param response
         * 
         * @param request
         * 
         * @param context
         * 
         * @param defaultContext -
         * 
         * default implementation of <code>ExternalFacesContext</code>.
         * 
         */
    public AbstractExternalContext(Object context, Object request,
	    Object response) {
	super();
	this.context = context;
	this.request = request;
	this.response = response;
    }

    protected abstract String getNamespace();
    
    
    public String encodeNamespace(String name) {
        
        return getNamespace()+name;
    }
    /*
         * 
         * (non-Javadoc)
         * 
         * 
         * 
         * @see javax.faces.context.ExternalContext#dispatch(java.lang.String)
         * 
         */
    public Map getApplicationMap() {
	if (this.applicationMap == null) {
	    this.applicationMap = new ContextAttributesMap() {
		protected Enumeration getEnumeration() {
		    return getContextAttributeNames();
		}

		protected Object getAttribute(String name) {
		    return getContextAttribute(name);
		}

		protected void setAttribute(String name, Object value) {
		    setContextAttribute(name, value);
		}

		protected void removeAttribute(String name) {
		    removeContextAttribute(name);
		}
	    };
	}
	return this.applicationMap;
    }

    protected abstract void removeContextAttribute(String name);

    protected abstract void setContextAttribute(String name, Object value);

    protected abstract Object getContextAttribute(String name);

    protected abstract Enumeration getContextAttributeNames();

    /*
         * (non-Javadoc)
         * 
         * @see javax.faces.context.ExternalContext#getAuthType()
         */
    public Object getContext() {
	return this.context;
    }

    /**
         * @param context
         */
    public void setContext(Object context) {
	this.context = context;
    }

    /*
         * (non-Javadoc)
         * 
         * @see javax.faces.context.ExternalContext#getInitParameter(java.lang.String)
         */
    public Map getInitParameterMap() {
	if (this.initParameterMap == null) {
	    this.initParameterMap = new ContextAttributesMap() {
		protected Object getAttribute(String name) {
		    return getInitParameter(name);
		}

		protected void setAttribute(String name, Object value) {
		    throw new UnsupportedOperationException();
		}

		protected Enumeration getEnumeration() {
		    return getInitParametersNames();
		}
	    };
	}
	return this.initParameterMap;
    }

    /**
         * Hoock method for initialization parameters.
         * 
         * @return
         */
    protected abstract Enumeration getInitParametersNames();

    /*
         * (non-Javadoc)
         * 
         * @see javax.faces.context.ExternalContext#getRequest()
         */
    public Object getRequest() {
	return this.request;
    }

    /*
         * (non-Javadoc)
         * 
         * @see javax.faces.context.ExternalContext#setRequest(java.lang.Object)
         */
    public void setRequest(Object request) {
	this.request = request;
    }

    public Map getRequestCookieMap() {
	// Portlet environment don't have methods to use cookies.
	return Collections.EMPTY_MAP;
    }

    /*
         * 
         * (non-Javadoc)
         * 
         * 
         * 
         * @see javax.faces.context.ExternalContext#getRequestHeaderMap()
         * 
         */
    public Map getRequestHeaderMap() {
	if (this.requestHeaderMap == null) {
	    this.requestHeaderMap = new ContextAttributesMap() {
		protected Enumeration getEnumeration() {
		    return getRequestHeaderNames();
		}

		protected Object getAttribute(String name) {
		    return getRequestHeader(name);
		}

		protected void setAttribute(String name, Object value) {
		    throw new UnsupportedOperationException();
		}
	    };
	}
	return this.requestHeaderMap;
    }

    protected abstract Object getRequestHeader(String name);

    protected abstract Enumeration getRequestHeaderNames();

    public Map getRequestHeaderValuesMap() {
	// 
	if (this.requestHeaderValues == null) {
	    this.requestHeaderValues = new ContextAttributesMap() {
		protected Enumeration getEnumeration() {
		    return getRequestHeaderNames();
		}

		protected Object getAttribute(String name) {
		    return getRequestHeaderValues(name);
		}

		protected void setAttribute(String name, Object value) {
		    throw new UnsupportedOperationException();
		}
	    };
	}
	return this.requestHeaderValues;
    }

    protected abstract String[] getRequestHeaderValues(String name);

    public Map getRequestMap() {
	if (this.requestMap == null) {
	    this.requestMap = new ContextAttributesMap() {
		protected Enumeration getEnumeration() {
		    return getRequestAttributeNames();
		}

		protected Object getAttribute(String name) {
		    return getRequestAttribute(name);
		}

		protected void setAttribute(String name, Object value) {
		    setRequestAttribute(name, value);
		}

		protected void removeAttribute(String name) {
		    removeRequestAttribute(name);
		}
	    };
	}
	return this.requestMap;
    }

    protected abstract void removeRequestAttribute(String name);

    protected abstract void setRequestAttribute(String name, Object value);

    protected abstract Object getRequestAttribute(String name);

    protected abstract Enumeration getRequestAttributeNames();

    public Map getRequestParameterMap() {
	// 
	if (this.requestParameterMap == null) {
	    this.requestParameterMap = new ContextAttributesMap() {
		protected Enumeration getEnumeration() {
		    return enumerateRequestParameterNames();
		}

		protected Object getAttribute(String name) {
		    return getRequestParameter(name);
		}

		protected void setAttribute(String name, Object value) {
		    throw new UnsupportedOperationException();
		}
	    };
	}
	return this.requestParameterMap;
    }

    protected abstract Object getRequestParameter(String name);

    protected abstract Enumeration enumerateRequestParameterNames();

    /*
     * (non-Javadoc)
     * 
     * @see javax.faces.context.ExternalContext#getRequestParameterNames()
     * 
     */
    public Iterator getRequestParameterNames() {
	return new EnumerationIterator(enumerateRequestParameterNames());
    }

    /*
         * 
         * (non-Javadoc)
         * 
         * 
         * 
         * @see javax.faces.context.ExternalContext#getRequestParameterValuesMap()
         * 
         */
    public Map getRequestParameterValuesMap() {
	if (this.requestParameterValuesMap == null) {
	    this.requestParameterValuesMap = new ContextAttributesMap() {

		protected Enumeration getEnumeration() {
		    return enumerateRequestParameterNames();
		}

		protected Object getAttribute(String name) {
		    return getRequestParameterValues(name);
		}

		protected void setAttribute(String name, Object value) {
		    throw new UnsupportedOperationException();
		}
	    };
	}
	return this.requestParameterValuesMap;
    }

    protected abstract  Object getRequestParameterValues(String name);

    /*
         * 
         * (non-Javadoc)
         * 
         * 
         * 
         * @see javax.faces.context.ExternalContext#getResponse()
         * 
         */
    public void setResponse(Object response) {
	this.response = response;
    }

    public Object getResponse() {
	return this.response;
    }

    /*
         * 
         * (non-Javadoc)
         * 
         * 
         * 
         * @see javax.faces.context.ExternalContext#getSessionMap()
         * 
         */
    public Map getSessionMap() {
	if (this.sessionMap == null) {
	    this.sessionMap = new ContextAttributesMap() {

		protected Enumeration getEnumeration() {
		    return getSessionAttributeNames();
		}

		protected Object getAttribute(String name) {
		    return getSessionAttribute(name);
		}

		protected void setAttribute(String name, Object value) {
		    setSessionAttribute(name, value);
		}
		
		protected void removeAttribute(String name) {
		    removeSessionAttribute(name);
		}
		

	    };
	}
	return this.sessionMap;
    }


    protected abstract void removeSessionAttribute(String name);

    protected abstract void setSessionAttribute(String name, Object value);

    protected abstract Object getSessionAttribute(String name);

    protected abstract Enumeration getSessionAttributeNames();
}