/*
 * Koekiebox CONFIDENTIAL
 *
 * [2012] - [2017] Koekiebox (Pty) Ltd
 * All Rights Reserved.
 *
 * NOTICE: All information contained herein is, and remains the property
 * of Koekiebox and its suppliers, if any. The intellectual and
 * technical concepts contained herein are proprietary to Koekiebox
 * and its suppliers and may be covered by South African and Foreign Patents,
 * patents in process, and are protected by trade secret or copyright law.
 * Dissemination of this information or reproduction of this material is strictly
 * forbidden unless prior written permission is obtained from Koekiebox.
 */

package com.fluidbpm.ws.client.v1.sqlutil.sqlnative;

import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

import org.json.JSONObject;

import com.fluidbpm.program.api.util.UtilGlobal;
import com.fluidbpm.program.api.vo.sqlutil.sqlnative.NativeSQLQuery;
import com.fluidbpm.program.api.vo.sqlutil.sqlnative.SQLResultSet;
import com.fluidbpm.program.api.vo.ws.WS;
import com.fluidbpm.ws.client.FluidClientException;
import com.fluidbpm.ws.client.v1.websocket.ABaseClientWebSocket;
import com.fluidbpm.ws.client.v1.websocket.AGenericListMessageHandler;
import com.fluidbpm.ws.client.v1.websocket.IMessageReceivedCallback;

/**
 * Java Web Socket Client for {@code SQLUtil} related actions.
 * Implementation is making use of {@link CompletableFuture}.
 *
 * {@code this} client allows one to execute native SQL using
 * one of the configured SQL DataSources.
 *
 * @author jasonbruwer on 2018-05-26
 * @since v1.8
 *
 * @see JSONObject
 * @see SQLResultSet
 */
public class SQLUtilWebSocketExecuteNativeSQLClient extends
        ABaseClientWebSocket<AGenericListMessageHandler<SQLResultSet>> {

    /**
     * Constructor that sets the Service Ticket from authentication.
     * The ResultSet will not be compressed.
     *
     * @param endpointBaseUrlParam URL to base endpoint.
     * @param messageReceivedCallbackParam Callback for when a message is received.
     * @param serviceTicketAsHexParam The Server issued Service Ticket.
     * @param timeoutInMillisParam The timeout of the request in millis.
     *
     * @see com.fluidbpm.program.api.vo.compress.CompressedResponse
     */
    public SQLUtilWebSocketExecuteNativeSQLClient(
            String endpointBaseUrlParam,
            IMessageReceivedCallback<SQLResultSet> messageReceivedCallbackParam,
            String serviceTicketAsHexParam,
            long timeoutInMillisParam) {
        this(endpointBaseUrlParam,
                messageReceivedCallbackParam,
                serviceTicketAsHexParam,
                timeoutInMillisParam,
                false,
                UtilGlobal.EMPTY);
    }

    /**
     * Constructor that sets the Service Ticket from authentication.
     *
     * @param endpointBaseUrlParam URL to base endpoint.
     * @param messageReceivedCallbackParam Callback for when a message is received.
     * @param serviceTicketAsHexParam The Server issued Service Ticket.
     * @param timeoutInMillisParam The timeout of the request in millis.
     * @param compressResponseParam Compress the SQL Result in Base-64.
     * @param compressResponseCharsetParam Compress response using provided charset.
     *
     * @see com.fluidbpm.program.api.vo.compress.CompressedResponse
     */
    public SQLUtilWebSocketExecuteNativeSQLClient(
            String endpointBaseUrlParam,
            IMessageReceivedCallback<SQLResultSet> messageReceivedCallbackParam,
            String serviceTicketAsHexParam,
            long timeoutInMillisParam,
            boolean compressResponseParam,
            String compressResponseCharsetParam) {
        super(endpointBaseUrlParam,
                messageReceivedCallbackParam,
                timeoutInMillisParam,
                WS.Path.SQLUtil.Version1.getExecuteNativeSQLWebSocket(
                        serviceTicketAsHexParam,
                        compressResponseParam,
                        compressResponseCharsetParam),
                compressResponseParam);

        this.setServiceTicket(serviceTicketAsHexParam);
    }

    /**
     * Executes a native SQL query on the remote Fluid instance.
     *
     * The relevant access must exist.
     *
     * @param nativeSQLQueryParam The SQL Query to execute.
     *
     * @return The SQL Execution result as {@code SQLResultSet}'s.
     *
     * @throws FluidClientException if data-source name is not set.
     */
    public List<SQLResultSet> executeNativeSQLSynchronized(
            NativeSQLQuery nativeSQLQueryParam) {

        if(nativeSQLQueryParam == null)
        {
            return null;
        }

        if(nativeSQLQueryParam.getDatasourceName() == null ||
                nativeSQLQueryParam.getDatasourceName().isEmpty())
        {
            throw new FluidClientException(
                    "No data-source name provided. Not allowed.",
                    FluidClientException.ErrorCode.FIELD_VALIDATE);
        }

        //No query to execute...
        if((nativeSQLQueryParam.getQuery() == null ||
                nativeSQLQueryParam.getQuery().isEmpty()) &&
                (nativeSQLQueryParam.getStoredProcedure() == null ||
                        nativeSQLQueryParam.getStoredProcedure().isEmpty()))
        {
            return null;
        }

        //Validate the echo...
        this.setEchoIfNotSet(nativeSQLQueryParam);

        //Start a new request...
        String uniqueReqId = this.initNewRequest();

        //Send the actual message...
        this.sendMessage(nativeSQLQueryParam, uniqueReqId);

        try {
            List<SQLResultSet> returnValue =
                    this.getHandler(uniqueReqId).getCF().get(
                            this.getTimeoutInMillis(),TimeUnit.MILLISECONDS);

            //Connection was closed.. this is a problem....
            if(this.getHandler(uniqueReqId).isConnectionClosed())
            {
                throw new FluidClientException(
                        "SQLUtil-WebSocket-ExecuteNativeSQL: " +
                                "The connection was closed by the server prior to the response received.",
                        FluidClientException.ErrorCode.IO_ERROR);
            }

            return returnValue;
        }
        //Interrupted...
        catch (InterruptedException exceptParam) {

            throw new FluidClientException(
                    "SQLUtil-WebSocket-ExecuteNativeSQL: " +
                            exceptParam.getMessage(),
                    exceptParam,
                    FluidClientException.ErrorCode.STATEMENT_EXECUTION_ERROR);
        }
        //Error on the web-socket...
        catch (ExecutionException executeProblem) {

            Throwable cause = executeProblem.getCause();

            //Fluid client exception...
            if(cause instanceof FluidClientException)
            {
                throw (FluidClientException)cause;
            }
            else
            {
                throw new FluidClientException(
                        "SQLUtil-WebSocket-ExecuteNativeSQL: " +
                                cause.getMessage(), cause,
                        FluidClientException.ErrorCode.STATEMENT_EXECUTION_ERROR);
            }
        }
        //Timeout...
        catch (TimeoutException eParam) {

            throw new FluidClientException(
                    "SQLUtil-WebSocket-ExecuteNativeSQL: Timeout while waiting for all return data. There were '"
                            +this.getHandler(uniqueReqId).getReturnValue().size()
                            +"' items after a Timeout of "+(
                            TimeUnit.MILLISECONDS.toSeconds(this.getTimeoutInMillis()))+" seconds."
                    ,FluidClientException.ErrorCode.IO_ERROR);
        }
        finally {
            this.removeHandler(uniqueReqId);
        }
    }

    /**
     * Create a new instance of the handler class for {@code this} client.
     *
     * @return new instance of {@code CreateFormContainerMessageHandler}
     */
    @Override
    public SQLResultSetMessageHandler getNewHandlerInstance() {
        return new SQLResultSetMessageHandler(this.messageReceivedCallback, this.compressResponse);
    }
}


/*
 * Koekiebox CONFIDENTIAL
 *
 * [2012] - [2017] Koekiebox (Pty) Ltd
 * All Rights Reserved.
 *
 * NOTICE: All information contained herein is, and remains the property
 * of Koekiebox and its suppliers, if any. The intellectual and
 * technical concepts contained herein are proprietary to Koekiebox
 * and its suppliers and may be covered by South African and Foreign Patents,
 * patents in process, and are protected by trade secret or copyright law.
 * Dissemination of this information or reproduction of this material is strictly
 * forbidden unless prior written permission is obtained from Koekiebox.
 */

package com.fluidbpm.program.api.util.sql.syntax;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;

import com.fluidbpm.program.api.util.UtilGlobal;
import com.fluidbpm.program.api.util.sql.ABaseSQLUtil;
import com.fluidbpm.program.api.util.sql.exception.FluidSQLException;
import com.fluidbpm.program.api.util.sql.impl.SQLFormFieldUtil;
import com.fluidbpm.program.api.util.sql.syntax.impl.StoredProcedureSyntax;

/**
 * Factory class used to construct SQL stored procedures.
 *
 * @author jasonbruwer
 * @since v1.0
 *
 * @see Connection
 * @see javax.sql.DataSource
 * @see PreparedStatement
 * @see java.sql.Statement
 */
public class SyntaxFactory {
	private static SyntaxFactory syntaxFactory;

	public static final String PLAIN = "Plain";
	public static final String SELECT_MANY = "Select Many";

	/**
	 * Default constructor.
	 */
	private SyntaxFactory()
	{
		super();
	}

	/**
	 * Gets the single instance of the {@code SyntaxFactory}.
	 *
	 * @return single instance of {@code this}.
	 */
	public static SyntaxFactory getInstance() {
		if(SyntaxFactory.syntaxFactory == null) {
			SyntaxFactory.syntaxFactory = new SyntaxFactory();
		}

		return SyntaxFactory.syntaxFactory;
	}

	/**
	 * Returns the {@code ISyntax} from the {@code sqlTypeParam} and {@code aliasParam}.
	 *
	 * @param sqlTypeParam The type of SQL DB engine.
	 * @param aliasParam The alias or stored procedure.
	 *
	 * @return implementation of {@code ISyntax}.
	 *
	 * @see ISyntax
	 * @see com.fluidbpm.program.api.util.sql.ABaseSQLUtil.SQLServerType
	 */
	public ISyntax getSyntaxFor(
			ABaseSQLUtil.SQLServerType sqlTypeParam,
			String aliasParam) {

		if(ISyntax.ProcedureMapping.isStoredProcedureMapping(aliasParam)) {
			return new StoredProcedureSyntax(
					aliasParam,
					ISyntax.ProcedureMapping.getParamCountForAlias(aliasParam));
		}

		throw new FluidSQLException(
				new SQLException("Unable to find Syntax for alias '"+
						aliasParam+"' and SQL Type '"+sqlTypeParam+"'."));
	}

