
/*
 * Resilient JHipster JDL file definition.
 * DON'T use infinite-scroll. The infinite-scroll paginate option 
 * 	has some kind of error, and makes it IMPOSSIBLE to login into the
 * 	APP.
 */

// POST generation metadata
// This metadata set the order of fields. And the only ones visible. All others, will be hidden
// @@ List::   < A list of properties for the list view. Ex: code;name;description >
// @@ Update:: < A list of properties for the Update/Create form. Ex: code;name;description >
// @@ View::   < A list of properties for the Detail form. Ex: code;name;description >
// The properties in this list, will be EDITABLE only when in CREATE mode. Readonly otherwise
// @@ READONLY::   < A list of properties for the Detail form. Ex: code;name;description >
// @@ IMAGE:: 	<Tells the post-generator to customize HTML of this type of fields>

/**
 * Monolith app
 * 
 * Resilient core functions microservice.
 */
application {
  config {
    baseName resilient
    packageName com.oguerreiro.resilient
    applicationType monolith
    authenticationType session
	devDatabaseType mysql
    prodDatabaseType mysql
    clientFramework angularX
    buildTool maven
    cacheProvider ehcache
    enableHibernateCache true
    enableTranslation true
    languages [pt-pt, en]
    nativeLanguage pt-pt
    serverPort 8081
  }
  
  entities *
}

/**
 * **************************************************
 * Core - Entities & Relations
 * **************************************************
 */

/**
 * Organization Nature enum
 * This identifies the nature of the organization entry level.
 */
enum OrganizationNature {
  /** 
  * Represents an organizational level (company; department; university; ...) 
  * Rules		    : An Organization always starts with and entry level ORGANIZATION. 
  * Parent's allowed: none; ORGANIZATION; LEVEL
  */
  ORGANIZATION,
  
  /** 
  * Represents a human. With or without a login to the APP. 
  * Rules			: Must have a parent Organization entry
  * Parent's allowed: any
  */
  PERSON,
  
  /** 
  * Represents physical building. 
  * Rules			: Must have a parent Organization entry
  * Parent's allowed: ORGANIZATION; LEVEL
  */
  FACILITY,
  
  /** 
  * Generic. Its a organizer, creating a level without any system meaning 
  * Rules			: Must have a parent Organization entry
  * Parent's allowed: any
  */
  LEVEL
}

/**
 * Organization Type
 * The organization type is a setup that defines the usage of the Organization level and other configurations.
 */
@dto(mapstruct)
entity OrganizationType {
  // @@ List:: icon;name;description
  // @@ Update:: code;name;description;nature;icon;metadataProperties
  // @@ View:: code;name;description;nature;icon;metadataProperties
  // @@ READONLY:: code;nature
  // @@ IMAGE:: icon

  /** User defined code. Must be unique in the OrganizationType */
  code 			String required minlength(3) unique
  /** The name of the type. Must be unique in the system */
  name 			String required minlength(3) unique
  /** A more complete description of the type. Whats the meaning of this type? */
  description 	String required minlength(3)
  /** The nature of the type */
  nature		OrganizationNature required
  /** Icon image associated with this organization type. Will be used in user interface. */
  icon 			ImageBlob
  
  /**
   * Record version for concurrency control.
   */
  version Integer
}
 
/**
 * Organization
 * Hierarchical organigram of the organization.
 */
