:- module(autobuild_input, 
    [
    get_all_states/1,
    get_partial_state_description/3,
    get_all_entities/1,
    get_all_assumptions/1,
    get_all_attributes/1,
    get_all_quantities/1,
    get_all_quantity_names/1,
    get_quantity_types/2,
    get_quantity_owner/2,
    get_quantity_space_name/2,
    get_quantity_space/2,
    get_naive_dependency_types/1,
    get_cluster_dependency_types/1,
    get_inequalities_from_smd/2,
    get_inequalities_from_scenario/1,
    get_influence_types/1,
    get_quantity_entity_types/2
    ]).

/** <module> Database : Automatic model building

@author Jochem Liem

 * Automatic model building algorithm
 * Inspired by Hylke Buisman's algorithm

*/

/* Simulation Results Helpers */

%% get_all_states(-StateIDs) is det
%  Get the ID's of all the states
get_all_states(StateIDs) :-
    findall(StateID, engine:state(StateID, _), StateIDs).

%% get_partial_state_description(+StateID, +StatePartID, -Part)
get_partial_state_description(StateID, StatePartID, Part) :-
	engine:state(StateID, Description),
	get_smd_part(Description, StatePartID, Part).

%% get_smd_part(+SMD, +PartID, -Part)
%  Get a specific part of a state description
get_smd_part(SMD, PartID, Part) :-
	SMD =.. Items,
	nth1(PartID, Items, Part).

%% get_all_entities(-Entities)
%  Get all entity names from all the states
get_all_entities(Entities) :-
    findall(EntityDef,
	(
	    get_partial_state_description(_, 3, system_elements(Structure)),
	    member(instance(InternalEntity, EntityDef), Structure),
	    EntityDef \== garp_internal,
	    % The InternalEntity is not meant for exogenous behaviour (garp_generated)
	    not(sub_string(InternalEntity, _, _, _, 'garp_generated')),
	    % The entities are of type entity
	    isa_transitive(EntityDef, entity)
	),
	EntitiesBag),
    list_to_set(EntitiesBag, Entities).

get_quantity_entity_types(Quantities, EntityTypes) :-
    bagof(
        EntityDef,
	Quantity^InternalEntity^(
	    member(Quantity, Quantities),
            get_quantity_owner(Quantity, InternalEntity),
            get_partial_state_description(_, 3, system_elements(Structure)),
            member(instance(InternalEntity, EntityDef), Structure)
	),
	EntityTypes
    ).

%% get_all_agents(-Agents)
%  Get all agent names from all the states
get_all_agents(Agents) :-
    findall(AgentDef, 
	(
	    get_partial_state_description(_, 3, system_elements(Structure)),
	    member(instance(InternalAgent, AgentDef), Structure),
	    AgentDef \== garp_internal,
	    % The InternalAgent is not meant for exogenous behaviour (garp_generated)
	    not(sub_string(InternalAgent, _, _, _, 'garp_generated')),
	    % The agents are not entities or assumptions
	    isa_transitive(AgentDef, agent)
	),
	AgentsBag),
    list_to_set(AgentsBag, Agents).

%% get_all_assumptions(-Assumptions)
%  Get all assumption names from all the states
get_all_assumptions(Assumptions) :-
    findall(AssumptionDef, 
	(
	    get_partial_state_description(_, 3, system_elements(Structure)),
	    member(instance(InternalAssumption, AssumptionDef), Structure),
	    AssumptionDef \== garp_internal,
	    % The InternalAssunmption is not meant for exogenous behaviour (garp_generated)
	    not(sub_string(InternalAssumption, _, _, _, 'garp_generated')),
	    % The assumptions are not entities or agents
	    isa_transitive(AssumptionDef, assumption)
	),
	AssumptionsBag),
    list_to_set(AssumptionsBag, Assumptions).

get_all_attributes(Attributes) :-
    findall([Attribute, Entity1, Entity2],
	(
	    get_partial_state_description(_, 3, system_elements(Structure)),
	    member(has_attribute(Entity1, Attribute, Entity2), Structure)
	),
	AttributesBag),
    list_to_set(AttributesBag, Attributes).