	/**
	 * Returns the {@code ISyntax} from the {@code sqlTypeParam} and {@code formFieldMappingParam}.
	 *
	 * @param sqlTypeParam The type of SQL DB engine.
	 * @param formFieldMappingParam The Form Field mapping.
	 * @return implementation of {@code ISyntax}.
	 *
	 * @see ISyntax
	 * @see com.fluidbpm.program.api.util.sql.impl.SQLFormFieldUtil.FormFieldMapping
	 */
	public ISyntax getFieldValueSyntaxFor(
			ABaseSQLUtil.SQLServerType sqlTypeParam,
			SQLFormFieldUtil.FormFieldMapping formFieldMappingParam
	) {
		Long dataType = formFieldMappingParam.dataType;
		if(dataType == null) {
			return null;
		}

		switch (dataType.intValue()) {
			case UtilGlobal.FieldTypeId._1_TEXT:
				return this.getSyntaxFor(
						sqlTypeParam, ISyntax.ProcedureMapping.Field.GetFormFieldValue_1_Text);
			case UtilGlobal.FieldTypeId._2_TRUE_FALSE:
				return this.getSyntaxFor(
						sqlTypeParam, ISyntax.ProcedureMapping.Field.GetFormFieldValue_2_TrueFalse);
			case UtilGlobal.FieldTypeId._3_PARAGRAPH_TEXT:
				return this.getSyntaxFor(
						sqlTypeParam, ISyntax.ProcedureMapping.Field.GetFormFieldValue_3_ParagraphText);
			case UtilGlobal.FieldTypeId._4_MULTI_CHOICE:
				if(this.isPlain(formFieldMappingParam.metaData))
				{
					return this.getSyntaxFor(
							sqlTypeParam, ISyntax.ProcedureMapping.Field.GetFormFieldValue_4_MultiChoice);
				}
				else if(this.isSelectMany(formFieldMappingParam.metaData))
				{
					return this.getSyntaxFor(
							sqlTypeParam, ISyntax.ProcedureMapping.Field.GetFormFieldMultipleValue_4_MultiChoice);
				}
				else
				{
					throw new FluidSQLException(
							new SQLException("Data Type '"+
									dataType
									+"' does not support '"+
									formFieldMappingParam.metaData+"'."));
				}

			case UtilGlobal.FieldTypeId._5_DATE_TIME:
				return this.getSyntaxFor(
						sqlTypeParam, ISyntax.ProcedureMapping.Field.GetFormFieldValue_5_DateTime);
			case UtilGlobal.FieldTypeId._6_DECIMAL:
				return this.getSyntaxFor(
						sqlTypeParam, ISyntax.ProcedureMapping.Field.GetFormFieldValue_6_Decimal);
			case UtilGlobal.FieldTypeId._7_TABLE_FIELD:
				return this.getSyntaxFor(
						sqlTypeParam, ISyntax.ProcedureMapping.Field.GetFormFieldValue_7_TableField);
			case UtilGlobal.FieldTypeId._8_TEXT_ENCRYPTED:
			case UtilGlobal.FieldTypeId._9_LABEL:
				return null;
			default:
				throw new FluidSQLException(
						new SQLException("Data Type '"+
								dataType
								+"' is not supported."));

		}
	}

	/**
	 * Checks whether {@code textToCheckParam} is Plain.
	 *
	 * @param textToCheckParam The String to check.
	 *
	 * @return Whether the {@code textToCheckParam} is of type Plain.
	 */
	private boolean isPlain(String textToCheckParam) {
		if(textToCheckParam == null || textToCheckParam.trim().isEmpty()) {
			return false;
		}

		String toCheckLower = textToCheckParam.toLowerCase();

		return toCheckLower.startsWith(PLAIN.toLowerCase());
	}

	/**
	 * Checks whether {@code textToCheckParam} is Select Many.
	 *
	 * @param textToCheckParam The String to check.
	 *
	 * @return Whether the {@code textToCheckParam} is of type Select Many.
	 */
	private boolean isSelectMany(String textToCheckParam) {
		if(textToCheckParam == null || textToCheckParam.trim().isEmpty()) {
			return false;
		}

		String toCheckLower = textToCheckParam.toLowerCase();
		return toCheckLower.startsWith(SELECT_MANY.toLowerCase());
	}
}


/*
 * Koekiebox CONFIDENTIAL
 *
 * [2012] - [2017] Koekiebox (Pty) Ltd
 * All Rights Reserved.
 *
 * NOTICE: All information contained herein is, and remains the property
 * of Koekiebox and its suppliers, if any. The intellectual and
 * technical concepts contained herein are proprietary to Koekiebox
 * and its suppliers and may be covered by South African and Foreign Patents,
 * patents in process, and are protected by trade secret or copyright law.
 * Dissemination of this information or reproduction of this material is strictly
 * forbidden unless prior written permission is obtained from Koekiebox.
 */

package com.fluidbpm.program.api.vo.sqlutil.sqlnative;

import java.sql.PreparedStatement;
import java.util.ArrayList;
import java.util.List;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import com.fluidbpm.program.api.vo.ABaseFluidJSONObject;

/**
 * <p>
 * The same as a SQL {@code ResultSet} row.
 * </p>
 *
 * @see PreparedStatement
 * @see java.sql.Connection#prepareCall(String)
 * @see java.sql.ResultSet
 *
 * @author jasonbruwer on 2018-03-13
 * @since v1.8
 */
public class SQLRow extends ABaseFluidJSONObject {

    public static final long serialVersionUID = 1L;

    private List<SQLColumn> sqlColumns;

    /**
     * The JSON mapping for the {@code SQLRow} object.
     */
    public static class JSONMapping {

        public static final String SQL_COLUMNS = "sqlColumns";
    }

    /**
     * Default constructor.
     */
    public SQLRow() {
        super();
    }

    /**
     * Populates local variables with {@code jsonObjectParam}.
     *
     * @param jsonObjectParam The JSON Object.
     */
    public SQLRow(JSONObject jsonObjectParam){
        super(jsonObjectParam);

        if(this.jsonObject == null)
        {
            return;
        }

        //SQL Columns...
        if (!this.jsonObject.isNull(JSONMapping.SQL_COLUMNS)) {

            JSONArray rulesArr = this.jsonObject.getJSONArray(
                    JSONMapping.SQL_COLUMNS);

            List<SQLColumn> sqlColumns = new ArrayList();
            for(int index = 0;index < rulesArr.length();index++)
            {
                sqlColumns.add(new SQLColumn(rulesArr.getJSONObject(index)));
            }

            this.setSqlColumns(sqlColumns);
        }
        else{
            this.setSqlColumns(null);
        }
    }

    /**
     * Conversion to {@code JSONObject} from Java Object.
     *
     * @return {@code JSONObject} representation of {@code UserQuery}
     * @throws JSONException If there is a problem with the JSON Body.
     *
     * @see ABaseFluidJSONObject#toJsonObject()
     */
    @Override
    public JSONObject toJsonObject() throws JSONException {

        JSONObject returnVal = super.toJsonObject();

        //SQL Columns...
        if(this.getSqlColumns() != null)
        {
            JSONArray jsonArray = new JSONArray();

            for(SQLColumn toAdd : this.getSqlColumns())
            {
                jsonArray.put(toAdd.toJsonObject());
            }

            returnVal.put(JSONMapping.SQL_COLUMNS, jsonArray);
        }

        return returnVal;
    }

    /**
     * Get the SQL columns.
     *
     * @return The SQL columns.
     */
    public List<SQLColumn> getSqlColumns() {
        return this.sqlColumns;
    }

    /**
     * Set the SQL columns.
     *
     * @param sqlInputsParam The SQL columns.
     */
    public void setSqlColumns(List<SQLColumn> sqlInputsParam) {
        this.sqlColumns = sqlInputsParam;
    }
}


/*
 * Koekiebox CONFIDENTIAL
 *
 * [2012] - [2017] Koekiebox (Pty) Ltd
 * All Rights Reserved.
 *
 * NOTICE: All information contained herein is, and remains the property
 * of Koekiebox and its suppliers, if any. The intellectual and
 * technical concepts contained herein are proprietary to Koekiebox
 * and its suppliers and may be covered by South African and Foreign Patents,
 * patents in process, and are protected by trade secret or copyright law.
 * Dissemination of this information or reproduction of this material is strictly
 * forbidden unless prior written permission is obtained from Koekiebox.
 */

package com.fluidbpm.program.api.vo.mail;

import org.json.JSONException;
import org.json.JSONObject;

import com.fluidbpm.program.api.vo.ABaseFluidJSONObject;
import com.fluidbpm.program.api.vo.ABaseFluidVO;
import com.fluidbpm.program.api.vo.attachment.Attachment;

/**
 * Fluid Mail Message Name and Value.
 *
 * Email Template {{name}} values gets replaced with the
 * {@code MailMessageNameValue}.
 *
 * @author jasonbruwer
 * @since v1.0
 *
 * @see Attachment
 * @see MailMessage
 * @see MailMessageAttachment
 * @see Attachment
 * @see ABaseFluidVO
 */
public class MailMessageNameValue extends ABaseFluidJSONObject {

    public static final long serialVersionUID = 1L;

    private String name;
    private String value;

    /**
     * The JSON mapping for the {@code MailMessageNameValue} object.
     */
    public static class JSONMapping
    {
        public static final String NAME = "name";
        public static final String VALUE = "value";
    }

    /**
     * Default constructor.
	 */
    public MailMessageNameValue() {
        super();
    }

    /**
     * Sets the name and value used against the template.
     *
     * @param nameParam The Name of the value to replace.
     * @param valueParam The replacement value.
     */
    public MailMessageNameValue(String nameParam, String valueParam) {
        super();

        this.setName(nameParam);
        this.setValue(valueParam);
    }

    /**
     * Populates local variables with {@code jsonObjectParam}.
     *
     * @param jsonObjectParam The JSON Object.
     */
    public MailMessageNameValue(JSONObject jsonObjectParam) {
        super(jsonObjectParam);

        if (this.jsonObject == null) {
            return;
        }

        //Name...
        if (!this.jsonObject.isNull(JSONMapping.NAME)) {

            this.setName(this.jsonObject.getString(
                    JSONMapping.NAME));
        }

        //Value...
        if (!this.jsonObject.isNull(JSONMapping.VALUE)) {

            this.setValue(this.jsonObject.getString(
                    JSONMapping.VALUE));
        }
    }

    /**
     * Conversion to {@code JSONObject} from Java Object.
     *
     * @return {@code JSONObject} representation of {@code MailMessageNameValue}
     * @throws JSONException If there is a problem with the JSON Body.
     *
     * @see ABaseFluidJSONObject#toJsonObject()
     */
    @Override
    public JSONObject toJsonObject() throws JSONException
    {
        JSONObject returnVal = super.toJsonObject();

        //Name...
        if(this.getName() != null)
        {
            returnVal.put(JSONMapping.NAME, this.getName());
        }

        //Value...
        if(this.getValue() != null)
        {
            returnVal.put(JSONMapping.VALUE, this.getValue());
        }

        return returnVal;
    }

    /**
     * Gets the name of the name-value to replace.
     *
     * @return The Name of the value to replace.
     */
    public String getName() {
        return this.name;
    }

    /**
     * Sets the name of the name-value to replace.
     *
     * @param nameParam The Name of the value to replace.
     */
    public void setName(String nameParam) {
        this.name = nameParam;
    }

    /**
     * Gets the replacement value.
     *
     * @return The replacement value.
     */
    public String getValue() {
        return this.value;
    }

    /**
     * Sets the replacement value.
     *
     * @param valueParam The replacement value.
     */
    public void setValue(String valueParam) {
        this.value = valueParam;
    }
}


/*
 * Koekiebox CONFIDENTIAL
 *
 * [2012] - [2017] Koekiebox (Pty) Ltd
 * All Rights Reserved.
 *
 * NOTICE: All information contained herein is, and remains the property
 * of Koekiebox and its suppliers, if any. The intellectual and
 * technical concepts contained herein are proprietary to Koekiebox
 * and its suppliers and may be covered by South African and Foreign Patents,
 * patents in process, and are protected by trade secret or copyright law.
 * Dissemination of this information or reproduction of this material is strictly
 * forbidden unless prior written permission is obtained from Koekiebox.
 */

package com.fluidbpm.ws.client.v1.config;

import org.apache.http.entity.ContentType;
import org.json.JSONObject;

import com.fluidbpm.program.api.vo.license.LicenseRequest;
import com.fluidbpm.program.api.vo.ws.WS.Path.License.Version1;
import com.fluidbpm.ws.client.v1.ABaseFieldClient;

/**
 * Java Web Service Client for Fluid License related actions.
 *
 * @author jasonbruwer on 2018-05-06
 * @version v1.8
 *
 * @see JSONObject
 * @see com.fluidbpm.program.api.vo.ws.WS.Path.License
 * @see com.fluidbpm.program.api.vo.license.LicenseRequest
 */
public class FluidLicenseClient extends ABaseFieldClient {

    /**
     * Constructor that sets the Service Ticket from authentication.
     *
     * @param endpointBaseUrlParam URL to base endpoint.
     * @param serviceTicketParam The Server issued Service Ticket.
     */
    public FluidLicenseClient(
            String endpointBaseUrlParam,
            String serviceTicketParam) {
        super(endpointBaseUrlParam);

        this.setServiceTicket(serviceTicketParam);
    }

