/**
 * This is the base class for all reports.
 */
class Report {
	/**
	 * Returns an object containing objects with the friendly field names and other properties.
	 * Field keys not found in this object will be displayed directly to the user.
	 */
	get fieldInformation() {
		return { };
	}

	/**
	 * Returns an object with the default field information that will apply if no specific rules are set for a column in the field information object.
	 */
	get defaultFieldInformation() {
		return {
			displayName: "unnamed",
			type: "string"
		};
	}

	/**
	 * Returns the request path of this report. It is relative to the application's request path.
	 */
	get requestPath() {
		return "";
	}

	/**
	 * Returns the friendly name of this report.
	 */
	get name() {
		return "Unnamed report";
	}

	constructor() {
		//Construct the empty data array.
		var titleRow = Object.keys(this.fieldInformation);
		this.data = [ titleRow ];
	}

	/**
	 * Returns the matching field name for the given field key.
	 * Will return the field key itself if no matching friendly name was found.
	 */
	getFieldName(key) {
		if (key in this.fieldNames) {
			return this.fieldNames[key].displayName;
		}

		return key;
	}

	/**
	 * Constructs the table title cell with the given field name and field information.
	 * The element that is passed as the third parameter is the cell element that may be filled to the developer's heart's content.
	 */
	buildTitleCell(fieldName, fieldInformation, cell) {
		cell.innerText = fieldInformation.displayName;
		cell.style.textAlign = this.getTextAlignForFieldType(fieldInformation.type);
	}

	/**
	 * Constructs the table cell with the given field name, value and field information.
	 * The element that is passed as the fourth parameter is the cell element that may be filled to the developer's heart's content.
	 * The index parameter is the current row index of the cell. Notice that 0 is the header row and 1 is the actual first row.
	 */
	buildCell(fieldName, value, fieldInformation, cell, index) {
		cell.innerText = value;
		cell.style.textAlign = this.getTextAlignForFieldType(fieldInformation.type);
	}

	/**
	 * Generates the raw text content with the given field name, value and field information.
	 * Returns the raw value by default. This behaviour may be overridden by other reports.
	 */
	buildCSVCell(fieldName, value, fieldInformation, index) {
		return value;
	}

	/**
	 * Constructs the table cell with the given value for use in the aggregation row.
	 */
	buildAggregationCell(fieldName, value, fieldInformation, cell) {
		cell.innerText = value;
		cell.style.textAlign = this.getTextAlignForFieldType(fieldInformation.type);
	}

	/**
	 * Returns the appropriate text alignment for the given field type as a string ("left", "right", "center").
	 * The default alignment is "left".
	 */
	getTextAlignForFieldType(type) {
		if (type == "boolean") {
			return "center";
		}
		else if ([ "number", "currency", "time" ].indexOf(type) != -1) {
			return "right";
		}

		return "left";
	}

	/**
	 * Returns the field information for the column with the given field name.
	 */
	getFieldInformation(fieldName) {
		//Get the default field information that is used when no specific rules are defined.
		var fieldInformation = this.defaultFieldInformation;

		//Use the raw field name as the default display name.
		fieldInformation.displayName = fieldName;

		//Override the default field information with the custom rules, if applicable.
		if (fieldName in this.fieldInformation) {
			var customFieldInformation = this.fieldInformation[fieldName];

			for (var property in customFieldInformation) {
				fieldInformation[property] = customFieldInformation[property];
			}
		}

		return fieldInformation;
	}
}