--[[
   This grouping script partition magnetic resonance (MR) images as follows:
   Scout images in their own sequences
   Group all other images by a combination of DICOM Series instance UID, echo type prop,
   view prop, series number and phase.   

	Cristian Bonciu,        August-September 2004
     -	Created and implemented the functionality from pseudo-code prototypes provided by Allan 
	Allan Noordvyk,     January 2005
     -	Added Pulse Sequence property support
	Allan Noordvyk			11 MAR 2005
     -	Addressed sort order issues discovered at beta site (also lack of sorting of scouts within a series).
	Allan Noordvyk       		03 MAY 2005
     -	Added exception to ignore slice location for sorting ADC MAPS series from GE devices, since it 
		is garbage (forgets sign) 
	Allan Noordvyk			04 MAY 2005
     -	Corrected PATIENT_POS_TAG defn to fix CRDB00032128
	Cristian Bonciu			09 JUN 2005 
	-	Added IMAGE_LOCATION_PATIENT as the first sorting hint; this hint is present only for 
		axial, sagittal and coronal images (having the View property defined to one of these values) and 
		when present, produces the following sorting order :
          -	head to foot for axials, 
          -	left to right for sagittals and 
          -	anterior to posterior for coronals   
	Allan Noordvyk         	18 JUL 2005
     -	CRDB00027821: Added split by Image Type as well for non-scouts so that Original and Derived
		images would not be intermixed.  
	Allan Noordvyk			19 JUL 2005
     -	CRDB00032128/CRDB00030856/CRDB00030415: Fixed uninitialized variable use problem with 
		DESCENDING_ORDER when used in IMAGE_LOCATION_PATIENT sort hint
	Mahesh Nagarajan		27 SEP 2005
     -	CRDB00035056: Wrong scrolling order of Sagittal and Coronal series in MR Study
     - 	According to DICOM standards (part 3 section C.2.7.6.2.1.1); "the direction of axes is defined 
		by patient's orientation.The x-axis is increasing to the left hand side of the patient. The y-axis 
		is increasing to the posterior side of the patient. The z-axis is increasing toward the head of the
		patient." This means that there is a problem with the following statement :-
		srtHint:AddSortHint(IMAGE_LOCATION_PATIENT_PROP, DESCENDING_ORDER)
		because for coronals; descending order results in images being arranged from "posterior to anterior" 
		and not "anterior to posterior" as suggested in the comment for the above statement. The problem with 
		the coronal images can be attributed to this.
	Mahesh Nagarajan		04 OCT 2005
     -	Changed order of sorting hints - pushed sorting hint "INSTANCE_NUMBER_TAG" to just above 
		"ALI_IMAGE_FILENAME_TAG" in response to CRDB00035707 owing to unreliable sorting results
     Mahesh Nagarajan		05 OCT 2005	
     -	Turns out that "INSTANCE_NUMBER_TAG" is the best sorting hint for MR-MIP images so if the 
		images are manufactured by Siemens and the series description is MIP, then sorting is done based on
		"INSTANCE_NUMBER_TAG"; otherwise, the regular sorting takes place.
     Mahesh Nagarajan		06 OCT 2005
     -	Corrected maketag statement for ECHO_TYPE_PROP    
     -	Added check for special case for Mercy Iowa Carotid Studies; sorting is done only by Instance Number    
     Allan Noordvyk			07 OCT 2005
     -	Changes below are related to STRQ1572 Sequencing: Improper sequencing for MIP images and other 
		issues observed in situ at Gwinnett Medical
     -	Adjusted sort of MIP's to not try to do fancy spatial stuff since this results in odd image orders
          (N.B. Replaces Mahesh's more targeted SIEMENS solution of Oct. 05 with one which should be true 
		for other vendors as well).
     -	Adjusted sort of MIP's to not try to do fancy spatial stuff since this results in odd image orders
     Mahesh Nagarajan		16 OCT 2005
     -	Removed check for special case for Mercy Iowa Carotid Studies; moved this into ExtractCommon.tls
     Mahesh Nagarajan		17 OCT 2005
     -	Removed addition of grouping hints after adding Series UID as a grouping hint for MIP series to prevent 
		over-splitting problems
     Mahesh Nagarajan		10 NOV 2005
     -	Modified sorting order for sort hint IMAGE_LOCATION_PATIENT_PROP; set sorting order to 
		ascending for Coronal images, and descending for axials and sagittals.
       - Added exception for Elkhart General hospital, Axials are sorted from toe to head in this case.
     Mahesh Nagarajan		22 NOV 2005
     -	For Image Type "MRCP"; sorting is by Image Number and grouping is by slice type
     -	Added grouping by Image Type for MIP images; otherwise Axial MIPs and radial MIPs are grouped 
		together in the same sequence.
     Mahesh Nagarajan		30 NOV 2005
     -	Added grouping hint for (0020,0100) REL Temporal Position Identifier to seperate the different diffusion
		weighted sequences
     -	Identify Spin & Roll MPRs and group them by Series Number and ACQ Protocol Name which has the 
		values "Spin" or "Roll"
     Mahesh Nagarajan		12 DEC 2005
     -	On request by Tina Penn (PACS Admin for Mountainview Medical Center, NM), added site customized sorting 
		scheme for Sagittals and Coronals; Sagittals to scroll from right to left and Coronals from back to front.
       - On request by Tina Penn (PACS Admin for Mountainview Medical Center, NM), added splitting of diffusion 
		sequences by Window Center.
     Mahesh Nagarajan		13 JAN 2006
     -	Added a new work-around for GE Diffusion sequences that interleave; these are sorted by image number so 
		that the sequences come one after another
     Mahesh Nagarajan		16 JAN 2006
     -	Added site customized code for Shields Healthcare (Boston, MA)
		1. Added all 3-plane locs to one sequence on request
		2. Sorting scheme: Axials go from bottom to top; Sagittals go from right to left & Coronals go from back to front
     -	Modified structure of grouping hints for Scout images to accomodate #1 from above
     -	Modified sorting hints for Scouts i.e. only image number is now used for sorting scouts. This helps beautify 
		the sequence obtained from grouping all the 3-Plane Locs together.
     Mahesh Nagarajan		18 JAN 2006
     -	Added sort hint for ID SOP Instance UID just before filename
     -	Removed restriction that allows grouping by image type for MIPS only, now all MR images are grouped by 
		(0008, 0008) ID Image Type
    Mahesh Nagarajan			20 JAN 2006
     -	A new approach to sorting Axial images from certain GE devices to counter the improper sorting trigerred 
		by intersecting slices; if theimages are Axial, associated with the body part "Spine" and the images are from
		a GE Signa Excite or Genesis_Signa; then the primary sorting hint is REL Slice Location.
    Mahesh Nagarajan			25 JAN 2006
     -	Added site-customized sorting routines for Mercy Iowa
     -	Installation at Iowa revealed an interesting problem. If a diffusion sequence of a coefficeint thats not
          b0 or b1 is detected; there are now no sort hints for it. The result is now a weird sequence. As a preventive 
          measure; if diffusion sequence of b0 or bn is detected, image number is added as a sort hint followed by the
          regular set of sort hints for positional information.
     Mahesh Nagarajan		08 FEB 2006
     -	Added site customized sorting of MR Brain studies for Vancouver Clinic.
    Mahesh Nagarajan			21 FEB 2006
     -	Sorting "bn" diffusion sequences on image number does not work well for some studies from Philips devices; for such
          studies, sorting is done on anatomical slice location.
    Mahesh Nagarajan			02 MAR 2006
     -	On request by PACS Admin at Mountain View Regional Medical Center, added site customized sorting
          for MR Brain studies
     Mahesh Nagarajan		27 MAR 2006
     -	Added grouping hints for (0018, 1060) ACQ Trigger Time &  (0018,110) ACQ Recon Diameter to resolve under-split 
          sequences at Hill Medical Corporation
     Mahesh Nagarajan		03 APR 2006
     -	On request by Provena St. Joseph, added all 3-plane locs to one sequence to reduce thumbnail clutter
     -	Added site-customized sort routines to ensure right-to-left ordering of sagittal images       
     Mahesh Nagarajan		03 APR 2006
     -	Based on nasty over-splits observed at Spectrum, removed the splitting hint for ACQ Trigger Time. Such sequences
          are now treated as undetected phase sequences and sorted on image number.
	Mahesh Nagarajan		24 APRIL 2006
     -	Site-Customized sorting for Trinity Ohio
     Mahesh Nagarajan          02 MAY 2006
     -	Removed (0018, 1060) ACQ Trigger Time as a splitter hint; the use of this tag has to be re-evaluated
     Mahesh Nagarajan          03 MAY 2006
     -	Splitting by (0020, 0100) REL Temporal Position Identifier only if number of temporal positions is greater than 6.
     Mahesh Nagarajan		04 MAY 2006
     -	Sorting FSPGR sequences by image number to ensure that multiple phases do not interleave
     -	Grouping scouts by series UID only to ensure lesser number of thumbnails for FAHC
     Mahesh Nagarajan		08 MAY 2006
     -	Reversed MRI Brain sorting for Roswell Park, Hess Memorial & Wayne Memorial
     Mahesh Nagarajan		15 MAY 2006
     -	MAJOR SCRIPT REVAMP; please compare with earlier version on VSS if necessary 
	 -	Removed site customized sorting and replaced it with sorting by image number
	Mahesh Nagarajan		17 MAY 2006
     -	Removed grouping hint for temporal position identifier, moved it into ExtractMR.tls 	
     Mahesh Nagarajan		27 MAY 2006
     -	Removed grouping hint for ACQ Recon Diameter; caused too much trouble with single image splits and is useless
		now that primary sorting is on image number
    Mahesh Nagarajan			26 JUL 2006
	-	Slight change of plans, we should sort first on temporal position identifier and then on image number; this
	    will ensure that different temporal positions will not interleave.		
     Cartik Sharma			28 DEC 2006
	-	Added property tag, image suppression to obtain water and fat suppression. Information is stored in
		Mckesson Tag 3711, 1310
     Mahesh Nagarajan		30 JAN 2007
	-	A very ugly but necessary site-customization for Main Line Health that tries to ensure that all breast 
	    MR sequences acquired from the GE modality (that are not rotational in nature) are sorted by table position. 
	    This ensures that the images are interleaved and slices with the same table location value are clumped together.
	Mahesh Nagarajan		31 JAN 2007
	-	MAJOR SCRIPT REVAMP; please compare with earlier version on VSS if necessary
	-	Implemented support for user controlled sorting on multiple attributes using prototypes from Mike McFarland. For
		more details on the sequencing engine changes, please consult the document titled "Lua Application Programming 
		Interface for Multiple Sorting Criteria Sequencing. The corresponding FEATs for HRS are FEAT219 and FEAT250.
	-	Site customized code will be removed and re-located to GroupMR.site files -> starting with 11.5, unless sort orders
		or splitting hints are fundamentally flawed, all change requests to sorting and grouping schemes will be incorporated
		into a site file for the site.
	- 	"All Images" will no longer be created in the sequencing scripts; HRS will take responsibility for generating this sequence
	- 	Modified syntaxes for grouping and sorting hints as part of v11.5 re-write
	Mahesh Nagarajan		14 MAY 2007
	-	Added new sorting category called "Perfusion Sort"; this will sort images first by slice lcoation and then by acquisition time.
	-	Changed the sort names; removed the modality prefix and sort suffix as it looks stupid
	Mahesh Nagarajan		28 MAY 2007
	- 	Bringing back the "All Images" sequence until the corresponding HRS feature gets implemented; this will get one sort order
		called "Default"
	Mahesh Nagarajan		13 JUN 2007
	-	Added specialised grouping for diffusion coefficient weighted images from GE; even though images have the same coefficient,
		they maybe clinically different owing to the direction in which the gradient is applied, and this needs to be used to split such
		a series down further.
    Mahesh Nagarajan			26 JUL 2007     
	-	Changing the "table position" hint to "slice location"; the latter is more generic as it refers to the location of the slice in 
		general and not specifically if it is relative to the table or patient space.
	-    Removing the "default" sort and making "image number" sort the default
	Mahesh Nagarajan		13 NOV 2007
	-	Tweaked the generation of the "Phase Sort"; this should be generated if the (0020,0012) REL Acquisition Number tag is 
		present. The presence of this tag does not necessarily mean that the phase property will be generated but will still need 
		to be used for sorting
	Mahesh Nagarajan		12 FEB 2008
	-	Adding back site-specific code snippets; after a long discussion with Cristian B., it is understood that this code has to stay 
		in the code until proper site files have been installed. Such code is added back but within "dollar sign" demarcations to ensure 
		easy removal at a later date.
	Mahesh Nagarajan		14 MAR 2008
	-	Fixed inconsistencies found between this branch (EXP) and the live sequencing script
		branch found by Shudong during code review
     Mahesh Nagarajan		11 APR 2008
	-	Replacing the sort hint for the Phase property with Temporal PositionIdentifier; the latter is of type int and makes 
		for a more sensible sorting hint
	Mahesh Nagarajan		22 MAY 2008
	-	Adding Baptist Memorial to list of sites that need a split on image type; the purpose of this exercise is to seperate the derived
		MPR/MIP data from the original axial data
	Mahesh Nagarajan		23 MAY 2008	
	-	Adding more aliases to correctly identify perfusion sequences at C.H.Trousseau
	Mahesh Nagarajan 		08 JUL 2008	
	  - Adding Spectrum to list of hospitals that require specialized sorting of Perfusion sequences
	Shudong Liu - 11 SEP 2008	
	-	University hospital of Cincinatti has different facilities which have different facility names. 'University Hospital Cinti' is added 
		to the list of hospitals where image number should be the primary instead of secondary sort hint.
	Shudong Liu - 8 OCT 2008
	-	Commented out the support for Enhanced Multi-Frame Objects. HRS 11 does not support EMF yet. 		
	Shudong Liu - 11 SEP 2008	
	  - University hospital of Cincinatti has different facilities which have different facility names. 'University Hospital Cinti' is added 
	    to the list of hospitals where image number should be the primary instead of secondary sort hint.(9120)
	Shudong Liu - 6 JAN 2009
	  - Customized for site University of Kentucky Medical Center to sort images by series time. (REI11225)
	Shudong Liu - 20 JAN 2009
	  - Customized for facility MOUNTAIN VIEW MEDICAL of site Novant Health not to split images by 
	    WINDOW_CENTER_TAG. 	(REI10961)
	Shudong Liu    Feb. 18, 2009
	- Removed "*All Images*" sequence for HMI 11.6	
	Shudong Liu - 20 APR 2009
	  - Customized for site North Country Imaging to group image by image type.	
    James Zhang - 08 June 2009
      - Fixed CRDB00076152.
    James Zhang - 08 June 2009
      - Customized for site Spectrum Health to group by Slice Location (0020/1041),
        as per CRDB76130 or REI 13603.
	James Zhang - 19 June 2009
	  - Added group hint ALI_DERIVED_IDENTIFIER_TAG for CRDB75126.	  
    James Zhang - 14 July 2009
      - Customized for site Spectrum Health to group by Slice Location (0020/1041),
        as per REI 14522(CRDB00077236).
    James Zhang - 15 July 2009
     - Customized for site Glens Falls Hospital (North Country Imaging) to split TOSHIBA cine series by slice location,
        as per REI 14604(CRDB00077393).
    James Zhang - 21 Sep 2009
     - Customized for Merrimack Valley to ignore group hint PHASE_PROP,
        as per REI 13580(CRDB00079853).
    James Zhang - 12 April 2010
      - Customized for site Spectrum Health to group by Series Number,
        as per REI 18897(CRDB00085827).
    James Zhang - 07 July 2010
     - Customized for site St. Lukes Episcopal Hospital (Texas) to group Dynamic
       Scans, as per REI 19035(CRDB00088229).
--]]