    /**
     * Request a new license based on the license request input.
     *
     * It is important to set the following fields.
     * {@code Valid From}
     * {@code Valid To}
     * {@code User Count}
     *
     * @param licenseRequestParam The license request used to issue a license request from.
     * @return The License Request file.
     */
    public String requestLicense(LicenseRequest licenseRequestParam) {

        if(licenseRequestParam != null &&
                this.serviceTicket != null)
        {
            licenseRequestParam.setServiceTicket(this.serviceTicket);
        }

        return this.executeTxtReceiveTxt(
                HttpMethod.POST,
                null,
                false,
                (licenseRequestParam == null) ? null :
                        licenseRequestParam.toJsonObject().toString(),
                ContentType.APPLICATION_JSON,
                Version1.licenseRequest());
    }

    /**
     * Applies a generated license for the server.
     *
     * @param licenseToApplyParam The clear license to apply.
     * @return The applied license.
     */
    public LicenseRequest applyLicense(String licenseToApplyParam)
    {
        LicenseRequest liceReq = new LicenseRequest();
        liceReq.setLicenseCipherText(licenseToApplyParam);

        if(this.serviceTicket != null)
        {
            liceReq.setServiceTicket(this.serviceTicket);
        }

        return new LicenseRequest(this.postJson(
                liceReq, Version1.licenseApply()));
    }
}


/*
 * Koekiebox CONFIDENTIAL
 *
 * [2012] - [2017] Koekiebox (Pty) Ltd
 * All Rights Reserved.
 *
 * NOTICE: All information contained herein is, and remains the property
 * of Koekiebox and its suppliers, if any. The intellectual and
 * technical concepts contained herein are proprietary to Koekiebox
 * and its suppliers and may be covered by South African and Foreign Patents,
 * patents in process, and are protected by trade secret or copyright law.
 * Dissemination of this information or reproduction of this material is strictly
 * forbidden unless prior written permission is obtained from Koekiebox.
 */

package com.fluidbpm.program.api.vo.userquery;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import com.fluidbpm.program.api.vo.ABaseFluidJSONObject;
import com.fluidbpm.program.api.vo.ABaseListing;
import com.fluidbpm.program.api.vo.field.Field;
import com.fluidbpm.program.api.vo.item.FluidItem;

/**
 * <p>
 *     Represents a Query that can be executed via the
 *     API. The {@code UserQuery}s are configured from the
 *     Administration.
 * </p>
 *
 * @author jasonbruwer
 * @since v1.1
 */
public class UserQuery extends ABaseListing<FluidItem> {

    public static final long serialVersionUID = 1L;

    private String name;
    private String description;

    private List<String> rules;

    private List<Field> inputs;

    private Date dateCreated;
    private Date dateLastUpdated;

    /**
     * The JSON mapping for the {@code UserQuery} object.
     */
    public static class JSONMapping
    {
        public static final String NAME = "name";
        public static final String DESCRIPTION = "description";
        public static final String INPUTS = "inputs";
        public static final String RULES = "rules";

        public static final String DATE_CREATED = "dateCreated";
        public static final String DATE_LAST_UPDATED = "dateLastUpdated";
    }

    /**
     * Default constructor.
     */
    public UserQuery() {
        super();
    }

    /**
     * Sets the Id associated with a 'User Query'.
     *
     * @param userQueryIdParam UserQuery Id.
     */
    public UserQuery(Long userQueryIdParam) {
        super();

        this.setId(userQueryIdParam);
    }

    /**
     * Populates local variables with {@code jsonObjectParam}.
     *
     * @param jsonObjectParam The JSON Object.
     */
    public UserQuery(JSONObject jsonObjectParam){
        super(jsonObjectParam);

        if(this.jsonObject == null)
        {
            return;
        }

        //Name...
        if (!this.jsonObject.isNull(JSONMapping.NAME)) {
            this.setName(this.jsonObject.getString(
                    JSONMapping.NAME));
        }

        //Description...
        if (!this.jsonObject.isNull(JSONMapping.DESCRIPTION)) {
            this.setDescription(this.jsonObject.getString(
                    JSONMapping.DESCRIPTION));
        }

        //Inputs...
        if (!this.jsonObject.isNull(JSONMapping.INPUTS)) {

            JSONArray fieldsArr = this.jsonObject.getJSONArray(
                    JSONMapping.INPUTS);

            List<Field> assFields = new ArrayList();
            for(int index = 0;index < fieldsArr.length();index++)
            {
                assFields.add(new Field(fieldsArr.getJSONObject(index)));
            }

            this.setInputs(assFields);
        }

        //Rules...
        if (!this.jsonObject.isNull(JSONMapping.RULES)) {

            JSONArray rulesArr = this.jsonObject.getJSONArray(
                    JSONMapping.RULES);

            List<String> rules = new ArrayList();
            for(int index = 0;index < rulesArr.length();index++)
            {
                rules.add(rulesArr.getString(index));
            }

            this.setRules(rules);
        }

        //Date Created...
        this.setDateCreated(this.getDateFieldValueFromFieldWithName(
                JSONMapping.DATE_CREATED));

        //Date Last Updated...
        this.setDateLastUpdated(this.getDateFieldValueFromFieldWithName(
                JSONMapping.DATE_LAST_UPDATED));
    }

    /**
     * Gets {@code UserQuery} name.
     *
     * @return A {@code UserQuery}s name.
     */
    public String getName() {
        return this.name;
    }

    /**
     * Sets {@code UserQuery} name.
     *
     * @param nameParam A {@code UserQuery} name.
     */
    public void setName(String nameParam) {
        this.name = nameParam;
    }

    /**
     * Gets {@code UserQuery} description.
     *
     * @return A {@code UserQuery}s description.
     */
    public String getDescription() {
        return this.description;
    }

    /**
     * Sets {@code UserQuery} description.
     *
     * @param descriptionParam A {@code UserQuery}s description.
     */
    public void setDescription(String descriptionParam) {
        this.description = descriptionParam;
    }

    /**
     * Sets {@code UserQuery} input {@code Field}s.
     *
     * @return A {@code UserQuery}s input {@code Field}s.
     *
     * @see Field
     */
    public List<Field> getInputs() {
        return this.inputs;
    }

    /**
     * Sets {@code UserQuery} input {@code Field}s.
     *
     * @param inputsParam A {@code UserQuery}s input {@code Field}s.
     *
     * @see Field
     */
    public void setInputs(List<Field> inputsParam) {
        this.inputs = inputsParam;
    }

    /**
     * Sets {@code UserQuery} rules.
     *
     * @return A {@code UserQuery}s rules.
     */
    public List<String> getRules() {
        return this.rules;
    }

    /**
     * Sets {@code UserQuery} rules.
     *
     * @param rulesParam A {@code UserQuery}s rules.
     */
    public void setRules(List<String> rulesParam) {
        this.rules = rulesParam;
    }

    /**
     * Gets The {@code Date} the User Query
     * was created.
     *
     * @return Date Created.
     */
    public Date getDateCreated() {
        return this.dateCreated;
    }

    /**
     * Sets The {@code Date} the User Query
     * was created.
     *
     * @param dateCreatedParam Date Created.
     */
    public void setDateCreated(Date dateCreatedParam) {
        this.dateCreated = dateCreatedParam;
    }

    /**
     * Gets The {@code Date} the User Query
     * was last updated.
     *
     * @return Date Last Updated.
     */
    public Date getDateLastUpdated() {
        return this.dateLastUpdated;
    }

    /**
     * Sets The {@code Date} the User Query
     * was last updated.
     *
     * @param dateLastUpdatedParam Date Last Updated.
     */
    public void setDateLastUpdated(Date dateLastUpdatedParam) {
        this.dateLastUpdated = dateLastUpdatedParam;
    }

    /**
     * Conversion to {@code JSONObject} from Java Object.
     *
     * @return {@code JSONObject} representation of {@code UserQuery}
     * @throws JSONException If there is a problem with the JSON Body.
     *
     * @see ABaseFluidJSONObject#toJsonObject()
     */
    @Override
    public JSONObject toJsonObject() throws JSONException {

        JSONObject returnVal = super.toJsonObject();

        //Name...
        if(this.getName() != null)
        {
            returnVal.put(JSONMapping.NAME,this.getName());
        }

        //Description...
        if(this.getDescription() != null)
        {
            returnVal.put(JSONMapping.DESCRIPTION,this.getDescription());
        }

        //Inputs...
        if(this.getInputs() != null)
        {
            JSONArray jsonArray = new JSONArray();

            for(Field toAdd : this.getInputs())
            {
                jsonArray.put(toAdd.toJsonObject());
            }

            returnVal.put(JSONMapping.INPUTS, jsonArray);
        }

        //Rules...
        if(this.getRules() != null)
        {
            JSONArray jsonArray = new JSONArray();

            for(String toAdd : this.getRules())
            {
                jsonArray.put(toAdd);
            }

            returnVal.put(JSONMapping.RULES, jsonArray);
        }

        //Date Created...
        if(this.getDateCreated() != null)
        {
            returnVal.put(JSONMapping.DATE_CREATED,
                    this.getDateAsLongFromJson(this.getDateCreated()));
        }

        //Date Last Updated...
        if(this.getDateLastUpdated() != null)
        {
            returnVal.put(JSONMapping.DATE_LAST_UPDATED,
                    this.getDateAsLongFromJson(this.getDateLastUpdated()));
        }

        return returnVal;
    }

    /**
     * Converts the {@code jsonObjectParam} to a {@code FluidItem} object.
     *
     * @param jsonObjectParam The JSON object to convert to {@code T}.
     * @return new instance of {@code FluidItem}.
     */
    @Override
    public FluidItem getObjectFromJSONObject(JSONObject jsonObjectParam) {
        return new FluidItem(jsonObjectParam);
    }
}


/*
 * Koekiebox CONFIDENTIAL
 *
 * [2012] - [2017] Koekiebox (Pty) Ltd
 * All Rights Reserved.
 *
 * NOTICE: All information contained herein is, and remains the property
 * of Koekiebox and its suppliers, if any. The intellectual and
 * technical concepts contained herein are proprietary to Koekiebox
 * and its suppliers and may be covered by South African and Foreign Patents,
 * patents in process, and are protected by trade secret or copyright law.
 * Dissemination of this information or reproduction of this material is strictly
 * forbidden unless prior written permission is obtained from Koekiebox.
 */

package com.fluidbpm.ws.client.v1.flow;

import java.util.ArrayList;
import java.util.List;

import org.json.JSONObject;

import com.fluidbpm.program.api.vo.field.Field;
import com.fluidbpm.program.api.vo.field.MultiChoice;
import com.fluidbpm.program.api.vo.item.FluidItem;
import com.fluidbpm.program.api.vo.item.RouteFieldListing;
import com.fluidbpm.program.api.vo.ws.WS.Path.RouteField.Version1;
import com.fluidbpm.ws.client.FluidClientException;
import com.fluidbpm.ws.client.v1.ABaseFieldClient;

/**
 * Java Web Service Client for Route Field related actions.
 *
 * @author jasonbruwer
 * @since v1.0
 * @version v1.8
 *
 * @see JSONObject
 * @see com.fluidbpm.program.api.vo.ws.WS.Path.RouteField
 * @see Field
 * @see ABaseFieldClient
 */
public class RouteFieldClient extends ABaseFieldClient {

	/**
	 * Constructor that sets the Service Ticket from authentication.
	 *
	 * @param endpointBaseUrlParam URL to base endpoint.
	 * @param serviceTicketParam The Server issued Service Ticket.
	 */
	public RouteFieldClient(
			String endpointBaseUrlParam,
			String serviceTicketParam) {
		super(endpointBaseUrlParam);

		this.setServiceTicket(serviceTicketParam);
	}