@dto(mapstruct)
entity Organization {
  // @@ List:: organizationType;code;name;parent
  // @@ Update:: parent;organizationType;code;name;image;inputInventory;outputInventory;user
  // @@ View:: parent;organizationType;code;name;image;inputInventory;outputInventory;user
  // @@ READONLY:: parent;organizationType;code
  
  //References:
  /*
  * Applies only to OrganizationType.OrganizationNature.PERSON. 
  * Associates a PERSON with a login User. It's NOT mandatory that all PERSON have a system user
  */
  //to User(user)
  //to Organization(parent)
  //to OrganizationType(organizationType)
	
  /** User defined code. Must be unique in the Organization */
  code 	String required minlength(3) unique
  /** The name of the Organization entry. Allows duplicate name's, but NOT duplicate code's. */
  name 	String required minlength(3)
  /* Optional image associated with this hierarchical level. NOT the same as OrganizationType.icon. 
  *  The Organization.imagem is not an icon and its intended to be specific of the entry it self 
  */
  image ImageBlob
  /*
  * Applies only to OrganizationType.OrganizationNature.ORGANIZATION. 
  * Means that this level is allowed to have inventory data input. Data can be inserted into table InputData associated to this Organization
  */
  inputInventory		Boolean
  
  /*
  * Applies only to OrganizationType.OrganizationNature.ORGANIZATION. 
  * Means that this level will be evaluated for inventory output variables. 
  */
  outputInventory		Boolean
  
  /**
   * Record version for concurrency control.
   */
  version Integer
}

// Metadata is a structure for any info associated with other entity domains.
// It's general information that can be used, for example, in formulas.

/**
 * Metadata type enum
 * The property type 
 */
enum MetadataType {
  STRING,
  BOOLEAN,
  INTEGER,
  DECIMAL,
  DATE
}

/**
 * Metadata Property
 * Configuration of a metadata property. Defines its type and a description of its usage.
 */
@dto(mapstruct)
entity MetadataProperty {
  // @@ List:: code;name;description;mandatory
  // @@ Update:: code;name;description;metadataTye;mandatory;pattern
  // @@ View:: code;name;description;metadataTye;mandatory;pattern
  // @@ READONLY:: code;metadataType
  
  code 			String required minlength(3) unique
  name 			String required
  description 	String 
  mandatory		Boolean
  metadataType	MetadataType required
  /** Regex pattern for validation (optional). Only applies when the value is not empty. */
  pattern		String
  
  /**
   * Record version for concurrency control.
   */
  version Integer
}

/**
 * Metadata Value
 * The value of a metadata property.
 */
@dto(mapstruct)
entity MetadataValue {
  /** Functional relational key to MetadataProperty */
  metadataPropertyCode 	String required
  
  /** 
   * The target domain key that this MetadataValue belongs. Its a class name or a key provided by the consumer. <br>
   * Used with targetDomainId to create as unique relation with the target domain
   * @see targetDomainId
   */
  targetDomainKey 		String required
  
  /** 
   * The target domain Id that this MetadataValue belongs. <br>
   * Used with targetDomainKey to create as unique relation with the target domain
   * @see targetDomainKey
   */
  targetDomainId 		Long required
  
  /**
   * The value of the MetadataProperty, persisted as a string. <br>
   */
  value 				String
  
  /**
   * Record version for concurrency control.
   */
  version Integer
}

relationship OneToMany {
  Organization{child(name)} to Organization{parent(name)}
  OrganizationType to Organization{organizationType(name)}
}

relationship OneToOne {
  /* Relation to builtInEntity User, must have the name "user", any other, JHipster generates TC with error */
  Organization{user(login)} to User with builtInEntity
}

relationship ManyToMany {
  // NOTE: For this to work, the OrganizationTypeMapper.toDtoMetadataPropertyName(MetadataProperty metadataProperty)
  //	   Must have an additional mapping for the version property : @Mapping(target = "version", source = "version")
  OrganizationType{metadataProperties(name)} to MetadataProperty{organizationType(name)}
}

/**
 * **************************************************
 * Inventory - Entities & Relations
 * **************************************************
 */
 
 /**
 * Variable InputMode enum
 * Defines how the input values for the variable are inserted.
 */
enum InputMode {
  /** Values are inserted by DataFile only. User can always change the value manually, but they can't delete it or insert it */
  DATAFILE,
  /** Values are inserted Manually. In this mode, only a human can insert and change the variable values. If a file or integration attempts to insert it, an error will be thrown */
  MANUAL,
  /** Values are inserted by Integration files. Very similar to the option DATAFILE */
  INTEGRATION,
  /** The variable can be inserted by any of the modes */
  ANY
}

 /**
 * Unit Variable Type
 * The type of data this unit represents
 */
