/*
 * This file is part of Nuts Framework.
 * Copyright(C) 2009-2012 Nuts Develop Team.
 *
 * Nuts Framework is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License any later version.
 * 
 * Nuts Framework 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Nuts Framework. If not, see <http://www.gnu.org/licenses/>.
 */
package nuts.exts.struts2;

import nuts.core.lang.StringEncrypts;
import nuts.core.lang.Strings;
import nuts.core.servlet.HttpServletUtils;
import nuts.exts.struts2.util.StrutsContextUtils;
import nuts.exts.xwork2.StateProvider;
import nuts.exts.xwork2.TextProvider;

import javax.servlet.http.Cookie;


/**
 * CookieStateProvider
 */
public class CookieStateProvider implements StateProvider {
	private final static String DOMAIN = "cookie-state-domain";
	private final static String PATH = "cookie-state-path";
	private final static String EXPIRE = "cookie-state-expire";
	private final static String SECURE = "cookie-state-secure";
	
	private String prefix;
	private String domain;
	private String path;
	private Integer expire;
	private Boolean secure;
	
	/**
	 * Constructor
	 */
	public CookieStateProvider() {
		this((String)null);
	}
	
	/**
	 * Constructor
	 * @param prefix prefix
	 */
	public CookieStateProvider(String prefix) {
		this(prefix, null, null, null, null);
	}
	
	/**
	 * Constructor
	 * @param textProvider text provider
	 */
	public CookieStateProvider(TextProvider textProvider) {
		this(null, textProvider);
	}
	
	/**
	 * Constructor
	 * @param prefix prefix
	 * @param textProvider text provider
	 */
	public CookieStateProvider(String prefix, TextProvider textProvider) {
		this(prefix, 
			textProvider.getText(DOMAIN, (String)null), 
			textProvider.getText(PATH, (String)null), 
			textProvider.getTextAsInt(EXPIRE, 0),
			textProvider.getTextAsBoolean(SECURE));
	}
	
	/**
	 * Constructor
	 * @param prefix prefix
	 * @param domain domain
	 * @param path path
	 * @param expire expire
	 * @param secure secure
	 */
	public CookieStateProvider(String prefix, String domain, String path, Integer expire, Boolean secure) {
		this.prefix = prefix;
		this.domain = domain;
		this.path = path;
		this.expire = expire;
		this.secure = secure;
	}

	/**
	 * @return the prefix
	 */
	public String getPrefix() {
		return prefix;
	}

	/**
	 * @param prefix the prefix to set
	 */
	public void setPrefix(String prefix) {
		this.prefix = prefix;
	}

	/**
	 * @return the expire
	 */
	public int getExpire() {
		return expire;
	}

	/**
	 * @param expire the expire to set
	 */
	public void setExpire(int expire) {
		this.expire = expire;
	}

	/**
	 * @return the domain
	 */
	public String getDomain() {
		return domain;
	}

	/**
	 * @param domain the domain to set
	 */
	public void setDomain(String domain) {
		this.domain = domain;
	}

	/**
	 * @return the path
	 */
	public String getPath() {
		return path;
	}

	/**
	 * @param path the path to set
	 */
	public void setPath(String path) {
		this.path = path;
	}

	/**
	 * get key name
	 * @param name state name
	 * @return key name
	 */
	private String getKey(String name) {
		return prefix == null ? name : prefix + name;
	}

	/**
	 * encode value 
	 * @param value value
	 * @return encoded value
	 */
	private String encodeValue(Object value) {
		try {
			return value == null ? Strings.EMPTY : StringEncrypts.encrypt(value.toString());
		}
		catch (Exception e) {
			return Strings.EMPTY;
		}
	}
	
	/**
	 * decode value 
	 * @param value value
	 * @return encoded value
	 */
	private String decodeValue(Object value) {
		try {
			return value == null ? Strings.EMPTY : StringEncrypts.decrypt(value.toString());
		}
		catch (Exception e) {
			return Strings.EMPTY;
		}
	}

	/**
	 * Save state
	 * @param name state name
	 * @param value state value
	 */
	public void saveState(String name, Object value) {
		String key = getKey(name);
		String val = encodeValue(value);

		Cookie c = new Cookie(key, val);

		if (domain != null) {
			c.setDomain(domain);
		}
		
		if (path == null) {
			path = StrutsContextUtils.getServletRequest().getRequestURI();
		}
		c.setPath(path);

		if (secure != null) {
			c.setSecure(secure);
		}

		if (value == null) {
			c.setMaxAge(0);
		}
		else if (expire != null) {
			c.setMaxAge(expire);
		}
		
		StrutsContextUtils.getServletResponse().addCookie(c);
	}
	
	/**
	 * Load state
	 * @param name state name
	 * @return state value 
	 */
	public Object loadState(String name) {
		String key = getKey(name);
		Cookie c = HttpServletUtils.getCookie(StrutsContextUtils.getServletRequest(), key);
		if (c != null) {
			return decodeValue(c.getValue());
		}
		return null;
	}
}