	/**
	 * Create a new Plain Text field.
	 *
	 * @param routeFieldParam Field to Create.
	 * @return Created Field.
	 */
	public Field createFieldTextPlain(Field routeFieldParam) {
		if(routeFieldParam != null && this.serviceTicket != null) {
			routeFieldParam.setServiceTicket(this.serviceTicket);
		}

		if(routeFieldParam != null) {
			routeFieldParam.setTypeAsEnum(Field.Type.Text);
			routeFieldParam.setTypeMetaData(FieldMetaData.Text.PLAIN);
		}

		return new Field(this.putJson(
				routeFieldParam, Version1.routeFieldCreate()));
	}

	/**
	 * Create a new True False field.
	 *
	 * @param routeFieldParam Field to Create.
	 * @return Created Field.
	 */
	public Field createFieldTrueFalse(Field routeFieldParam) {
		if(routeFieldParam != null && this.serviceTicket != null) {
			routeFieldParam.setServiceTicket(this.serviceTicket);
		}

		if(routeFieldParam != null) {
			routeFieldParam.setTypeAsEnum(Field.Type.TrueFalse);
			routeFieldParam.setTypeMetaData(FieldMetaData.TrueFalse.TRUE_FALSE);
		}

		return new Field(this.putJson(
				routeFieldParam, Version1.routeFieldCreate()));
	}

	/**
	 * Create a new Paragraph Text field.
	 *
	 * @param routeFieldParam Field to Create.
	 * @return Created Field.
	 */
	public Field createFieldParagraphTextPlain(Field routeFieldParam) {
		if(routeFieldParam != null && this.serviceTicket != null) {
			routeFieldParam.setServiceTicket(this.serviceTicket);
		}

		if(routeFieldParam != null) {
			routeFieldParam.setTypeAsEnum(Field.Type.ParagraphText);
			routeFieldParam.setTypeMetaData(FieldMetaData.ParagraphText.PLAIN);
		}

		return new Field(this.putJson(
				routeFieldParam, Version1.routeFieldCreate()));
	}

	/**
	 * Create a new Paragraph HTML field.
	 *
	 * @param routeFieldParam Field to Create.
	 * @return Created Field.
	 */
	public Field createFieldParagraphTextHTML(Field routeFieldParam) {
		if(routeFieldParam != null && this.serviceTicket != null) {
			routeFieldParam.setServiceTicket(this.serviceTicket);
		}

		if(routeFieldParam != null) {
			routeFieldParam.setTypeAsEnum(Field.Type.ParagraphText);
			routeFieldParam.setTypeMetaData(FieldMetaData.ParagraphText.HTML);
		}

		return new Field(this.putJson(
				routeFieldParam, Version1.routeFieldCreate()));
	}

	/**
	 * Create a new Multi Choice field.
	 *
	 * @param routeFieldParam Field to Create.
	 * @param multiChoiceValuesParam The available multi choice values.
	 * @return Created Field.
	 */
	public Field createFieldMultiChoicePlain(
			Field routeFieldParam,
			List<String> multiChoiceValuesParam
	) {
		if(routeFieldParam != null && this.serviceTicket != null) {
			routeFieldParam.setServiceTicket(this.serviceTicket);
		}

		if(multiChoiceValuesParam == null) {
			multiChoiceValuesParam = new ArrayList();
		}

		if(routeFieldParam != null) {
			routeFieldParam.setTypeAsEnum(Field.Type.MultipleChoice);
			routeFieldParam.setTypeMetaData(FieldMetaData.MultiChoice.PLAIN);
			routeFieldParam.setFieldValue(new MultiChoice(multiChoiceValuesParam));
		}

		return new Field(this.putJson(
				routeFieldParam, Version1.routeFieldCreate()));
	}

	/**
	 * Create a new Multi Choice select Many field.
	 *
	 * @param routeFieldParam Field to Create.
	 * @param multiChoiceValuesParam The available multi choice values.
	 * @return Created Field.
	 */
	public Field createFieldMultiChoiceSelectMany(
			Field routeFieldParam,
			List<String> multiChoiceValuesParam
	) {
		if(routeFieldParam != null && this.serviceTicket != null) {
			routeFieldParam.setServiceTicket(this.serviceTicket);
		}

		if(multiChoiceValuesParam == null ||
				multiChoiceValuesParam.isEmpty()) {
			throw new FluidClientException(
					"No Multi-choice values provided.",
					FluidClientException.ErrorCode.FIELD_VALIDATE);
		}

		if(routeFieldParam != null) {
			routeFieldParam.setTypeAsEnum(Field.Type.MultipleChoice);
			routeFieldParam.setTypeMetaData(FieldMetaData.MultiChoice.SELECT_MANY);
			routeFieldParam.setFieldValue(new MultiChoice(multiChoiceValuesParam));
		}

		return new Field(this.putJson(
				routeFieldParam, Version1.routeFieldCreate()));
	}

	/**
	 * Create a new Date only field.
	 *
	 * @param routeFieldParam Field to Create.
	 * @return Created Field.
	 */
	public Field createFieldDateTimeDate(Field routeFieldParam) {
		if(routeFieldParam != null && this.serviceTicket != null) {
			routeFieldParam.setServiceTicket(this.serviceTicket);
		}

		if(routeFieldParam != null) {
			routeFieldParam.setTypeAsEnum(Field.Type.DateTime);
			routeFieldParam.setTypeMetaData(FieldMetaData.DateTime.DATE);
		}

		return new Field(this.putJson(
				routeFieldParam, Version1.routeFieldCreate()));
	}

	/**
	 * Create a new Date and time field.
	 *
	 * @param routeFieldParam Field to Create.
	 * @return Created Field.
	 */
	public Field createFieldDateTimeDateAndTime(Field routeFieldParam) {
		if(routeFieldParam != null && this.serviceTicket != null) {
			routeFieldParam.setServiceTicket(this.serviceTicket);
		}

		if(routeFieldParam != null) {
			routeFieldParam.setTypeAsEnum(Field.Type.DateTime);
			routeFieldParam.setTypeMetaData(FieldMetaData.DateTime.DATE_AND_TIME);
		}

		return new Field(this.putJson(
				routeFieldParam, Version1.routeFieldCreate()));
	}

	/**
	 * Create a new Decimal field.
	 *
	 * @param routeFieldParam Field to Create.
	 * @return Created Field.
	 */
	public Field createFieldDecimalPlain(Field routeFieldParam) {
		if(routeFieldParam != null && this.serviceTicket != null) {
			routeFieldParam.setServiceTicket(this.serviceTicket);
		}

		if(routeFieldParam != null) {
			routeFieldParam.setTypeAsEnum(Field.Type.Decimal);
			routeFieldParam.setTypeMetaData(FieldMetaData.Decimal.PLAIN);
		}

		return new Field(this.putJson(
				routeFieldParam, Version1.routeFieldCreate()));
	}

	/**
	 * Update an existing Text field.
	 *
	 * @param routeFieldParam Field to Update.
	 * @return Updated Field.
	 */
	public Field updateFieldTextPlain(Field routeFieldParam) {
		if(routeFieldParam != null && this.serviceTicket != null) {
			routeFieldParam.setServiceTicket(this.serviceTicket);
		}

		if(routeFieldParam != null) {
			routeFieldParam.setTypeAsEnum(Field.Type.Text);
			routeFieldParam.setTypeMetaData(FieldMetaData.Text.PLAIN);
		}

		return new Field(this.postJson(
				routeFieldParam, Version1.routeFieldUpdate()));
	}

	/**
	 * Update an existing True False field.
	 *
	 * @param routeFieldParam Field to Update.
	 * @return Updated Field.
	 */
	public Field updateFieldTrueFalse(Field routeFieldParam) {
		if(routeFieldParam != null && this.serviceTicket != null) {
			routeFieldParam.setServiceTicket(this.serviceTicket);
		}

		if(routeFieldParam != null) {
			routeFieldParam.setTypeAsEnum(Field.Type.TrueFalse);
			routeFieldParam.setTypeMetaData(FieldMetaData.TrueFalse.TRUE_FALSE);
		}

		return new Field(this.postJson(
				routeFieldParam, Version1.routeFieldUpdate()));
	}

	/**
	 * Update an existing Paragraph Text field.
	 *
	 * @param routeFieldParam Field to Update.
	 * @return Updated Field.
	 */
	public Field updateFieldParagraphTextPlain(Field routeFieldParam) {
		if(routeFieldParam != null && this.serviceTicket != null) {
			routeFieldParam.setServiceTicket(this.serviceTicket);
		}

		if(routeFieldParam != null) {
			routeFieldParam.setTypeAsEnum(Field.Type.ParagraphText);
			routeFieldParam.setTypeMetaData(FieldMetaData.ParagraphText.PLAIN);
		}

		return new Field(this.postJson(
				routeFieldParam, Version1.routeFieldUpdate()));
	}

	/**
	 * Update an existing Paragraph HTML field.
	 *
	 * @param routeFieldParam Field to Update.
	 * @return Updated Field.
	 */
	public Field updateFieldParagraphTextHTML(Field routeFieldParam) {
		if(routeFieldParam != null && this.serviceTicket != null) {
			routeFieldParam.setServiceTicket(this.serviceTicket);
		}

		if(routeFieldParam != null) {
			routeFieldParam.setTypeAsEnum(Field.Type.ParagraphText);
			routeFieldParam.setTypeMetaData(FieldMetaData.ParagraphText.HTML);
		}

		return new Field(this.postJson(
				routeFieldParam, Version1.routeFieldUpdate()));
	}

	/**
	 * Update an existing Multi Choice field.
	 *
	 * @param routeFieldParam Field to Update.
	 * @param multiChoiceValuesParam New available Multi-choices.
	 * @return Updated Field.
	 */
	public Field updateFieldMultiChoicePlain(
			Field routeFieldParam,
			List<String> multiChoiceValuesParam
	) {
		if(routeFieldParam != null && this.serviceTicket != null) {
			routeFieldParam.setServiceTicket(this.serviceTicket);
		}

		if(multiChoiceValuesParam == null ||
				multiChoiceValuesParam.isEmpty()) {
			throw new FluidClientException(
					"No Multi-choice values provided.",
					FluidClientException.ErrorCode.FIELD_VALIDATE);
		}

		if(routeFieldParam != null) {
			routeFieldParam.setTypeAsEnum(Field.Type.MultipleChoice);
			routeFieldParam.setTypeMetaData(FieldMetaData.MultiChoice.PLAIN);
			routeFieldParam.setFieldValue(new MultiChoice(multiChoiceValuesParam));
		}

		return new Field(this.postJson(
				routeFieldParam, Version1.routeFieldUpdate()));
	}

	/**
	 * Update an existing Multi Choice select many field.
	 *
	 * @param routeFieldParam Field to Update.
	 * @param multiChoiceValuesParam New available Multi-choices.
	 * @return Updated Field.
	 */
	public Field updateFieldMultiChoiceSelectMany(
			Field routeFieldParam,
			List<String> multiChoiceValuesParam
	) {
		if(routeFieldParam != null && this.serviceTicket != null) {
			routeFieldParam.setServiceTicket(this.serviceTicket);
		}

		if(multiChoiceValuesParam == null ||
				multiChoiceValuesParam.isEmpty()) {
			throw new FluidClientException(
					"No Multi-choice values provided.",
					FluidClientException.ErrorCode.FIELD_VALIDATE);
		}

		if(routeFieldParam != null) {
			routeFieldParam.setTypeAsEnum(Field.Type.MultipleChoice);
			routeFieldParam.setTypeMetaData(FieldMetaData.MultiChoice.SELECT_MANY);
			routeFieldParam.setFieldValue(new MultiChoice(multiChoiceValuesParam));
		}

		return new Field(this.postJson(
				routeFieldParam, Version1.routeFieldUpdate()));
	}

	/**
	 * Update an existing Date field.
	 *
	 * @param routeFieldParam Field to Update.
	 * @return Updated Field.
	 */
	public Field updateFieldDateTimeDate(Field routeFieldParam) {
		if(routeFieldParam != null && this.serviceTicket != null) {
			routeFieldParam.setServiceTicket(this.serviceTicket);
		}

		if(routeFieldParam != null) {
			routeFieldParam.setTypeAsEnum(Field.Type.DateTime);
			routeFieldParam.setTypeMetaData(FieldMetaData.DateTime.DATE);
		}

		return new Field(this.postJson(
				routeFieldParam, Version1.routeFieldUpdate()));
	}