-- Enable tracing in this module for debugging (comment out for production version)
-- AliDSTraceLevel = 2 

function DeclareTags()
    ECHO_TYPE_PROP = maketag("3711","110C")
    IMAGE_SUPPR_PROP = maketag("3711", "1310") -- Glen Falls, Split sequence for fat/water suppression images
    DIFF_COEF_PROP = maketag("3711","1302")
    ECHO_NUMBER_TAG = maketag("0018","0086")
	GE_PRIV_VAS_COLL_TAG = maketag( "0043", "1030" )
	NUM_TEMP_POS_TAG = maketag( "0020", "0105" )        -- REL No. of Temporal Positions
end

function RegisterSortingHintTypes( )
-- ////////////////////////////////////////////////////////////////////////////
-- This function will register the various sort orders that are created for MR
-- ////////////////////////////////////////////////////////////////////////////
	RegisterHintType( "IMAGE NUMBER SORT", "Image Number" )
	RegisterHintType( "SLICE LOCATION SORT", "Slice Location" )
	RegisterHintType( "ACQUISITION TIME SORT", "Acquisition Time" )
	RegisterHintType( "PHASE SORT", "Phase" )
	RegisterHintType( "FILE NAME SORT", "File Name" )
	RegisterHintType( "PERFUSION SORT", "Perfusion" )
