(*
 * $Id$
 *
 * JSDAI(TM), a way to implement STEP, ISO 10303
 * Copyright (C) 1997-2008, LKSoftWare GmbH, Germany
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License
 * version 3 as published by the Free Software Foundation (AGPL v3).
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * JSDAI is a registered trademark of LKSoftWare GmbH, Germany
 * This software is also available under commercial licenses.
 * See also http://www.jsdai.net/
 *)

(*
   Derived from ISO TC184/SC4/WG12 N - ISO/CD-TS 10303-xxxx Network functional usage view - EXPRESS ARM
   by LKSoftWare GmbH for implementation purpose within IDA-STEP(TM)
*)

SCHEMA Functional_usage_view_xim;

 USE FROM Analytical_model_xim;	

 USE FROM Shape_property_assignment_xim;    -- ISO/TS 10303-1032 
 
  REFERENCE FROM product_identification_xim(          -- ISO/TS 10303-1017 
          types_of_product 
  ); 

REFERENCE FROM support_resource_schema   -- ISO 10303-41
  (bag_to_set);
  
  USE FROM Network_functional_design_view_xim;
  
	USE FROM product_property_definition_schema(
		product_definition_shape,
		shape_aspect,
		shape_aspect_relationship);
  
  USE FROM Functional_usage_view_mim;
  
	TYPE fuuv_am_port_assignment_select = EXTENSIBLE GENERIC_ENTITY SELECT BASED_ON analytical_model_port_assignment_select WITH  
		(Functional_unit_usage_view_terminal_definition);
	END_TYPE;

  ENTITY Equivalent_functional_terminals_assignment
  	(* CONNOTATIONAL *) SUBTYPE OF (shape_aspect);
      equivalent_terminals : SET[2:?] OF Functional_unit_usage_view_terminal_definition;
    DERIVE
      SELF\shape_aspect.of_shape : product_definition_shape := ?;
      SELF\shape_aspect.product_definitional : LOGICAL := ?;
      SELF\shape_aspect.description : text := ?;
  END_ENTITY;

  ENTITY Equivalent_functional_unit_definition_assignment
  	(* CONNOTATIONAL *) SUBTYPE OF (product_definition);
  	  name_x                                 : STRING; --ee_name;  
      equivalent_functional_unit_definitions : SET[2:?] OF Functional_unit_definition;
    DERIVE
     SELF\product_definition.frame_of_reference : product_definition_context := ?;
     SELF\product_definition.formation : product_definition_formation := ?;
     SELF\product_definition.description : text := ?;
     SELF\product_definition.id : identifier := name;
  END_ENTITY;
 
  ENTITY Functional_product
  	SUBTYPE OF (Information_product);
    UNIQUE 
      UR1: SELF\product.id;
    WHERE 
      WR1 : SIZEOF([ 'functional' ] * types_of_product(SELF))= 1 ;
  END_ENTITY;
  
  ENTITY Functional_terminal_group_assignment
  	(* CONNOTATIONAL *) SUBTYPE OF (applied_group_assignment);
      SELF\group_assignment.assigned_group RENAMED composed_group	: Functional_terminal_group;
      functional_usage_view_terminal 															: Scalar_terminal_definition;
    DERIVE
      SELF\applied_group_assignment.items : SET [1:?] OF groupable_item := ?;
  END_ENTITY;
 
   ENTITY Functional_unit_definition
    (* CONNOTATIONAL *) ABSTRACT SUBTYPE OF (Information_definition, Item_shape, functional_unit);
    SELF\Product_view_definition.defined_version : Functional_version;
    DERIVE
    	SELF\Item_shape.described_element : shapeable_item := SELF;
  END_ENTITY;

	ENTITY Functional_unit_make_from_relationship
		(* CONNOTATIONAL *) SUBTYPE OF (Product_definition_relationship);
		SELF\Product_definition_relationship.relating_product_definition RENAMED relating_view : Functional_unit_usage_view;		
		SELF\Product_definition_relationship.related_product_definition RENAMED related_view   : Functional_unit_usage_view;
	  WHERE
        WR1 : acyclic_functional_unit_make_from_relationship (SELF, [related_view], 
            'FUNCTIONAL_USAGE_VIEW_XIM.FUNCTIONAL_UNIT_MAKE_FROM_RELATIONSHIP');
	END_ENTITY;

  ENTITY Functional_unit_usage_view
    (* CONNOTATIONAL *) SUBTYPE OF (Functional_unit_definition);
    DERIVE analytical_model_application_reference : SET[0:?] OF Analytical_model_application := get_ama(access_mechanism[1]);
    INVERSE
      access_mechanism : SET[0:?] OF functional_unit_usage_view_terminal_definition FOR associated_functional_unit_definition;
    WHERE
      WR1: SIZEOF(analytical_model_application_reference) <= 1;
      WR2: NOT(SIZEOF(analytical_model_application_reference) = 1) OR
        (SIZEOF(QUERY( am <* access_mechanism |
           NOT((SIZEOF(USEDIN(am,'ANALYTICAL_MODEL_XIM.ANALYTICAL_MODEL_PORT_ASSIGNMENT_ARMX.ASSIGNED_ITEM')) = 0) OR
              (SIZEOF(QUERY( ampa <* USEDIN(am, 'ANALYTICAL_MODEL_XIM.ANALYTICAL_MODEL_PORT_ASSIGNMENT_ARMX.ASSIGNED_ITEM') |
                 NOT(analytical_model_application_reference[1] :=: ampa.associated_analytical_model_application) 
                 )) = 0))
        )) = 0);
  END_ENTITY;

  ENTITY Functional_unit_usage_view_terminal_definition
    SUPERTYPE OF (Scalar_terminal_definition)
    	(* CONNOTATIONAL *) SUBTYPE OF (functional_unit_terminal_definition);
      SELF\shape_aspect.of_shape RENAMED associated_functional_unit_definition : Functional_unit_usage_view;
      SELF\shape_aspect.name RENAMED signal_name 	                           : STRING;
    DERIVE
      SELF\shape_aspect.description : text := ?;
      SELF\shape_aspect.product_definitional : LOGICAL := ?;
