AS 
BEGIN
SET NOCOUNT ON

-- program name from ProgramAlias (AliasType=0)
IF OBJECT_ID('tempdb..#program_alias') IS NOT NULL DROP TABLE #program_alias
SELECT ProgramID, ProgramName, ProgramTypeID, OccurID, AncestorName AS Ancestor 
INTO #program_alias
FROM fGetProgram_Ancestor_Aliases (NULL)

-- program hierarchy for ProgramTypeID (8,15,16) -> ASSEMBLER
IF OBJECT_ID('tempdb..#prog_hierarchy') IS NOT NULL DROP TABLE #prog_hierarchy
;WITH prog_hierarchy
AS
(
	SELECT	p.ProgramID AS RootProgramID, p.ProgramName AS RootProgramName, p.ProgramTypeID AS RootProgramTypeID, p.OccurID AS RootProgramOccurID,
		p.ProgramID, p.ProgramName, p.ProgramTypeID, p.OccurID AS ProgramOccurID, 0 AS Lvl
	FROM #program_alias p
	WHERE p.ProgramTypeID IN (8)

	UNION ALL

	SELECT	parent.RootProgramID, parent.RootProgramName, parent.RootProgramTypeID, parent.RootProgramOccurID,
		p.ProgramID, p.ProgramName, p.ProgramTypeID, p.OccurID, parent.Lvl + 1 AS Lvl
	FROM #program_alias p
		INNER JOIN prog_hierarchy parent ON parent.ProgramName = p.Ancestor  AND parent.ProgramID != p.ProgramID
	WHERE NULLIF(p.Ancestor,'') IS NOT NULL
		AND p.ProgramTypeID IN (15, 16)
		AND (p.ProgramTypeID IN (15, 16) AND parent.ProgramTypeID IN (8))
)

SELECT	RootProgramID, RootProgramName, RootProgramTypeID, RootProgramOccurID,
	ProgramID, ProgramName, ProgramTypeID, ProgramOccurID,
	Lvl,
	ROW_NUMBER()OVER(PARTITION BY ProgramID ORDER BY Lvl DESC) AS RN
INTO #prog_hierarchy
FROM prog_hierarchy
OPTION (MAXRECURSION 0)

SELECT	prg.ProgramID, prg.ProgramName, prg.ProgramTypeID, ISNULL(pth.PathStr, '') AS ProgramPathStr,
	prg.Halstead_dn1, prg.Halstead_tN1, prg.Halstead_dn2, prg.Halstead_tN2, prg.CyclomaticScore, prg.TotalStmts, prg.DeadStmts, prg.Sloc,
	CONVERT(VARCHAR(19), pf.LastUpdated, 120) AS LastUpdated
