package eu.dnetlib.server;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import org.apache.shiro.session.Session;
import org.apache.shiro.subject.Subject;
import org.springframework.stereotype.Service;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;

import com.google.gwt.user.server.rpc.RemoteServiceServlet;

import eu.dnetlib.client.LoginService;
import eu.dnetlib.efg1914.authoring.managers.UserManager;
import eu.dnetlib.efg1914.authoring.managers.UserManagerException;
import eu.dnetlib.efg1914.authoring.users.User;
import eu.dnetlib.efg1914.commons.store.XMLStoreException;

/**
 * The server side implementation of the RPC service.
 */
@SuppressWarnings("serial")
@Service("LoginService")
public class LoginServiceImpl extends RemoteServiceServlet implements LoginService {
	private transient org.apache.log4j.Logger log = org.apache.log4j.Logger.getLogger(LoginServiceImpl.class);

	private UserManager userManager = null;

	private WebApplicationContext context = null;

	public LoginServiceImpl() {

	}

	public String login(String username, String password, boolean RememberMe) throws XMLStoreException {

		try {
			context = WebApplicationContextUtils.getWebApplicationContext(getServletContext());
			if (context == null) {
				log.error("WebApplicationContex  null on login");
				throw new XMLStoreException("WebApplicationContex  null on login");
			}

			userManager = (UserManager) context.getBean("userManager");

			if (userManager == null) {
				log.error("userManager  null on login");
				throw new XMLStoreException("userManager  null on login");
			}

			User u = userManager.login(username, password, RememberMe);

			if (u == null) {
				log.error("user not authenticated");

				throw new XMLStoreException("user not authenticated");
			}

			Subject shiroSubject = userManager.get_subject(username);

			Session shiroSession = userManager.get_session(u);

			shiroSession.setTimeout(((12*60* 60 * 1000)+(2* 60 * 1000)));

			log.info("user  tokens " + shiroSubject.getPrincipals());
			// create session and store userid

			HttpServletRequest request = this.getThreadLocalRequest();
			HttpSession session = request.getSession(true);

			session.setAttribute("UserID", u);
			session.setAttribute("shiroSession", shiroSession);
			session.setAttribute("shiroSubject", shiroSubject);

			// Specifies the time, in seconds, between client requests before
			// the servlet container will invalidate
			// this session. A negative time indicates the session should never
			// timeout.
            //in seconds
			session.setMaxInactiveInterval(12*60*60);
			log.info("&&&&&&&&&&&&&&&&& session tMaxInactiveInterval:::: " + session.getMaxInactiveInterval());
			return session.getId();

		} catch (UserManagerException e) {
			e.printStackTrace();
			log.warn(e);
			throw new XMLStoreException(e);

		}
	}

	public boolean checkLogin() throws XMLStoreException {
		context = WebApplicationContextUtils.getWebApplicationContext(getServletContext());
		if (context == null) {
			throw new XMLStoreException("WebApplicationContex  null on checkLogin");
		}

		userManager = (UserManager) context.getBean("userManager");
		if (userManager == null) {
			throw new XMLStoreException("userManager  null on checkLogin");
		}

		HttpServletRequest request = this.getThreadLocalRequest();
		// dont create a new one -> false
		HttpSession session = request.getSession(false);

		if (session == null || session.getAttribute("UserID") == null) {
			return false;
		}

		Subject subj = (Subject) session.getAttribute("shiroSubject");
		if (subj != null && subj.isAuthenticated()) {
			return true;
		} else {
			return false;
		}

	}

	public User getUser() {

		User user = null;
		HttpServletRequest httpServletRequest = this.getThreadLocalRequest();
		HttpSession session = httpServletRequest.getSession();
		Object userObj = session.getAttribute("UserID");
		if (userObj != null && userObj instanceof User) {
			user = (User) userObj;
		}
		if (userObj == null) {
			log.warn("User not set in session");
		}

		return user;
	}

	public void logout() throws XMLStoreException {
		context = WebApplicationContextUtils.getWebApplicationContext(getServletContext());
		if (context == null) {
			throw new XMLStoreException("WebApplicationContex  null on logout");
		}
		userManager = (UserManager) context.getBean("userManager");
		if (userManager == null) {
			throw new XMLStoreException("userManager  null on logout");
		}

		HttpServletRequest request = this.getThreadLocalRequest();
		// dont create a new one -> false
		HttpSession session = request.getSession(false);
		// Subject subj = (Subject) session.getAttribute("shiroSubject");
		// subj.logout();

		if (session != null) {
			Object userObj = session.getAttribute("UserID");
			if (userObj != null && userObj instanceof User) {
				User user = (User) userObj;
				try {
					userManager.logout(user.getUsername(), user.getPassword());

				} catch (UserManagerException e) {
					log.warn(e);
					throw new XMLStoreException(e);

				}
			}
			session.invalidate();

		}

	}

	public boolean isValid() {
		HttpServletRequest request = this.getThreadLocalRequest();
		// dont create a new one -> false
		if (request != null) {
			HttpSession session = request.getSession(false);
			if (session != null) {
				Object userObj = session.getAttribute("UserID");
				if (userObj != null && userObj instanceof User) {
					long time=System.currentTimeMillis();
					log.info("&&&&&&&&&&&&&&&&& session tMaxInactiveInterval:::: " + session.getMaxInactiveInterval());
					log.info("&&&&&&&&&&&&&&&&& session create:::: " + ( session.getCreationTime()));
					log.info("&&&&&&&&&&&&&&&&& session last access:::: " + ( session.getLastAccessedTime()));
					log.info("&&&&&&&&&&&&&&&&& session current time:::: " + ( time));
					log.info("&&&&&&&&&&&&&&&&& session   diff:::: " + ( time- session.getLastAccessedTime()));

					return true;
				}
			}
		}
		return false;
	}
 	public int getSessionMaxInterval() {
		HttpServletRequest request = this.getThreadLocalRequest();
		// dont create a new one -> false
		if (request != null) {
			HttpSession session = request.getSession(false);
			if (session != null) {
				Object userObj = session.getAttribute("UserID");
				if (userObj != null && userObj instanceof User) {
				
					return session.getMaxInactiveInterval()*1000;
				}
			}
		}
		return 12*60*60*1000;
	}
}