/*
 * 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.aems.util;

import nuts.aems.WebApplet;
import nuts.aems.constant.COOKIE;
import nuts.aems.constant.GC;
import nuts.aems.constant.REQ;
import nuts.aems.interceptor.UserAuthenticationInterceptor;
import nuts.aems.model.bean.User;
import nuts.aems.model.bean.UserGroup;
import nuts.aems.model.dao.UserGroupDAO;
import nuts.aems.model.metadata.UserMetaData;
import nuts.core.bind.json.Jsons;
import nuts.core.dao.DaoSession;
import nuts.core.lang.Arrays;
import nuts.core.lang.StringEncrypts;
import nuts.core.lang.Strings;
import nuts.core.net.SendMail;
import nuts.core.servlet.HttpServletUtils;
import nuts.exts.struts2.actions.ActionUtilities;
import nuts.exts.struts2.actions.CommonAction;
import nuts.exts.struts2.util.StrutsContextUtils;
import nuts.exts.struts2.views.freemarker.FreemarkerUtils;
import nuts.exts.xwork2.util.ContextUtils;

import java.io.IOException;
import java.util.Collection;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.mail.Email;
import org.apache.commons.mail.EmailException;
import org.apache.commons.mail.HtmlEmail;
import org.apache.commons.mail.SimpleEmail;

import com.opensymphony.xwork2.util.ValueStack;

import freemarker.template.TemplateException;


/**
 * ActionUtils.
 */
public class BaseActionUtils extends ActionUtilities {

	/**
	 * Constructor
	 */
	public BaseActionUtils(CommonAction action) {
		super(action);
	}

	/**
	 * @return the cache
	 */
	public Map getCache() {
		return WebApplet.get().getCache();
	}
	
	/**
	 * @param u user
	 * @return true - if the user is administrators
	 */
	public boolean isAdminUser(User u) {
		return GC.ADMIN_LEVEL.equals(u.getGroupLevel());
	}

	/**
	 * getLoginUser
	 * @return user
	 */
	public User getLoginUser() {
		return (User)getRequest().get(REQ.USER);
	}

	/**
	 * setLoginUser
	 * @param user user
	 */
	public void setLoginUser(User user) {
		user.setLoginTime(System.currentTimeMillis());

		Map<String, Object> m = UserMetaData.getInstance().getDataProperties(user);
		m.remove(UserMetaData.PN_INVALID);
		m.remove(UserMetaData.PN_UUSID);
		m.remove(UserMetaData.PN_UTIME);

		String ticket = StringEncrypts.encrypt(Jsons.toJson(m));
		String cookiePath = StrutsContextUtils.getServletContext().getContextPath() + "/";
		
		Cookie c = new Cookie(COOKIE.USER_TICKET, ticket);
		if (Boolean.TRUE.equals(user.getAutoLogin())) {
			c.setMaxAge(COOKIE.USER_TICKET_AGE);
		}
		c.setPath(cookiePath);

		StrutsContextUtils.getServletResponse().addCookie(c);

		getRequest().put(REQ.USER, user);
	}

	/**
	 * removeLoginUser
	 */
	public void removeLoginUser() {
		getRequest().remove(REQ.USER);

		HttpServletResponse res = StrutsContextUtils.getServletResponse();
		String cookiePath = StrutsContextUtils.getServletContext().getContextPath() + "/";
		
		HttpServletUtils.removeCookie(
			res, 
			COOKIE.USER_TICKET,
			cookiePath);

		if (log.isDebugEnabled()) {
			log.debug("remove cookie: " 
					+ COOKIE.USER_TICKET 
					+ " "
					+ cookiePath);
		}
	}

	/**
	 * @param user user 
	 * @param das data access session
	 */
	public void setUserGroupInfo(User user, DaoSession das) {
		if (user.getGroupId() != null) {
			UserGroupDAO ugdao = new UserGroupDAO(das);
			UserGroup ug = ugdao.fetch(user.getGroupId());
			if (ug != null) {
				user.setGroupLevel(ug.getLevel());
				user.setGroupPermits(ug.getPermits());
			}
		}
	}

	/**
	 * hasPermission
	 * @param namespace namespace
	 * @param action action
	 * @return true if action has access permit
	 */
	public boolean hasPermission(String namespace, String action) {
		try {
			User user = getLoginUser();
			if (user == null) {
				return false;
			}

			return UserAuthenticationInterceptor.hasPermission(user, namespace, action);
		}
		catch (Exception ex) {
			return false;
		}
	}

	/**
	 * @return app version
	 */
	public String getAppVersion() {
		return WebApplet.get().getAppVersion();
	}
	
	/**
	 * @param key key
	 * @return the property
	 */
	public String getAppProperty(String key) {
		return WebApplet.get().getProperty(key);
	}
	
	/**
	 * @param key key
	 * @param def default value
	 * @return the property
	 */
	public String getAppProperty(String key, String def) {
		return WebApplet.get().getProperty(key, def);
	}
	
	/**
	 * @return true if database resource loader is activated
	 */
	public boolean isDatabaseResourceLoader() {
		return WebApplet.get().getDatabaseResourceLoader() != null;
	}
	