end

function Execute()
-- ////////////////////////////////////////////////////////////////////////////
-- This function will create grouping and sorting hints for MR Sequencing 
-- ////////////////////////////////////////////////////////////////////////////

   TraceC("Group MR executing\n")
   
    -- N.B. Since this script is used for multiple MR based modalities (MR, MRA, MS) we
    -- don't do a single modality sanity check like in single modality scripts.
	
	-- If this is an EMF MR object, let the proper script handle it
	local EMF_MR_CLASS_UID = "1.2.840.10008.5.1.4.1.1.4.1" 
    local sopClassAttr = GetAttr(SOP_CLASS_UID_TAG)
	
	--if (sopClassAttr~=nil and BestMatchInAttr(sopClassAttr, EMF_MR_CLASS_UID) ) then
	--	return nil
	--	-- =====================================================		
	--end
	
    DeclareTags()

    -- Use series description property for identifying the series.
    local descStr = ValueForTag(SERIES_DESC_PROP,"?") -- const string

	-- Note image type and whether this is a maximum intensity projection for later
    local imageType = ValueForTag( IMAGE_TYPE_PROP )
    local isMRCP = (imageType ~= nil and imageType == "MRCP")
    
    -- Check to see if series is a special MPR i.e. Spin or Roll MPR; such sequences are
    -- treated similar to MIP sequences
    local isSpecialMPR = nil;
    if (imageType ~= nil and imageType == "MPR") then
        SPIN_VAL = "Spin"
        ROLL_VAL = "Roll"
        local acqProtocolName = GetAttr(ACQ_PROTOCOL_TAG)
        if (acqProtocolName) then
            isSpecialMPR = BestWordMatchInAttr(acqProtocolName, SPIN_VAL, ROLL_VAL);
        end
    end
    
    --~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	--~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	-- The following code is to set up the parameters for sorting by slice location.    
    
    -- Define constants so intended sort order, when used, is more readable.
    local ASCENDING_ORDER = true
    local DESCENDING_ORDER = false

    -- For most views and patient positions, ascending slice order will give you expected results
    local sliceOrder = ASCENDING_ORDER
	local locPatientOrder = DESCENDING_ORDER
    local isADCmAPS = true
	
	local SiteName = GetAttr(INSTITUTION_NAME_TAG)

	-- The default sort order for slice location is Axial ->Top to Bottom; Sagittal -> Left to Right
	-- and Coronal -> Front to Back
	if (ValueForTag( VIEW_PROP ) == "Coronal") then
		locPatientOrder =  ASCENDING_ORDER
	else
		locPatientOrder =  DESCENDING_ORDER
	end

    -- If this isn't an ADC MAPS series from a GE MR...
    if (not(descStr == "ADC MAPS" and ValueForTag(DEVICE_MANUFACTURER_TAG) == "GE MEDICAL SYSTEMS")) then
        -- It is safe to use slice order for sorting the images
		isADCmAPS = false -- used later to check if sort hint for SLICE_LOC_TAG is to be added
     
        -- If the view is axial and the patient was scanned head-first...
        if (ValueForTag( VIEW_PROP ) == "Axial" and ValueForTag( PATIENT_POS_TAG ) == "HFS") then
            sliceOrder = DESCENDING_ORDER -- flip slice coordinates so head at top of stack
        end
        -- Sort by slice order as primary choice
    end
    --~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    --~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~	

	-- Not checking for file name as it should always exist
	local sortHint01 = SortingHint:new( "File Name", "FILE NAME SORT" )
	sortHint01:AddEntry( ALI_IMAGE_FILENAME_TAG, true )
		
	-- Create a "Sort Hint Set" here; all alternate sorts will be added to this one if they are created
	local sortHintSet01 = SortingHintSet:new( )
	sortHintSet01:AddHint( sortHint01 ) 	
    
	-- Creating an image number sort for MR - created only if (0020, 0013) REL Image Number exists
	if (HasAttr(INSTANCE_NUMBER_TAG)) then
		local sortHint02 = SortingHint:new( "Image Number", "IMAGE NUMBER SORT" )
		sortHint02:AddEntry( INSTANCE_NUMBER_TAG, ASCENDING_ORDER ) 
		
		-- If we are here, then the image number sort was created successfully; adding it to the sort hint set for MR
		sortHintSet01:AddHint( sortHint02, true )
	end	
	
	-- Creating a slice location sort for MR - created only if either (0020, 1041) REL Slice Location or 
	-- (3711, 110e) Image Position exist
	if (HasAttr(SLICE_LOC_TAG) or HasAttr(IMAGE_LOCATION_PATIENT_PROP)) then
		local sortHint03 = SortingHint:new( "Slice Location", "SLICE LOCATION SORT" )
		sortHint03:AddEntry( IMAGE_LOCATION_PATIENT_PROP, locPatientOrder )
		if (isADCmAPS == false) then
			-- This check ensures that the sort hint for SLICE_LOC_TAG is ignored for ADC MAPS series from GE devices
			sortHint03:AddEntry( SLICE_LOC_TAG, sliceOrder )
		end
		
		-- If we are here, then the slice location sort was created successfully; adding it to the sort hint set for MR
		sortHintSet01:AddHint( sortHint03 )
	end
	
	-- Creating an acquisition time sort for MR - created only if (0008, 0032) ID Acquisition Time  or 
	-- (0008, 0033) ID Image Time exist
	if (HasAttr(ACQUISITON_TIME_TAG) or HasAttr(IMAGE_ACQUISITON_TIME_TAG)) then
		local sortHint04 = SortingHint:new( "Acquisition Time", "ACQUISITION TIME SORT" )
	    sortHint04:AddEntry( ACQUISITON_DATETIME_TAG, ASCENDING_ORDER )
		sortHint04:AddEntry( ACQUISITON_DATE_TAG, ASCENDING_ORDER )
		sortHint04:AddEntry( ACQUISITON_TIME_TAG, ASCENDING_ORDER )
		sortHint04:AddEntry( IMAGE_ACQUISITION_DATE_TAG, ASCENDING_ORDER )
		sortHint04:AddEntry( IMAGE_ACQUISITON_TIME_TAG, ASCENDING_ORDER )
		
		-- If we are here, then the acquisition time sort was created successfully; adding it to the sort hint set for MR
		sortHintSet01:AddHint( sortHint04 )
	end	
	
    -- James: Site hack for St. Lukes Episcopal Hospital
    local isDynamicScan = false
	if (SiteName ~=nil and BestWordMatchInAttr(SiteName, "St. Luke's Episcopal Hospital")) then
        local tagValue = ValueForTag(NUM_TEMP_POS_TAG)
        if (1 < tagValue) then
            isDynamicScan = true
        end
    end
	
	-- Creating a phase sort for MR - created only if (0020, 0100) REL Temporal Position Identifier exists
	if (HasAttr(TEMP_POSITION_IDENTIFIER_TAG) or HasAttr(ACQ_NUMBER_TAG)) then
		local sortHint05 = SortingHint:new( "Phase", "PHASE SORT" )

        if (not isDynamicScan) then
            sortHint05:AddEntry( TEMP_POSITION_IDENTIFIER_TAG, ASCENDING_ORDER )
        end
		sortHint05:AddEntry( ACQ_NUMBER_TAG, ASCENDING_ORDER )
		sortHint05:AddEntry( IMAGE_LOCATION_PATIENT_PROP, locPatientOrder )
		if (isADCmAPS == false) then
			-- This check ensures that the sort hint for SLICE_LOC_TAG is ignored for ADC MAPS series from GE devices
			sortHint05:AddEntry( SLICE_LOC_TAG, sliceOrder )
		end
		-- Alternates just in case slice location is not available
		sortHint05:AddEntry( INSTANCE_NUMBER_TAG, ASCENDING_ORDER ) 
		sortHint05:AddEntry( ALI_IMAGE_FILENAME_TAG, ASCENDING_ORDER )
		
		-- If we are here, then the phase sort was created successfully; adding it to the sort hint set for MR
		sortHintSet01:AddHint( sortHint05 )
	end	

	-- Creating a perfusion sort for MR - only if (0020, 1041) REL Slice Location or 
	-- (3711, 110e) Image Position exist, and 0008, 0032) ID Acquisition Time  or 
	-- (0008, 0033) ID Image Time exist
	if ((HasAttr(SLICE_LOC_TAG) or HasAttr(IMAGE_LOCATION_PATIENT_PROP)) and
		(HasAttr(ACQUISITON_TIME_TAG) or HasAttr(IMAGE_ACQUISITON_TIME_TAG))	) then
	
		local sortHint06 = SortingHint:new( "Perfusion", "PERFUSION SORT" )

		sortHint06:AddEntry( IMAGE_LOCATION_PATIENT_PROP, locPatientOrder )
		if (isADCmAPS == false) then
			-- This check ensures that the sort hint for SLICE_LOC_TAG is ignored for ADC MAPS series from GE devices
			sortHint06:AddEntry( SLICE_LOC_TAG, sliceOrder )
		end	
		
	    sortHint06:AddEntry( ACQUISITON_DATETIME_TAG, ASCENDING_ORDER )
		sortHint06:AddEntry( ACQUISITON_DATE_TAG, ASCENDING_ORDER )
		sortHint06:AddEntry( ACQUISITON_TIME_TAG, ASCENDING_ORDER )
		sortHint06:AddEntry( IMAGE_ACQUISITION_DATE_TAG, ASCENDING_ORDER )
		sortHint06:AddEntry( IMAGE_ACQUISITON_TIME_TAG, ASCENDING_ORDER )
		
		sortHintSet01:AddHint( sortHint06 )
	end

	--$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
	-- MaxN-30 JAN 2006: A very ugly but necessary site-customization for breast studies
	-- performed at Main Line Health. These hack tries to ensure that all breast MR sequences
	-- acquired from the GE modality that are not rotational in nature, are sorted by table
	-- position. This ensures that the images are interleaved and slices with the same table
	-- location value are clumped together.
	local ManufacturerName = GetAttr(DEVICE_MANUFACTURER_TAG)
	local BodyRegion = GetAttr(BODY_REGION_PROP)
	local SeriesDesc = GetAttr(SERIES_DESC_PROP)
	if (SiteName and ((ValueForTag(INSTITUTION_NAME_TAG)=="Main Line Health-Bryn Mawr") or (ValueForTag(INSTITUTION_NAME_TAG)=="BMH Radiology"))) then
		if (ManufacturerName and ValueForTag(DEVICE_MANUFACTURER_TAG)=="GE MEDICAL SYSTEMS") then
			if (BodyRegion and ValueForTag(BODY_REGION_PROP) == "Breast") then
				if (SeriesDesc and ValueForTag(SERIES_DESC_PROP) ~= "PJN") then
					-- Retrieve the sorting hint if it exists and make it default
					if (sortHintSet01:HasHint("SLICE LOCATION SORT")) then
						local tempSortHint = sortHintSet01:GetHint("SLICE LOCATION SORT")
						sortHintSet01:AddHint(tempSortHint, true)
					end
				end
			end
		end
	end
	
	if (SiteName~=nil and (ValueForTag(INSTITUTION_NAME_TAG)=="Kaiser Permanente Moanalua")) then
		if (ManufacturerName~=nil and ValueForTag(DEVICE_MANUFACTURER_TAG)=="Philips Medical Systems") then
			if (SeriesDesc~=nil and BestWordMatchInAttr(SeriesDesc, "BREAS3D DYN/AX")) then
				-- Retrieve the sorting hint if it exists and make it default
				if (sortHintSet01:HasHint("SLICE LOCATION SORT")) then
					local tempSortHint = sortHintSet01:GetHint("SLICE LOCATION SORT")
					sortHintSet01:AddHint(tempSortHint, true)
				end
			end
		end
	end	
	
		
	-- MaxN: Perfusion sequences are basically composed of images pertain to a few specific slice locations; 
	-- and anumber of images are acquired from these slice locations at different time intervals. The following 
	-- hack ensures that perfusion sequences are sorted primarily on slice location followed by acquisition time. 
	-- The hack is currently activated for boca-Raton & Trousseau (France)
	if ( SiteName~=nil and BestWordMatchInAttr(SiteName, "Boca raton", "Boca-Raton") ) then
		if (SeriesDesc~=nil and BestMatchInAttr(SeriesDesc, "Four_Slice_Perfusion", "trufi_cine")) then
			-- Retrieve the sorting hint if it exists and make it default
			if (sortHintSet01:HasHint("PERFUSION SORT")) then
				local tempSortHint = sortHintSet01:GetHint("PERFUSION SORT")
				sortHintSet01:AddHint(tempSortHint, true)
			end
		end
	end
	
	if ( SiteName~=nil and BestWordMatchInAttr(SiteName, "TROUSSEAU") ) then
		if (SeriesDesc~=nil and BestWordMatchInAttr(SeriesDesc, "perf/BTFE", "perf")) then
			-- Retrieve the sorting hint if it exists and make it default
			if (sortHintSet01:HasHint("PERFUSION SORT")) then
				local tempSortHint = sortHintSet01:GetHint("PERFUSION SORT")
				sortHintSet01:AddHint(tempSortHint, true)
			end
		end
	end
	
	if ( SiteName~=nil and BestWordMatchInAttr(SiteName, "Spectrum") ) then
		if (SeriesDesc~=nil and BestWordMatchInAttr(SeriesDesc, "PERFUSION")) then
			-- Retrieve the sorting hint if it exists and make it default
			if (sortHintSet01:HasHint("PERFUSION SORT")) then
				local tempSortHint = sortHintSet01:GetHint("PERFUSION SORT")
				sortHintSet01:AddHint(tempSortHint, true)
			end	
		end
	end
	
	-- MaxN: Another site hack for Triad - Abilene; they perform multiple breath-holds on MR abdomen studies and
	-- these get split into different series before being imported to PACS; the only solution is to ignore series UID 
	-- for splitting in these cases. The sorting needs to be adjusted in such cases as the image number assignment starts
	-- at 1 for each such broken up series; sorting by file name for images of type original
	if ( SiteName~=nil and BestWordMatchInAttr(SiteName, "Abilene Regional") ) then
		if ( ValueForTag(DEVICE_MANUFACTURER_TAG) == "GE MEDICAL SYSTEMS" and ValueForTag(DEVICE_MODEL_TAG) == "GENESIS_SIGNA" ) then
			if (isOriginal) then
				-- No need to check as it exists (in global scope unlike other hints)
				sortHintSet01:AddHint( sortHint01, true ) 
			end
		end
	end

	--MaxN: Site hack for Roper Hospital; Fiesta sequences should be sorted primarily on image number. These images 
	-- seem to provide acquisition numbers that interfere with nornmal sorting of such sequences.
	if ( SiteName~=nil and BestWordMatchInAttr(SiteName, "Roper Hospital", "UNIV HOSP CINTI-INPT", "University Hospital Cinti") ) then
		if (SeriesDesc~=nil and BestWordMatchInAttr(SeriesDesc, "Chamber", "LVOT", "FGRET", "Fiesta")) then
			-- Retrieve the sorting hint if it exists and make it default
			if (sortHintSet01:HasHint("IMAGE NUMBER SORT")) then
				local tempSortHint = sortHintSet01:GetHint("IMAGE NUMBER SORT")
				sortHintSet01:AddHint(tempSortHint, true)
			end
		end
	end
	
	--MaxN: Site hack for SDMI; adding a primary sort by acquisition number to prevent interleaving of multi-phase sequences
	if ( SiteName~=nil and BestWordMatchInAttr(SiteName, "SDMI:F", "SDMI") ) then
		if ( ValueForTag(ACQ_DEVICE_PROP) == "Toshiba OpArt" and ValueForTag(VIEW_PROP) == "Sagittal" ) then
			-- Retrieve the sorting hint if it exists and replace it
			if (sortHintSet01:HasHint("IMAGE NUMBER SORT")) then
				sortHintSet01:RemoveHint("IMAGE NUMBER SORT")
				local tempSortHint = SortingHint:new( "Image Number Sort", "IMAGE NUMBER SORT" )
				tempSortHint:AddEntry(INSTANCE_NUMBER_TAG, false)
				sortHintSet:AddHint(tempSortHint, true)
			end
		end
	end
	--$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
	
    TraceC( "Group MR sort hints created.\n")
	
	local groupHint01 = GroupingHint:new(descStr)
    local seqNameStr = "MR Sequence" -- const string

	if( HasAttr(ALI_DERIVED_IDENTIFIER_TAG) ) then
		groupHint01:AddEntry(ALI_DERIVED_IDENTIFIER_TAG)
	else
        --$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
        -- MaxN: Another site hack for Triad - Abilene; they perform multiple breath-holds
        -- on MR abdomen studies and these get split into different series before being imported 
        -- to PACS; the only solution is to ignore series UID for splitting in these cases
        if ( SiteName~=nil and BestWordMatchInAttr(SiteName, "Abilene Regional") ) then
            if ( ValueForTag(DEVICE_MANUFACTURER_TAG) == "GE MEDICAL SYSTEMS" and 
                                            ValueForTag(DEVICE_MODEL_TAG) == "GENESIS_SIGNA" ) then
                if ( ValueForTag( IMAGE_TYPE_PROP ) == "Original" ) then
            
                    if( HasAttr(SERIES_DESC_TAG) ) then
                        TraceC("Grouping hint: series desc. tag\n")
                        groupHint01:AddEntry(SERIES_DESC_TAG)
                    end
                    
                    AddImage2Sequence(seqNameStr, groupHint01, sortHintSet01)
                    return
                end
            end
        end
        
        -- MaxN: Site hack for Christus St. Francis Cabrini;ensuring that certain sequences titled 
        -- "New Series" are presented without any further splitting
        local sDescTag = GetAttr(SERIES_DESC_TAG)
        if ( SiteName~=nil and BestWordMatchInAttr(SiteName, "Christus St Francis Cabrini") ) then
            if( sDescTag~=nil and BestWordMatchInAttr(sDescTag, "New Series") ) then
                if( HasAttr(SERIES_UID_PROP)) then
                    TraceC("Grouping hint: series UID\n")
                    groupHint01:AddEntry(SERIES_UID_PROP)
                end
                
                AddImage2Sequence(seqNameStr, groupHint01, sortHintSet01)
                return
            end
        end

        -- James: Site hack for Spectrum Health:
        -- 1. group by Slice Location if series description has word "Function"
        --    or "function";
        -- 2. group by Series Number if cardic series description has "T2*".
        if (SiteName~=nil and BestWordMatchInAttr(SiteName, "Spectrum")) then
            -- perform case insensitive search
            local seekWord = string.lower(descStr)
            if (string.find(seekWord, "function", 1, true) ~= nil) then
                if(HasAttr(SLICE_LOC_TAG)) then
                    TraceC("Grouping hint: slice location tag\n")
                    groupHint01:AddEntry(SLICE_LOC_TAG)
                end
                
                AddImage2Sequence(seqNameStr, groupHint01, sortHintSet01)
                return
            elseif (ValueForTag(BODY_REGION_PROP) == "Heart" and
                    string.find(descStr, "T2*", 1, true) ~= nil) then
                if(HasAttr(SERIES_NUMBER_TAG)) then
                    TraceC("Grouping hint: series number tag\n")
                    groupHint01:AddEntry(SERIES_NUMBER_TAG)
                end

                AddImage2Sequence(seqNameStr, groupHint01, sortHintSet01)
                return
            end
        end

        -- James: Site hack for St. Lukes Episcopal Hospital
        if (isDynamicScan) then
            groupHint01:AddEntry(NUM_TEMP_POS_TAG)
        end

        --$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
            
        if( HasAttr(SERIES_UID_PROP) and not isDynamicScan) then
            TraceC("Grouping hint: series UID\n")
            groupHint01:AddEntry(SERIES_UID_PROP)
        end

        if ( HasAttr(IMAGE_SUPPR_PROP)) then 
            TraceC("Grouping hint: image suppression\n")
            groupHint01:AddEntry(IMAGE_SUPPR_PROP)
        end
        
        if( HasAttr(ECHO_TYPE_PROP) ) then
            TraceC("Grouping hint: echo type property\n")
            groupHint01:AddEntry(ECHO_TYPE_PROP)
        end

        if( HasAttr(PULSE_SEQ_PROP) ) then
            TraceC("Grouping hint: pulse sequence property\n")
            groupHint01:AddEntry(PULSE_SEQ_PROP)
        end
            
        if( HasAttr(ECHO_NUMBER_TAG) ) then
            TraceC("Grouping hint: echo number tag\n")
            groupHint01:AddEntry(ECHO_NUMBER_TAG)
        end
        
        if( HasAttr(SERIES_NUMBER_TAG) and not isDynamicScan) then
            TraceC("Grouping hint: series number tag\n")
            groupHint01:AddEntry(SERIES_NUMBER_TAG)
        end

        -- Bypass PHASE_PROP for site(s) that do not like it
        if (SiteName == nil or BestWordMatchInAttr(SiteName, "Merrimack Valley MRI") == nil) then
            if( HasAttr(PHASE_PROP) ) then
                TraceC("Grouping hint: phase property\n")
                groupHint01:AddEntry(PHASE_PROP)
            end
        end
        
        if( HasAttr(DIFF_COEF_PROP) ) then
            TraceC("Grouping hint: diffusion coefficient property\n")
            groupHint01:AddEntry(DIFF_COEF_PROP)
            
            -- Specialized splitting for images from GE devices
            if( HasAttr(GE_PRIV_VAS_COLL_TAG) ) then
                TraceC("Grouping hint: Diffusion Type\n")
                groupHint01:AddEntry(GE_PRIV_VAS_COLL_TAG)
            end
            
            --$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
            local SiteName = GetAttr(INSTITUTION_NAME_TAG)
            if (SiteName) then
                local SiteAddress = GetAttr(INSTITUTION_ADDRESS_TAG)
                local FromNovantHealth  = nil
                if (SiteAddress) then 
                    FromNovantHealth = BestWordMatchInAttr(SiteAddress, "BOX 11767PO")
                end
                
                MOUNTAIN_VIEW_VAL = "Mountain View"
                local FromMountainView =  BestWordMatchInAttr(SiteName, MOUNTAIN_VIEW_VAL)
                
                local SafeToUseWindowCenter = false
                if ( FromMountainView ~=nil and FromNovantHealth == nil ) then
                    SafeToUseWindowCenter = true
                end
                
                -- add Window center as grouping hint only when diff. coef. is detected at Mountan View Regional, NM
                if ( SafeToUseWindowCenter and HasAttr(WINDOW_CENTER_TAG)) then
                    TraceC("Grouping hint: window center tag\n")
                    groupHint01:AddEntry(WINDOW_CENTER_TAG) 
                end
            end
            --$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
            
        end
        
        if (isMRCP) then
            -- Ensures that thin MRCPs are seperated from thick MRCPs
            if( HasAttr(SLICE_THICKNESS_TAG) ) then
                TraceC("Grouping hint: slice thickness tag\n")
                groupHint01:AddEntry(SLICE_THICKNESS_TAG)
            end
        end
        
        if (isSpecialMPR) then
            -- Ensures that Spin MPRs are seperated from Roll MPRs
            if( HasAttr(ACQ_PROTOCOL_TAG) ) then
                TraceC("Grouping hint: protocol name tag\n")
                groupHint01:AddEntry(ACQ_PROTOCOL_TAG)
            end
        end
        
        --$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
        -- French hospital - CHRU BRETONNEAU; grouping hint for ACQ trigger time
        -- only if series description is "AX DYN +"
        if (SiteName~=nil and BestWordMatchInAttr(SiteName, "CHRU BRETONNEAU")) then
            if (ValueForTag(SERIES_DESC_TAG) == "AX DYN +") then
                if( HasAttr(ACQ_TRIGGER_TIME_TAG) ) then
                    TraceC("Grouping hint: acq trigger time tag\n")
                    groupHint01:AddEntry(ACQ_TRIGGER_TIME_TAG)
                end
            end
        end
        
        -- French hospital - C.H TROUSSEAU; grouping hint for View
        if (SiteName~=nil and BestWordMatchInAttr(SiteName, "C.H TROUSSEAU")) then
            if (ValueForTag(IMAGE_TYPE_PROP) == "Original") then
                if( HasAttr(VIEW_PROP) ) then
                    TraceC("Grouping hint: view property\n")
                    groupHint01:AddEntry(VIEW_PROP)
                end
            end
        end
        -- Grouping Hint for image type property for the following sites - (1) CMI-St
        -- Elizabeths Campus (2) Hackley Hospital (3) Baptist
        if (SiteName~=nil and BestWordMatchInAttr(SiteName, "CMI-ST. ELIZABETHS CAMPUS", "HACKLEY HOSPITAL",
                                                             "Baptist Memorial", "North Country Imaging" )) then
            if( HasAttr(IMAGE_TYPE_PROP) and ValueForTag(IMAGE_TYPE_PROP) == "Original" ) then
                TraceC("Grouping hint: image type property\n")
                groupHint01:AddEntry(IMAGE_TYPE_PROP)
            end
        end
        
        -- Split TOSHIBA cine series by slice location for Glens Falls Hospital (North Country Imaging)
        if (SiteName~=nil and BestWordMatchInAttr(SiteName, "North Country Imaging")) then
            if (ManufacturerName~=nil and BestWordMatchInAttr(ManufacturerName, "TOSHIBA")) then
                if( HasAttr(PULSE_SEQ_PROP) and ValueForTag(PULSE_SEQ_PROP) == "Cine" ) then
                    if(HasAttr(SLICE_LOC_TAG)) then
                        TraceC("Grouping hint: slice location tag\n")
                        groupHint01:AddEntry(SLICE_LOC_TAG)
                    end
                end
            end
        end
        --$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
    end 
    
    AddImage2Sequence(seqNameStr, groupHint01, sortHintSet01)
	
    TraceC( "Group MR execution complete.\n")
    
end