(* Might be uncommented in the future *)      
(*    INVERSE
      node_assignment : SET[0:?] OF functional_unit_network_terminal_definition_node_assignment FOR connected_terminal;
      bus_assignment  : SET[0:?] OF functional_unit_network_terminal_definition_bus_assignment FOR connected_terminal; *)
    UNIQUE
      UR1 : signal_name,
 associated_functional_unit_definition;
(* Might be uncommented in the future  
    WHERE
      WR1 : (EXISTS(node_assignment) AND NOT (EXISTS(bus_assignment))) OR (NOT (EXISTS(node_assignment)) AND EXISTS(bus_assignment)) OR (NOT (EXISTS(node_assignment)) AND NOT (EXISTS(bus_assignment)));
*)      
  END_ENTITY;

  ENTITY Functional_unit_usage_view_terminal_definition_make_from_relationship
  	(* CONNOTATIONAL *) SUBTYPE OF (make_from_functional_unit_terminal_definition_relationship);
      associated_make_from : Functional_unit_make_from_relationship;
      SELF\shape_aspect_relationship.related_shape_aspect RENAMED reusable_feature		: Functional_unit_usage_view_terminal_definition;
      SELF\shape_aspect_relationship.relating_shape_aspect RENAMED resultant_feature	: Functional_unit_usage_view_terminal_definition;
    DERIVE
      SELF\shape_aspect.of_shape : product_definition_shape := ?;
      SELF\shape_aspect.description : text := ?;
      SELF\shape_aspect.product_definitional : LOGICAL := ?;
      SELF\shape_aspect.name : label := ?;
    UNIQUE
      UR1 : reusable_feature,
 resultant_feature;
    WHERE
      WR1 : reusable_feature :<>: resultant_feature;
      WR2 : reusable_feature.associated_functional_unit_definition :<>: resultant_feature.associated_functional_unit_definition;
      WR3 : reusable_feature.associated_functional_unit_definition :=: 
      		associated_make_from\Functional_unit_make_from_relationship.relating_view;
      WR4 : resultant_feature.associated_functional_unit_definition :=: 
      		associated_make_from\Functional_unit_make_from_relationship.related_view;
      WR5 : acyclic_functional_unit_usage_view_terminal_definition_make_from_relationship
        (SELF, [resultant_feature], 
        'FUNCTIONAL_USAGE_VIEW_XIM.FUNCTIONAL_UNIT_USAGE_VIEW_TERMINAL_DEFINITION_MAKE_FROM_RELATIONSHIP');
  END_ENTITY;

  ENTITY Functional_version
    (* CONNOTATIONAL *) SUBTYPE OF (Information_version);
    SELF\product_definition_formation.of_product : Functional_product;
  END_ENTITY;

  ENTITY Scalar_terminal_definition
    (* CONNOTATIONAL *) SUBTYPE OF (Functional_unit_usage_view_terminal_definition);
  END_ENTITY;

  ENTITY Scalar_terminal_definition_link_armx
  	(* CONNOTATIONAL *) SUBTYPE OF (scalar_terminal_definition_link);
      SELF\shape_aspect_relationship.relating_shape_aspect RENAMED precedent_terminal_definition  : Scalar_terminal_definition;
      SELF\shape_aspect_relationship.related_shape_aspect RENAMED subsequent_terminal_definition	: Scalar_terminal_definition;
    DERIVE
      SELF\shape_aspect.of_shape : product_definition_shape := ?;
      SELF\shape_aspect.description : text := ?;
      SELF\shape_aspect.product_definitional : LOGICAL := ?;
      SELF\shape_aspect.name : label := ?;
    UNIQUE
      UR1 : precedent_terminal_definition,
 subsequent_terminal_definition;
    WHERE
      WR1 : precedent_terminal_definition :<>: subsequent_terminal_definition;
      WR2 : acyclic_scalar_terminal_definition_link (SELF,
        [subsequent_terminal_definition],
        'FUNCTIONAL_USAGE_VIEW_XIM.SCALAR_TERMINAL_DEFINITION_LINK_ARMX');
  END_ENTITY;

  FUNCTION acyclic_scalar_terminal_definition_link
    (relation : Scalar_terminal_definition_link_armx; relatives : SET[1:?] OF
    Scalar_terminal_definition; specific_relation : STRING) : BOOLEAN; 
    LOCAL
      x : SET OF Scalar_terminal_definition_link_armx;
    END_LOCAL;

    IF relation.precedent_terminal_definition IN relatives THEN
      RETURN (FALSE);
    END_IF;
    x := QUERY(pd <* bag_to_set(USEDIN(relation.precedent_terminal_definition,
      'FUNCTIONAL_USAGE_VIEW_XIM.' + 'SCALAR_TERMINAL_DEFINITION_LINK_ARMX.' +
      'SUBSEQUENT_TERMINAL_DEFINITION')) | specific_relation IN TYPEOF(pd));
    REPEAT i := 1 TO HIINDEX(x);
      IF NOT acyclic_scalar_terminal_definition_link(x[i], relatives +
        relation.precedent_terminal_definition, specific_relation) THEN
        RETURN (FALSE);
      END_IF;
    END_REPEAT;
   RETURN (TRUE);
  END_FUNCTION;

  FUNCTION acyclic_functional_unit_make_from_relationship
    (relation : Functional_unit_make_from_relationship; relatives : SET[1:?] OF 
    Scalar_terminal_definition; specific_relation : STRING) : BOOLEAN; 
  LOCAL
     x : SET OF Functional_unit_make_from_relationship;
  END_LOCAL;

    IF relation.relating_view IN relatives THEN
      RETURN (FALSE);
    END_IF;
    x := QUERY(pd <* bag_to_set(USEDIN(relation.relating_view,
      'FUNCTIONAL_USAGE_VIEW_XIM.' + 'FUNCTIONAL_UNIT_MAKE_FROM_RELATIONSHIP.' +
      'RELATED_VIEW')) | specific_relation IN TYPEOF(pd));
    REPEAT i := 1 TO HIINDEX(x);
      IF NOT acyclic_functional_unit_make_from_relationship(x[i], relatives +
        relation.relating_view, specific_relation) THEN
        RETURN (FALSE);
      END_IF;
    END_REPEAT;
    RETURN (TRUE);
  END_FUNCTION; 

  FUNCTION acyclic_functional_unit_usage_view_terminal_definition_make_from_relationship
     (relation : Functional_unit_usage_view_terminal_definition_make_from_relationship; 
     relatives : SET[1:?] OF Functional_unit_usage_view_terminal_definition; 
     specific_relation: STRING) : BOOLEAN; 
     LOCAL
       x : SET OF Functional_unit_usage_view_terminal_definition_make_from_relationship;
     END_LOCAL;
    
     IF relation.reusable_feature IN relatives THEN
       RETURN (FALSE);
     END_IF;
     x := QUERY(pd <* bag_to_set(USEDIN(relation.reusable_feature,
      'FUNCTIONAL_USAGE_VIEW_XIM.' +
      'FUNCTIONAL_UNIT_USAGE_VIEW_TERMINAL_DEFINITION_MAKE_FROM_RELATIONSHIP.' +
      'RESULTANT_FEATURE')) | specific_relation IN TYPEOF(pd));
     REPEAT i := 1 TO HIINDEX(x);
       IF NOT
         acyclic_functional_unit_usage_view_terminal_definition_make_from_relationship(x[i],
         relatives + relation.reusable_feature, specific_relation) THEN
           RETURN (FALSE);
       END_IF;
     END_REPEAT;
    RETURN (TRUE);
  END_FUNCTION; 

  FUNCTION get_ama(
	input : analytical_model_port_assignment_select) : SET OF Analytical_model_application;
    LOCAL
	  ama : SET[0:?] OF Analytical_model_application := [];  --this gives us access to the information base
	 ampa : SET[0:?] OF Analytical_model_port_assignment_armx :=[];
    END_LOCAL;
	  ampa := bag_to_set(USEDIN (input, 'ANALYTICAL_MODEL_XIM.'+
	  'ANALYTICAL_MODEL_PORT_ASSIGNMENT_ARMX.ASSIGNED_ITEM'));
	-- iterate over ampa
	  REPEAT i := 1 to SIZEOF(ampa) by 1;
		ama := ama + ampa[i].associated_analytical_model_application;
	  END_REPEAT;

	  RETURN(ama);
  END_FUNCTION;

END_SCHEMA;

