package com.uas.report.axis;

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

import com.uas.report.util.StringUtils;

public class ResourceDescriptor {

	public static final String TYPE_FOLDER = "folder";
	public static final String TYPE_REPORTUNIT = "reportUnit";

	public static final String TYPE_REFERENCE = "reference";
	public static final String REFERENCE_TYPE = "referenceType";

	public static final String PROP_VERSION = "PROP_VERSION";
	public static final String PROP_PARENT_FOLDER = "PROP_PARENT_FOLDER";
	public static final String PROP_RESOURCE_TYPE = "PROP_RESOURCE_TYPE";

	// File resource properties
	public static final String PROP_FILERESOURCE_HAS_DATA = "PROP_HAS_DATA";

	public static final String TYPE_IMAGE = "img";
	public static final String TYPE_FONT = "font";
	public static final String TYPE_JRXML = "jrxml";
	public static final String TYPE_JAR = "jar";
	public static final String TYPE_RESOURCE_BUNDLE = "prop";
	public static final String TYPE_STYLE_TEMPLATE = "jrtx";
	public static final String TYPE_XML = "xml";
	public static final String TYPE_JSON = "json";
	public static final String TYPE_CSS = "css";
	public static final String TYPE_ACCESS_GRANT_SCHEMA = "accessGrantSchema";
	public static final String TYPE_MONGODB_JDBC_CONFIG = "config";
	public static final String TYPE_AZURE_CERTIFICATE = "cer";
	public static final String TYPE_SECURE_FILE = "secureFile";
	public static final String TYPE_DASHBOARD_COMPONENTS_SCHEMA = "dashboardComponent";
	public static final String TYPE_UNKNOW = "unknow";

	// SQL resource properties
	public static final String PROP_QUERY_DATA = "PROP_QUERY_DATA";
	public static final String PROP_QUERY_DATA_ROW = "PROP_QUERY_DATA_ROW";
	public static final String PROP_QUERY_DATA_ROW_COLUMN = "PROP_QUERY_DATA_ROW_COLUMN";

	private List<ResourceProperty> properties = new ArrayList<>();
	private HashMap<String, ResourceProperty> hm = new HashMap<>();

	private String name;
	private String label;
	private String description;
	private boolean isNew = false;
	private String wsType;
	private String uriString;

	private Date creationDate;

	private List<ResourceDescriptor> children = new ArrayList<>();
	private List<ListItem> parameters = new ArrayList<>();

	// This data is used to store the data for sunsequent calls to
	// getQueryData....
	private List<InputControlQueryDataRow> queryDataCache = null;
	private byte[] data;
	private String fileType;
	private String referenceType;

	public List<ResourceProperty> getProperties() {
		return properties;
	}

	public void setProperties(List<ResourceProperty> properties) {
		this.properties = properties;
	}

	public HashMap<String, ResourceProperty> getHm() {
		return hm;
	}