	/**
	 * @return true if database template loader is activated
	 */
	public boolean isDatabaseTemplateLoader() {
		return WebApplet.get().getDatabaseTemplateLoader() != null;
	}
	
	/**
	 * @return true if gae support
	 */
	public boolean isGaeSupport() {
		return WebApplet.isGaeSupport();
	}

	public void addEmailCc(Email email, String cc) throws EmailException {
		for (String s : splitMail(cc)) {
			email.addCc(s);
		}
	}
	
	public void addEmailBcc(Email email, String bcc) throws EmailException {
		for (String s : splitMail(bcc)) {
			email.addBcc(s);
		}
	}
	
	public Collection<String> splitMail(String str) {
		Set<String> ms = new HashSet<String>();
		
		String[] ss = Strings.split(str, " \r\n\t,;\u3000");
		if (ss != null) {
			ms.addAll(Arrays.asList(ss));
		}

		return ms; 
	}

	/**
	 * send email
	 * @param email email
	 * @param name template name
	 * @param context context
	 */
	public void sendTemplateMail(Email email, String name,
			Object context) throws TemplateException, IOException, EmailException {
		ValueStack vs = ContextUtils.getValueStack();
		if (context != null) {
			vs.push(context);
		}
		
		try {
			sendTemplateMail(email, name);
		}
		finally {
			if (context != null) {
				vs.pop();
			}
		}
	}

	/**
	 * send email
	 * @param email email
	 * @param name template name
	 */
	public void sendTemplateMail(Email email, String name)
			throws TemplateException, IOException, EmailException {
		
		String subject = "";
		String content = FreemarkerUtils.processTemplate(name);

		int cr = content.indexOf('\n');
		if (cr > 0) {
			subject = Strings.strip(content.substring(0, cr));
			content = content.substring(cr + 1);
		}

		email.setSubject(subject);
		if (email instanceof HtmlEmail) {
			((HtmlEmail)email).setHtmlMsg(content);
		}
		else {
			email.setMsg(content);
		}

		sendMail(email);
	}
	
	/**
	 * send email
	 * @param email email
	 * @throws EmailException if an email error occurs
	 */
	public void sendMail(Email email) throws EmailException {
		try {
			String debug = getAppProperty(GC.MAIL_DEBUG);
			if ("true".equals(debug)) {
				email.setDebug(true);
			}

			String charset = getAppProperty(GC.MAIL_CHARSET, "");
			if (Strings.isNotEmpty(charset)) {
				email.setCharset(charset);
			}

			email.setFrom(getAppProperty(GC.MAIL_FROM_MAIL), 
				getAppProperty(GC.MAIL_FROM_NAME));

			String host = getAppProperty(GC.MAIL_SMTP_HOST, "");
			if (Strings.isNotEmpty(host)) {
				email.setHostName(host);
			}
			
			String port = getAppProperty(GC.MAIL_SMTP_PORT);
			if (Strings.isNumeric(port)) {
				email.setSmtpPort(Integer.parseInt(port));
			}

			String ssl = getAppProperty(GC.MAIL_SMTP_SSL);
			if ("true".equals(ssl)) {
				email.setSSL(true);
				if (Strings.isNumeric(port)) {
					email.setSslSmtpPort(port);
				}
			}
			
			String tls = getAppProperty(GC.MAIL_SMTP_TLS);
			if ("true".equals(tls)) {
				email.setTLS(true);
			}
			
			String username = getAppProperty(GC.MAIL_SMTP_USER, "");
			if (Strings.isNotEmpty(username)) {
				email.setAuthentication(username, getAppProperty(GC.MAIL_SMTP_PASSWORD, ""));
			}
			
			String bounce = getAppProperty(GC.MAIL_SMTP_BOUNCE, "");
			if (Strings.isNotEmpty(bounce)) {
				email.setBounceAddress(bounce);
			}

			SendMail.send(email);
		}
		catch (EmailException e) {
			log.warn("send mail failed!", e);
			throw e;
		}
	}

	/**
	 * ignore email exception
	 * @return true if mail-exception is set to warn/ignore
	 */
	public boolean ignoreEmailException() {
		String iee = getAppProperty(GC.MAIL_EXCEPTION, "");
		
		if ("warn".equals(iee) || "ignore".equals(iee)) {
			return true;
		}
		
		return false;
	}

	/**
	 * send email
	 * @param user user 
	 * @param name template name
	 * @param context context object
	 * @throws IOException io error 
	 * @throws TemplateException  template error
	 * @throws EmailException  email error
	 */
	public void sendTemplateMail(User user, String name,
			Object context) throws TemplateException, IOException, EmailException {
		SimpleEmail email = new SimpleEmail();

		email.addTo(user.getEmail(), user.getName());
		
		sendTemplateMail(email, name, context);
	}

	/**
	 * send email
	 * @param user user
	 * @param name template name
	 * @throws IOException io error 
	 * @throws TemplateException  template error
	 * @throws EmailException  email error
	 */
	public void sendTemplateMail(User user, String name)
			throws TemplateException, IOException, EmailException {
		SimpleEmail email = new SimpleEmail();

		email.addTo(user.getEmail(), user.getName());
		
		sendTemplateMail(email, name);
	}
}
