/**
 * $Id: UserHelper.java,v 1.12 2008/02/12 09:34:08 korowa Exp $
 *
 * Copyright (c) Siemens AG 2008 
 *           (c) Universität Paderborn 2008 
 * Licensed under EUPL 1.1. 
 */

package vkc.db.helper;

import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Timestamp;
import java.util.Date;
import java.util.HashMap;

import javax.servlet.http.HttpServletRequest;

import vkc.db.entities.VKCUser;
import vkc.db.entities.VKCCategory;
import vkc.db.entities.VKCDocument;
import vkc.db.serializer.VKCSysParameterSerializer;
import vkc.db.serializer.VKCUserSerializer;
import vkc.exception.DBException;
import vkc.exception.DisabledUserAccountException;
import vkc.exception.MaxAllowedUsersExceededException;
import vkc.exception.PasswordMismatchException;
import vkc.exception.UnknownUserException;
import vkc.exception.UserAccountNotEnabledException;
import vkc.misc.MailUtils;
import vkc.misc.TemplateParser;
import vkc.misc.VKCLogManager;
import vkc.util.DateUtils;
import vkc.util.ServletUtils;
import vkc.util.VKCCoder;
import vkc.util.VKCStringUtils;
import vkc.view.WebShare;
import vkc.view.bean.ResourceInfo;
import vkc.view.bean.UserStatistics;