enum UnitValueType {
  /** Decimal value */
  DECIMAL,
  /** boolean value */
  BOOLEAN
}

/**
 * UnitType
 * Type of measure unit types. Convertions can only be done within Unit's of the same UnitType
 */
@dto(mapstruct)
entity UnitType {
  // @@ List:: name;description;valueType
  // @@ Update:: name;description;valueType
  // @@ View:: name;description;valueType
  
  name 			String 			required unique
  description   String 			required
  valueType 	UnitValueType  	required
  
  /**
   * Record version for concurrency control.
   */
  version Integer
}

/**
 * Unit
 */
@dto(mapstruct)
entity Unit {
  // @@ List:: unitType;symbol;name;description
  // @@ Update:: unitType;code;symbol;name;description;convertionRate
  // @@ View:: unitType;code;symbol;name;description;convertionRate
  // @@ Readonly:: unitType;code
  
  /** Required code to use in integrations */
  code				String required unique
  /** Math symbol that is usually used as sufix for this unit. Eg. 'm3' for square metters.*/
  symbol			String required
  /** Math name for this unit. Eg. 'Square metters'.*/
  name 				String required
  description   	String
  
  /**
   * The convertion rate (CR), relative to the base unit.
   * This values awnsers the question: When the base unit is 1 (one), whats the value of this unit measure ?
   * Ex: How many Ml (miligrams) 1Kg has? 1000
   * The formula to convert between any value unit the scale is:
   * 	<Value>*CR(target unit)/CR(source unit)
   */
  convertionRate	BigDecimal required
  
  /**
   * Record version for concurrency control.
   */
  version Integer
}

/**
 * Unit Converter
 */
@dto(mapstruct)
entity UnitConverter {
  // @@ List:: fromUnit;toUnit;name;description
  // @@ Update:: fromUnit;toUnit;name;description;convertionFormula
  // @@ View:: fromUnit;toUnit;name;description;convertionFormula
  // @@ Readonly:: fromUnit;toUnit
  
	//References:
	//to Unit(fromUnit)
	//to Unit(toUnit)
	
	name 			String required
	description   	String required
  
	/**
	* The convertion formula to convert the fromUnit into the toUnit.
	*/
	convertionFormula	String required
  
	/**
	* Record version for concurrency control.
	*/
	version Integer
}

// Standard GEE Variable definition schema
// VariableScope 
//    (1-n) VariableCategory 
//       (1-n) Variable
// ---------------------------------------------------

/**
 * Variable Scope
 * Example: GEE Scope 1/2/3 or General Info
 */
@dto(mapstruct)
entity VariableScope {
  // @@ List:: code;name;description
  // @@ Update:: code;name;description
  // @@ View:: code;name;description
  // @@ Readonly:: code
  
	/** 
	 * Unique key, user defined. 
	 * Be aware, that this will be used to create the Variable.code
	 * NOTE: The field type is string, but restricted to only numbers
	 */
	code	String required pattern(/^[0-9]*$/) unique
	/** The name or title for this scope */
	name		String required
	/** A description or usage of this scope */
	description String required
	
	/** Record version for concurrency control. */
	version Integer
}

/**
 * Variable Category
 * Sub-division of VariableScope in Categories
 */
@dto(mapstruct)
entity VariableCategory {
  // @@ List:: code;name;description
  // @@ Update:: variableScope;code;name;description
  // @@ View:: variableScope;code;name;description
  // @@ Readonly:: variableScope;code
  
	//References:
	//to VariableScope
	
	/** 
	 * Unique key, user defined. 
	 * Be aware, that this will be used to create the Variable.code
	 * NOTE: The field type is string, but restricted to only numbers
	 */
	code	String required pattern(/^[0-9]*$/)
	/** The name or title for this category */
	name		String required
	/** A description or usage of this category */
	description String required
	
	/** Record version for concurrency control. */
	version Integer
}