	/**
	 * Update an existing Date and Time field.
	 *
	 * @param routeFieldParam Field to Update.
	 * @return Updated Field.
	 */
	public Field updateFieldDateTimeDateAndTime(Field routeFieldParam) {
		if(routeFieldParam != null && this.serviceTicket != null) {
			routeFieldParam.setServiceTicket(this.serviceTicket);
		}

		if(routeFieldParam != null) {
			routeFieldParam.setTypeAsEnum(Field.Type.DateTime);
			routeFieldParam.setTypeMetaData(FieldMetaData.DateTime.DATE_AND_TIME);
		}

		return new Field(this.postJson(
				routeFieldParam, Version1.routeFieldUpdate()));
	}

	/**
	 * Update an existing Decimal field.
	 *
	 * @param routeFieldParam Field to Update.
	 * @return Updated Field.
	 */
	public Field updateFieldDecimalPlain(Field routeFieldParam) {
		if(routeFieldParam != null && this.serviceTicket != null) {
			routeFieldParam.setServiceTicket(this.serviceTicket);
		}

		if(routeFieldParam != null) {
			routeFieldParam.setTypeAsEnum(Field.Type.Decimal);
			routeFieldParam.setTypeMetaData(FieldMetaData.Decimal.PLAIN);
		}

		return new Field(this.postJson(
				routeFieldParam, Version1.routeFieldUpdate()));
	}

	/**
	 * Update an existing 'Route field' value.
	 *
	 * @param routeFieldValueParam Field to Update.
	 * @return Updated Field.
	 */
	public Field updateFieldValue(Field routeFieldValueParam) {
		if(routeFieldValueParam != null && this.serviceTicket != null) {
			routeFieldValueParam.setServiceTicket(this.serviceTicket);
		}

		return new Field(this.postJson(
				routeFieldValueParam, Version1.routeFieldUpdateValue()));
	}

	/**
	 * Create an new 'Route field' value.
	 *
	 * @param routeFieldValueToCreateParam Field to Create.
	 * @param fluidItemParam Fluid item to create field for.
	 * @return Created Field.
	 */
	public Field createFieldValue(
			Field routeFieldValueToCreateParam,
			FluidItem fluidItemParam) {
		if(routeFieldValueToCreateParam != null && this.serviceTicket != null) {
			routeFieldValueToCreateParam.setServiceTicket(this.serviceTicket);
		}

		Long fluidItmId = (fluidItemParam == null) ? null : fluidItemParam.getId();

		return new Field(this.putJson(
				routeFieldValueToCreateParam,
				Version1.routeFieldCreateValue(fluidItmId)));
	}

	/**
	 * Retrieves field information by {@code fieldIdParam}.
	 *
	 * @param fieldIdParam The field Primary Key.
	 * @return Field Definition by primary key.
	 */
	public Field getFieldById(Long fieldIdParam) {
		Field field = new Field(fieldIdParam);

		//Set for Payara server...
		field.setFieldValue(new MultiChoice());

		if(this.serviceTicket != null) {
			field.setServiceTicket(this.serviceTicket);
		}

		return new Field(this.postJson(
				field, Version1.getById()));
	}

	/**
	 * Retrieve the Route field values for {@code fluidItemParam}.
	 *
	 * If the id is not set, the {@code Form} id must be set.
	 *
	 * @param fluidItemParam The fluid item to get route fields for.
	 *
	 * @return Route Fields by the FluidItem {@code fluidItemParam}.
	 *
	 * @see RouteFieldListing
	 * @see Field
	 */
	public List<Field> getRouteFieldValuesBy(FluidItem fluidItemParam) {
		if(this.serviceTicket != null && fluidItemParam != null) {
			fluidItemParam.setServiceTicket(this.serviceTicket);
		}

		return new RouteFieldListing(this.postJson(
				fluidItemParam, Version1.getValuesBy())).getListing();
	}

	/**
	 * Deletes a field from Fluid.
	 *
	 * @param fieldParam The field to delete. Important that Id is set.
	 * @return Deleted Field.
	 */
	public Field deleteField(Field fieldParam) {
		if(fieldParam != null && this.serviceTicket != null) {
			fieldParam.setServiceTicket(this.serviceTicket);
		}

		return new Field(this.postJson(fieldParam, Version1.routeFieldDelete()));
	}

	/**
	 * Forcefully Deletes a field from Fluid.
	 *
	 * Only 'admin' is allowed to make this call.
	 *
	 * @param fieldParam The field to delete. Important that Id is set.
	 * @return Deleted Field.
	 */
	public Field forceDeleteField(Field fieldParam) {
		if(fieldParam != null && this.serviceTicket != null) {
			fieldParam.setServiceTicket(this.serviceTicket);
		}

		return new Field(this.postJson(
				fieldParam, Version1.routeFieldDelete(true)));
	}
}


/*
 * Koekiebox CONFIDENTIAL
 *
 * [2012] - [2017] Koekiebox (Pty) Ltd
 * All Rights Reserved.
 *
 * NOTICE: All information contained herein is, and remains the property
 * of Koekiebox and its suppliers, if any. The intellectual and
 * technical concepts contained herein are proprietary to Koekiebox
 * and its suppliers and may be covered by South African and Foreign Patents,
 * patents in process, and are protected by trade secret or copyright law.
 * Dissemination of this information or reproduction of this material is strictly
 * forbidden unless prior written permission is obtained from Koekiebox.
 */

package com.fluidbpm.program.api.vo;

import java.util.ArrayList;
import java.util.List;

import javax.xml.bind.annotation.XmlTransient;

import org.json.JSONException;
import org.json.JSONObject;

import com.fluidbpm.program.api.util.UtilGlobal;
import com.fluidbpm.program.api.util.sql.impl.SQLFormFieldUtil;
import com.fluidbpm.program.api.vo.field.Field;

/**
 * <p>
 *     The Base class for any sub-class that wants to make use of the
 *     ElasticSearch. See {@code https://www.elastic.co}.
 *
 * @author jasonbruwer
 * @since v1.0
 *
 * @see ABaseFluidVO
 * @see JSONObject
 */
public abstract class ABaseFluidElasticSearchJSONObject extends ABaseFluidJSONObject{

    public static final long serialVersionUID = 1L;

    /**
     * Default constructor.
     */
    public ABaseFluidElasticSearchJSONObject() {
        super();
    }

    /**
     * Populates local variables Id and Service Ticket with {@code jsonObjectParam}.
     *
     * @param jsonObjectParam The JSON Object.
     */
    public ABaseFluidElasticSearchJSONObject(JSONObject jsonObjectParam) {
        super(jsonObjectParam);
    }

    /**
     * Conversion to {@code JSONObject} for storage in ElasticSearch.
     *
     * @return {@code JSONObject} representation of {@code subclass-type}
     * @throws JSONException If there is a problem with the JSON Body.
     *
     * @see ABaseFluidJSONObject#toJsonObject()
     */
    @XmlTransient
    public abstract JSONObject toJsonForElasticSearch() throws JSONException;

    /**
     * The JSON mapping for ElasticSearch and its field definitions.
     * The JSON mapping is crucial in defining the correct types to make storage of
     * data-types more effective.
     *
     * @return {@code JSONObject} representation of {@code Form} definition.
     * @throws JSONException If there is a problem with constructing the mapping.
     *
     * @see ABaseFluidJSONObject#toJsonObject()
     */
    @XmlTransient
    public abstract JSONObject toJsonMappingForElasticSearch() throws JSONException;

    /**
     * Populate the object based on the ElasticSearch JSON structure.
     *
     * @param jsonObjectParam The JSON object to populate from.
     * @param formFieldsParam The Form Fields to use.
     *
     * @throws JSONException If there is a problem with the JSON Body.
     *
     * @see ABaseFluidJSONObject#toJsonObject()
     */
    @XmlTransient
    public abstract void populateFromElasticSearchJson(
            JSONObject jsonObjectParam,
            List<Field> formFieldsParam) throws JSONException;

    /**
     * Convert the {@code SQLFormFieldUtil.FormFieldMapping} to {@code Field}.
     *
     * @param formFieldMappingsParam The {@code formFieldMappingsParam} to convert.
     * @return The converted {@code Field}s.
     */
    @XmlTransient
    public List<Field> convertTo(List<SQLFormFieldUtil.FormFieldMapping> formFieldMappingsParam)
    {
        if(formFieldMappingsParam == null)
        {
            return null;
        }

        List<Field> returnVal = new ArrayList();

        for(SQLFormFieldUtil.FormFieldMapping mappingToConvert : formFieldMappingsParam)
        {
            returnVal.add(this.convertTo(mappingToConvert));
        }

        return returnVal;
    }

    /**
     * Utility method to convert from a {@code SQLFormFieldUtil.FormFieldMapping} to a {@code Field}.
     *
     * @param formFieldMappingParam The {@code SQLFormFieldUtil.FormFieldMapping} to convert.
     *
     * @return Converted {@code Field} from {@code SQLFormFieldUtil.FormFieldMapping}.
     */
    @XmlTransient
    public Field convertTo(SQLFormFieldUtil.FormFieldMapping formFieldMappingParam)
    {
        switch (formFieldMappingParam.dataType.intValue())
        {
            //Text...
            case UtilGlobal.FieldTypeId._1_TEXT:
                return new Field(
                        formFieldMappingParam.formFieldId,
                        formFieldMappingParam.name,
                        null, Field.Type.Text);

            //True False...
            case UtilGlobal.FieldTypeId._2_TRUE_FALSE:
                return new Field(
                        formFieldMappingParam.formFieldId,
                        formFieldMappingParam.name,
                        null, Field.Type.TrueFalse);
            //Paragraph Text...
            case UtilGlobal.FieldTypeId._3_PARAGRAPH_TEXT:
                return new Field(
                        formFieldMappingParam.formFieldId,
                        formFieldMappingParam.name,
                        null,
                        Field.Type.ParagraphText);
            //Multiple Choice...
            case UtilGlobal.FieldTypeId._4_MULTI_CHOICE:
                return new Field(
                        formFieldMappingParam.formFieldId,
                        formFieldMappingParam.name,
                        null,
                        Field.Type.MultipleChoice);
            //Date Time...
            case UtilGlobal.FieldTypeId._5_DATE_TIME:
                return new Field(
                        formFieldMappingParam.formFieldId,
                        formFieldMappingParam.name,
                        null,
                        Field.Type.DateTime);
            //Decimal...
            case UtilGlobal.FieldTypeId._6_DECIMAL:
                return new Field(
                        formFieldMappingParam.formFieldId,
                        formFieldMappingParam.name,
                        null,
                        Field.Type.Decimal);
            //Table Field...
            case UtilGlobal.FieldTypeId._7_TABLE_FIELD:

                return new Field(
                        formFieldMappingParam.formFieldId,
                        formFieldMappingParam.name,
                        null,
                        Field.Type.Table);
            //TODO __8__ encrypted field...
            //Label...
            case UtilGlobal.FieldTypeId._9_LABEL:

                return new Field(
                        formFieldMappingParam.formFieldId,
                        formFieldMappingParam.name,
                        formFieldMappingParam.description,
                        Field.Type.Label);
            default:
                throw new IllegalStateException("Unable to map '"+
                        formFieldMappingParam.dataType.intValue() +"', to Form Field value.");
        }
    }
}


/*
 * Koekiebox CONFIDENTIAL
 *
 * [2012] - [2017] Koekiebox (Pty) Ltd
 * All Rights Reserved.
 *
 * NOTICE: All information contained herein is, and remains the property
 * of Koekiebox and its suppliers, if any. The intellectual and
 * technical concepts contained herein are proprietary to Koekiebox
 * and its suppliers and may be covered by South African and Foreign Patents,
 * patents in process, and are protected by trade secret or copyright law.
 * Dissemination of this information or reproduction of this material is strictly
 * forbidden unless prior written permission is obtained from Koekiebox.
 */

package com.fluidbpm.ws.client.v1.config;

import org.json.JSONObject;

