package zall.bean;

import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.List;

import zall.manager.AuthenticationManager;
import zutil.Hasher;
import zutil.db.DBConnection;
import zutil.db.bean.DBBean;
import zutil.db.bean.DBBeanSQLResultHandler;
import zutil.db.bean.DBBean.*;

@DBTable("User")
public class User extends DBBean {

    public enum AuthType {
        USER_INPUT, COOKIE
    }

    protected String name;
    protected String email;
    protected boolean emailVerified;
    protected String passwordHash;
    protected String passwordSalt;
    // Date
    protected Timestamp loginDate;
    // security
    protected transient AuthType authBy;
    protected String ipHost;
    protected String cookieHash;

    protected boolean superUser;
    protected boolean enabled;


    public static User load(DBConnection db, Long id) throws SQLException {
        return load(db, User.class, id);
    }

    public static List<User> load(DBConnection db) throws SQLException {
        PreparedStatement sql = db.getPreparedStatement("SELECT * FROM User");
        return DBConnection.exec(sql, DBBeanSQLResultHandler.createList(User.class, db));
    }

    /**
     * Uses normal user and password to get user object,
     * this function will save the bean
     *
     * @return the user object or null if non where found
     */
    public static User load(DBConnection db, String email) throws SQLException {
        PreparedStatement sql = db.getPreparedStatement(
                "SELECT * FROM User WHERE email=? LIMIT 1");
        sql.setString(1, email);

        User user = DBConnection.exec(sql, DBBeanSQLResultHandler.create(User.class, db));
        return user;
    }

    public static List<User> loadSuperUsers(DBConnection db) throws SQLException {
        PreparedStatement sql = db.getPreparedStatement(
                "SELECT * FROM User WHERE superUser=1");
        return DBConnection.exec(sql, DBBeanSQLResultHandler.createList(User.class, db));
    }

    /**
     * Uses a cookie value to get the user object,
     * this function will save the bean
     *
     * @return the user object or null if non where found
     */
    public static User loadByCookieHash(DBConnection db, String hash) throws SQLException {
        PreparedStatement sql = db.getPreparedStatement(
                "SELECT * FROM User WHERE cookieHash=? LIMIT 1");
        sql.setString(1, hash);

        return DBConnection.exec(sql, DBBeanSQLResultHandler.create(User.class, db));
    }


    public User() {
        // Default values
        emailVerified = false;
        superUser = false;
        enabled = false;
    }

    public boolean verifyEmail(String hash) {
        return emailVerified = generateEmailVerificationHash().equals(hash);
    }

    public String generateEmailVerificationHash() {
        return Hasher.MD5("##helloWorld-->2011" + email + name + passwordHash);
    }


    public Timestamp getLoginDate() {
        if (loginDate == null)
            loginDate = new Timestamp(0);
        return loginDate;
    }

    public void setLoginDate(Timestamp loginDate) {
        this.loginDate = loginDate;
    }

    public void setAuthBy(AuthType authBy) {
        this.authBy = authBy;
    }

    public AuthType getAuthBy() {
        return authBy;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        if (this.email != null && this.email.equals(email))
            return;
        emailVerified = false;
        this.email = email;
    }

    public boolean isEmailVerified() {
        return emailVerified;
    }

    public void setEmailVerified(boolean verified) {
        this.emailVerified = verified;
    }

    public String getPasswordHash() {
        return passwordHash;
    }

    public void setPassword(String password) {
        String newPasswordSalt = Hasher.SHA1(Math.random()).substring(0, 5);
        String newPasswordHash = AuthenticationManager.generatePasswordHash(password, newPasswordSalt);

        // We wait with setting the actual fields if there is an exception
        this.passwordSalt = newPasswordSalt;
        this.passwordHash = newPasswordHash;
    }

    public String getPasswordSalt() {
        return passwordSalt;
    }

    public String getCookieHash() {
        return cookieHash;
    }

    public void setCookieHash(String cookieHash) {
        this.cookieHash = cookieHash;
    }

    public String getIpHost() {
        return ipHost;
    }

    public void setIpHost(String ipHost) {
        this.ipHost = ipHost;
    }

    public boolean isSuperUser() {
        return superUser;
    }

    public void setSuperUser(boolean superUser) {
        this.superUser = superUser;
    }

    public boolean isEnabled() {
        return enabled;
    }

    public void setEnabled(boolean enabled) {
        this.enabled = enabled;
    }

    public boolean equals(User u) {
        return u != null && getId().equals(u.getId());
    }

}
