@ProgramID_IN INTEGER,
@ForwardOrBackward_IN SMALLINT
AS
BEGIN
SET NOCOUNT ON
            --EXEC EZViewer_CalledProgramID_New 4, -1 ;
            --DECLARE @ProgramID_IN INTEGER = 4 ,@ForwardOrBackward_IN SMALLINT = -1
		    DECLARE @ProgramID INTEGER ,@ForwardOrBackward SMALLINT = 1 ;/* 1 Forward  and  -1 Backward; forward forced */
			DECLARE @errormsg  NVARCHAR(4000) = '' ;
		    DECLARE @rc INTEGER ,@i INTEGER ,@j INTEGER;


			IF OBJECT_ID('tempdb..#x') IS NOT NULL DROP TABLE #x ;
			CREATE TABLE #x (FromProgramID INTEGER ,ToProgramID INTEGER) ;

			IF OBJECT_ID('tempdb..#fin') IS NOT NULL DROP TABLE #fin ;
			CREATE TABLE #fin (FromProgramID INTEGER ,ToProgramID INTEGER /*,Calling_Concat VARCHAR(MAX) ,Lvl INTEGER*/) ;

            SET @ProgramID = COALESCE(@ProgramID_IN , 0);
			SET @ForwardOrBackward = COALESCE(@ForwardOrBackward_IN , 1 ); -- DEFAULT IS FORWARD


			IF  ( @ForwardOrBackward NOT IN (-1, 1) )
			BEGIN
					SET     @errormsg = 'Please use corect ForwardOrBackward: 1 -> FORWARD  or  -1 -> BACKWARD' ;
					RAISERROR (@errormsg , 16, 1 );
					RETURN;
			END;


			INSERT INTO #x (FromProgramID, ToProgramID)
			SELECT os.ProgID, sr.ResourceID
			FROM StatementReference sr
				INNER JOIN OccurrencesStmt os ON sr.OccurID = os.OccurID
			WHERE sr.ResourceType = 5
			GROUP BY os.ProgID, sr.ResourceID ;

			CREATE NONCLUSTERED INDEX ncid1 ON #x (FromProgramID) INCLUDE (ToProgramID) ;
            CREATE NONCLUSTERED INDEX ncid2 ON #x (ToProgramID)   INCLUDE (FromProgramID) ;

	-- GET LEVEL 0
			INSERT INTO #fin (FromProgramID, ToProgramID /*,Calling_Concat ,Lvl*/)
			SELECT x.FromProgramID, x.ToProgramID
			       --,'#' + CAST( (CASE @ForwardOrBackward WHEN 1 THEN x.FromProgramID ELSE x.ToProgramID END) AS VARCHAR(MAX)) + '#' + CAST((CASE @ForwardOrBackward WHEN 1 THEN x.ToProgramID ELSE x.FromProgramID END) AS VARCHAR(MAX)) AS Calling_Concat , 0 AS Lvl
			FROM #x x
			WHERE @ProgramID = CASE @ForwardOrBackward WHEN 1 THEN x.FromProgramID ELSE x.ToProgramID END ;

    -- IMBRICATIONS LEVELES  1-> 2000 (2000 levels of imbrication)
           SET @i = 1 ;
		   SET @j = 2001 ;

    -- GET NEXT LEVELS VALUES
			WHILE ( @i < @j )
			BEGIN
						--SELECT @i
                        SET @rc= 0 ;

                        IF (@ForwardOrBackward = 1)
							BEGIN

									INSERT INTO #fin(FromProgramID ,ToProgramID /*,Calling_Concat ,Lvl*/)
									SELECT f1.FromProgramID, x.ToProgramID
										--,f1.Calling_Concat  + '#' + CAST(x.ToProgramID AS VARCHAR(MAX)),  f1.Lvl + 1
									FROM #x x
											INNER JOIN #fin f1 ON f1.ToProgramID = x.FromProgramID
											LEFT OUTER JOIN #fin f2 ON f1.FromProgramID = f2.FromProgramID
																AND x.ToProgramID = f2.ToProgramID
									WHERE  f2.FromProgramID IS NULL ;

									SET @rc = @@ROWCOUNT ;

							END
						ELSE
							BEGIN

							           INSERT INTO #fin(FromProgramID ,ToProgramID /*,Calling_Concat ,Lvl*/)
										SELECT  x.FromProgramID, f1.ToProgramID
												--,f1.Calling_Concat  + '#' + CAST(x.FromProgramID AS VARCHAR(MAX)),  f1.Lvl + 1
										FROM #x x
												INNER JOIN #fin f1 ON x.ToProgramID = f1.FromProgramID
												LEFT OUTER JOIN #fin f2 ON f1.ToProgramID = f2.ToProgramID
																	AND x.FromProgramID = f2.FromProgramID
										WHERE  f2.ToProgramID IS NULL ;

										SET @rc = @@ROWCOUNT ;

							END;


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


            SELECT f.ProgramSourceID AS ProgramID, f.ProgramTargetID AS CalledOrCallingProgramID, p.ProgramName AS CalledOrCallingProgramName
		         --,f.Calling_Concat ,f.Lvl
		    FROM   (
		            SELECT FromProgramID AS ProgramSourceID ,ToProgramID AS ProgramTargetID --,Calling_Concat ,Lvl
				    FROM #fin	
					WHERE @ForwardOrBackward = 1

					UNION

                    SELECT ToProgramID AS ProgramSourceID ,FromProgramID AS ProgramTargetID --,Calling_Concat ,Lvl
				    FROM #fin	
					WHERE @ForwardOrBackward = -1
		           ) f
			             INNER JOIN (
										SELECT pgm.ProgramID ,COALESCE(pa.AliasName, pgm.ProgramName) AS ProgramName
										FROM Programs pgm
											LEFT OUTER JOIN ProgramAliases pa  ON pgm.ProgramID = pa.ProgramId AND pa.AliasType = 0
									) p ON f.ProgramTargetID = p.ProgramID
			ORDER BY f.ProgramTargetID ;
		

            IF OBJECT_ID('tempdb..#fin') IS NOT NULL DROP TABLE #fin ;
		    IF OBJECT_ID('tempdb..#x')   IS NOT NULL DROP TABLE #x ;
END