import com.fluidbpm.program.api.vo.config.Configuration;
import com.fluidbpm.program.api.vo.config.ConfigurationListing;
import com.fluidbpm.program.api.vo.ws.WS;
import com.fluidbpm.ws.client.v1.ABaseClientWS;

/**
 * Used to change any of the Flow's / Workflows.
 *
 * This is ideal for doing automated tests against
 * the Fluid platform.
 *
 * @author jasonbruwer
 * @since v1.1
 *
 * @see JSONObject
 * @see com.fluidbpm.program.api.vo.ws.WS.Path.Configuration
 * @see com.fluidbpm.program.api.vo.config.Configuration
 * @see ABaseClientWS
 */
public class ConfigurationClient extends ABaseClientWS {

    /**
     * Constructor that sets the Service Ticket from authentication.
     *
     * @param endpointBaseUrlParam URL to base endpoint.
     * @param serviceTicketParam The Server issued Service Ticket.
     */
    public ConfigurationClient(
            String endpointBaseUrlParam,
            String serviceTicketParam) {
        super(endpointBaseUrlParam);

        this.setServiceTicket(serviceTicketParam);
    }

    /**
     * Retrieves a Configuration by Key.
     *
     * @param configurationKeyParam The Flow key.
     * @return The Configuration.
     */
    public Configuration getConfigurationByKey(String configurationKeyParam)
    {
        Configuration configuration = new Configuration();

        configuration.setKey(configurationKeyParam);

        if(this.serviceTicket != null)
        {
            configuration.setServiceTicket(this.serviceTicket);
        }

        return new Configuration(this.postJson(
                configuration, WS.Path.Configuration.Version1.getByKey()));
    }

    /**
     * Retrieves all Configurations.
     *
     * @return All the Configurations.
     */
    public ConfigurationListing getAllConfigurations()
    {
        Configuration configuration = new Configuration();

        if(this.serviceTicket != null)
        {
            configuration.setServiceTicket(this.serviceTicket);
        }

        return new ConfigurationListing(this.postJson(
                configuration, WS.Path.Configuration.Version1.getAllConfigurations()));
    }
}


/*
 * Koekiebox CONFIDENTIAL
 *
 * [2012] - [2017] Koekiebox (Pty) Ltd
 * All Rights Reserved.
 *
 * NOTICE: All information contained herein is, and remains the property
 * of Koekiebox and its suppliers, if any. The intellectual and
 * technical concepts contained herein are proprietary to Koekiebox
 * and its suppliers and may be covered by South African and Foreign Patents,
 * patents in process, and are protected by trade secret or copyright law.
 * Dissemination of this information or reproduction of this material is strictly
 * forbidden unless prior written permission is obtained from Koekiebox.
 */

package com.fluidbpm.program.api.vo.license;

import java.util.Date;

import org.json.JSONException;
import org.json.JSONObject;

import com.fluidbpm.program.api.vo.ABaseFluidJSONObject;
import com.fluidbpm.program.api.vo.ABaseFluidVO;

/**
 * License request for Fluid.
 *
 * @author jasonbruwer on 2018-04-29
 * @since v1.8
 *
 * @see ABaseFluidVO
 */
public class LicenseRequest extends ABaseFluidJSONObject {

    public static final long serialVersionUID = 1L;

    private String machineName;
    private String licenseType;
    private String licenseCipherText;
    private Integer userCount;
    private Date dateValidFrom;
    private Date dateValidTo;

    /**
     * The JSON mapping for the {@code LicenseRequest} object.
     */
    public static class JSONMapping
    {
        public static final String MACHINE_NAME = "machineName";
        public static final String LICENSE_TYPE = "licenseType";
        public static final String USER_COUNT = "userCount";
        public static final String DATE_VALID_FROM = "dateValidFrom";
        public static final String DATE_VALID_TO = "dateValidTo";
        public static final String LICENSE_CIPHER_TEXT = "licenseCipherText";
    }

    /**
     * Default constructor.
     */
    public LicenseRequest() {
        super();
    }

    /**
     * Populates local variables with {@code jsonObjectParam}.
     *
     * @param jsonObjectParam The JSON Object.
     */
    public LicenseRequest(JSONObject jsonObjectParam) {
        super(jsonObjectParam);

        if(this.jsonObject == null)
        {
            return;
        }

        //Machine Name...
        if (!this.jsonObject.isNull(JSONMapping.MACHINE_NAME)) {

            this.setMachineName(this.jsonObject.getString(
                    JSONMapping.MACHINE_NAME));
        }

        //License Type...
        if (!this.jsonObject.isNull(JSONMapping.LICENSE_TYPE)) {

            this.setLicenseType(this.jsonObject.getString(
                    JSONMapping.LICENSE_TYPE));
        }

        //License Cipher Text...
        if (!this.jsonObject.isNull(JSONMapping.LICENSE_CIPHER_TEXT)) {

            this.setLicenseCipherText(this.jsonObject.getString(
                    JSONMapping.LICENSE_CIPHER_TEXT));
        }

        //User Count...
        if (!this.jsonObject.isNull(JSONMapping.USER_COUNT)) {

            this.setUserCount(this.jsonObject.getInt(
                    JSONMapping.USER_COUNT));
        }

        //Date Valid From...
        this.setDateValidFrom(
                this.getDateFieldValueFromFieldWithName(
                        JSONMapping.DATE_VALID_FROM));

        //Date Valid To...
        this.setDateValidTo(
                this.getDateFieldValueFromFieldWithName(
                        JSONMapping.DATE_VALID_TO));
    }

    /**
     * Conversion to {@code JSONObject} from Java Object.
     *
     * @return {@code JSONObject} representation of {@code LicenseRequest}
     * @throws JSONException If there is a problem with the JSON Body.
     *
     * @see ABaseFluidJSONObject#toJsonObject()
     */
    @Override
    public JSONObject toJsonObject() throws JSONException
    {
        JSONObject returnVal = super.toJsonObject();

        //Machine Name...
        if(this.getMachineName() != null)
        {
            returnVal.put(JSONMapping.MACHINE_NAME,
                    this.getMachineName());
        }

        //Cipher Text...
        if(this.getLicenseCipherText() != null)
        {
            returnVal.put(JSONMapping.LICENSE_CIPHER_TEXT,
                    this.getLicenseCipherText());
        }

        //License Type...
        if(this.getLicenseType() != null)
        {
            returnVal.put(JSONMapping.LICENSE_TYPE,
                    this.getLicenseType());
        }

        //User Count...
        if(this.getUserCount() != null)
        {
            returnVal.put(JSONMapping.USER_COUNT,
                    this.getUserCount());
        }

        //Date Valid From...
        if(this.getDateValidFrom() != null)
        {
            returnVal.put(JSONMapping.DATE_VALID_FROM,
                    this.getDateAsLongFromJson(this.getDateValidFrom()));
        }

        //Date Valid To...
        if(this.getDateValidTo() != null)
        {
            returnVal.put(JSONMapping.DATE_VALID_TO,
                    this.getDateAsLongFromJson(this.getDateValidTo()));
        }

        return returnVal;
    }

    /**
     * Gets the Machine name.
     *
     * @return Machine name.
     */
    public String getMachineName() {
        return this.machineName;
    }

    /**
     * Sets the Machine Name.
     *
     * @param machineNameParam The name of the machine.
     */
    public void setMachineName(String machineNameParam) {
        this.machineName = machineNameParam;
    }

    /**
     * Gets the License type.
     *
     * @return License type.
     */
    public String getLicenseType() {
        return this.licenseType;
    }

    /**
     * Sets the license type.
     *
     * @param licenseTypeParam The type of license.
     */
    public void setLicenseType(String licenseTypeParam) {
        this.licenseType = licenseTypeParam;
    }

    /**
     * Gets the user count.
     *
     * @return The number of users.
     */
    public Integer getUserCount() {
        return this.userCount;
    }

    /**
     * Sets the user count.
     *
     * @param userCountParam The number of users.
     */
    public void setUserCount(Integer userCountParam) {
        this.userCount = userCountParam;
    }

    /**
     * Gets the Valid From date.
     *
     * @return The from date.
     */
    public Date getDateValidFrom() {
        return this.dateValidFrom;
    }

    /**
     * Sets the Valid From date.
     *
     * @param dateValidFromParam The from date.
     */
    public void setDateValidFrom(Date dateValidFromParam) {
        this.dateValidFrom = dateValidFromParam;
    }

    /**
     * Gets the Valid to date.
     *
     * @return The to date.
     */
    public Date getDateValidTo() {
        return this.dateValidTo;
    }

    /**
     * Sets the Valid to date.
     *
     * @param dateValidToParam The to date.
     */
    public void setDateValidTo(Date dateValidToParam) {
        this.dateValidTo = dateValidToParam;
    }

    /**
     * Gets the license cipher text.
     *
     * @return The license cypher text.
     */
    public String getLicenseCipherText() {
        return this.licenseCipherText;
    }

    /**
     * Sets the license cipher text.
     *
     * @param licenseCipherTextParam The license cypher text.
     */
    public void setLicenseCipherText(String licenseCipherTextParam) {
        this.licenseCipherText = licenseCipherTextParam;
    }
}


/*
 * Koekiebox CONFIDENTIAL
 *
 * [2012] - [2017] Koekiebox (Pty) Ltd
 * All Rights Reserved.
 *
 * NOTICE: All information contained herein is, and remains the property
 * of Koekiebox and its suppliers, if any. The intellectual and
 * technical concepts contained herein are proprietary to Koekiebox
 * and its suppliers and may be covered by South African and Foreign Patents,
 * patents in process, and are protected by trade secret or copyright law.
 * Dissemination of this information or reproduction of this material is strictly
 * forbidden unless prior written permission is obtained from Koekiebox.
 */

package com.fluidbpm.ws.client.v1.form;

import java.util.List;
import java.util.UUID;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

import org.json.JSONObject;

import com.fluidbpm.program.api.vo.form.Form;
import com.fluidbpm.program.api.vo.ws.WS;
import com.fluidbpm.ws.client.FluidClientException;
import com.fluidbpm.ws.client.v1.websocket.ABaseClientWebSocket;
import com.fluidbpm.ws.client.v1.websocket.AGenericListMessageHandler;
import com.fluidbpm.ws.client.v1.websocket.IMessageReceivedCallback;

/**
 * Java Web Socket Client for {@code Form} related actions.
 *
 * IMPORTANT: This class is Thread safe.
 *
 * @author jasonbruwer
 * @since v1.4
 *
 * @see JSONObject
 * @see WS.Path.FormContainer
 * @see Form
 */
