@BRDcomputetype_IN TINYINT -- USELESS PARAMETER
AS
BEGIN
SET XACT_ABORT ON
SET NOCOUNT ON

                        --0. DECLARATION AREA
						DECLARE @BRDcomputetype INTEGER; 
					    DECLARE @BRDID INTEGER, @BRDCurrentVersion INTEGER, @BRDVariableCount INTEGER = NULL, @BRDVariableDistinctCount INTEGER = NULL ;
					    DECLARE @date DATETIME = GETDATE() ;
					    DECLARE @ProjVersion INTEGER, @ProjGUID VARCHAR(255), @ProjectName VARCHAR(250) ;
                        DECLARE @NrProg INTEGER = 0, @MaxProgID INTEGER = 0, @Msg VARCHAR(100) = '' ;  
						
					    DECLARE @errorstate INTEGER = 0, @errornumber INTEGER = 0, @errormsg NVARCHAR(4000) = '' ;  
					    DECLARE @returnCode INTEGER = NULL;

						DECLARE @ResourceTypeID_Prog INTEGER = (SELECT TOP 1 ResourceID FROM ResourceTypes WHERE Name = 'PROGRAM') ;
						DECLARE @ResourceTypeID_Var  INTEGER = (SELECT TOP 1 ResourceID FROM ResourceTypes WHERE Name = 'VARIABLES') ;
						

                         SET @BRDcomputetype = COALESCE(@BRDcomputetype_IN, 0); /* 0 FULL , 1 PARTIAL*/ 
						 SET @BRDcomputetype = 0; -- we have to compute  VarIDConsolidate for all variables all the time ... so FULL is faster than PARTIAL +UPDATE on variable table



					    SET @BRDCurrentVersion = COALESCE( ( SELECT ProjectVersion 
													 FROM  BRD_Status (NOLOCK) 
													 WHERE  BRDID = (SELECT MAX(BRDID) FROM BRD_Status (NOLOCK) WHERE BRDProcessStatusTypeID = 2)) -- last BRD succssfull
													 , 0
													);	
					   
					   SELECT @ProjVersion = Version FROM VC_Version;	
                       
					   SELECT @ProjGUID = PropValue FROM Pj_ProjectProp WHERE ID_PropType = 64; -- ProjectGUID
					   SELECT @ProjectName = PropValue FROM Pj_ProjectProp WHERE ID_PropType = 65; -- ProjectName
					  
					   --SELECT @ProjVersion,  @ProjGUID, @ProjectName



