content: // This file is part of AceWiki.
  // Copyright 2008-2013, AceWiki developers.
  // 
  // AceWiki is free software: you can redistribute it and/or modify it under the terms of the GNU
  // Lesser General Public License as published by the Free Software Foundation, either version 3 of
  // the License, or (at your option) any later version.
  // 
  // AceWiki is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
  // even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  // Lesser General Public License for more details.
  // 
  // You should have received a copy of the GNU Lesser General Public License along with AceWiki. If
  // not, see http://www.gnu.org/licenses/.
  
  package ch.uzh.ifi.attempto.acewiki.core;
  
  import java.security.MessageDigest;
  import java.util.ArrayList;
  import java.util.List;
  import java.util.Map;
  import java.util.Set;
  
  import com.google.common.base.Splitter;
  import com.google.common.collect.ImmutableSet;
  
  /**
   * This class represents an AceWiki user.
   * 
   * @author Tobias Kuhn
   */
  public class User {
  
  	private static final Splitter SPLITTER_RIGHTS = Splitter.on(",").omitEmptyStrings().trimResults();
  	
  	private final long id;
  	private String name;
  	private String hashedPw;
  	private Map<String, String> userdata;
  	private final UserBase userBase;
  	
  	/**
  	 * Creates a new user.
  	 * 
  	 * @param id The user id.
  	 * @param name The name of the user.
  	 * @param hashedPw The hashed password.
  	 * @param userdata The user data map.
  	 */
  	User(long id, String name, String hashedPw, Map<String, String> userdata, UserBase userBase) {
  		this.id = id;
  		this.name = name;
  		this.hashedPw = hashedPw;
  		this.userdata = userdata;
  		this.userBase = userBase;
  		save();
  	}
  	
  	/**
  	 * Creates a new user.
  	 * 
  	 * @param id The user id.
  	 * @param name The name of the user.
  	 * @param pw The password in plain text.
  	 * @param userdata The user data map.
  	 * @return The new user object.
  	 */
  	static User createUser(long id, String name, String pw, Map<String, String> userdata, UserBase userBase) {
  		return new User(id, name, getPasswordHash(pw), userdata, userBase);
  	}
  	
  	/**
  	 * Returns the id of the user.
  	 * 
  	 * @return The id.
  	 */
  	public long getId() {
  		return id;
  	}
  	
  	/**
  	 * Returns the name of the user.
  	 * 
  	 * @return The name of the user.
  	 */
  	public String getName() {
  		return name;
  	}
  	
  	/**
  	 * Returns the hashed password.
  	 * 
  	 * @return The hashed password.
  	 */
  	public String getHashedPassword() {
  		return hashedPw;
  	}
  
  	// The rights can be granted by manually editing the users' file and adding a line a la:
  	// rights:all,some,delete_user,edit_grammar
  	public Set<String> getRights() {
  		return ImmutableSet.copyOf(SPLITTER_RIGHTS.split(getUserData("rights")));
  	}
  
  	public boolean hasRight(String right) {
  		Set<String> rights = getRights();
  		if (rights.contains("all")) return true;
  		return rights.contains(right);
  	}
  	
  	/**
  	 * Returns the user data with the given property name.
  	 * 
  	 * @param name The property name.
  	 * @return The data for the respective name.
  	 */
  	public String getUserData(String name) {
  		String value = userdata.get(name);
  		if (value == null) return "";
  		return value;
  	}
  	
  	/**
  	 * Sets the user data element with the respective name.
  	 * 
  	 * @param name The name of the user data element.
  	 * @param value The value to be set.
  	 */
  	public void setUserData(String name, String value) {
  		userdata.put(name, value);
  		save();
  	}
  	
  	/**
  	 * Changes the password for the user.
  	 * 
  	 * @param oldPw The old password in plain text.
  	 * @param newPw The new password in plain text.
  	 */
  	public void changePassword(String oldPw, String newPw) {
  		if (!isCorrectPassword(oldPw)) return;
  		hashedPw = getPasswordHash(newPw);
  		save();
  	}
  	
  	/**
  	 * Adds to a counter in the user data.
  	 * 
  	 * @param name The name of the user data element.
  	 * @param c The value by which the counter should be increased.
  	 */
  	public void addToUserDataCounter(String name, int c) {
  		String value = userdata.get(name);
  		if (value == null) {
  			userdata.put(name, c + "");
  		} else {
  			int v;
  			try {
  				v = new Integer(value);
  			} catch (NumberFormatException ex) {
  				v = 0;
  			}
  			userdata.put(name, (v + c) + "");
  		}
  		save();
  	}
  	
  	/**
  	 * Checks whether a certain password is the correct password for this user.
  	 * 
  	 * @param pw The password to be checked in plain text.
  	 * @return true if the password is correct.
  	 */
  	public boolean isCorrectPassword(String pw) {
  		return getPasswordHash(pw).equals(hashedPw);
  	}
  	
  	/**
  	 * Returns a hash value for a given plain-text password using the SHA-256 algorithm.
  	 * 
  	 * @param password The plain-text password for which a hash value should be created.
  	 * @return The hash value.
  	 */
  	public static String getPasswordHash(String password) {
  		try {
  			MessageDigest md = MessageDigest.getInstance("SHA-256");
  			md.update(password.getBytes());
  			byte[] byteData = md.digest();
  			StringBuffer sb = new StringBuffer();
  			for (int i = 0; i < byteData.length; i++) {
  				sb.append(Integer.toString((byteData[i] & 0xff) + 0x100, 16).substring(1));
  			}
  			return sb.toString();
  		} catch (Exception ex) {
  			ex.printStackTrace();
  			return null;
  		}
  	}
  	
  	/**
  	 * Returns the user base to which this user belongs.
  	 * 
  	 * @return The user base.
  	 */
  	public UserBase getUserBase() {
  		return userBase;
  	}
  	
  	/**
  	 * Returns all key of this user's properties in the form of key/value pairs.
  	 * 
  	 * @return All user data keys.
  	 */
  	public List<String> getUserDataKeys() {
  		return new ArrayList<String>(userdata.keySet());
  	}
  	
  	private void save() {
  		userBase.getStorage().save(this);
  	}
  
  }
  