/**
 * Licensed under the MICE s.r.l.
 * End User License Agreement
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.micegroup.it/voila/license.html
 */
package it.mice.voila.runtime.util;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import org.apache.commons.lang.StringEscapeUtils;
import org.apache.commons.lang.StringUtils;

/**
 * Java bean used to manage user messages in the middle layer.
 */
public class UserMessage implements Serializable {
	
    /**
	 * serial version UID.
	 */
	private static final long serialVersionUID = -4769151668326993215L;
	/**
	 * constant for object dump serialization
	 */
    private static final String FIELD_DELIMITER = "|_|";
	/**
	 * constant for object dump serialization
	 */
    private static final String PARAM_DELIMITER = "|__|";    
	
	private String messageKey = null;
	private String messageText = null;
    private String fieldPath = null;
    private Object rejectedValue = null;
    private Object[] messageParams = null;
    // indica il livello di errore: 0-info 1-warning  2-error
    private String severity = SEVERITY_ERROR;
    public static final String SEVERITY_INFO = "info";
    public static final String SEVERITY_WARNING = "warning";
    public static final String SEVERITY_ERROR = "error";

    /**
     * Default empty constructor.
     */
    public UserMessage() {
    }

    /**
     * Build a message based on message key.
     * @param msgKey the message key.
     */
    public UserMessage(String msgKey) {
        messageKey = msgKey;
    }

    /**
     * Build a message based on message key and a single argument.
     * @param msgKey the message key.
     * @param argument the argument to replace in the message.
     */
    public UserMessage(String msgKey, Object argument) {
        messageKey = msgKey;
        messageParams = new Object[1];
        messageParams[0] = argument;
    }

    /**
     * Build a message based on message key and two arguments.
     * @param msgKey the message key.
     * @param argument1 the first argument to replace in the message.
     * @param argument2 the second argument to replace in the message.
     */
    public UserMessage(String msgKey, Object argument1, Object argument2) {
        messageKey = msgKey;
        messageParams = new Object[2];
        messageParams[0] = argument1;
        messageParams[1] = argument2;
    }

    /**
     * Build a message based on message key and two arguments.
     * @param msgKey the message key.
     * @param argument1 the first argument to replace in the message.
     * @param argument2 the second argument to replace in the message.
     * @param argument3 the third argument to replace in the message.
     */
    public UserMessage(String msgKey, Object argument1, Object argument2, Object argument3) {
        messageKey = msgKey;
        messageParams = new Object[3];
        messageParams[0] = argument1;
        messageParams[1] = argument2;
        messageParams[2] = argument3;
    }

    /**
     * Build a message based on message key and two arguments.
     * @param msgKey the message key.
     * @param argument1 the first argument to replace in the message.
     * @param argument2 the second argument to replace in the message.
     * @param argument3 the third argument to replace in the message.
     * @param argument4 the fourth argument to replace in the message.
     */
    public UserMessage(String msgKey, Object argument1, Object argument2, Object argument3, Object argument4) {
        messageKey = msgKey;
        messageParams = new Object[4];
        messageParams[0] = argument1;
        messageParams[1] = argument2;
        messageParams[2] = argument3;
        messageParams[3] = argument4;
    }

    /**
     * Build a message based on message key and an array of arguments.
     * @param msgKey the message key.
     * @param args array of arguments.
     */
    public UserMessage(String msgKey, Object args[]) {
        messageKey = msgKey;
        messageParams = args;
    }

    /**
     * @return messageKey
     */
    public String getMessageKey() {
        return messageKey;
    }

    /**
     * @return messageParams
     */
    public Object[] getMessageParams() {
        return messageParams;
    }

    /**
     *
     * @param escape the escape.
     * @return messageParams.
     */
    public Object[] getMessageParams(boolean escape) {
    	if (escape && messageParams != null) {
    		Object[] result = messageParams.clone();
    		for (int i = 0; i < result.length; i++) {
    			if (result[i] instanceof String) {
    				result[i] = StringEscapeUtils.escapeXml(result[i].toString());
    			}
			}
    		return result;
    	}
        return messageParams;
    }

    /**
     * @param string the string.
     */
    public void setMessageKey(String string) {
        messageKey = string;
    }

    /**
     * @param objects the object.
     */
    public void setMessageParams(Object[] objects) {
        messageParams = objects;
    }

    /**
     * @return messageParams
     */
    public String getParamsAsString() {
    	return StringUtils.join(messageParams, "|");
    }

    /** Return severity error level: 0-info 1-warning  2-error
     * @return severity error level
     */
    public String getSeverity() {
        return severity;
    }

    /** imposta il livello di errore: 0-info 1-warning  2-error
     * @param severity severity constant to be set for the message.
     * @return this, useful for inline commands. (ex. <code>userMessages.add(new UserMessage(key, parm1).setSeverity(...))</code>).
     */
    public UserMessage setSeverity(String severity) {
        this.severity = severity;
        return this;
    }


    public String getFieldPath() {
		return fieldPath;
	}

	public void setFieldPath(String fieldPath) {
		this.fieldPath = fieldPath;
	}

	/**
	 * @return the rejectedValue
	 */
	public Object getRejectedValue() {
		return rejectedValue;
	}

	/**
	 * @param rejectedValue the rejectedValue to set
	 */
	public void setRejectedValue(Object rejectedValue) {
		this.rejectedValue = rejectedValue;
	}

	public String getMessageText() {
		return messageText;
	}

	public void setMessageText(String messageText) {
		this.messageText = messageText;
	}

	public String toString() {
        final StringBuffer sb = new StringBuffer();
        sb.append("UserMessage");
        sb.append("{fieldPath='").append(fieldPath).append('\'');
        sb.append("{messageKey='").append(messageKey).append('\'');
        sb.append(", messageParams=").append(messageParams == null ? "null" : Arrays.asList(messageParams).toString());
        sb.append(", severity='").append(severity).append('\'');
        sb.append('}');
        return sb.toString();
    }
	
	public String toObjectDump() {
        final StringBuffer sb = new StringBuffer();
        sb.append(fieldPath).append(FIELD_DELIMITER);
        sb.append(messageKey).append(FIELD_DELIMITER);
        // per i parametri utilizziamo il formatter util per convertirli in stringhe
        if (messageParams != null) {
	        for (int i = 0; i < messageParams.length; i++) {
	        	sb.append(FormatterUtil.formatAttributeToString(messageParams[i]));
	        	if (i < (messageParams.length - 1)) {
	        		sb.append(PARAM_DELIMITER);
	        	}
	        }
        }
        sb.append(FIELD_DELIMITER);
        sb.append(severity);
        return sb.toString();
	}

	public void setObjectDump(String key) {
		String[] array = StringUtils.splitByWholeSeparator(key, FIELD_DELIMITER);
		int ctr = 0;
		fieldPath = getStringCheckedAgainstNullContent(array[ctr++]);
		messageKey = getStringCheckedAgainstNullContent(array[ctr++]);
		String params[] = StringUtils.splitByWholeSeparator(array[ctr++], PARAM_DELIMITER);
		List<String> parameters = new ArrayList<String>();
		for (String param : params) {
			if (getStringCheckedAgainstNullContent(param)!=null) {
				parameters.add(param);
			}
		}
		if (!parameters.isEmpty()) {
			messageParams = parameters.toArray();
		}
		severity = getStringCheckedAgainstNullContent(array[ctr++]);
	}
	
	private String getStringCheckedAgainstNullContent(String token) {
		return (token.equals("null")) ? null : token;
	}	
	
	public boolean isFieldError() {
		return getFieldPath() != null;
	}
}