public class WebSocketFormContainerCreateClient extends
        ABaseClientWebSocket<WebSocketFormContainerCreateClient.CreateFormContainerMessageHandler> {

    /**
     * Constructor that sets the Service Ticket from authentication.
     *
     * @param endpointBaseUrlParam URL to base endpoint.
     *
     * @param messageReceivedCallbackParam Callback for when a message is received.
     *
     * @param serviceTicketAsHexParam The Server issued Service Ticket.
     * @param timeoutInMillisParam The timeout of the request in millis.
     */
    public WebSocketFormContainerCreateClient(
            String endpointBaseUrlParam,
            IMessageReceivedCallback<Form> messageReceivedCallbackParam,
            String serviceTicketAsHexParam,
            long timeoutInMillisParam) {
        super(endpointBaseUrlParam,
                messageReceivedCallbackParam,
                timeoutInMillisParam,
                WS.Path.FormContainer.Version1.formContainerCreateWebSocket(
                        serviceTicketAsHexParam));

        this.setServiceTicket(serviceTicketAsHexParam);
    }

    /**
     * Creates a new (Form) for the {@code formToCreateParam}.
     *
     * @param formToCreateParam The Fluid Form to create.
     *
     * @return The {@code formToCreateParam} created as {@code Form}.
     */
    public Form createFormContainerSynchronized(
            Form formToCreateParam) {

        if(formToCreateParam == null)
        {
            return null;
        }

        //Send all the messages...
        if(formToCreateParam.getEcho() == null || formToCreateParam.getEcho().trim().isEmpty())
        {
            formToCreateParam.setEcho(UUID.randomUUID().toString());
        }

        //Start a new request...
        String uniqueReqId = this.initNewRequest();

        //Send the actual message...
        this.sendMessage(formToCreateParam, uniqueReqId);

        try {
            List<Form> returnValue = this.getHandler(uniqueReqId).getCF().get(
                    this.getTimeoutInMillis(),TimeUnit.MILLISECONDS);

            //Connection was closed.. this is a problem....
            if(this.getHandler(uniqueReqId).isConnectionClosed())
            {
                throw new FluidClientException(
                        "WebSocket-CreateFormContainer: " +
                                "The connection was closed by the server prior to the response received.",
                        FluidClientException.ErrorCode.IO_ERROR);
            }

            if(returnValue == null || returnValue.isEmpty())
            {
                return null;
            }

            return returnValue.get(0);
        }
        //Interrupted...
        catch (InterruptedException exceptParam) {

            throw new FluidClientException(
                    "WebSocket-Interrupted-CreateFormContainer: " +
                            exceptParam.getMessage(),
                    exceptParam,
                    FluidClientException.ErrorCode.STATEMENT_EXECUTION_ERROR);
        }
        //Error on the web-socket...
        catch (ExecutionException executeProblem) {

            Throwable cause = executeProblem.getCause();

            //Fluid client exception...
            if(cause instanceof FluidClientException)
            {
                throw (FluidClientException)cause;
            }
            else
            {
                throw new FluidClientException(
                        "WebSocket-CreateFormContainer: " +
                                cause.getMessage(), cause,
                        FluidClientException.ErrorCode.STATEMENT_EXECUTION_ERROR);
            }
        }
        //Timeout...
        catch (TimeoutException eParam) {

            throw new FluidClientException(
                    "WebSocket-CreateFormContainer: Timeout while waiting for all return data. There were '"
                            +this.getHandler(uniqueReqId).getReturnValue().size()
                            +"' items after a Timeout of "+(
                            TimeUnit.MILLISECONDS.toSeconds(this.getTimeoutInMillis()))+" seconds."
                    ,FluidClientException.ErrorCode.IO_ERROR);
        }
        finally {
            this.removeHandler(uniqueReqId);
        }
    }

    /**
     * Create a new instance of the handler class for {@code this} client.
     *
     * @return new instance of {@code CreateFormContainerMessageHandler}
     */
    @Override
    public CreateFormContainerMessageHandler getNewHandlerInstance() {
        return new CreateFormContainerMessageHandler(this.messageReceivedCallback);
    }

    /**
     * Gets the single form. Still relying on a single session.
     */
    static class CreateFormContainerMessageHandler extends AGenericListMessageHandler<Form>
    {
        private Form returnedForm;

        /**
         * The default constructor that sets a ancestor message handler.
         *
         * @param messageReceivedCallbackParam The optional message callback.
         */
        public CreateFormContainerMessageHandler(
                IMessageReceivedCallback<Form> messageReceivedCallbackParam) {

            super(messageReceivedCallbackParam);
        }

        /**
         * New {@code Form} by {@code jsonObjectParam}
         *
         * @param jsonObjectParam The JSON Object to parse.
         * @return new {@code Form}.
         */
        @Override
        public Form getNewInstanceBy(JSONObject jsonObjectParam) {

            this.returnedForm = new Form(jsonObjectParam);

            return this.returnedForm;
        }

        /**
         * Gets the value from that was returned after the WS call.
         *
         * @return The returned form.
         */
        public Form getReturnedForm() {
            return this.returnedForm;
        }
    }
}


/*
 * Koekiebox CONFIDENTIAL
 *
 * [2012] - [2017] Koekiebox (Pty) Ltd
 * All Rights Reserved.
 *
 * NOTICE: All information contained herein is, and remains the property
 * of Koekiebox and its suppliers, if any. The intellectual and
 * technical concepts contained herein are proprietary to Koekiebox
 * and its suppliers and may be covered by South African and Foreign Patents,
 * patents in process, and are protected by trade secret or copyright law.
 * Dissemination of this information or reproduction of this material is strictly
 * forbidden unless prior written permission is obtained from Koekiebox.
 */

package com.fluidbpm.program.api.vo.auth0;

import java.util.ArrayList;
import java.util.List;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import com.fluidbpm.program.api.vo.ABaseFluidJSONObject;

/**
 * An Auth0 connection used by Fluid.
 *
 * See more at: https://auth0.com/
 *
 * @author jasonbruwer
 * @since v1.0
 *
 * @see NormalizedUserProfile
 * @see ABaseFluidJSONObject
 */
public class Connection extends ABaseFluidJSONObject {

    public static final long serialVersionUID = 1L;

    private String userId;
    private String name;
    private String email;
    private boolean emailVerified;
    private String nickname;
    private String picture;
    private String givenName;
    private String familyName;
    private String locale;

    private List<Client> identities;

    /**
     * The JSON mapping for the {@code Connection} object.
     */
    public static class JSONMapping
    {
        public static final String USER_ID = "user_id";
        public static final String NAME = "name";
        public static final String EMAIL = "email";
        public static final String EMAIL_VERIFIED = "email_verified";
        public static final String NICKNAME = "nickname";
        public static final String PICTURE = "picture";
        public static final String GIVEN_NAME = "given_name";
        public static final String FAMILY_NAME = "family_name";

        public static final String IDENTITIES = "identities";//Array...
        //Done with identities...

        public static final String LOCALE = "locale";
    }

    /**
     * Client representation of a client.
     *
     * @see ABaseFluidJSONObject
     */
    public static class Client extends ABaseFluidJSONObject
    {
        public static final long serialVersionUID = 1L;

        private String accessToken;
        private String provider;
        private String userId;
        private String connection;
        private boolean isSocial;

        /**
         * The JSON mapping for the {@code Client} object.
         */
        public static class JSONMapping
        {
            public static final String USER_ID = "user_id";
            public static final String ACCESS_TOKEN = "access_token";
            public static final String PROVIDER = "provider";
            public static final String CONNECTION = "connection";
            public static final String IS_SOCIAL = "isSocial";
        }

        /**
         * Default constructor.
         */
        public Client() {
            super();
        }

        /**
         * Populates local variables with {@code jsonObjectParam}.
         *
         * @param jsonObjectParam The JSON Object.
         */
        public Client(JSONObject jsonObjectParam) {
            super(jsonObjectParam);

            if(this.jsonObject == null)
            {
                return;
            }

            //Access Token...
            if (!this.jsonObject.isNull(JSONMapping.ACCESS_TOKEN)) {
                this.setAccessToken(this.jsonObject.getString(
                        JSONMapping.ACCESS_TOKEN));
            }

            //Provider...
            if (!this.jsonObject.isNull(JSONMapping.PROVIDER)) {
                this.setProvider(this.jsonObject.getString(
                        JSONMapping.PROVIDER));
            }

            //User Id...
            if (!this.jsonObject.isNull(Connection.JSONMapping.USER_ID)) {
                this.setUserId(this.jsonObject.getString(
                        JSONMapping.USER_ID));
            }

            //Connection...
            if (!this.jsonObject.isNull(JSONMapping.CONNECTION)) {
                this.setConnection(this.jsonObject.getString(
                        JSONMapping.CONNECTION));
            }

            //Is Social...
            if (!this.jsonObject.isNull(JSONMapping.IS_SOCIAL)) {
                this.setSocial(this.jsonObject.getBoolean(
                        JSONMapping.IS_SOCIAL));
            }
        }

        /**
         * Gets the Access Token.
         *
         * @return Access Token.
         */
        public String getAccessToken() {
            return this.accessToken;
        }

        /**
         * Sets the Access Token.
         *
         * @param accessTokenParam Access Token.
         */
        public void setAccessToken(String accessTokenParam) {
            this.accessToken = accessTokenParam;
        }

        /**
         * Gets the Provider.
         *
         * @return Provider.
         */
        public String getProvider() {
            return this.provider;
        }

        /**
         * Sets the Provider.
         *
         * @param providerParam Provider.
         */
        public void setProvider(String providerParam) {
            this.provider = providerParam;
        }

        /**
         * Gets the User Id.
         *
         * @return User Id.
         */
        public String getUserId() {
            return this.userId;
        }

        /**
         * Sets the User Id.
         *
         * @param userIdParam User Id.
         */
        public void setUserId(String userIdParam) {
            this.userId = userIdParam;
        }

        /**
         * Gets the Connection.
         *
         * @return The Connection.
         */
        public String getConnection() {
            return this.connection;
        }

        /**
         * Sets the Connection.
         *
         * @param connectionParam The Connection.
         */
        public void setConnection(String connectionParam) {
            this.connection = connectionParam;
        }

        /**
         * Gets whether the Client is social.
         *
         * @return Whether the Client is social.
         */
        public boolean isSocial() {
            return this.isSocial;
        }

        /**
         * Sets whether the Client is social.
         *
         * @param socialParam Whether the Client is social.
         */
        public void setSocial(boolean socialParam) {
            this.isSocial = socialParam;
        }

        /**
         * Conversion to {@code JSONObject} from Java Object.
         *
         * @return {@code JSONObject} representation of {@code Client}
         * @throws JSONException If there is a problem with the JSON Body.
         *
         * @see ABaseFluidJSONObject#toJsonObject()
         */
        @Override
        public JSONObject toJsonObject() throws JSONException {

            JSONObject returnVal = super.toJsonObject();

            //Access Token...
            if(this.getAccessToken() != null)
            {
                returnVal.put(JSONMapping.ACCESS_TOKEN, this.getAccessToken());
            }

            //Provider...
            if(this.getProvider() != null)
            {
                returnVal.put(JSONMapping.PROVIDER, this.getProvider());
            }

            //User Id...
            if(this.getUserId() != null)
            {
                returnVal.put(JSONMapping.USER_ID, this.getUserId());
            }

            //Connection...
            if(this.getConnection() != null)
            {
                returnVal.put(JSONMapping.CONNECTION, this.getConnection());
            }

            //Is Social...
            returnVal.put(JSONMapping.IS_SOCIAL, this.isSocial());

            return returnVal;
        }
    }

    /**
     * Default constructor.
     */
    public Connection() {
        super();
    }

    /**
     * Populates local variables with {@code jsonObjectParam}.
     *
     * @param jsonObjectParam The JSON Object.
     */
    public Connection(JSONObject jsonObjectParam) {
        super(jsonObjectParam);

        if(this.jsonObject == null)
        {
            return;
        }

        //User Id...
        if (!this.jsonObject.isNull(JSONMapping.USER_ID)) {
            this.setUserId(this.jsonObject.getString(JSONMapping.USER_ID));
        }

        //Name...
        if (!this.jsonObject.isNull(JSONMapping.NAME)) {
            this.setName(this.jsonObject.getString(JSONMapping.NAME));
        }

        //Email...
        if (!this.jsonObject.isNull(JSONMapping.EMAIL)) {
            this.setEmail(this.jsonObject.getString(JSONMapping.EMAIL));
        }

        //Email Verified...
        if (!this.jsonObject.isNull(JSONMapping.EMAIL_VERIFIED)) {
            this.setEmailVerified(this.jsonObject.getBoolean(JSONMapping.EMAIL_VERIFIED));
        }

        //Nickname...
        if (!this.jsonObject.isNull(JSONMapping.NICKNAME)) {
            this.setNickname(this.jsonObject.getString(JSONMapping.NICKNAME));
        }

        //Picture...
        if (!this.jsonObject.isNull(JSONMapping.PICTURE)) {
            this.setPicture(this.jsonObject.getString(JSONMapping.PICTURE));
        }

        //Given Name...
        if (!this.jsonObject.isNull(JSONMapping.GIVEN_NAME)) {
            this.setGivenName(this.jsonObject.getString(JSONMapping.GIVEN_NAME));
        }

        //Family Name...
        if (!this.jsonObject.isNull(JSONMapping.FAMILY_NAME)) {
            this.setFamilyName(this.jsonObject.getString(JSONMapping.FAMILY_NAME));
        }

        //Locale...
        if (!this.jsonObject.isNull(JSONMapping.LOCALE)) {
            this.setLocale(this.jsonObject.getString(JSONMapping.LOCALE));
        }

        //Roles...
        if (!this.jsonObject.isNull(JSONMapping.IDENTITIES)) {

            this.identities = new ArrayList<Client>();

            JSONArray identityListing = this.jsonObject.getJSONArray(JSONMapping.IDENTITIES);

            for(int index = 0;index < identityListing.length();index++)
            {
                this.identities.add(new Client(identityListing.getJSONObject(index)));
            }
        }
    }