public class UserHelper {
    /**
     * Authentifizierung
     *
     * @param username
     * @param password
     * @param request
     * @return
     * @throws UnknownUserException
     * @throws DisabledUserAccountException
     * @throws PasswordMismatchException
     * @throws UnsupportedEncodingException
     * @throws NoSuchAlgorithmException
     * @throws MaxAllowedUsersExceededException 
     * @throws UserAccountNotEnabledException 
     */
    public static VKCUser authenticate(String username, String password, HttpServletRequest request)
        throws UnknownUserException,
                DisabledUserAccountException,
                PasswordMismatchException,
                UnsupportedEncodingException,
                NoSuchAlgorithmException,
                DBException, 
                MaxAllowedUsersExceededException,
                UserAccountNotEnabledException {
        int maxAllowedUsers = VKCSysParameterSerializer.retrieveIntValue("LOGIN", "MaxAllowedUsers", 0);
        int activeUsersCount = WebShare.getActiveUsers().length;
        
        if (maxAllowedUsers > 0 && activeUsersCount >= maxAllowedUsers) {
            //Maximale Anzahl an erlaubten Benutzer wurde überschritten
            throw new MaxAllowedUsersExceededException("The maximum number of allowed users in VKC exceeded");
        }

        VKCUser user = VKCUserSerializer.retrieveUser(username);

        if (user == null) {
            // kein Benutzkonto unter dem Namen bekannt
            throw new UnknownUserException(username + " is unknown!");
        }

        if (user.getValidFrom()!= null && user.getValidFrom().after(new Date())) {
            // Benutzerkontoaktivierung liegt in der Zukunft
            String zeitPunkt = user.getValidFrom().toString();
            throw new UserAccountNotEnabledException(zeitPunkt.substring(0,zeitPunkt.indexOf('.') ));
        }
        
        if (!user.isUserValid()) {
            // Benutzerkonto ist deaktiviert
            throw new DisabledUserAccountException("Account of " + username + " is disabled!");
        }

        // MD5 Passwort liegt vor
        byte[] md5Bytes = (username + password).getBytes("ISO-8859-1");

        MessageDigest digest = MessageDigest.getInstance("MD5");
        digest.reset();
        digest.update(md5Bytes);

        byte[] fingerPrint = digest.digest();
        fingerPrint = VKCCoder.base64Encode(fingerPrint);

        String md5Password = new String(fingerPrint, "ISO-8859-1");

        if (!md5Password.equals(user.getPassword().trim())) {
            // Falsche Passworteingabe
			if (VKCSysParameterSerializer.retrieveIntValue("LOGIN", "UserLockEnabled", 1) != 0) {
	        	int count = user.getPwdMismatchCount().intValue() + 1;
	        	int maxCount = VKCSysParameterSerializer.retrieveIntValue("LOGIN", "MaxPwdMismatchCount", 0);
	        	long cms = System.currentTimeMillis();
	        	VKCUserSerializer.setUserPwdMismatchCount(user.getUserId(), new Integer(count));
	        	VKCUserSerializer.setUserValidFrom(user.getUserId(), new Timestamp(cms + (count * count * count * 10 * 1000)));
	        	user.setValidFrom(new Timestamp(cms + (count * count * count * 10 * 1000)));
//	        	if (count > maxCount) {
//	        		long hours = VKCSysParameterSerializer.retrieveIntValue("LOGIN", "UserLockTime", 0);
//	        		long cms = System.currentTimeMillis();
//	        		
//	        		if (hours > 0) {
//	        			VKCUserSerializer.setUserValidFrom(user.getUserId(), new Timestamp(cms + (hours * 60 * 60 * 1000)));
//	        			user.setValidFrom(new Timestamp(cms + (hours * 60 * 60 * 1000)));
//	        			
//	        			if (VKCSysParameterSerializer.retrieveIntValue("LOGIN", "UserLockNotification", 0) != 0) {
//	            			sendUserLockMail("temporarily", user, new Timestamp(cms));
//	        			}
//	        		} else {
//	        			VKCUserSerializer.disableUser(user.getUserId());
//	        			user.setAccountValid(false);
//
//	        			if (VKCSysParameterSerializer.retrieveIntValue("LOGIN", "UserLockNotification", 0) != 0) {
//	            			sendUserLockMail("permanently", user, new Timestamp(cms));
//	        			}
//	        		}
//	        		
//	                String log = user.getLastnameLabel();
//	                log += " locked automaticlly ( " + "userId = " +  user.getUserId() + " ) at " + new Timestamp(cms);
//	        		log += " - Remotehost = " + request.getRemoteHost() + " - Remoteaddress = " + request.getRemoteAddr();
//	        		VKCLogManager.infoLog(UserHelper.class, log);
//	                
//	        		throw new DisabledUserAccountException("Account of " + username + " is disabled!");
//	        	}
			}
			String zeitPunkt = ".";
			if (VKCSysParameterSerializer.retrieveIntValue("LOGIN", "UserLockEnabled", 1) != 0) {
			    zeitPunkt = user.getValidFrom().toString();            
			}
        	throw new PasswordMismatchException(zeitPunkt.substring(0,zeitPunkt.indexOf('.')));
        }

        user.setClearPassword(password);

//		if (VKCSysParameterSerializer.retrieveIntValue("LOGIN", "UserLockEnabled", 1) != 0) {
	        user.setPwdMismatchCount(new Integer(0));
	    	VKCUserSerializer.setUserPwdMismatchCount(user.getUserId(), new Integer(0));
//		}
        
        return user;
    }

