package org.wikiwebserver.util;

import java.util.StringTokenizer;


public class Validator {
    
    public static String validateEmail(String email) throws ValidationError, ValidationWarning {
        if (email == null || email.length() == 0) {
            throw new ValidationError("Email address required");
        }        
        
        int atIdx = email.indexOf('@');
        if (atIdx == -1) {
            throw new ValidationError("Invalid email address (missing @)");
        } else if (atIdx == 0) {
            throw new ValidationError("Invalid email address (missing username)");
        } else if (email.indexOf('@', atIdx+1) > -1) {
            throw new ValidationError("Invalid email address (too many @s)");
        } else if (email.indexOf("..", atIdx) > -1) {
            throw new ValidationError("Invalid email address (multiple sequential periods)");
        }     
        
               
        validateUserName(email.substring(0, atIdx));
        validateDomainName(email.substring(atIdx+1));
        
        if (email.length() > 64) {
            throw new ValidationError("An email address can not be over 64 characters");
        }  
        
        return null;
    }    
    
    public static void validateWebAddress(String address) throws ValidationError, ValidationWarning {
        if (address == null || address.length() == 0) {
            throw new ValidationError("Web address required");
        }  
        
        if (!address.startsWith("http://") && !address.startsWith("https://")) {
            throw new ValidationError("A web address must start with http:// or https://");
        }
        
        int idx = address.indexOf("://");
        if (address.length() < idx+3) {
            throw new ValidationError("Missing domain name");
        }
        
        String domain = address.substring(idx+3);
        if (domain.startsWith(".")) {
            throw new ValidationError("A domain can not start with a period");
        }
        
        String path = domain;
        idx = domain.indexOf("/");
        if (idx > 0) {
            domain = domain.substring(0, idx);
            if (idx+1 >= path.length()) {
                path = path.substring(idx+1);
            }
        }
        
        validateDomainName(domain);
    }     
    
    public static void validateUserName(String name) throws ValidationError, ValidationWarning {
        if (name == null || name.length() == 0) {
            throw new ValidationError("No username specified");
        } else if (name.startsWith(".")) {
            throw new ValidationError("Username can not start with a period");
        } else if (name.endsWith(".")) {
            throw new ValidationError("Username can not end with a period");
        }         
        
        for (int i=0; i<name.length(); i++) {
            int c = name.charAt(i);
            if (!(c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' ||
                  c >= '0' && c <= '9' || c == '-' || c == '.' ||
                  c == '_')) {
                throw new ValidationError("Invalid character in username (code: " + c + ")");
            }
        }
    }
    
    public static void validateDomainName(String name) throws ValidationError, ValidationWarning {
        if (name == null || name.length() == 0) {
            throw new ValidationError("No domain specified");
        } else if (name.startsWith(".")) {
            throw new ValidationError("Domain can not start with a period");
        } else if (name.endsWith(".")) {
            throw new ValidationError("Domain can not end with a period");
        } else if (name.indexOf('.') == -1) {
            throw new ValidationError("Domain suffix expected");
        }         
        
        for (int i=0; i<name.length(); i++) {
            int c = name.charAt(i);
            if (!(c >= 'a' && c <= 'z' || c >= '0' && 
                  c <= '9' || c == '-' || c == '.')) {
                throw new ValidationError("Invalid character in domain (code: " + c + ")");
            }
        }
    }
    
    public static void validatePassword(String password) throws ValidationError, ValidationWarning {
        
        if (password == null || password.length() == 0) {
            throw new ValidationError("Password required");
        } else if (password.length() < 8) {
            throw new ValidationError("Password must be at least 8 characters");
        } else if (!containsNumbers(password)) {
            throw new ValidationWarning("Tip: Add numbers to increase security");
        } else if (!containsUppercase(password)) {
            throw new ValidationWarning("Tip: Add upper case characters to increase security");
        } else if (!containsLowercase(password)) {
            throw new ValidationWarning("Tip: Add lower case characters to increase security");
        }
    }        
    
    public static boolean containsNumbers(String value) {
        for (char c : value.toCharArray()) {
            if (c >= '0' && c <= '9') return true;
        }
        return false;
    }  
    
    public static boolean containsUppercase(String value) {
        for (char c : value.toCharArray()) {
            if (c >= 'A' && c <= 'Z') return true;
        }
        return false;
    }  
    
    public static boolean containsLowercase(String value) {
        for (char c : value.toCharArray()) {
            if (c >= 'a' && c <= 'z') return true;
        }
        return false;
    }     
    
    public static String upperCaseFirstLetterOfWords(String value) {
        
        if (value == null) return null;
        
        StringBuilder newValue = new StringBuilder();
        StringTokenizer tkn = new StringTokenizer(value, " ");
        
        while (tkn.hasMoreTokens()) {
            String word = tkn.nextToken();
            newValue.append(word.substring(0, 1).toUpperCase());
            newValue.append(word.substring(1));
            if (tkn.hasMoreTokens()) newValue.append(" ");
        }
        
        if (value.endsWith(" ")) newValue.append(" ");
        
        return newValue.toString();
    }
}