/**
 * Variable Definition (GEE variable classification)
 */
@dto(mapstruct)
entity Variable {
  // @@ List:: name;description;input;output
  // @@ Update:: variableScope;variableCategory;code;name;baseUnit;description
  // @@ View:: variableScope;variableCategory;code;name;baseUnit;description
  // @@ Readonly:: variableScope;variableCategory;code
  
	//References:
	//to VariableScope
	//to VariableCategory
	//to Unit (baseUnit) - The unit of the variable
	
	/** 
	 * Unique key, composed by: <br>
	 * VariableScope.code + VariableCategory.code + <index>
	 * NOTA: User will provide the index property, and the software will create the code
	 * 		 index and code are NOT changeable
	 */
	code	String required pattern(/^[0-9]*$/) unique
	/** Variable index */
	variableIndex	Integer		required
	/** The name or title for the variable */
	name			String required
	/** The descriptions of the variable. Its meaning. Its usage. */
	description		String required
	/** Defines this variable as input. Values will be inserted for this variable */
	input			Boolean required
	/** Defines the way of input. See the enum for instructions. */
	inputMode		InputMode required
	/** Defines this variable as output. This variable will be evaluated for output */
	output			Boolean required
	/** The formula to calculate the output valut of the variable. Mandatory when output==TRUE */
	outputFormula	String
	
	/** Record version for concurrency control. */
	version 	Integer
}
filter Variable

/**
 * Variable allowed input units. Also defines the converters needed if the 
 */
@dto(mapstruct)
entity VariableUnits {
  // @@ List:: variable;unit
  // @@ Update:: variable;unit
  // @@ View:: variable;unit
  // @@ Readonly:: variable;unit
  
  //References:
  //to Variable
  //to Unit (unit) - The allowed unit for input
	
  /** Record version for concurrency control. */
  version 	Integer
}

/**
 * Variable Class
 * A sub-variable classification. Example: Variable=FUEL CONSUMPTIOM; CLASS=GASOLINE; OR ELECTRICAL; ETC...
 */
@dto(mapstruct)
entity VariableClass {
  // @@ List:: variable;code;name
  // @@ Update:: variable;code;name
  // @@ View:: variable;code;name
  // @@ Readonly:: variable;code
  
	//References:
	//to Variable
	
	/** Code of the class. Must be unique within the Variavle */
	code	String	required
	/** Human name of the class. Must be unique within the Variable, because it will be used as key for the Excel integration data. */
	name	String	required
	
	/** Record version for concurrency control. */
	version 	Integer
}

// Period schema
// Period (1-n) PeriodVersion
// ---------------------------------------------------

/**
 * Period status enum
 */
enum PeriodStatus {
  OPEN,
  REOPEN,
  CLOSED
}

/**
 * Data Source enum
 */
enum DataSourceType {
  MANUAL,
  FILE,
  AUTO,
  /** Special case, where a InputData value from an Organization is distributed to other Organization's */
  DISTRIB
}

/**
 * Upload file type enum
 */
enum UploadType {
  /** Custom Excel file template, for variable input upload */
  INVENTORY,
  
  /** Exported file from the accounting software */
  ACCOUNTING
}

/**
 * Upload file status enum
 */
enum UploadStatus {
  UPLOADED,
  PROCESSING,
  PROCESSED,
  ERROR
}

/**
 * Period 
 */
@dto(mapstruct)
entity Period (period) {
  // @@ List:: name;description;beginDate;endDate;state
  // @@ Update:: name;description;beginDate;endDate;state
  // @@ View:: name;description;beginDate;endDate;state
  
	//References:
	//?
	
	/** Name of the period */
	name			String required
	/** Description for the period */
	description		String	
	/** Period start date */
	beginDate		LocalDate required
	/** Period end date */
	endDate			LocalDate required
	/** State of the Period */
	state			PeriodStatus required
	
	/** The creation date (insert). When the data was inserted into the system. */
	creationDate		Instant required
	/** The actual username logged into the system, that inserted the data. NOT a reference to the user, but the login username. */
	creationUsername	String required
	/** Record version for concurrency control. */
	version 	Integer
}

