/* ************************************************************************
#
#  DivConq
#
#  http://divconq.com/
#
#  Copyright:
#    Copyright 2012 eTimeline, LLC. All rights reserved.
#
#  License:
#    See the license.txt file in the project's top-level directory for details.
#
#  Authors:
#    * Andy White
#
************************************************************************ */
package divconq.db.common;

import divconq.db.IDatabaseManager;
import divconq.db.UpdateRequest;
import divconq.db.update.DynamicListField;
import divconq.db.update.DynamicScalarField;
import divconq.db.update.ScalarField;
import divconq.lang.BigDateTime;
import divconq.lang.OperationResult;
import divconq.struct.ListStruct;
import divconq.struct.RecordStruct;
import divconq.struct.Struct;
import divconq.util.StringUtil;

/**
 * Insert a new user record into dcDatabase.  UserName is required.
 * 
 * @author Andy
 *
 */
public class AddUserRequest extends UpdateRequest {
	protected RecordStruct fields = null;
	
	public void setUserName(String v) {
		this.fields.setField("dcUserName", v);
	}
	
	public void setFirstName(String v) {
		this.fields.setField("dcFirstName", v);
	}
	
	public void setLastName(String v) {
		this.fields.setField("dcLastName", v);
	}
	
	public void setPassword(String v) {
		this.fields.setField("dcPassword", v);
	}
	
	public void setEmail(String v) {
		this.fields.setField("dcEmail", v);
	}
	
	public void setLocale(String v) {
		this.fields.setField("dcLocale", v);
	}
	
	public void setChronology(String v) {
		this.fields.setField("dcChronology", v);
	}
	
	public void setConfirmed(boolean v) {
		this.fields.setField("dcConfirmed", v);
		
		if (v)
			this.fields.removeField("dcConfirmCode");
		else
			this.fields.setField("dcConfirmCode", StringUtil.buildSecurityCode());
	}
	
	public void addAuthorizationTag(String... tags) {
		ListStruct list = this.fields.getFieldAsList("dcAuthorizationTag");
		
		if (list == null) {
			list = new ListStruct();
			this.fields.setField("dcAuthorizationTag", list);
		}
		
		for (String tag : tags)
			list.addItem(tag);
	}
	
	public AddUserRequest(RecordStruct fields) {
		super("dcInsertRecord");
		
		this.fields = fields;
	}
	
	public AddUserRequest(String username) {
		super("dcInsertRecord");
		
		this.fields = new RecordStruct();
		this.setUserName(username);
		this.setConfirmed(false);
	}
	
	public AddUserRequest(String username, String firstname, String lastname, String email, String password) {
		this(username);
		
		this.setFirstName(firstname);
		this.setLastName(lastname);
		this.setEmail(email);
		this.setPassword(password);
	}
	
	public AddUserRequest(String username, String firstname, String lastname, String email, String password, boolean confirmed) {
		this(username, firstname, lastname, email, password);
		
		this.setConfirmed(confirmed);
	}
	
	public AddUserRequest(String username, String firstname, String lastname, String email, String password, boolean confirmed, String locale, String chronology) {
		this(username, firstname, lastname, email, password, confirmed);
		
		this.setLocale(locale);
		this.setChronology(chronology);
	}
	
	/* (non-Javadoc)
	 * @see divconq.db.UpdateRequest#getDatabaseParams()
	 */
	@Override
	public RecordStruct getDatabaseParams(IDatabaseManager dbm) {
		// prepare password
		String password = this.fields.getFieldAsString("dcPassword");
		this.fields.setField("dcPassword", dbm.getObfuscator().hashStringToHex(password));
		
		// prepare parameters
		this.parameters = new RecordStruct();	
		this.parameters.setField("Table", "dcUser");		
		this.parameters.setField("Filter", "dcIsAccountTaken");
		
		BigDateTime when = BigDateTime.nowDateTime();
		
		RecordStruct flds = new RecordStruct();
		
		if (!this.fields.isFieldEmpty("dcUserName")) {
			DynamicScalarField fld = new DynamicScalarField("dcUserName", null, this.fields.getFieldAsString("dcUserName").trim().toLowerCase(), when);
			flds.setField("dcUserName", fld.convert(flds, dbm));
		}
		
		if (this.fields.hasField("dcFirstName")) {
			DynamicScalarField fld = new DynamicScalarField("dcFirstName", null, this.fields.getFieldAsString("dcFirstName"), when);
			flds.setField("dcFirstName", fld.convert(flds, dbm));
		}
		
		if (this.fields.hasField("dcLastName")) {
			DynamicScalarField fld = new DynamicScalarField("dcLastName", null, this.fields.getFieldAsString("dcLastName"), when);
			flds.setField("dcLastName", fld.convert(flds, dbm));
		}
		
		if (this.fields.hasField("dcEmail")) {
			DynamicScalarField fld = new DynamicScalarField("dcEmail", null, this.fields.getFieldAsString("dcEmail"), when);
			flds.setField("dcEmail", fld.convert(flds, dbm));
		}
		
		if (this.fields.hasField("dcPassword")) {
			DynamicScalarField fld = new DynamicScalarField("dcPassword", null, this.fields.getFieldAsString("dcPassword"), when);
			flds.setField("dcPassword", fld.convert(flds, dbm));
		}
		
		if (this.fields.hasField("dcLocale")) {
			ScalarField fld = new ScalarField("dcLocale", this.fields.getFieldAsString("dcLocale"));
			flds.setField("dcLocale", fld.convert(flds, dbm));
		}
		
		if (this.fields.hasField("dcChronology")) {
			ScalarField fld = new ScalarField("dcChronology", this.fields.getFieldAsString("dcChronology"));
			flds.setField("dcChronology", fld.convert(flds, dbm));
		}
		
		if (this.fields.hasField("dcConfirmCode")) {
			ScalarField fld = new ScalarField("dcConfirmCode", this.fields.getFieldAsString("dcConfirmCode"));
			flds.setField("dcConfirmCode", fld.convert(flds, dbm));
		}
		
		if (this.fields.hasField("dcConfirmed")) {
			ScalarField fld = new ScalarField("dcConfirmed", this.fields.getFieldAsBoolean("dcConfirmed"));
			flds.setField("dcConfirmed", fld.convert(flds, dbm));
		}
		
		if (this.fields.hasField("dcAuthorizationTag")) {
			ListStruct list = this.fields.getFieldAsList("dcAuthorizationTag");
			
			for (Struct tag : list.getItems()) {
				DynamicListField fld = new DynamicListField("dcAuthorizationTag", null, tag, when);
				flds.setField("dcAuthorizationTag", fld.convert(flds, dbm));
			}
		}
		
		this.parameters.setField("Fields", flds);
		
		return this.parameters;
	}
	
	/* (non-Javadoc)
	 * @see divconq.db.UpdateRequest#validate(divconq.lang.OperationResult)
	 */
	@Override
	public void validate(OperationResult or) {
		super.validate(or);
		
		if (StringUtil.isEmpty(this.fields.getFieldAsString("dcUserName")))
			or.errorTr(127);

		String password = this.fields.getFieldAsString("dcPassword");

		AddUserRequest.meetsPasswordPolicy(or, password);
	}
	
	/**
	 * Checks that a given password meets the applications password policy.  
	 * 
	 * @param or log messages for this operation
	 * @param password proposed password
	 */
	static public void meetsPasswordPolicy(OperationResult or, String password) {
		// TODO make this into a configurable beast
		
		if (StringUtil.isEmpty(password)) {
			or.errorTr(125);
			return;
		}
		
		if (password.length() < 6) 
			or.errorTr(126);
	}
}
