class SecurityServiceImpl extends RemoteServiceServlet implements SecurityService {

	@Override
	public GUIUser saveUser(GUIUser user, GUIInfo info) throws ServerException {
		Session session = ServiceUtil.validateSession(getThreadLocalRequest());

		UserDAO userDao = (UserDAO) Context.get().getBean(UserDAO.class);
		boolean createNew = false;
		String decodedPassword = "";

		try {
			// Disallow the editing of other users if you do not have access to
			// the Security
			if (user.getId() != session.getUserId() && getThreadLocalRequest() != null)
				ServiceUtil.checkMenu(getThreadLocalRequest(), Menu.SECURITY);

			User usr;
			if (user.getId() != 0) {
				usr = userDao.findById(user.getId());
				userDao.initialize(usr);
			} else {
				usr = new User();
				createNew = true;
			}

			usr.setTenantId(session.getTenantId());
			usr.setCity(user.getCity());
			usr.setCountry(user.getCountry());
			usr.setEmail(user.getEmail());
			usr.setEmail2(user.getEmail2());
			usr.setFirstName(user.getFirstName());
			usr.setName(user.getName());
			usr.setLanguage(user.getLanguage());
			usr.setPostalcode(user.getPostalCode());
			usr.setState(user.getState());
			usr.setStreet(user.getAddress());
			usr.setTelephone(user.getPhone());
			usr.setTelephone2(user.getCell());
			usr.setUsername(user.getUsername());
			usr.setEnabled(user.isEnabled() ? 1 : 0);
			usr.setPasswordExpires(user.isPasswordExpires() ? 1 : 0);
			usr.setPasswordExpired(user.isPasswordExpired() ? 1 : 0);
			usr.setWelcomeScreen(user.getWelcomeScreen());
			usr.setIpWhiteList(user.getIpWhitelist());
			usr.setIpBlackList(user.getIpBlacklist());
			usr.setEmailSignature(user.getEmailSignature());
			usr.setDefaultWorkspace(user.getDefaultWorkspace());
			usr.setQuota(user.getQuota());
			usr.setSecondFactor(StringUtils.isEmpty(user.getSecondFactor()) ? null : user.getSecondFactor());
			usr.setKey(user.getKey());
			usr.setType(user.getType());
			usr.setDocsGrid(user.getDocsGrid());
			usr.setHitsGrid(user.getHitsGrid());

			if (createNew) {
				User existingUser = userDao.findByUsername(user.getUsername());
				if (existingUser != null) {
					log.warn("Tried to create duplicate username {}", user.getUsername());
					user.setWelcomeScreen(-99);
					return user;
				}

				// Generate an initial password(that must be changed)
				ContextProperties pbean = Context.get().getProperties();
				int minsize = 8;
				try {
					minsize = pbean.getInt(session.getTenantName() + ".password.size");
				} catch (Throwable t) {

				}
				decodedPassword = PasswordGenerator.generate(minsize);
				usr.setDecodedPassword(decodedPassword);
				usr.setPasswordExpired(1);
				usr.setPasswordChanged(new Date());
			}

			UserHistory transaction = new UserHistory();
			transaction.setSession(session);
			transaction.setEvent(UserEvent.UPDATED.toString());
			boolean stored = userDao.store(usr, transaction);
			if (!stored)
				throw new Exception("User not stored");
			user.setId(usr.getId());

			GroupDAO groupDao = (GroupDAO) Context.get().getBean(GroupDAO.class);
			usr.removeGroupMemberships(null);
			long[] ids = new long[user.getGroups().length];
			for (int i = 0; i < user.getGroups().length; i++) {
				ids[i] = user.getGroups()[i].getId();
				usr.addGroup(groupDao.findById(ids[i]));
			}
			userDao.store(usr);

			Group adminGroup = groupDao.findByName("admin", session.getTenantId());
			groupDao.initialize(adminGroup);

			// The admin user must be always member of admin group
			if ("admin".equals(user.getUsername()) && !user.isMemberOf("admin")) {
				usr.addGroup(adminGroup);
				userDao.store(usr);
			}

			// Notify the user by email
			if (createNew && user.isNotifyCredentials())
				try {
					notifyAccount(usr, decodedPassword);
				} catch (Throwable e) {
					log.warn(e.getMessage(), e);
				}

			return getUser(user.getId());
		} catch (Throwable t) {
			return (GUIUser) ServiceUtil.throwServerException(session, log, t);
		}
	}

}