/**
 * Period versions
 * Always have at least one version. 
 */
@dto(mapstruct)
entity PeriodVersion {
	//References:
	//to Period
	
	/** Name of the version */
	name			String required
	/** Description for the version  */
	description		String	
	/** Period version (sequencial) */
	periodVersion	Integer required
	/** State of the Period */
	state			PeriodStatus required
	
	/** The creation date (insert). When the data was inserted into the system. */
	creationDate		Instant required
	/** The actual username logged into the system, that inserted the data. NOT a reference to the user, but the login username. */
	creationUsername	String required
	/** Record version for concurrency control. */
	version 	Integer
}

/**
 * Input data Values
 * The values inserted from:
 * 	- Each Organic Unit
 *  - Variable
 *  - PeriodVersion
 */
@dto(mapstruct)
entity InputData {
	//References:
	//to Variable		  	  		  - The Variable that this data reports
	//to Period			  	  		  - The period that this data belongs
	//to PeriodVersion    	  		  - The period version active, when the data was inserted
	//to Unit (sourceUnit)	  		  - The Unit that the data was inserted. Must be one of the allowed input units for the variable
	//to Unit (unit)		  		  - The Unit of the variableValue. Its the unit configured in Variable.baseUnit
	//to Organization (owner) 		  - The owner of the data. The Organization responsable for generating this data (that consumed this value)
	//to InputData (inputData)		  - In case of InputData.source==DataSourceType.DISTRIB, this points to the parent owner InputData
	//to InputDataUpload			  - In case of InputData.source==DataSourceType.FILE, this points to the InputDataUpload file that contains this data
	
	/** The value of the data in the source Unit. This might be different from the Variable baseUnit. @see variableValue and variableUnit */
	sourceValue		BigDecimal	required
	/** The value of the data converted to the variable baseUnit. */
	variableValue	BigDecimal	required
	/** 
	* The value that the InputData.owner is accounted for. 
	* In case a variableValue is distributed to other Organization's (InputData.source==DataSources.DISTRIB)
	* , this will have the value to consider when calculating the final inventory value for the variable
	*/
	imputedValue	BigDecimal	required
	/** What was the source of this data ? */
	sourceType			DataSourceType required
	/** 
	* The date that this data relates to. 
	* Eg. energy consumptium happens every month, this should be the date of invoice 
	* [optional]
	*/
	dataDate		LocalDate

	/** Last change date */
	changeDate	Instant required	
	/** The actual username logged into the system, that last changed the data */
	changeUsername	String required
	/** Where this data originates from? Where were the data collected ? */
	dataSource		String
	/** Who collected the data ? */
	dataUser		String
	/** Comments added by the user */
	dataComments	String
	
	/** The creation date (insert). When the data was inserted into the system. */
	creationDate		Instant required
	/** The actual username logged into the system, that inserted the data. NOT a reference to the user, but the login username. */
	creationUsername	String required
	/** Record version for concurrency control. */
	version 	Integer
}

/**
 * Input data upload file
 * Users can upload an Excel file with InputData that will automatically insert values in the table InputData
 */