	public void setHm(HashMap<String, ResourceProperty> hm) {
		this.hm = hm;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getLabel() {
		return label;
	}

	public void setLabel(String label) {
		this.label = label;
	}

	public String getWsType() {
		return wsType;
	}

	public void setWsType(String wsType) {
		this.wsType = wsType;
	}

	public String getUriString() {
		return uriString;
	}

	public void setUriString(String uriString) {
		this.uriString = uriString;
	}

	public boolean isNew() {
		return isNew;
	}

	public void setIsNew(boolean isNew) {
		this.isNew = isNew;
	}

	public String getDescription() {
		return description;
	}

	public void setDescription(String description) {
		this.description = description;
	}

	public Date getCreationDate() {
		return creationDate;
	}

	public void setCreationDate(Date creationDate) {
		this.creationDate = creationDate;
	}

	public List<ResourceDescriptor> getChildren() {
		return children;
	}

	public void setChildren(List<ResourceDescriptor> children) {
		this.children = children;
	}

	public List<ListItem> getParameters() {
		return parameters;
	}

	public void setParameters(List<ListItem> parameters) {
		this.parameters = parameters;
	}

	public byte[] getData() {
		return data;
	}

	public void setData(byte[] data) {
		this.data = data;
	}

	public String getReferenceType() {
		return referenceType;
	}

	public void setReferenceType(String referenceType) {
		this.referenceType = referenceType;
	}

	public List<InputControlQueryDataRow> getQueryDataCache() {
		return queryDataCache;
	}

	public void setQueryDataCache(List<InputControlQueryDataRow> queryDataCache) {
		this.queryDataCache = queryDataCache;
	}

	public String getFileType() {
		return fileType;
	}

	public void setFileType(String fileType) {
		this.fileType = fileType;
	}

	public void setVersion(int version) {
		setResourceProperty(PROP_VERSION, "" + version);
	}

	public int getVersion() {
		String version = getResourcePropertyValue(PROP_VERSION);
		if (StringUtils.isEmpty(version)) {
			return Resource.DEFAULT_VERSION;
		}
		return Integer.parseInt(version);
	}

	public boolean hasData() {
		String s = getResourcePropertyValue(PROP_FILERESOURCE_HAS_DATA);
		if (s != null)
			return s.equals("true");
		return false;
	}

	public void setHasData(boolean hasData) {
		setResourceProperty(PROP_FILERESOURCE_HAS_DATA, "" + hasData);
	}

	public String getResourceType() {
		return getResourcePropertyValue(PROP_RESOURCE_TYPE);
	}

	public void setResourceType(String resourceType) {
		setResourceProperty(PROP_RESOURCE_TYPE, resourceType);
	}

	public void setParentFolder(String parentFolder) {
		setResourceProperty(PROP_PARENT_FOLDER, parentFolder);
	}

	public String getParentFolder() {
		return getResourcePropertyValue(PROP_PARENT_FOLDER);
	}

	/**
	 * Return the property PROP_QUERY_DATA as set of InputControlQueryDataRow
	 * the structure is as follow: PROP_QUERY_DATA { PROP_QUERY_DATA_ROW {
	 * PROP_QUERY_DATA_COLUMN_VALUE } } } This method is performed only once,
	 * and the result is cached in queryDataCache. Subsequent calls to this
	 * method will return always queryDataCache.
	 * 
	 */
	public List<InputControlQueryDataRow> getQueryData() {

		if (queryDataCache != null)
			return queryDataCache;

		queryDataCache = new ArrayList<>();

		ResourceProperty rp = getResourceProperty(PROP_QUERY_DATA);
		if (rp != null) {
			// Look for rows....
			for (int i = 0; i < rp.getProperties().size(); ++i) {
				ResourceProperty rpRow = (ResourceProperty) rp.getProperties().get(i);
				if (rpRow.getName().equals(PROP_QUERY_DATA_ROW)) {
					InputControlQueryDataRow icqdr = new InputControlQueryDataRow();
					icqdr.setValue(rpRow.getValue());

					// Look for row details...
					for (int k = 0; k < rpRow.getProperties().size(); ++k) {
						ResourceProperty rpRowChild = (ResourceProperty) rpRow.getProperties().get(k);
						if (rpRowChild.getName().equals(PROP_QUERY_DATA_ROW_COLUMN)) {
							icqdr.getColumnValues().add(rpRowChild.getValue());
						}
					}

					queryDataCache.add(icqdr);
				}
			}

		}
		return queryDataCache;
	}

	/**
	 * Convenient way to create the PROP_QUERY_DATA properties from a set of
	 * InputControlQueryDataRow the structure will be create as follow:
	 * PROP_QUERY_DATA { PROP_QUERY_DATA_ROW { PROP_QUERY_DATA_COLUMN_VALUE } }
	 * } A call to this method will set to null the queryDataCache
	 * 
	 */
	public void setQueryData(List<InputControlQueryDataRow> queryData) {

		queryDataCache = null;

		ResourceProperty rp = new ResourceProperty(PROP_QUERY_DATA);

		for (int i = 0; i < queryData.size(); ++i) {
			InputControlQueryDataRow icqdr = queryData.get(i);

			ResourceProperty rpRow = new ResourceProperty(PROP_QUERY_DATA_ROW, "" + icqdr.getValue());

			for (int k = 0; k < icqdr.getColumnValues().size(); ++k) {
				Object columnValue = icqdr.getColumnValues().get(k);
				rpRow.getProperties().add(new ResourceProperty(PROP_QUERY_DATA_ROW_COLUMN,
						(columnValue == null) ? "" : "" + columnValue));
			}

			rp.getProperties().add(rpRow);
		}

		setResourceProperty(rp);

	}

	public ResourceProperty getResourceProperty(String resourcePropertyName) {
		return hm.get(resourcePropertyName);
	}

	/**
	 * Return the value of the property resourcePropertyName as String Return
	 * null if the property is not found or the [operty value is null.
	 *
	 */
	public String getResourcePropertyValue(String resourcePropertyName) {
		ResourceProperty rp = getResourceProperty(resourcePropertyName);
		if (rp != null)
			return rp.getValue();

		return null;
	}

	/**
	 * Add or replace the resource property in the ResourceDescriptor.
	 */
	public void setResourceProperty(ResourceProperty rp) {
		if (rp == null)
			return;
		removeResourceProperty(rp.getName());
		this.getProperties().add(rp);
		this.hm.put(rp.getName(), rp);
	}

	/**
	 * Remove all the resource properties with name = rp.getName()
	 */
	public void removeResourceProperty(ResourceProperty rp) {
		removeResourceProperty(rp.getName());
	}

	/**
	 * Remove all resources with name = resourcePropertyName
	 */
	public void removeResourceProperty(String resourcePropertyName) {
		Object obj = this.hm.remove(resourcePropertyName);
		if (obj != null) {
			this.getProperties().remove(obj);
		}
	}

	/**
	 * Setting a property to a null value is the same as remove it.
	 *
	 */
	public void setResourceProperty(String resourcePropertyName, String value) {
		if (resourcePropertyName == null)
			return;
		if (value == null) {
			removeResourceProperty(resourcePropertyName);
		} else {
			ResourceProperty rp = new ResourceProperty(resourcePropertyName);
			rp.setValue(value);
			setResourceProperty(rp);
		}
	}

	@Override
	public String toString() {
		return "ResourceDescriptor [properties=" + properties + ", hm=" + hm + ", name=" + name + ", label=" + label
				+ ", description=" + description + ", isNew=" + isNew + ", wsType=" + wsType + ", uriString="
				+ uriString + ", creationDate=" + creationDate + ", children=" + children + ", parameters=" + parameters
				+ ", queryDataCache=" + queryDataCache + ", data=" + Arrays.toString(data) + ", fileType=" + fileType
				+ ", referenceType=" + referenceType + "]";
	}

}
