text: /*
   *
   *  Copyright (C) 2015-2022, Open Connections GmbH
   *  All rights reserved.  See COPYRIGHT file for details.
   *
   *  This software and supporting documentation are maintained by
   *
   *    OFFIS e.V.
   *    R&D Division Health
   *    Escherweg 2
   *    D-26121 Oldenburg, Germany
   *
   *
   *  Module: dcmiod
   *
   *  Author: Michael Onken
   *
   *  Purpose: Class for managing the Multi-Frame Dimension Module
   *
   */
  
  #ifndef MODMULTIFRAMEDIMENSION_H
  #define MODMULTIFRAMEDIMENSION_H
  
  #include "dcmtk/config/osconfig.h"
  #include "dcmtk/dcmiod/iodrules.h"
  #include "dcmtk/dcmiod/modbase.h"
  
  /** Class representing the Multi-Frame Dimension Module:
   *
   * Dimension Organization Sequence: (SQ, VM 1-n, Type 1)
   * > Dimension Organization UID: (UI, 1, 1)
   * Dimension Organization Type: (CS, 1, 1)
   * Dimension Index Sequence: (SQ, 1-n, 1)
   * > Dimension Index Pointer (AT, 1, 1)
   * > Dimension Index Private Creator (LO, 1, 1C)
   * > Functional Group Pointer (AT, 1, 1C)
   * > Functional Group Private Creator (LO, 1, 1C)
   * > Dimension Organization UID (UI, 1, 1C)
   * > Dimension Description Label (LO, 1, 3)
   *
   * The Dimension Organization UIDs within the Dimension Organization Sequence
   * cannot be set explicitly. Instead the sequence is populated from the data
   * found within the Dimension Index Sequence.
   */
  class DCMTK_DCMIOD_EXPORT IODMultiframeDimensionModule : public IODModule
  {
  
  public:
      /** Helper class representing an item within the Dimension Index Sequence,
       *  i.e.\ a single dimension description
       */
      class DCMTK_DCMIOD_EXPORT DimensionOrganizationItem : public IODComponent
      {
  
      public:
          /** Constructor
           *  @param  data The item to be used for data storage. If NULL, the
           *          class creates an empty data container.
           *  @param  rules The rule set for this class. If NULL, the class creates
           *          one from scratch and adds its values.
           *  @param  parent The parent of the IOD component (NULL if none or unknown)
           */
          DimensionOrganizationItem(OFshared_ptr<DcmItem> data, OFshared_ptr<IODRules> rules, IODComponent* parent);
  
          /** Constructor
           *  @param  parent The parent of the IOD component (NULL if none or unknown)
           */
          DimensionOrganizationItem(IODComponent* parent = NULL);
  
          /** Destructor
           */
          virtual ~DimensionOrganizationItem();
  
          /** Get name of module ("DimensionIndexPointerSequence")
           *  @return Name of the module ("DimensionIndexPointerSequence")
           */
          virtual OFString getName() const;
  
          /** Resets rules of this module to their original values
           */
          virtual void resetRules();
  
          /** Get Dimension Organization UID
           *  @param  value  Reference to variable in which the value should be
           *          stored
           *  @param  pos  Index of the value to get (0..vm-1), -1 for all components
           *  @return EC_Normal if successful, an error code otherwise
           */
          virtual OFCondition getDimensionOrganizationUID(OFString& value, const signed long pos = 0) const;
  
          /** Set Dimension Organization UID
           *  @param  value Value to be set (single value only) or "" for no value
           *  @param  checkValue Check 'value' for conformance with VR (PN) and VM (1) if enabled
           *  @return status EC_Normal if successful, an error code otherwise
           */
          virtual OFCondition setDimensionOrganizationUID(const OFString& value, const OFBool checkValue = OFTrue);
      };
  
      /** Class representing a Dimension Index Pointer Sequence Item
       *  managed by the Multi-frame Dimension Module
       */
      class DimensionIndexItem : public IODComponent
      {
  
      public:
          /** Constructor
           *  @param  data The item to be used for data storage. If NULL, the
           *          class creates an empty data container.
           *  @param  rules The rule set for this class. If NULL, the class creates
           *          one from scratch and adds its values.
           *  @param  parent The parent of the IOD component (NULL if none or unknown)
           */
          DimensionIndexItem(OFshared_ptr<DcmItem> data, OFshared_ptr<IODRules> rules, IODComponent* parent);
  
          /** Constructor
           *  @param  parent The parent of the IOD component (NULL if none or unknown)
           */
          DimensionIndexItem(IODComponent* parent = NULL);
  
          /** Destructor
           */
          virtual ~DimensionIndexItem();
  
          /** Get name of module ("DimensionIndexSequence")
           *  @return Name of the module ("[parent.]DimensionIndexSequence")
           */
          virtual OFString getName() const;
  
          /** Resets rules to their original values
           */
          virtual void resetRules();
  
          /** Get Dimension Index Pointer
           *  @param  value  Reference to variable in which the value should be stored
           *  @param  pos    Index of the value to get (0..vm-1), -1 for all components
           *  @return EC_Normal if successful, an error code otherwise
           */
          virtual OFCondition getDimensionIndexPointer(DcmTagKey& value, const signed long pos = 0) const;
  
          /** Get Dimension Index Private Creator
           *  @param  value  Reference to variable in which the value should be stored
           *  @param  pos    Index of the value to get (0..vm-1), -1 for all components
           *  @return EC_Normal if successful, an error code otherwise
           */
          virtual OFCondition getDimensionIndexPrivateCreator(OFString& value, const signed long pos = 0) const;
  
          /** Get Functional Group Pointer
           *  @param  value  Reference to variable in which the value should be stored
           *  @param  pos    Index of the value to get (0..vm-1), -1 for all components
           *  @return EC_Normal if successful, an error code otherwise
           */
          virtual OFCondition getFunctionalGroupPointer(DcmTagKey& value, const signed long pos = 0) const;
  
          /** Get Functional Group Private Creator
           *  @param  value  Reference to variable in which the value should be stored
           *  @param  pos    Index of the value to get (0..vm-1), -1 for all components
           *  @return EC_Normal if successful, an error code otherwise
           */
          virtual OFCondition getFunctionalGroupPrivateCreator(OFString& value, const signed long pos = 0) const;
  
          /** Get Dimension Organization UID
           *  @param  value  Reference to variable in which the value should be stored
           *  @param  pos    Index of the value to get (0..vm-1), -1 for all components
           *  @return EC_Normal if successful, an error code otherwise
           */
          virtual OFCondition getDimensionOrganizationUID(OFString& value, const signed long pos = 0) const;
  
          /** Get Dimension Description Label
           *  @param  value  Reference to variable in which the value should be stored
           *  @param  pos    Index of the value to get (0..vm-1), -1 for all components
           *  @return EC_Normal if successful, an error code otherwise
           */
          virtual OFCondition getDimensionDescriptionLabel(OFString& value, const signed long pos = 0) const;
  
          /** Set Dimension Index Pointer
           *  @param  value Value to be set (single value only) or "" for no value
           *  @param  checkValue Check 'value'. Not evaluated (here for consistency
           *          with other setter functions).
           *  @return status EC_Normal if successful, an error code otherwise
           */
          virtual OFCondition setDimensionIndexPointer(const DcmTagKey& value, const OFBool checkValue = OFTrue);
  
          /** Set Dimension Index Private Creator
           *  @param  value Value to be set (single value only) or "" for no value
           *  @param  checkValue Check 'value' for conformance with VR (PN) and VM (1) if enabled
           *  @return status EC_Normal if successful, an error code otherwise
           */
          virtual OFCondition setDimensionIndexPrivateCreator(const OFString& value, const OFBool checkValue = OFTrue);
  
          /** Set Dimension Index Functional Group Pointer
           *  @param  value Value to be set (single value only) or "" for no value
           *  @param  checkValue Check 'value'. Not evaluated (here for consistency
           *          with other setter functions).
           *  @return status EC_Normal if successful, an error code otherwise
           */
          virtual OFCondition setFunctionalGroupPointer(const DcmTagKey& value, const OFBool checkValue = OFTrue);
  
          /** Set Dimension Index Functional Group Private Creator
           *  @param  value Value to be set (single value only) or "" for no value
           *  @param  checkValue Check 'value. Not evaluated (here for consistency
           *          with other setter functions).
           *
           *  @return status EC_Normal if successful, an error code otherwise
           */
          virtual OFCondition setFunctionalGroupPrivateCreator(const OFString& value, const OFBool checkValue = OFTrue);
  
          /** Set Dimension Organization UID
           *  @param  value Value to be set (single value only) or "" for no value
           *  @param  checkValue Check 'value' for conformance with VR and VM if enabled
           *  @return status EC_Normal if successful, an error code otherwise
           */
          virtual OFCondition setDimensionOrganizationUID(const OFString& value, const OFBool checkValue = OFTrue);
  
          /** Set Dimension Description Label
           *  @param  value Value to be set (single value only) or "" for no value
           *  @param  checkValue Check 'value' for conformance with VR and VM if enabled
           *  @return status EC_Normal if successful, an error code otherwise
           */
          virtual OFCondition setDimensionDescriptionLabel(const OFString& value, const OFBool checkValue = OFTrue);
      };
  
      /** Constructor
       *  @param  item The item to be used for data storage. If NULL, the
       *          class creates an empty data container.
       *  @param  rules The rule set for this class. If NULL, the class creates
       *          one from scratch and adds its values.
       */
      IODMultiframeDimensionModule(OFshared_ptr<DcmItem> item, OFshared_ptr<IODRules> rules);
  
      /** Constructor
       */
      IODMultiframeDimensionModule();
  
      /** Destructor
       */
      virtual ~IODMultiframeDimensionModule();
  
      /** Convenience method to add Dimension Index.
       *  @param  dimensionIndexPointer The Dimension Index Pointer attribute
       *  @param  dimensionOrganizationUID The Dimension Organization UID of the dimension organization
       *          the pointer refers to. If UID does not exist yet (in the Dimension
       *          Organization Sequence, it is created there automatically).
       *  @param  functionalGroupPointer The functional group where the pointer attribute can be found
       *  @param  dimensionDescriptionLabel The description label of this dimension (optional)
       *  @param  dimensionIndexPrivateCreator The private creator of the Dimension Index Pointer
       *          attribute. Required if dimensionIndexPointer points to a private attribute tag.
       *  @param  functionalGroupPrivateCreator The private creator of the functional group. Required
       *          if functionalGroupPointer points to a private attribute tag.
       *  @return EC_Normal if index could be added, error otherwise (basic parameter checking)
       *
       */
      virtual OFCondition addDimensionIndex(const DcmTagKey& dimensionIndexPointer,
                                            const OFString& dimensionOrganizationUID,
                                            const DcmTagKey& functionalGroupPointer,
                                            const OFString& dimensionDescriptionLabel     = "",
                                            const OFString& dimensionIndexPrivateCreator  = "",
                                            const OFString& functionalGroupPrivateCreator = "");
  
      /** Clear (removes) all attributes handled by the modules of this component.
       *  Rules are not reset.
       */
      virtual void clearData();
  
      /** Read data into this module from given item
       *  @param  source The item to read from
       *  @param  clearOldData If OFTrue, old data in this module is cleared first (default: OFTrue)
       *  @return EC_Normal if reading was successful, error otherwise
       */
      virtual OFCondition read(DcmItem& source, const OFBool clearOldData = OFTrue);
  
      /** Write this module to given item
       *  @param  destination The item to write to
       *  @return EC_Normal if writing was successful, error otherwise
       */
      virtual OFCondition write(DcmItem& destination);
  
      /** Resets rules to their original values.
       */
      virtual void resetRules();
  
      /** Get name of module ("MultiframeDimensionModule")
       *  @return Name of the module ("MultiframeDimensionModule")
       */
      virtual OFString getName() const;
  
      /** Get Dimension Organization Type
       *  @param  value  Reference to variable in which the value should be stored
       *  @param  pos    Index of the value to get (0..vm-1), -1 for all components
       *  @return EC_Normal if successful, an error code otherwise
       */
      virtual OFCondition getDimensionOrganizationType(OFString& value, const signed long pos = 0) const;
  
      /** Set Dimension Organization Type (Defined Terms as of DICOM 2014a "3D" and "3D_TEMPORAL")
       *  @param  value Value to be set (single value only) or "" for no value
       *  @param  checkValue Check 'value' for conformance with VR and VM if enabled
       *  @return status EC_Normal if successful, an error code otherwise
       */
      virtual OFCondition setDimensionOrganizationType(const OFString& value, const OFBool checkValue = OFTrue);
  
      /** Get content of the Dimension Index Sequence
       *  @return Reference to the Dimension Index Pointer Sequence
       */
      virtual OFVector<DimensionIndexItem*>& getDimensionIndexSequence();
  
      /** Get content of the Dimension Organization Sequence
       *  @return Reference to the Dimension Organization Sequence
       */
      virtual OFVector<DimensionOrganizationItem*>& getDimensionOrganizationSequence();
  
      /** Check dimensions for consistency with functional groups. Note that one can provide
       *  an item that provides the dataset containing the functional groups to check against.
       *  This item must contain on main level the Shared and Per-frame Functional Group
       *  Sequence. If no item is given (NULL pointer) it is tried to find these sequences
       *  within "this" object which works in the case that this class was initialized with
       *  an existing item (or the fg data was inserted in another way afterwards).
       *  @param  fgItem The item containing functional group information
       *  @return EC_Normal, if consistency is fine, error otherwise
       */
      virtual OFCondition checkDimensions(DcmItem* fgItem = NULL);
  
      /** Get specific index pointer element from per-frame functional group
       *  sequence. Prints out error messages if index does not exist or
       *  index location information provided by parameters is incomplete or invalid
       *  @param  perFrameFG An instance of the Per-Frame Functional Group Sequence that
       *          should be searched
       *  @param  fgPointer The tag key of the functional group the value resides in
       *  @param  indexPointer The tag of the dimension value inside the functional group
       *  @param  fgPrivateCreator The private creator of the fgPointer tag key. Only required
       *          if fgPointer is a private tag key (odd element number)
       *  @param  privateCreator The private creator of the indexPointer tag key. Only required
       *          if indexPointer is a private tag key (odd element number)
       *  @return The element pointed to. If element could not be located, NULL is returned.
       */
      virtual DcmElement* getIndexElement(DcmSequenceOfItems* perFrameFG,
                                          const DcmTagKey& fgPointer,
                                          const DcmTagKey& indexPointer,
                                          const OFString& fgPrivateCreator,
                                          const OFString& privateCreator);
  
      /** Enable or disable calling of the checkDimensions() routine when writing the module.
       *  Checking can be very time-consuming if many frames are present. Default is OFTrue.
       *  @param  doCheck If enabled, checkDimensions() is called when writing.
       */
      virtual void setCheckOnWrite(const OFBool doCheck);
  
      /** Returns whether checkDimensions() routine is called when writing the module.
       *  @returns OFTrue if calling of checkDimensions() is enabled when writing, OFFalse otherwise.
       */
      virtual OFBool getCheckOnWrite();
  
  protected:
      /** Go over Dimension Index Pointers and extract Dimension Organization UIDs for
       *  Dimension Organization Sequence.
       */
      void createDimensionOrganizationData();
  
  private:
      /// This module's name (MultiframeDimensionModule)
      static const OFString m_ModuleName;
  
      /// Vector with all items of the Dimension Index Pointer Sequence
      OFVector<DimensionIndexItem*> m_DimensionIndexSequence;
  
      /// Vector with all items of the Dimension Organization Sequence
      OFVector<DimensionOrganizationItem*> m_DimensionOrganizationSequence;
  
      /// If enabled, dimension structures are checked when writing the module.
      /// This can be very time-consuming if many frames are present. Default is
      /// OFTrue.
      OFBool m_CheckOnWrite;
  };
  
  #endif // MODMULTIFRAMEDIMENSION_H
  