@dto(mapstruct)
entity InputDataUpload {
  // @@ List:: title;type;state
  // @@ Update:: title;type;dataFile;comments;state 
  // @@ View:: title;type;dataFile;comments:state
  
	//References:
	//to Period			  	  		  - The period that this data belongs
	//to PeriodVersion    	  		  - The period version active, when the data was inserted
	//to Organization (owner) 		  - The owner of the data. The Organization responsable for generating this data (that consumed this value)

	/** A simple text with a title, for human reference and better relation */
	title			String required
	/** An Excel file, that must match a template for input */
	dataFile			Blob required
	/** The name of the uploaded Excel file */
	uploadFileName		String 
	/** The generated name of the Excel file, used to save to disk */
	diskFileName		String 
	/** Type of the Upload */
	type				UploadType required
	/** State of the Upload */
	state				UploadStatus required
	/** Optional comments */
	comments		String
	
	/** The creation date (insert). When the data was inserted into the system. */
	creationDate		Instant required
	/** The actual username logged into the system, that inserted the data. NOT a reference to the user, but the login username. */
	creationUsername	String required
	/** Record version for concurrency control. */
	version 	Integer
}

/**
 * Input data upload file
 * Users can upload an Excel file with InputData that will automatically insert values in the table InputData
 */
@dto(mapstruct)
entity InputDataUploadLog {
	//References:
	//to InputDataUpload			  	  		 - The InputDataUpload that this log belongs
	
	/** The log of the event. Eg. "InputDataUpload created"; "InputDataUpload replaced with new file"; "125 records inserted"; "User XPTO confirmed the file replacement." */
	logMessage			String	required
	
	/** The creation date (insert). When the data was inserted into the system. */
	creationDate		Instant required
	/** The actual username logged into the system, that inserted the data. NOT a reference to the user, but the login username. */
	creationUsername	String required
	/** Record version for concurrency control. */
	version 	Integer
}

/**
 * Output data Values
 * The values calculated using the Variable.outputFormula, for all variables with Variable.output==TRUE.
 */
@dto(mapstruct)
entity OutputData {
	//References:
	//to Variable		  	  		  - The Variable that this data reports
	//to Period			  	  		  - The period that this data belongs
	//to PeriodVersion    	  		  - The period version active, when the data was inserted
	//to Unit (baseUnit)		      - The Unit of the variableValue. Its the unit configured in Variable.baseUnit
	//to Organization (owner) 		  - The owner of the data. The Organization responsable for generating this data (that consumed this value)
	
	/** The evaluated value, calculated by Variable.outputFormula. This will probably represent an emission value. */
	value	BigDecimal	required
	
	/** Record version for concurrency control. */
	version 	Integer
}
	
relationship OneToMany {
  UnitType to Unit{unitType(name)}
  Unit{fromUnit(name)} to UnitConverter{fromUnit(name)}
  Unit{toUnit(name)} to UnitConverter{toUnit(name)}
  Unit{baseUnit(name)} to Variable{baseUnit(name)}
  
  VariableScope to VariableCategory{variableScope(name)}
  VariableScope to Variable {variableScope(name)}
  VariableCategory to Variable {variableCategory(name)}
  Variable to VariableClass{variable(name)}
  Period to PeriodVersion{period(name)}
  
  //InputData references
  Variable to InputData{variable(name)}
  Period to InputData{period(name)}
  PeriodVersion to InputData{periodVersion(name)}
  Unit{sourceUnit} to InputData{sourceUnit(name)}
  Unit to InputData{unit(name)}
  Organization to InputData{owner(name)}
  InputData to InputData{sourceInputData}
  InputDataUpload to InputData{sourceInputDataUpload}
  
  //InputDataUpload
  Period to InputDataUpload{period(name)}
  PeriodVersion to InputDataUpload{periodVersion(name)}
  Organization to InputDataUpload{owner(name)}

  //OutputData references
  Variable to OutputData{variable(name)}
  Period to OutputData{period(name)}
  PeriodVersion to OutputData{periodVersion(name)}
  Unit to OutputData{baseUnit(name)}
  Organization to InputData{owner(name)}
  
  //VariableUnits
  Variable to VariableUnits{variable(name)}
  Unit to VariableUnits{unit(name)}
  
  //InputDataUploadLog
  InputDataUpload to InputDataUploadLog{inputDataUpload(title)}
}

/** paginate Entry, Tag with infinite-scroll */
// paginate Organization, Metadata with pagination

service * with serviceClass