%% get_all_quantity_names(-QuantityNames)
%  Get all the quantity and quantity space names from all the states
get_all_quantity_names(QandQSNames) :-
    get_all_quantities(Quantities),
    findall(QName, 
	(
	    member(Quantity, Quantities),
	    Quantity =.. [_QType, _AttachedTo, QName, _, _QSName]
	),
	QuantityNamesBag),
    list_to_set(QuantityNamesBag, QandQSNames).

%% get_all_quantities(-QuantityNames)
%  Get the set of quantity datastructures from all the states
get_all_quantities(Quantities) :-
    findall(Quantity, 
	(
	    get_partial_state_description(_, 4, parameters(Quantities)),
	    member(Quantity, Quantities)
	),
	QuantitiesBag),
    list_to_set(QuantitiesBag, Quantities).

%% get_quantity_types(+Quantities, -QuantityTypes)
% 
get_quantity_types(Quantities, QuantityTypes) :-
    get_all_quantities(QuantityStructures),
    findall(
        QuantityType,
	(
	    member(Quantity, Quantities),
	    member(QuantityStructure, QuantityStructures),
            QuantityStructure =.. [QuantityType, _, Quantity, _, _]
	),
	QuantityTypes
    ).

%% get_quantity_owner(+QuantityName, -EntityName)
% Return the entity to which a quantity is connected
get_quantity_owner(QuantityName, Owner) :-
    get_all_quantities(Quantities),
    member(Quantity, Quantities),
    Quantity =.. [_QType, Owner, QuantityName, _, _QSpace].

%% get_quantity_space_name(+Quantityname, -QuantitySpaceName) 
%  Find the internal quantity space name for a quantity
get_quantity_space_name(QuantityName, QuantitySpaceName) :-
    get_all_quantities(Quantities),
    member(Quantity, Quantities),
    Quantity =.. [_QType, _Owner, QuantityName, _, QuantitySpaceName].

%% get_quantity_space
%  Get the internal quantity space values for a quantity
get_quantity_space(QuantityName, QuantitySpaceValues) :-
    get_all_quantities(Quantities),
    member(Quantity, Quantities),
    Quantity =.. [_QType, _Owner, QuantityName, _, QuantitySpaceName],
    engine:quantity_space(QuantitySpaceName, x, QSValuesVariables, _),
    findall(Value,
	(
	    member(ValueVariable, QSValuesVariables),
	    (
		point(PointValueVariable) = ValueVariable ->
		PointValueVariable =.. PointValueList,
		nth1(1, PointValueList, PointValue),
		Value = point(PointValue)
	    ;
		Value = ValueVariable
	    )
	),
	QuantitySpaceValues
    ).

%% get_naive_dependency_types(-Types:list)
%  Get all the possible naive dependency types
get_naive_dependency_types(
    [	
    inf_pos_by,
    inf_neg_by,
    prop_pos,
    prop_neg,
    q_correspondence,
    mirror_q_correspondence
    ]).


%% get_cluster_dependency_types(-Types:list)
%  Get the dependencies required for clusters
get_cluster_dependency_types(
    [
    prop_pos,
    q_correspondence,
    prop_neg,
    mirror_q_correspondence
    ]).

%% get_inequalities_from_scenario(-Inequalities:list)
%  Get the given inequalities from the scenario
get_inequalities_from_scenario(Inequalities) :-
    get_partial_state_description(1, 8, Scenario),
    get_inequalities_from_smd(Scenario, Inequalities).

%% get_inequalities_from_smd(+SMD, -Inequalities:list)
%  Return the inequalities from an SMD
get_inequalities_from_smd(SMD, Inequalities) :-
	get_smd_part(SMD, 6, par_relations(ParRelations)),
	findall(
	    Inequality,
	    (
		member(Inequality,ParRelations),
		Inequality =.. [Type, Q1, Q2], 
		member(Type, [greater, smaller, smaller_or_equal, greater_or_equal, equal]),
		% There should be no min(_,_) or plus(_,_) in the (in)equality
		Q1 =.. Q1List, length(Q1List, LQ1), LQ1 < 3,
		Q2 =.. Q2List, length(Q2List, LQ2), LQ2 < 3
	    ),
	    Inequalities).

%% get_influence_types(-InfluenceTypes:list).
% InfluenceTypes is a list of possible influence types (i.e. [inf_pos_by, inf_neg_by]).
get_influence_types([inf_pos_by, inf_neg_by]).
