(*
 * $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/
 *)

SCHEMA lksoft_extensions_xim;

USE FROM Fabrication_technology_xim;
USE FROM Part_template_2d_shape_xim;
USE FROM Land_xim;

REFERENCE FROM Fabrication_technology_xim(get_stack);

  TYPE sto_or_group_xim = SELECT
	(Stratum_technology_occurrence_armx,
	 Stratum_technology_occurrence_group_xim);
  END_TYPE;

  (** All subtypes of this entity shall not be converted to MIM
      by XIM to MIM converter. There can still be some
      custom code that creates MIM population out of them upon
      export to MIM, but it is outside XIM to MIM converter. *)
  ENTITY Ignorable_xim
    ABSTRACT SUPERTYPE;
  END_ENTITY;

  ENTITY Land_with_join_terminal_xim
    SUBTYPE OF (Land_armx, Land_join_terminal);
    DERIVE
	  SELF\component_feature_armx.associated_component : Land_armx := SELF;
  END_ENTITY;
 
  ENTITY Stratum_feature_template_component_with_stratum_feature_xim
    SUBTYPE OF (Stratum_feature_template_component_armx, Stratum_feature_armx);
    DERIVE
      SELF\Stratum_feature_template_component_armx.implementation_or_resident_stratum : Stratum_feature_armx := SELF;
  END_ENTITY;

  (** This AO and its subtypes provide capabilities to represent
      stratum stack (subset of capabilities provided by Stratum_technology_occurrence_link),
      but unlike Stratum_technology_occurrence_link is modeled in a way best
      suitable for the GUI (Layer Stack Editor).

      Each Stratum_technology_occurrence_group_xim is a node in a tree. It has
      one and only one parent node and a list of children nodes (attribute elements).
      The root node of the tree is a Local_linear_stack_armx derived as stack attribute.

      IP1: Each node in this subtree shall be unique. So for example same Stratum_technology_occurrence
      shall show up at most once in the entire tree starting from the root. Same goes for groups. *)
  ENTITY Stratum_technology_occurrence_group_xim
    ABSTRACT SUPERTYPE OF (ONEOF(Sequential_stratum_technology_occurrence_group_xim,Parallel_stratum_technology_occurrence_group_xim,Optional_stratum_technology_occurrence_group_xim))
	SUBTYPE OF (Ignorable_xim);
	  name : OPTIONAL label;
      elements : LIST OF UNIQUE sto_or_group_xim;
      implementation : SET [0:?] OF Stratum_technology_occurrence_link_armx;
    DERIVE
      stack : Local_linear_stack_armx := get_group_stack(SELF);
    INVERSE
      parent : SET[0:1] OF Stratum_technology_occurrence_group_xim FOR elements;
    WHERE
      -- implementation shall not contain Stratum_technology_occurrence_links
      -- that are not available in Local_linear_stack_armx this group is child of
      WR1: implementation <= stack.stratum_technology_sequence;
      -- all Stratum_technology_occurrences that are members of elements shall
      -- be referenced by at least one member of implementation
      WR2: SIZEOF(QUERY(elem <* elements | ('FABRICATION_TECHNOLOGY_XIM.STRATUM_TECHNOLOGY_OCCURRENCE_ARMX' IN TYPEOF(elem)
		AND NOT (elem IN get_stack(implementation))))) = 0;
      -- each member of implementation shall reference at least one member of elements
      WR3: SIZEOF(QUERY(stol <* implementation | NOT (stol.precedent_sto IN elements) AND NOT(stol.subsequent_sto IN elements))) = 0;
  END_ENTITY;

  ENTITY Structured_layout_component_sub_assembly_relationship_with_component_xim
    SUBTYPE OF (Structured_layout_component_sub_assembly_relationship_armx, Assembly_component_armx);
    DERIVE
	  -- not sure if we need this derivation as assembly_component_armx has this attribute derived to self
	  -- in its supertype component_definition
	  SELF\product_definition_relationship.related_product_definition : Assembly_component_armx := SELF;
  END_ENTITY;

  (** One or none elements of this group can be made available in the final stack.
      First member of the elements shall be considered default one. *)
  ENTITY Optional_stratum_technology_occurrence_group_xim
    SUPERTYPE OF (Alternative_stratum_technology_occurrence_group_xim)
    SUBTYPE OF (Stratum_technology_occurrence_group_xim);
      SELF\Stratum_technology_occurrence_group_xim.elements : LIST OF UNIQUE Stratum_technology_occurrence_armx;
    WHERE
	  WR1: SIZEOF(parent) = 1;
  END_ENTITY;

  (** One element of this group shall be made available in the final stack. So this
      group provides alternate elements and one of them must be picked for the final stack. *)
  ENTITY Alternative_stratum_technology_occurrence_group_xim
    SUBTYPE OF (Optional_stratum_technology_occurrence_group_xim);
  END_ENTITY;

  ENTITY Parallel_stratum_technology_occurrence_group_xim
    SUBTYPE OF (Stratum_technology_occurrence_group_xim);
    WHERE
	  WR1: SIZEOF(parent) = 1;
  END_ENTITY;

  (** This group establishes sequence of stratums in the stack. Each member of elements
      with lower index shall be considered to be above each member with higher index in the stack.
      IP1: For each pair of <b>Stratum_technology_occurrence</b> in elements, that are
      adjacent to each other (have indexes i and i+1), their shall be one
      and only one member (<b>Stratum_technology_occurrence_link</b>) of implementation,
      such that its <b>Stratum_technology_occurrence_link.precedent_sto</b> shall be
      elements[i] and its <b>Stratum_technology_occurrence_link.subsequent_sto</b>
      shall be elements[i + 1]. *)
  ENTITY Sequential_stratum_technology_occurrence_group_xim
    SUBTYPE OF (Stratum_technology_occurrence_group_xim);
    WHERE
      -- this group shall either have another group as a parent, or shall be
      -- a root group of some Local_linear_stack
      WR1: (SIZEOF(parent) = 1) XOR (SIZEOF(USEDIN(SELF, 'PART_TEMPLATE_2D_SHAPE_XIM.LOCAL_LINEAR_STACK_ARMX.' + 'ROOT_XIM')) = 1);
      -- each group can be root for at most one Local_linear_stack
      WR2: (SIZEOF(USEDIN(SELF, 'PART_TEMPLATE_2D_SHAPE_XIM.LOCAL_LINEAR_STACK_ARMX.' + 'ROOT_XIM')) <= 1);
  END_ENTITY;

  (** returns the root for the tree the specified input group belongs to *)
  FUNCTION get_group_stack(input : Stratum_technology_occurrence_group_xim) : Local_linear_stack_armx;
    LOCAL
      group : Stratum_technology_occurrence_group_xim := input;
      root_group : Stratum_technology_occurrence_group_xim := ?;
      stack : Local_linear_stack_armx := ?;
    END_LOCAL;
      -- we find a root group, the group that has no parent groups
    REPEAT WHILE (root_group = ?);
      IF (SIZEOF(group.parent) = 1)
      THEN
        group := group.parent[1];
      ELSE
        root_group := group;
      END_IF;
    END_REPEAT;

    -- if data is correct, then root group shall be of type Sequential_stratum_technology_occurrence_group_xim
    --    and shall be referenced by one and only one Local_linear_stack_armx as root_xim
    IF 'LKSOFT_EXTENSIONS_XIM.SEQUENTIAL_STRATUM_TECHNOLOGY_OCCURRENCE_GROUP_XIM' IN TYPEOF(root_group) THEN
	    -- stack shall be ? if usedin shall return empty bag
      stack := USEDIN(root_group, 'PART_TEMPLATE_2D_SHAPE_XIM.LOCAL_LINEAR_STACK_ARMX.' + 'ROOT_XIM')[1];
    END_IF;

    -- either we found a stack here, or data is invalid
    RETURN (stack);
  END_FUNCTION;
  
END_SCHEMA;