:- module(autobuild_garp_build_interface,
    [
    internal_entity_instance_to_entity_instance/3,
    internal_entity_instance_to_entity_definition/2,
    internal_quantity_instance_to_quantity_instance/4,
    internal_quantity_instance_to_quantity_and_quantity_space_definition/3,
    internal_name_to_string/2,
    list_replaceall/4,
    isa_transitive/2
    ]).

/** <module>  Build a model from Garp representation : Automatic model building

@author Jochem Liem

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

*/

% Given the name of an instance in a model fragment return the object
% Works since instance names are unique
% get_entity_instance/2
% get_entity_instance(+ModelFragment, +InternName, -GarpInstance) :-
internal_entity_instance_to_entity_instance(InternName, ModelFragment, Entity) :-
    internal_name_to_string(InternName, CInternName),
    get(ModelFragment?elements, find_all, message(@prolog, ==, @arg1?class_name, 'garpInstance'), AllGarpInstances),
    get(AllGarpInstances, find_all, message(@prolog, ==, @arg1?name, CInternName),	Result),
    chain_list(Result, [Entity|_]).


internal_entity_instance_to_entity_definition(InternalEntity, EntityDef) :-
    % Get the build entity definition name of the entity
    engine:state(1, SMD),
    autobuild_input:get_smd_part(SMD, 3, system_elements(StructureList)),
    member(instance(InternalEntity,InternalEntityDefinition), StructureList),
    internal_name_to_string(InternalEntityDefinition, EntityName),
    % Get the entity definition
    design:getEntityDefinitionName(@model, EntityName, EntityDef).

internal_configuration_to_configuration_definition(InternalConfiguration, ConfigurationDef) :-
    internal_name_to_string(InternalConfiguration, ConfigurationName),
    % Get the configuration definition
    design:getConfigurationDefinition(@model, ConfigurationName, ConfigurationDef).

internal_quantity_instance_to_quantity_instance(InternalQuantityName, ModelFragment, Quantity, Entity) :-
    get_quantity_owner(InternalQuantityName, OwnerInternal),
    internal_name_to_string(InternalQuantityName, QuantityName),
    internal_entity_instance_to_entity_instance(OwnerInternal, ModelFragment, Entity),
    string_length(QuantityName, QuantityNameLength),
    Length is QuantityNameLength - 1,
    get(Entity?quantities, find_all, message(@prolog, sub_string, QuantityName, 0, Length, 1, @arg1?name), QuantityList),
    chain_list(QuantityList, [Quantity|_]).

internal_quantity_instance_to_quantity_and_quantity_space_definition(InternalQuantityInstance, QuantityDef, QuantitySpaceDef) :-
     % Get the build quantity definition name of the quantity
    engine:state(1, SMD),
    autobuild_input:get_smd_part(SMD, 4, parameters(QuantityList)),
    member(Quantity, QuantityList),
    Quantity =.. QuantityParts,
    nth1(3, QuantityParts, InternalQuantityInstance),
    nth1(1, QuantityParts, InternalQuantityDef),
    internal_name_to_string(InternalQuantityDef, QuantityName),
    % Get the quantity definition
    design:getQuantityDefinition(@model, QuantityName, QuantityDef),

    % Get quantity space definition
    nth1(5, QuantityParts, InternalQuantitySpaceInstance),
    internal_name_to_string(InternalQuantitySpaceInstance, QuantitySpaceName),
    design:getQuantitySpaceDefinition(@model, QuantitySpaceName, QuantitySpaceDef).



%% internal_name_to_string(+Atom, -String)
% Converts an atom to a string, capitalizing the first letter,
% and replacing underscores with spaces. Mainly required for
% converting internal names like oil_left to the names used in XPCE,
% in this case 'Oil left'
% internal_name_to_string(+Atom, -String)
internal_name_to_string(In, Out) :-
    atom_chars(In, [C|T]),
    upcase_atom(C, UC),
    list_replaceall([UC|T], '_', ' ', NList),
    atom_chars(Out, NList).

%% list_replaceall(+ListIn, +Find, +Replace, -ListOut)
% Replace all occurrences of Find in ListIn with Replace
% list_replaceall/4
list_replaceall([], _, _, []).
list_replaceall([Find|T], Find, Replace, [Replace|Out]) :-
	list_replaceall(T, Find, Replace, Out), !.
list_replaceall([H|T], Find, Replace, [H|Out]) :-
	list_replaceall(T, Find, Replace, Out), !.

%% isa_transitive(X, Y)
%  Check is X isa B (transitive)
isa_transitive(X,Y) :-
    engine:isa(X,Y).

isa_transitive(X,Y) :-
    engine:isa(X,Z),
    isa_transitive(Z,Y).