FROM
(
	SELECT	ProgramID, ProgramName, ProgramTypeID, ProgramOccurID,
		COALESCE(SUM(Halstead_Var_D_CNT), 0) AS Halstead_dn1,
		COALESCE(SUM(Halstead_Var_CNT), 0) AS Halstead_tN1,
		COALESCE(SUM(Halstead_StatementType_D_CNT), 0) AS Halstead_dn2,
		COALESCE(SUM(Halstead_StatementType_CNT), 0) AS Halstead_tN2,
		COALESCE(SUM(CyclomaticScore), 0) AS CyclomaticScore,
		COALESCE(SUM(OccurID_CNT), 0) AS TotalStmts,
		COALESCE(SUM(DeadStmts_NumOfStatements), 0) AS DeadStmts,
		COALESCE(SUM(SLOC), 0) AS Sloc
	FROM
	(
		SELECT	CASE WHEN h.RootProgramID IS NOT NULL 
				THEN h.RootProgramID
				ELSE p.ProgramId
			END AS ProgramID,
			CASE WHEN h.RootProgramID IS NOT NULL 
				THEN h.RootProgramName
				ELSE p.ProgramName
			END AS ProgramName,
			CASE WHEN h.RootProgramID IS NOT NULL 
				THEN h.RootProgramTypeID
				ELSE p.ProgramTypeID
			END AS ProgramTypeID,
			CASE WHEN h.RootProgramID IS NOT NULL 
				THEN h.RootProgramOccurID
				ELSE p.OccurID
			END AS ProgramOccurID,
			hld1.Halstead_Var_D_CNT,
			hld1.Halstead_Var_CNT,
			hld2.Halstead_StatementType_D_CNT,
			hld2.Halstead_StatementType_CNT,
			cycl.CyclomaticScore,
			totalStmts.OccurID_CNT,
			CASE WHEN p.ProgramTypeID = 1 
				THEN deadStmts.NumOfStatements_COBOL
				ELSE deadStmts.NumOfStatements_OTHERS
			END AS DeadStmts_NumOfStatements,
			statsLines.SLOC
		FROM #program_alias p
			--Halstead operators-Variables
			LEFT OUTER JOIN (
				         SELECT os.ProgID AS ProgramID, COUNT(v.VarName) AS Halstead_Var_CNT, COUNT(DISTINCT v.VarName) AS Halstead_Var_D_CNT
					 FROM StatementReference sr
					      INNER JOIN OccurrencesStmt os ON os.OccurID = sr.OccurID
					      INNER JOIN Variables v ON v.VarID = sr.ResourceID
				         WHERE sr.ResourceType = 4
					 GROUP BY os.ProgID
	
			) hld1 ON p.ProgramID = hld1.ProgramID
			--Halstead operands-StatementType
			LEFT OUTER JOIN (
				SELECT	os.ProgID AS ProgramID, COUNT(StatementType) AS Halstead_StatementType_CNT, COUNT(DISTINCT StatementType) AS Halstead_StatementType_D_CNT
				FROM OccurrencesStmt os
				GROUP BY os.ProgID
			) hld2 ON p.ProgramID = hld2.ProgramID
			LEFT OUTER JOIN (
				SELECT	ProgramID, CyclomaticScore AS CyclomaticScore
				FROM ProgramCyclomaticScores
			) cycl ON p.ProgramID = cycl.ProgramID
			LEFT OUTER JOIN (
				SELECT	ProgID AS ProgramID, COUNT(OccurID) AS OccurID_CNT
				FROM OccurrencesStmt
				GROUP BY ProgID
			) totalStmts ON p.ProgramID = totalStmts.ProgramID
			--deadStmtsOTHERS + deadStmtsCOBOL
			LEFT OUTER JOIN (
				SELECT	ProgramID,
					-- COBOL
					SUM(CASE WHEN par.UnreachablePara = - 1 
						THEN par.NumOfStatements
						ELSE 0
					END) AS NumOfStatements_COBOL,
					-- OTHERS
					SUM(CASE WHEN par.OrdinalNum != 1 AND par.IsExitPara = 0 AND sr.ResourceID IS NULL 
						THEN par.NumOfStatements
						ELSE 0
					END) AS NumOfStatements_OTHERS
				FROM Paragraphs par
					LEFT OUTER JOIN (
						SELECT	ResourceID
						FROM StatementReference
						WHERE ResourceType = 2
						GROUP BY ResourceID
					) sr ON par.ParaID = sr.ResourceID
				GROUP BY par.ProgramID
			) deadStmts ON p.ProgramId = deadStmts.ProgramID
			-- sloc from statistics
			LEFT OUTER JOIN (
				SELECT	p.ProgramID, sts.SLOC
				FROM Occurrences o
					INNER JOIN Programs p ON  p.OccurID = o.OccurID AND p.ProgramTypeID IN (1, 8)
					INNER JOIN (
						SELECT	s.PathID, s.Code AS SLOC
						FROM StatisticsLines s
						WHERE s.ScopeId IN (13, 15)
					) sts ON sts.PathID = o.PathID
			) statsLines ON p.ProgramID = statsLines.ProgramID
			LEFT OUTER JOIN #prog_hierarchy h ON p.ProgramID = h.ProgramID AND h.RN = 1
	) m
	GROUP BY ProgramID, ProgramName, ProgramTypeID, ProgramOccurID
) prg
	LEFT OUTER JOIN Occurrences occ ON occ.OccurID = prg.ProgramOccurID
	LEFT OUTER JOIN Paths pth ON pth.PathID = occ.PathID
	LEFT OUTER JOIN ( 
		SELECT 	pth.PathID,
			COALESCE( mm.LastUpdateDate, mnm.UpdateDate, mlm.UpdateDate, zcc.dateTimeLastModified, zcb.dateTimeLastModified) AS LastUpdated
		FROM dbo.Pj_File pf
			INNER JOIN dbo.Pj_File_VS_MainframeMembers pfmm ON pf.ID_File = pfmm.Pj_FileID
			INNER JOIN dbo.Paths pth ON pth.PathStr = pf.FilePath
			LEFT OUTER JOIN dbo.MFMembers mm ON  pfmm.MemberType IN (0, 1, 2) AND mm.MemberID = pfmm.MemberID
			LEFT OUTER JOIN dbo.MFNaturalMembers mnm ON pfmm.MemberType IN (3, 6) AND mnm.NatMemberID = pfmm.MemberID
			LEFT OUTER JOIN dbo.MFLibrarianMembers mlm ON  pfmm.MemberType = 4 AND mlm.LibrarianMemberID = pfmm.MemberID
			LEFT OUTER JOIN dbo.ZMF_CM_Components zcc ON  pfmm.MemberType = 5 AND zcc.ID = pfmm.MemberID
			LEFT OUTER JOIN dbo.ZMF_CM_Components_Baseline zcb ON  pfmm.MemberType = 7 AND zcb.ID = pfmm.MemberID
	) pf ON pf.PathID = occ.PathID

END