    private static void sendUserLockMail(String type, VKCUser user, Timestamp loginAttempt) {
		try {
			String senderAddr  = VKCSysParameterSerializer.retrieveValue("MAIL", "AdminEmail", "");
			String smtpServer  = VKCSysParameterSerializer.retrieveValue("MAIL", "MailServer", "");
			String smtpUsername  = VKCSysParameterSerializer.retrieveValue("MAIL", "MailUsername", "");
			String smtpPassword  = VKCSysParameterSerializer.retrieveValue("MAIL", "MailPassword", "");
			String vkc_rootURL = WebShare.getRootURL() + WebShare.getContextPath();
			String subject     = WebShare.resources.getMessage( user.getLanguage().getLocale(), "vkc.lockuser");
			String recepient   = VKCStringUtils.decodeXmlEntities(user.getEmail());

			TemplateParser asciiTemplate = TemplateParser.getTemplateParser();
			TemplateParser htmlTemplate = TemplateParser.getTemplateParser();
			
			HashMap context = new HashMap();
			context.put("adminEmail", senderAddr);
			context.put("homepage", vkc_rootURL);
			context.put("lockuser", user);
			context.put("fullname", VKCStringUtils.filterUnicodeChars(user.getFirstname() + " " + user.getLastname()));
			context.put("loginAttempt", loginAttempt);
			context.put("dateutils", new DateUtils());
			context.put("resources", new ResourceInfo(WebShare.resources, user.getLanguage().getLocale()));
			context.put("vkcstringutils", new VKCStringUtils());
			context.put("template", user.getTemplate().getName());
	
			asciiTemplate.setContextData(context);
			htmlTemplate.setContextData(context);
            
			String asciiText = "";
			String htmlText = "";
			String asciiPath = "";
			String htmlPath = "";
			

			if ("permanently".equals(type)) {
				asciiPath = "templates/${template.name}/velocitytemplates/mail/lockuser_permanently_notification.plain";
				htmlPath = "templates/${template.name}/velocitytemplates/mail/lockuser_permanently_notification.html";
			} else if ("temporarily".equals(type)) {
				asciiPath = "templates/${template.name}/velocitytemplates/mail/lockuser_temporarily_notification.plain";
				htmlPath = "templates/${template.name}/velocitytemplates/mail/lockuser_temporarily_notification.html";
			}

			asciiText = asciiTemplate.createString(ServletUtils.replacePathVars(asciiPath, user));
			htmlText = htmlTemplate.createString(ServletUtils.replacePathVars(htmlPath, user));
			
			MailUtils m = new MailUtils(user);
            if(user.isEnableHtmlNotification())m.sendSMTPMailWithVKCLogo(senderAddr, recepient, subject, asciiText, htmlText, null, null, smtpServer, smtpUsername, smtpPassword);
            else m.sendSMTPMail(senderAddr, recepient, subject, asciiText, null, null, null, smtpServer, smtpUsername, smtpPassword);
		} catch (Exception e) {
			VKCLogManager.errorLog(UserHelper.class, "1", " - email sending failes: " + e.getMessage(),e);
		}
	}

	public final static UserStatistics getUserStatistics(Integer userId) throws DBException {
        Connection conn = null;

        try {
            conn = WebShare.database.getConnection();

            return getUserStatistics(userId, conn);
        } catch (Exception e) {
            e.printStackTrace();
            throw new DBException(e);
        } finally {
            DBHelper.close(conn);
        }
    }

    public final static UserStatistics getUserStatistics(Integer userId, Connection c ) throws DBException {
        PreparedStatement stmt1 = null;
        PreparedStatement stmt2 = null;
        ResultSet rs1 = null;
        ResultSet rs2 = null;
        UserStatistics statistics = new UserStatistics();
        statistics.setUserId( userId );

        try {
            // count of number of published documents by the user
            // consider only those which are marked as "published"
            // because otherwise documents in trash of given user would be counted
            String sqlStmt = "SELECT COUNT(publisherId) AS COUNT_PUB_DOCS " +
                             "  FROM documents " +
                             " WHERE publisherId = ? " +
                             "   AND documents.flag = " + VKCDocument.FLAG_PUBLISHED;
            stmt1 = c.prepareStatement(sqlStmt);
            stmt1.setInt(1, userId.intValue());
            rs1 = stmt1.executeQuery();
            rs1.next();
            statistics.setNumPublishedDocuments(rs1.getInt("COUNT_PUB_DOCS"));

            // count of all created categories
            // consider only those which are marked as "published"
            // because otherwise categories in trash of given user would be counted
            sqlStmt = "SELECT COUNT(creatorId) AS COUNT_CREATED_CATS " +
                      "  FROM categories " + 
                      " WHERE creatorId = ? " +
                      "   AND (categories.flag = " + VKCCategory.FLAG_CREATED  + " OR categories.flag = " + VKCCategory.FLAG_ACTIVE + ")"; 
            stmt2 = c.prepareStatement(sqlStmt);
            stmt2.setInt(1, userId.intValue());
            rs2 = stmt2.executeQuery();
            rs2.next();
            statistics.setNumCreatedCategories(rs2.getInt("COUNT_CREATED_CATS"));

            return statistics;
        } catch (Exception e) {
            throw new DBException(e);
        } finally {
            DBHelper.close(rs1);
            DBHelper.close(rs2);
            DBHelper.close(stmt1);
            DBHelper.close(stmt2);
        }
    }
}