BEGIN TRY

					    --0. TRY TO PUT LOCK ON SP
						  EXEC @returnCode = sp_getapplock @Resource = 'BRD_PrepareCache', @LockMode = 'Exclusive',  @LockOwner = 'Session', @LockTimeout = 50, @DbPrincipal  = 'public';

						  IF @returnCode NOT IN (0, 1)
						  BEGIN
							 RAISERROR ( 'Unable to acquire exclusive Lock on BRD_PrepareCache', 16, 1 );       
							 RETURN;
						  END;      
				    


						--0. DOUBLE CHECK IF WE CAN COMPUTE BRD 
						  IF EXISTS ( 
								    SELECT 1 
								    FROM BRD_Status (NOLOCK)
								    WHERE BRDProcessStatusTypeID = 1 /*0 prepare; 1 computation;  2 success; 3 error */
									   AND BRDID = (SELECT MAX(BRDID) FROM BRD_Status(NOLOCK))    
								    ) 
									   BEGIN 
												RAISERROR ('BRD Prepare Cache is already in progress.', 16, 1 );     
												RETURN;

									   END;




                              --0. LOACAL CONFIGURATION AREA
							 IF OBJECT_ID('tempdb..#pgmtype') IS NOT NULL DROP TABLE #pgmtype;
							 CREATE TABLE #pgmtype (ProgramTypeID INTEGER PRIMARY KEY );
							 INSERT INTO #pgmtype (ProgramTypeID) VALUES(1) ; /*COBOL*/



                             --1. BRD FULL
		                     -- GET PROGRAMS TO DEAL WITH
							 IF OBJECT_ID('tempdb..#pgmflt') IS NOT NULL DROP TABLE #pgmflt;
							 CREATE TABLE #pgmflt (ProgID INTEGER NOT NULL PRIMARY KEY);
							 

							INSERT INTO #pgmflt (ProgID)
							SELECT  pgm.ProgramID 
							FROM Programs pgm
							WHERE EXISTS (SELECT 1 FROM #pgmtype pgmtp WHERE pgm.ProgramTypeID = pgmtp.ProgramTypeID)
									AND pgm.OccurID > 0
							GROUP BY pgm.ProgramID ;
								   
                                    
							 --SELECT * FROM #pgmflt ;




						-- 2. GET SOME INFO FOR LOG PURPOSE
								SELECT  @NrProg = COUNT(*), @MaxProgID = MAX(ProgID) FROM #pgmflt;
								SET @Msg = '##ProgNr=' + CAST(COALESCE(@NrProg, 0) AS VARCHAR(20)) + '; MaxProgID='+ CAST(COALESCE(@MaxProgID, 0) AS VARCHAR(20)) + '##';



								 -- PUT A FLAG SINCE WE HAVE STARTED COMPUTATION 
								INSERT INTO BRD_Status(ProjectName, ProjectGUID, ProjectVersion, BRDProcessStatusTypeID, BRDProcessType, BRDVariableCount, BRDVariableDistinctCount, eTimeStamp, Notes)
								SELECT  @ProjectName, 
									   @ProjGUID, 
									   @ProjVersion,
									   0, -- prepare
									   CASE @BRDcomputetype WHEN 0 THEN 'FULL' ELSE 'PARTIAL' END, 
									   COALESCE(@BRDVariableCount, 0),
									   COALESCE(@BRDVariableDistinctCount, 0),
									   @date,  
									   @Msg + '##0 - '+ CONVERT(VARCHAR(23), @date, 121) + '##' ;
								
									SET @BRDID = IDENT_CURRENT( 'BRD_Status' );  







						-- 3. GET AUXILIARY DATA

								-- 3.2  data from configuration area ( category <-> statementtype)
									--  a statement type could be in many categories so we have to do a pivote

									IF OBJECT_ID('tempdb..#categ') IS NOT NULL DROP TABLE #categ;
									SELECT *
									INTO #categ
									FROM
									(
										SELECT bwcd.StatementTypeID AS StatementTypeID, bwc.CategoryID , 1 as AggCol
										FROM BRD_Category bwc
											LEFT OUTER JOIN BRD_CategoryDetails bwcd ON bwc.CategoryID = bwcd.CategoryID AND bwcd.IsActive = 1 
										WHERE bwc.IsActive = 1
											AND bwcd.StatementTypeID IS NOT NULL
									) src
										PIVOT (
											MAX(AggCol)
											FOR CategoryID IN ([1],[2],[3],[4],[5],[6],[7],[8])
											) AS PivotTable;

                       

					        IF OBJECT_ID('tempdb..#copy') IS NOT NULL DROP TABLE #copy ;
						    CREATE TABLE #copy (ResourceID INTEGER NOT NULL,
	                                            ResourceTypeID INTEGER NOT NULL,
												ResourceName VARCHAR(250) NOT NULL, 
												ResourceHash VARCHAR(32) NOT NULL,
												ResourcePathID INTEGER NOT NULL,
												PRIMARY KEY (ResourceID, ResourceTypeID)) ;
							
							INSERT INTO #copy (ResourceID, ResourceTypeID, ResourceName, ResourceHash,  ResourcePathID)
							SELECT DISTINCT r.ResourceID, r.ResourceType, r.Name, h.SemanticUID, occ.PathID
							FROM Resources r
								   INNER JOIN Occurrences occ ON r.OccurID = occ.OccurID
								   INNER JOIN SemanticUIDContainer h On r.ResourceID = h.ResourceID AND r.ResourceType = h.ResourceType
							WHERE r.ResourceType = 13 ; --IN (13 /*COPY*/, 67 /*PL1_COPY*/, 99 /*ASSEMBLER_COPY*/)

			               CREATE NONCLUSTERED INDEX ncidx_copy_Res ON #copy (ResourcePathID, ResourceID, ResourceTypeID, ResourceName) ;



              -- 4. GET MAIN DATA 
  							
		    		 -- 4.0 for further filtering
				            IF OBJECT_ID('tempdb..#varout') IS NOT NULL DROP TABLE #varout
						    CREATE TABLE #varout (VarID INTEGER );

						    IF OBJECT_ID('tempdb..#varflt') IS NOT NULL DROP TABLE #varflt
						    CREATE TABLE #varflt (VarID INTEGER NOT NULL);


							IF OBJECT_ID('tempdb..#varflttmp') IS NOT NULL DROP TABLE #varflttmp
						    CREATE TABLE #varflttmp (VarID INTEGER NOT NULL,  VarILevel INTEGER ,Test TINYINT NOT NULL);
				  
	  

				   --4.1' technical variables .... so we will have to remove
				        
							 INSERT INTO #varout (VarID)
							 SELECT VarID
							 FROM Variables 
							 WHERE isFiller = -1
							       OR
							       VarName LIKE 'DFHCOMMAREA'
								  OR
								  VarName LIKE 'SQLCODE'
								  --OR
								  -- VarName LIKE 'RETURN-CODE'
								  -- OR
								  -- VarName LIKE 'SQLSTATE%'
								  --  OR
								  --  VarName LIKE 'SQLWARN%'
								;





				  
				       --4.1  VARIABLE USAGE
						   IF OBJECT_ID('tempdb..#stmt') IS NOT NULL DROP TABLE #stmt;
						   CREATE TABLE #stmt(  VarID INTEGER NOT NULL,
						                        VarILevel INTEGER,
												StatementTypeID INTEGER,
												ProgID INTEGER,
												CopyID INTEGER,
												CopyTypeID INTEGER ,
												OccurID INTEGER,
												PathID INTEGER,
												StartRow INTEGER,
												EndRow INTEGER,
												StartCol INTEGER,
												EndCol INTEGER,
												IsCalculation TINYINT,
												IsCondition TINYINT,
												IsDBIO TINYINT,
												IsFileIO TINYINT,
												IsMQ TINYINT,
												IsScreen TINYINT,
												IsAssignment TINYINT,
												Is88VarLvlCondition TINYINT) ;
                                 
						   INSERT INTO #stmt
						    (VarID, VarILevel, StatementTypeID, ProgID, CopyID, CopyTypeID, OccurID,
						     PathID,  StartRow, EndRow,  StartCol, EndCol, 
							 IsCalculation, IsCondition, IsDBIO, IsFileIO, IsMQ, IsScreen, IsAssignment ,Is88VarLvlCondition)
						   OUTPUT inserted.VarID, inserted.VarILevel, inserted.IsFileIO + inserted.IsMQ + inserted.IsScreen INTO #varflttmp(VarID, VarILevel, Test)
						   SELECT 
						     VarID, VarILevel, StatementTypeID, ProgID, 
							 CopyID, CopyTypeID, OccurID,
						     PathID,  StartRow, EndRow,  StartCol, EndCol, 
							MAX(IsCalculation) AS IsCalculation, 
							MAX(IsCondition) AS IsCondition,  
							MAX(IsDBIO) AS IsDBIO, 
							MAX(IsFileIO) AS IsFileIO,
							MAX(IsMQ) AS IsMQ, 
							MAX(IsScreen) AS IsScreen, 
							MAX(IsAssignment) AS IsAssignment,
							MAX(Is88VarLvlCondition) AS Is88VarLvlCondition
						FROM (
							      SELECT  sr.ResourceID AS VarID
								         ,v.iLevel AS VarILevel
										 ,sr.StatementType AS StatementTypeID
										 ,os.ProgID 
										 ,cpy.ResourceID AS CopyID
										 ,cpy.ResourceTypeID AS CopyTypeID
										 ,os.OccurID
										 ,os.PathID
										 ,os.StartRow
										 ,os.EndRow
										 ,os.StartCol
										 ,os.EndCol
										 -- categories
										 ,CASE WHEN ctg.[1] IS NOT NULL AND sr.bRead IN (1, 2)                                 THEN 1 ELSE 0 END IsCalculation
										 ,CASE WHEN sr.bRead > 3                                                               THEN 1 ELSE 0 END IsCondition
										 ,CASE WHEN ctg.[3] IS NOT NULL AND sr.bRead IN (1, 2) AND db.OccurID IS NOT NULL      THEN 1 ELSE 0 END IsDBIO
										 ,CASE WHEN ctg.[4] IS NOT NULL AND sr.bRead IN (1, 2)                                 THEN 1 ELSE 0 END IsFileIO
										 ,CASE WHEN ctg.[5] IS NOT NULL AND sr.bRead IN (1, 2)                                 THEN 1 ELSE 0 END IsMQ
										 -- screen
										 ,CASE WHEN ctg.[6] IS NOT NULL AND sr.bRead IN (1, 2) AND sr.StatementType IN (694, 698) /* IMS: GU, ISRT*/ AND scrn.OccurID IS NOT NULL THEN 1
											  WHEN ctg.[6] IS NOT NULL AND sr.bRead IN (1, 2) AND sr.StatementType NOT IN (694, 698) THEN 1 ELSE 0 END IsScreen	
										 -- screen
										 ,CASE WHEN ctg.[7] IS NOT NULL AND sr.bRead IN (1, 2)                                  THEN 1 ELSE 0 END IsAssignment
										 ,CASE WHEN sr.bRead > 3 AND v.iLevel = 88                                              THEN 1 ELSE 0 END Is88VarLvlCondition
									FROM StatementReference sr
									    INNER JOIN OccurrencesStmt os ON sr.OccurID = os.OccurID
									    INNER JOIN Variables v ON sr.ResourceID = v.VarID --AND v.OccurID > 0
									    LEFT OUTER JOIN #varout vo ON v.VarID = vo.VarID -- remove technical variables
									    LEFT OUTER JOIN #categ ctg ON ctg.StatementTypeID = sr.StatementType
									    LEFT OUTER JOIN 
													(
													   SELECT sr2.OccurID
													   FROM StatementReference sr2
														   INNER JOIN OccurrencesStmt os2 ON os2.OccurID = sr2.OccurID
													   WHERE sr2.ResourceType IN (1, 56, 77, 78, 182, 209)
														    AND sr2.bread in (1,2) -- involved in READ, WRITE 
													   GROUP BY sr2.OccurID
													) db ON db.OccurID = sr.OccurID
                                        LEFT OUTER JOIN 
													(
													   SELECT sr2.OccurID
													   FROM StatementReference sr2
														   INNER JOIN OccurrencesStmt os2 ON os2.OccurID = sr2.OccurID
													   WHERE sr2.ResourceType IN (212) -- IMS Message Descriptor
														    AND sr2.bread in (1,2) -- involved in READ, WRITE 
													   GROUP BY sr2.OccurID

													) scrn ON scrn.OccurID = sr.OccurID
                                                 LEFT OUTER JOIN #copy cpy ON cpy.ResourcePathID = os.PathID  -- if statement is from copy
									 WHERE sr.ResourceType = @ResourceTypeID_Var /*VARIALES*/    
										  AND sr.ResourceID > 0
										  AND vo.VarID IS NULL
										  AND EXISTS (SELECT 1 FROM #pgmflt f WHERE os.ProgID = f.ProgID) 
							      ) src
                               GROUP BY  VarID, VarILevel ,StatementTypeID, ProgID, CopyID, CopyTypeID, OccurID,
						                 PathID,  StartRow, EndRow,  StartCol, EndCol  ;

				 



					 --4.2  determine variable hierarchy (Parent -> Child) only for specific variable not for all (IsFileIO + IsMQ + IsScreen)
					   -- level 0 
					   IF OBJECT_ID('tempdb..#varhierarchy') IS NOT NULL DROP TABLE #varhierarchy;
					   SELECT VarID, VarID AS ChildVarID
							 --,  '##' + CAST(VarID AS VARCHAR(MAX)) AS VarChain
							 , 0 AS Lvl
					   INTO #varhierarchy
					   FROM (
					         SELECT VarID
						    FROM #varflttmp
						    WHERE Test > 0  /* only variable that are in screen, mq, file*/
						          AND VarID > 0
								  AND VarILevel != 88
						    GROUP BY VarID
					         )src;




					    DECLARE @rc INT=0, @i INT = 1, @j INT = 2001;-- level 1-> 2000 (2000 levels of imbrication)
					    WHILE (@i < @j)
							 BEGIN


								    --down direction
								    INSERT INTO #varhierarchy(VarID, ChildVarID, 
								                     -- VarChain, 
												  Lvl )
								    SELECT  f1.VarID, x.VarID, 
										-- f1.VarChain + '#' + CAST(x.VarID AS VARCHAR(MAX)),
										 @i  AS Lvl 
								    FROM Variables x
										INNER JOIN #varhierarchy f1 ON  f1.Lvl = (@i - 1) AND f1.ChildVarID = x.Father
										LEFT OUTER JOIN #varout vo ON x.VarID = vo.VarID  -- remove technical variables
										--LEFT OUTER JOIN #varhierarchy f2 ON f1.VarID = f2.VarID AND x.VarID = f2.ChildVarID					  
								    WHERE  x.iLevel != 88 AND 
										  vo.VarID IS NULL
								          --f2.VarID IS NULL
										;
					   
								    SET @rc = @@ROWCOUNT;



								  --SELECT @i, GETDATE(), @rc

								    IF (@rc = 0 )
									  SET @i = @j;
								    ELSE 
									  SET @i = @i + 1;
					    END;



                        --4.3 variable hierarchy step 2 (Child -> Parent) only for Level 88 variable hierarchy (up direction)
						-- only father must me be in hierarchy but is inserted as child for compatibility with already implemented logic 
						-- Lvl = 10088 since we rely further on it
						INSERT INTO #varhierarchy(VarID, ChildVarID, Lvl)
						SELECT v.VarId, v.Father ,10088 AS Lvl
						FROM Variables v
							 INNER JOIN (   SELECT VarID
											FROM #stmt 
											WHERE Is88VarLvlCondition = 1 
											GROUP BY VarID 
											) f ON v.VarId = f.VarID 
						WHERE v.VarId != v.Father AND v.Father > 0;



                       INSERT INTO #varflt(VarID)
					   SELECT VarID
					   FROM (  
					         SELECT vh.ChildVarID AS VarID  FROM #varhierarchy vh  WHERE vh.Lvl > 0

							 UNION

							 SELECT VarID FROM #varflttmp

							 UNION

							 SELECT v.VarID
					           FROM Variables v 
							       LEFT OUTER JOIN #varout vo ON v.VarID = vo.VarID -- remove technical variables
					           WHERE  vo.VarID IS NULL
							       AND EXISTS (SELECT 1 FROM #pgmflt f WHERE v.ProgIDReference = f.ProgID)
						    )src 
					  WHERE src.VarID > 0 ;



                         CREATE NONCLUSTERED INDEX ncidx_varflt_VarID ON #varflt (VarID) ;
 


			   -- 3.2 variable header
						  IF OBJECT_ID('tempdb..#var') IS NOT NULL DROP TABLE #var; 
						  SELECT  
							 v1.VarID 
							,v1.VarName
							,h.SemanticUID AS VariableHash 
							,DENSE_RANK() OVER (ORDER BY v1.PathID, v1.StartRow, v1.EndRow, v1.StartCol, v1.EndCol, v1.VarName) AS VarIDConsolidate
							,v1.CopyID
							,v1.CopyTypeID
							,v1.CopyName
							,v1.RootVarID
							,rec.VarName AS RecordName
							,v1.ProgID
							,pgm.ProgramName AS ProgName
							,v1.PathID  ,v1.StartRow  ,v1.EndRow  ,v1.StartCol  ,v1.EndCol
						INTO #var
						FROM	(
								SELECT  
								    v.VarID 
								   ,v.VarName
								   ,v.Ancestor AS RootVarID
								   ,v.ProgIDReference  AS ProgID
								   ,occ.PathID 
								   ,occ.StartRow 
								   ,occ.EndRow 
								   ,occ.StartCol 
								   ,occ.EndCol
								   ,cpy.ResourceID AS CopyID
							       ,cpy.ResourceTypeID AS CopyTypeID
							       ,cpy.ResourceName AS CopyName
								FROM Variables v
								      INNER JOIN Occurrences occ ON v.OccurID = occ.OccurID
									  LEFT OUTER JOIN #copy cpy ON occ.PathID = cpy.ResourcePathID
								WHERE v.VarID IN (SELECT VarID FROM #varflt)
                                      AND v.IsCopy = CASE WHEN cpy.ResourceID IS NOT NULL THEN -1  
									                      ELSE 0 END
									  -- if a variable is defined in copy then must exist a copyID					  
							  )v1
						          INNER JOIN SemanticUIDContainer h ON  v1.VarID = h.ResourceID AND h.ResourceType = @ResourceTypeID_Var
							      LEFT OUTER JOIN Variables rec ON v1.RootVarID = rec.VarID
							      LEFT OUTER JOIN Programs pgm ON v1.ProgID = pgm.ProgramID  ;






	       BEGIN TRANSACTION

				   SET @date = GETDATE();

			        UPDATE BRD_Status
			        SET  	BRDProcessStatusTypeID = 1, -- start
					        eTimeStamp = @date,
							Notes = ISNULL(Notes, '') + '##1 - '+ CONVERT(VARCHAR(23), @date, 121) + '##'    -- start							   
                       WHERE  BRDID = @BRDID;


            -- A. BRD_DirectStatements
			
					IF EXISTS (
					   SELECT 1
					   FROM SYS.INDEXES si
						   JOIN SYS.OBJECTS so ON si.object_id=so.object_id
					   WHERE  so.name ='BRD_DirectStatements'
							AND si.name='NCIDX_BRD_DS_MultyCol'
							 )
					 DROP INDEX NCIDX_BRD_DS_MultyCol ON BRD_DirectStatements;


					 TRUNCATE TABLE BRD_DirectStatements ;
						 

					 INSERT INTO BRD_DirectStatements
							(VarID, StatementTypeID, ProgID, CopyID, CopyTypeID, OccurID, 
							PathID, StartRow, EndRow, StartCol, EndCol, 
							IsCalculation, IsCondition, IsDBIO, IsFileIO, IsMQ, IsScreen, IsAssignment, Is88VarLvlCondition,
							BRDID)
					 SELECT s.VarID, s.StatementTypeID, s.ProgID, s.CopyID, s.CopyTypeID, s.OccurID, 
							s.PathID, s.StartRow, s.EndRow, s.StartCol, s.EndCol, 
							s.IsCalculation, s.IsCondition, s.IsDBIO, s.IsFileIO, s.IsMQ, s.IsScreen, s.IsAssignment ,s.Is88VarLvlCondition
							,@BRDID AS BRDID
					 FROM #stmt s
					 WHERE s.VarID IN (SELECT v.VarID FROM #var v) ;
			 

                    CREATE NONCLUSTERED INDEX NCIDX_BRD_DS_MultyCol ON BRD_DirectStatements (OccurID ASC) INCLUDE (VarID, ProgID, IsCalculation, IsCondition, IsAssignment ,Is88VarLvlCondition);

	


             -- B. BRD_Variables

					 IF EXISTS (
					SELECT 1
					FROM SYS.INDEXES si
						JOIN SYS.OBJECTS so ON si.object_id=so.object_id
					WHERE  so.name ='BRD_Variables'
						  AND si.name='NCIDX_BRD_V_MultyCol'
							 )
					   DROP INDEX NCIDX_BRD_V_MultyCol ON BRD_Variables ;


					IF EXISTS (
					SELECT 1
					FROM SYS.INDEXES si
						JOIN SYS.OBJECTS so ON si.object_id=so.object_id
					WHERE  so.name ='BRD_Variables'
							AND si.name='NCIDX_BRD_V_VarName_VarID'
								)
						DROP INDEX NCIDX_BRD_V_VarName_VarID ON BRD_Variables;


					IF EXISTS (
					SELECT 1
					FROM SYS.INDEXES si
						JOIN SYS.OBJECTS so ON si.object_id=so.object_id
					WHERE  so.name ='BRD_Variables'
						  AND si.name='NCIDX_BRD_V_VarName_VarHash_CpyPgm'
							 )
					   DROP INDEX NCIDX_BRD_V_VarName_VarHash_CpyPgm ON BRD_Variables;


				     TRUNCATE TABLE BRD_Variables ;
					  

					 INSERT INTO BRD_Variables
						   (VarID, VarName, VariableHash, VarIDConsolidate, 
							CopyID, CopyTypeID, CopyName, RootVarID, RecordName, ProgID, ProgName, 
							PathID, StartRow, EndRow, StartCol, EndCol, DirectIndirectDistProgNr
						   ,BRDID)
					 SELECT  v.VarID ,v.VarName ,v.VariableHash ,v.VarIDConsolidate
							 ,v.CopyID, v.CopyTypeID, v.CopyName, v.RootVarID, v.RecordName, v.ProgID, v.ProgName 
							 ,v.PathID, v.StartRow, v.EndRow, v.StartCol, v.EndCol 
							 ,ISNULL(pnr.DirectIndirectDistProgNr, 0)  AS DirectIndirectDistProgNr
							 ,@BRDID AS BRDID
					 FROM #var v
							LEFT OUTER JOIN
											   ( -- number of distinct programs 
											        SELECT VarId, COUNT(DISTINCT ProgID) AS DirectIndirectDistProgNr
													FROM (				 
														SELECT VarID, ProgID AS ProgID
														FROM  #stmt
											    
														UNION

														SELECT vh.ChildVarID AS VarID, s.ProgID 
														FROM #varhierarchy  vh
															 INNER JOIN #stmt s ON s.VarID = vh.VarID 
														WHERE vh.Lvl > 0              
																 AND s.IsFileIO + s.IsMQ + s.IsScreen + s.Is88VarLvlCondition > 0	 
													    )src
												    GROUP BY VarID
												) pnr ON pnr.VarID = v.VarID;



						CREATE NONCLUSTERED INDEX NCIDX_BRD_V_MultyCol               ON BRD_Variables (VarID ASC)   INCLUDE(VarName, CopyName, ProgName, RecordName, DirectIndirectDistProgNr);
						CREATE NONCLUSTERED INDEX NCIDX_BRD_V_VarName_VarID          ON BRD_Variables (VarName ASC) INCLUDE (VarID, DirectIndirectDistProgNr);
						CREATE NONCLUSTERED INDEX NCIDX_BRD_V_VarName_VarHash_CpyPgm ON BRD_Variables (VarName ASC) INCLUDE (CopyID, CopyTypeID, ProgID, VariableHash) ; 
                        

						/* - time consuming 
						UPDATE v
						SET v.VarIDConsolidate = x.VarIDConsolidate
						FROM BRD_Variables v
							   INNER JOIN (
										   SELECT VarID , DENSE_RANK() OVER (ORDER BY PathID, StartRow, EndRow, StartCol, EndCol, VarName) AS VarIDConsolidate
										   FROM BRD_Variables 
										   ) x ON v.VarID = x.VarID ; 
						 */


			            SELECT @BRDVariableCount = COUNT(VarID), @BRDVariableDistinctCount = COUNT(DISTINCT VarName) FROM BRD_Variables; 
			
	                  


                  -- C. BRD_VariableHierarchy

					     TRUNCATE TABLE BRD_VariableHierarchy;

  
						 INSERT INTO BRD_VariableHierarchy
							   (VarID, ChildVarID, ChildLevel, BRDID)
						 SELECT VarID, ChildVarID AS ChildVarID, lvl AS ChildLevel, @BRDID AS BRDID
						 FROM #varhierarchy
						 WHERE Lvl > 0 
							   AND VarID IN (SELECT v.VarID FROM #var v) ;

	                  


                   -- D. BRD_VariableUsageStatistics

                          TRUNCATE TABLE BRD_VariableUsageStatistics;


						  INSERT INTO BRD_VariableUsageStatistics
									( VarID
									,DNrStmtCalc
									,DNrStmtCond ,INrStmtCond 
									,DNrStmtDB 
									,DNrStmtFile, INrStmtFile 
									,DNrStmtMQ, INrStmtMQ 
									,DNrStmtScreen, INrStmtScreen
									,IsFromCopy
									,BRDID)
						  SELECT     v.VarID
									,ISNULL(dstat.NrStmtCalc, 0) AS DNrStmtCalc
									,ISNULL(dstat.NrStmtCond, 0) AS DNrStmtCond ,ISNULL(istat.NrStmtCond, 0) AS INrStmtCond 
									,ISNULL(dstat.NrStmtDB, 0)  AS DNrStmtDB
									,ISNULL(dstat.NrStmtFile, 0) AS DNrStmtFile, ISNULL(istat.NrStmtFile, 0) AS INrStmtFile 
									,ISNULL(dstat.NrStmtMQ, 0) AS DNrStmtMQ, ISNULL(istat.NrStmtMQ, 0) AS INrStmtMQ 
									,ISNULL(dstat.NrStmtScreen, 0) AS DNrStmtScreen, ISNULL(istat.NrStmtScreen, 0) AS INrStmtScreen 
									,v.IsFromCopy AS IsFromCopy 
									,@BRDID AS  BRDID 
							FROM (
									SELECT  v1.VarID, c.IsFromCopy
									FROM  #var v1
										CROSS JOIN (
													SELECT 1 -- from copy
													UNION
													SELECT 0 -- from program
													) c (IsFromCopy) 
									)v 
									LEFT OUTER JOIN (  -- direct statistics
													SELECT VarID, 
													      CASE WHEN CopyID IS NULL THEN 0 ELSE 1 END AS IsFromCopy, 
													      SUM(IsCalculation) AS NrStmtCalc , SUM(IsCondition) AS NrStmtCond, SUM(IsDBIO) AS NrStmtDB, 
														  SUM(IsFileIO) AS NrStmtFile , SUM(IsMQ) AS NrStmtMQ, SUM(IsScreen) AS NrStmtScreen
													FROM #stmt
													GROUP BY VarID, CASE WHEN CopyID IS NULL THEN 0 ELSE 1 END
												) dstat ON v.VarID = dstat.VarID  AND  v.IsFromCopy = dstat.IsFromCopy
									LEFT OUTER JOIN ( -- indirect statistics
												-- propagate statements to child level
												SELECT vh.ChildVarID, src11.IsFromCopy 
													--,vh.VarID, 
													    ,SUM(src11.NrStmtCond) AS NrStmtCond
														,SUM(src11.NrStmtFile) AS NrStmtFile
														,SUM(src11.NrStmtMQ) AS NrStmtMQ
														,SUM(src11.NrStmtScreen) AS NrStmtScreen
												FROM #varhierarchy  vh
													INNER JOIN 
																(  -- count statistics
																SELECT VarID,  
																       CASE WHEN CopyID IS NULL THEN 0 ELSE 1 END AS IsFromCopy, 
																	   SUM(Is88VarLvlCondition) AS NrStmtCond, 
																       SUM(IsFileIO) AS NrStmtFile, SUM(IsMQ) AS NrStmtMQ, SUM(IsScreen) AS NrStmtScreen
																FROM #stmt
																GROUP BY VarID, CASE WHEN CopyID IS NULL THEN 0 ELSE 1 END
																HAVING SUM(Is88VarLvlCondition) + SUM(IsFileIO) + SUM(IsMQ) + SUM(IsScreen) > 0
																)src11 ON src11.VarID = vh.VarID 
												WHERE vh.Lvl > 0
												GROUP BY vh.ChildVarID, src11.IsFromCopy
												) istat ON v.VarID = istat.ChildVarID AND v.IsFromCopy = istat.IsFromCopy                   
								WHERE     ISNULL(dstat.NrStmtCalc,   0) + ISNULL(dstat.NrStmtCond,   0)  + ISNULL(istat.NrStmtCond, 0)  + ISNULL(dstat.NrStmtDB, 0) 
										+ ISNULL(dstat.NrStmtFile,   0) + ISNULL(istat.NrStmtFile,   0)  + ISNULL(dstat.NrStmtMQ  , 0)  + ISNULL(istat.NrStmtMQ, 0) 
										+ ISNULL(dstat.NrStmtScreen, 0) + ISNULL(istat.NrStmtScreen, 0)  > 0 ;





                -- E. BRD_ResourceDetail
  
  							   IF EXISTS (
											SELECT 1
											FROM SYS.INDEXES si
												INNER JOIN SYS.OBJECTS so ON si.object_id=so.object_id
											WHERE  so.name ='BRD_ResourceDetails'
												  AND si.name='NCIDX_BRD_RD_ResourceID_TypeID_Hash'
										  )
							   DROP INDEX NCIDX_BRD_RD_ResourceID_TypeID_Hash ON BRD_ResourceDetails;


			                  TRUNCATE TABLE BRD_ResourceDetails ;
					

							  INSERT INTO BRD_ResourceDetails(ResourceID, ResourceTypeID, ResourceName, ResourceHash, ResourcePathID, BRDID)
							  SELECT ResourceID, ResourceTypeID, ResourceName, ResourceHash, ResourcePathID 
									,@BRDID AS BRDID
							  FROM (
									SELECT ResourceID, ResourceTypeID, ResourceName, ResourceHash,  ResourcePathID
									FROM #copy

									UNION 

									SELECT r.ProgramID AS ResourceID, @ResourceTypeID_Prog AS ResourceTypeID, r.ProgramName AS ResourceName, h.SemanticUID AS ResourceHash,  occ.PathID AS ResourcePathID
									FROM Programs r
										INNER JOIN Occurrences occ ON r.OccurID = occ.OccurID
										INNER JOIN SemanticUIDContainer h On r.ProgramID = h.ResourceID AND @ResourceTypeID_Prog = h.ResourceType
									WHERE EXISTS (SELECT 1 FROM #pgmflt f WHERE r.ProgramID = f.ProgID) 
									) res ;


                             CREATE NONCLUSTERED INDEX NCIDX_BRD_RD_ResourceID_TypeID_Hash  ON BRD_ResourceDetails (ResourceID ASC, ResourceTypeID ASC) INCLUDE (ResourceHash, ResourceName);   

		   
				     



				-- F. BRD_CopyToResources

								TRUNCATE TABLE BRD_CopyToResources ;


								INSERT INTO BRD_CopyToResources(CopyID, CopyTypeID, ResourceID, ResourceTypeID, ResourcePathID, StartRow, EndRow, StartCol, EndCol, BRDID)
								SELECT  DISTINCT
										 sr.ResourceID AS CopyID
										,sr.ResourceType AS CopyTypeID
										,CASE WHEN cpy.ResourcePathID IS NOT NULL THEN cpy.ResourceID 
											  ELSE os.ProgID
										 END AS ResourceID
										,CASE WHEN cpy.ResourcePathID IS NOT NULL THEN cpy.ResourceTypeID 
											  ELSE @ResourceTypeID_Prog
										 END AS ResourcePathID
										,os.PathID AS ResourcePathID
										,os.StartRow
										,os.EndRow
										,os.StartCol
										,os.EndCol
										,@BRDID AS BRDID	
								FROM  ( 
											SELECT rx.ResourceID, rx.ResourceType, rx.OccurID
											FROM StatementReference rx
											WHERE rx.StatementType = 44
												  AND EXISTS (SELECT 1 FROM  #copy s2 WHERE rx.ResourceID = s2.ResourceID AND rx.ResourceType = s2.ResourceTypeID)
										)sr
										INNER JOIN OccurrencesStmt os ON sr.OccurID = os.OccurID AND os.StatementType = 44 
										LEFT OUTER JOIN #copy cpy ON os.PathID = cpy.ResourcePathID ; 

										

                -- G. BRD_Paths

     							TRUNCATE TABLE BRD_Paths ;


								INSERT INTO BRD_Paths(PathID, PathStr, BRDID)
								SELECT   pth.PathID 
								        ,pth.PathStr
										,@BRDID AS BRDID	
								FROM Paths pth
								WHERE EXISTS ( SELECT 1 
								               FROM (  
									                   SELECT PathID FROM #stmt 
													   UNION ALL
													   SELECT PathID FROM #var 
													   UNION ALL
													   SELECT ResourcePathID AS PathID FROM BRD_CopyToResources
                                                       UNION ALL
													   SELECT ResourcePathID AS PathID FROM BRD_ResourceDetails 
								                    ) pf WHERE pf.PathID = pth.PathID
                                              );
											 



								 SET @date = GETDATE();
								 UPDATE BRD_Status
								  SET  	BRDProcessStatusTypeID = 2, -- success 
										BRDVariableCount = COALESCE(@BRDVariableCount, 0),
										BRDVariableDistinctCount = COALESCE(@BRDVariableDistinctCount, 0),
									    eTimeStamp = @date,
										Notes = ISNULL(Notes, '') + '##2 - '+ CONVERT(VARCHAR(23), @date, 121) + '##'    -- success							   
									 WHERE  BRDID = @BRDID;
						 
						 
								IF @@TRANCOUNT > 0 COMMIT TRANSACTION;
	 

								--release the lock on stored proc
								EXEC @returnCode = sp_releaseapplock
												@Resource = 'BRD_PrepareCache',                       
												@LockOwner = 'Session',
												@DbPrincipal  = 'public';


    END TRY
    BEGIN CATCH

                   SELECT   @errornumber = ERROR_NUMBER() 
			               ,@errorstate  = ERROR_STATE() 
					       ,@errormsg    = ERROR_MESSAGE();


                           IF @@TRANCOUNT > 0 ROLLBACK TRANSACTION;

                           SET @date = GETDATE();

							UPDATE  BRD_Status
							SET  	BRDProcessStatusTypeID = 3, -- error 
									BRDVariableCount = 0,
									BRDVariableDistinctCount = 0,
									eTimeStamp = @date,
									Notes = ISNULL(Notes, '') + '##3 - '+ CONVERT(VARCHAR(23), @date, 121) 
															  + ' SQLERRNUMBER=' + COALESCE(CAST(@errornumber AS VARCHAR(20)),  '') 
															  + ' SQLERRSTATE='  + COALESCE(CAST(@errorstate  AS VARCHAR(20)),  '') 
														 + ' SQLERRMSG='    + COALESCE(CAST(@errormsg   AS VARCHAR(4000)), '')        
														  + '##'    -- error								   
							WHERE  BRDID = @BRDID;
						

							IF @returnCode IN (0, 1)
								  BEGIN
							  				EXEC @returnCode = sp_releaseapplock
											@Resource = 'BRD_PrepareCache',                       
											@LockOwner = 'Session',
											@DbPrincipal  = 'public';

								  END;    					
										
							 RAISERROR (@errormsg, 16, 1 ); 
							 RETURN;
															   
	  
    END CATCH


 -- END AREA
    --CLEAN-UP 
    IF OBJECT_ID('tempdb..#pgmtype')       IS NOT NULL DROP TABLE #pgmtype;
    IF OBJECT_ID('tempdb..#pgmflt')        IS NOT NULL DROP TABLE #pgmflt;
    IF OBJECT_ID('tempdb..#varout')        IS NOT NULL DROP TABLE #varout;
    IF OBJECT_ID('tempdb..#varflt')        IS NOT NULL DROP TABLE #varflt;
    IF OBJECT_ID('tempdb..#varflttmp')     IS NOT NULL DROP TABLE #varflttmp
    IF OBJECT_ID('tempdb..#categ')         IS NOT NULL DROP TABLE #categ;
    IF OBJECT_ID('tempdb..#copy')          IS NOT NULL DROP TABLE #copy;
    IF OBJECT_ID('tempdb..#stmt')          IS NOT NULL DROP TABLE #stmt;
    IF OBJECT_ID('tempdb..#varhierarchy')  IS NOT NULL DROP TABLE #varhierarchy;
    IF OBJECT_ID('tempdb..#var')           IS NOT NULL DROP TABLE #var;

   END;