    /**
     * Gets the User Id.
     *
     * @return User Id.
     */
    public String getUserId() {
        return this.userId;
    }

    /**
     * Sets the User Id.
     *
     * @param userIdParam User Id.
     */
    public void setUserId(String userIdParam) {
        this.userId = userIdParam;
    }

    /**
     * Gets the name.
     *
     * @return The name.
     */
    public String getName() {
        return this.name;
    }

    /**
     * Sets the name.
     *
     * @param nameParam The name.
     */
    public void setName(String nameParam) {
        this.name = nameParam;
    }

    /**
     * Gets the Email.
     *
     * @return The Email.
     */
    public String getEmail() {
        return this.email;
    }

    /**
     * Sets the Email.
     *
     * @param emailParam The Email.
     */
    public void setEmail(String emailParam) {
        this.email = emailParam;
    }

    /**
     * Gets whether the email is verified.
     *
     * @return Email Verified.
     */
    public boolean isEmailVerified() {
        return this.emailVerified;
    }

    /**
     * Sets whether the email is verified.
     *
     * @param emailVerifiedParam Email Verified.
     */
    public void setEmailVerified(boolean emailVerifiedParam) {
        this.emailVerified = emailVerifiedParam;
    }

    /**
     * Gets the User nickname.
     *
     * @return User Nickname.
     */
    public String getNickname() {
        return this.nickname;
    }

    /**
     * Sets the User nickname.
     *
     * @param nicknameParam User Nickname.
     */
    public void setNickname(String nicknameParam) {
        this.nickname = nicknameParam;
    }

    /**
     * Gets URL to the Users picture.
     *
     * @return Link to picture.
     */
    public String getPicture() {
        return this.picture;
    }

    /**
     * Sets URL to the Users picture.
     *
     * @param pictureParam Link to picture.
     */
    public void setPicture(String pictureParam) {
        this.picture = pictureParam;
    }

    /**
     * Gets the User's given name.
     *
     * @return Given name.
     */
    public String getGivenName() {
        return this.givenName;
    }

    /**
     * Sets the User's given name.
     *
     * @param givenNameParam Given name.
     */
    public void setGivenName(String givenNameParam) {
        this.givenName = givenNameParam;
    }

    /**
     * Gets the User's given name.
     *
     * @return User Family Name.
     */
    public String getFamilyName() {
        return this.familyName;
    }

    /**
     * Sets the User's given name.
     *
     * @param familyNameParam User Family Name.
     */
    public void setFamilyName(String familyNameParam) {
        this.familyName = familyNameParam;
    }

    /**
     * Gets the User's locale.
     *
     * @return Users Locale.
     */
    public String getLocale() {
        return this.locale;
    }

    /**
     * Sets the User's locale.
     *
     * @param localeParam Users Locale.
     */
    public void setLocale(String localeParam) {
        this.locale = localeParam;
    }

    /**
     * Gets the Identities associated with the user.
     *
     * @return User's Identities.
     */
    public List<Client> getIdentities() {
        return this.identities;
    }

    /**
     * Sets the Identities associated with the user.
     *
     * @param identitiesParam User's Identities.
     */
    public void setIdentities(List<Client> identitiesParam) {
        this.identities = identitiesParam;
    }

    /**
     * Gets a comma seperated list of providers from {@code Identity}'s.
     *
     * @return Text list of Providers for user {@code Identities}.
     *
     * @see NormalizedUserProfile#getIdentities()
     */
    public String getListOfProvidersFromIdentities()
    {
        if(this.getIdentities() == null || this.getIdentities().isEmpty())
        {
            return "";
        }

        StringBuilder returnVal = new StringBuilder();

        for(Client client : this.getIdentities())
        {
            returnVal.append(client.getProvider());
            returnVal.append(",");
        }

        String toString = returnVal.toString();
        return toString.substring(0,toString.length() - 1);
    }

    /**
     * Conversion to {@code JSONObject} from Java Object.
     *
     * @return {@code JSONObject} representation of {@code Connection}.
     * @throws JSONException If there is a problem with the JSON Body.
     *
     * @see ABaseFluidJSONObject#toJsonObject()
     */
    @Override
    public JSONObject toJsonObject() throws JSONException {

        JSONObject returnVal = super.toJsonObject();

        //User Id...
        if(this.getUserId() != null)
        {
            returnVal.put(JSONMapping.USER_ID, this.getUserId());
        }

        //Name...
        if(this.getName() != null)
        {
            returnVal.put(JSONMapping.NAME, this.getName());
        }

        //Email...
        if(this.getEmail() != null)
        {
            returnVal.put(JSONMapping.EMAIL, this.getEmail());
        }

        //Email Verified...
        returnVal.put(JSONMapping.EMAIL_VERIFIED, this.isEmailVerified());

        //Nickname...
        if(this.getNickname() != null)
        {
            returnVal.put(JSONMapping.NICKNAME, this.getNickname());
        }

        //Picture...
        if(this.getPicture() != null)
        {
            returnVal.put(JSONMapping.PICTURE, this.getPicture());
        }

        //Given Name...
        if(this.getGivenName() != null)
        {
            returnVal.put(JSONMapping.GIVEN_NAME, this.getGivenName());
        }

        //Family Name...
        if(this.getFamilyName() != null)
        {
            returnVal.put(JSONMapping.FAMILY_NAME, this.getFamilyName());
        }

        //Locale...
        if(this.getLocale() != null)
        {
            returnVal.put(JSONMapping.LOCALE, this.getLocale());
        }

        //Identities...
        if(this.getIdentities() != null && !this.getIdentities().isEmpty())
        {
            JSONArray identitiesArr = new JSONArray();
            for(Client toAdd :this.getIdentities())
            {
                identitiesArr.put(toAdd.toJsonObject());
            }

            returnVal.put(JSONMapping.IDENTITIES,identitiesArr);
        }

        return returnVal;
    }
}


/*
 * Koekiebox CONFIDENTIAL
 *
 * [2012] - [2017] Koekiebox (Pty) Ltd
 * All Rights Reserved.
 *
 * NOTICE: All information contained herein is, and remains the property
 * of Koekiebox and its suppliers, if any. The intellectual and
 * technical concepts contained herein are proprietary to Koekiebox
 * and its suppliers and may be covered by South African and Foreign Patents,
 * patents in process, and are protected by trade secret or copyright law.
 * Dissemination of this information or reproduction of this material is strictly
 * forbidden unless prior written permission is obtained from Koekiebox.
 */

package com.fluidbpm.ws.client.v1.attachment;

import java.util.List;

import com.fluidbpm.program.api.vo.attachment.Attachment;
import com.fluidbpm.program.api.vo.attachment.AttachmentListing;
import com.fluidbpm.program.api.vo.form.Form;
import com.fluidbpm.program.api.vo.ws.WS;
import com.fluidbpm.ws.client.v1.ABaseClientWS;

/**
 * Used to upload attachment data for {@code Form}s.
 *
 * This is ideal for doing automated tests against
 * the Fluid platform.
 *
 * @author jasonbruwer
 * @since v1.8
 * @version v1.8
 *
 * @see com.fluidbpm.program.api.vo.attachment.Attachment
 * @see ABaseClientWS
 */
public class AttachmentClient extends ABaseClientWS {

    /**
     * Constructor that sets the Service Ticket from authentication.
     *
     * @param endpointBaseUrlParam URL to base endpoint.
     * @param serviceTicketParam The Server issued Service Ticket.
     */
    public AttachmentClient(String endpointBaseUrlParam,
                            String serviceTicketParam) {
        super(endpointBaseUrlParam);

        this.setServiceTicket(serviceTicketParam);
    }

    /**
     * Uploads a new Attachment.
     * If there is an existing attachment with the same name, a new version will be
     * uploaded.
     *
     * @param attachmentParam The attachment to upload.
     * @return The created attachment.
     *
     * @see Attachment
     */
    public Attachment createAttachment(Attachment attachmentParam)
    {
        if(attachmentParam != null && this.serviceTicket != null)
        {
            attachmentParam.setServiceTicket(this.serviceTicket);
        }

        return new Attachment(this.putJson(
                attachmentParam, WS.Path.Attachment.Version1.attachmentCreate()));
    }

    /**
     * Retrieves a Attachment by Primary Key.
     *
     * @param attachmentIdParam The Attachment primary key.
     * @param includeAttachmentDataParam Include the attachment data (Base-64).
     *
     * @return The Attachment associated with {@code attachmentIdParam}.
     */
    public Attachment getAttachmentById(
            Long attachmentIdParam,
            boolean includeAttachmentDataParam)
    {
        Attachment attachment = new Attachment(attachmentIdParam);

        if(this.serviceTicket != null)
        {
            attachment.setServiceTicket(this.serviceTicket);
        }

        return new Attachment(this.postJson(
                attachment, WS.Path.Attachment.Version1.getById(
                        includeAttachmentDataParam)));
    }

    /**
     * Retrieves all the Attachments associated with Form {@code formParam}.
     *
     * @param formParam The Form to use for lookup.
     * @param includeAttachmentDataParam Include the attachment data (Base-64).
     *
     * @return The Attachments associated with {@code formParam}.
     */
    public List<Attachment> getAttachmentsByForm(
            Form formParam,
            boolean includeAttachmentDataParam)
    {
        if(formParam != null && this.serviceTicket != null)
        {
            formParam.setServiceTicket(this.serviceTicket);
        }

        AttachmentListing returnedListing =
                new AttachmentListing(postJson(
                        formParam, WS.Path.Attachment.Version1.getAllByFormContainer(
                                includeAttachmentDataParam,false)));

        return (returnedListing == null) ? null :
                returnedListing.getListing();
    }

    /**
     * Retrieves only {@code image} Attachments by Primary Key.
     *
     * @param formParam The Form to use for lookup.
     * @param includeAttachmentDataParam Include the attachment data (Base-64).
     *
     * @return The Attachment associated with {@code attachmentIdParam}.
     */
    public List<Attachment> getImageAttachmentsByForm(
            Form formParam,
            boolean includeAttachmentDataParam)
    {
        if(formParam != null && this.serviceTicket != null)
        {
            formParam.setServiceTicket(this.serviceTicket);
        }

        AttachmentListing returnedListing =
                new AttachmentListing(postJson(
                        formParam, WS.Path.Attachment.Version1.getAllByFormContainer(
                                includeAttachmentDataParam, true)));

        return (returnedListing == null) ? null :
                returnedListing.getListing();
    }

    /**
     * Delete an existing Attachment.
     *
     * @param attachmentParam The Attachment to delete.
     * @return The deleted Attachment.
     */
    public Attachment deleteAttachment(Attachment attachmentParam)
    {
        if(attachmentParam != null && this.serviceTicket != null)
        {
            attachmentParam.setServiceTicket(this.serviceTicket);
        }

        return new Attachment(this.postJson(
                attachmentParam, WS.Path.Attachment.Version1.attachmentDelete()));
    }

    /**
     * Forcefully Delete an existing Attachment.
     *
     * Only 'admin' can forcefully delete a Attachment.
     *
     * @param attachmentParam The Attachment to delete.
     * @return The deleted Attachment.
     */
    public Attachment forceDeleteAttachment(Attachment attachmentParam)
    {
        if(attachmentParam != null && this.serviceTicket != null)
        {
            attachmentParam.setServiceTicket(this.serviceTicket);
        }

        return new Attachment(this.postJson(
                attachmentParam,
                WS.Path.Attachment.Version1.attachmentDelete(true)));
    }
}