      @StartJobID int, 
	  @EndJobId int, 
	  @StartSchid int, 
	  @maxnodesnumber int 
AS
BEGIN
SET NOCOUNT ON
SET XACT_ABORT ON

 DECLARE @j INT = 1 
 DECLARE @level INT = 1
 DECLARE @id INT = 1 -- allways the first job (tgt) in waiting stack will be processed
 DECLARE @src INT, @tgt INT, @ord INT, @ssid INT, @tsid INT, @deptype INT
 DECLARE @maxcycleid INT, @maxpathid INT, @pathid2 INT, @tgt2 INT, @id2 INT, @ord12 INT, @cycleid2 INT, @ord2 INT 
 DECLARE @cyclejobid INT, @cycleord INT
 DECLARE @maxiterations int = 300000  -- safegard
 DECLARE @nodesnumber INT = 0
 
 SET @maxnodesnumber  = COALESCE(@maxnodesnumber, 5000)

IF  @maxnodesnumber > 5000  SET @maxnodesnumber = 5000
  
  
--A. Get basic data Job's relationship
	   IF OBJECT_ID('tempdb..#CA7_JobsTriggeredByJobs') IS NOT NULL DROP TABLE #CA7_JobsTriggeredByJobs
	   SELECT TriggeredBy_JobID, JobID, inSCHID, outSCHID
	   INTO #CA7_JobsTriggeredByJobs
	   FROM CA7_JobsTriggeredByJobs 

	   CREATE CLUSTERED INDEX cidx_11 ON #CA7_JobsTriggeredByJobs (JobID ASC ) 
	   CREATE NONCLUSTERED INDEX ncidx11 ON #CA7_JobsTriggeredByJobs (TriggeredBy_JobID ASC) INCLUDE( JobID, inSCHID, outSCHID)




	   IF OBJECT_ID('tempdb..#CA7_JobsDependentOnJobs') IS NOT NULL DROP TABLE #CA7_JobsDependentOnJobs
	   SELECT  DependentOn_JobID, JobID, SCHID, DependencyTypeID
	   INTO #CA7_JobsDependentOnJobs
	   FROM CA7_JobsDependentOnJobs

	   CREATE NONCLUSTERED INDEX ncidx21 ON  #CA7_JobsDependentOnJobs (DependentOn_JobID ASC ) INCLUDE( JobID, SCHID, DependencyTypeID)




--B. Declare/Create temporary objects 
--    insert initial data


        IF OBJECT_ID('tempdb..#TempDiscovered') IS NOT NULL DROP TABLE #TempDiscovered
	   CREATE TABLE #TempDiscovered (
							 ID INT IDENTITY(1,1) NOT NULL,
							 Flag int,
							 src int,
							 tgt int,
							 ord int,
							 ssid int,
							 tsid int,
							 deptype int  )




        IF OBJECT_ID('tempdb..#PreDiscovered') IS NOT NULL DROP TABLE #PreDiscovered
	   CREATE TABLE #PreDiscovered (
							 ID INT IDENTITY(1,1) NOT NULL,
							 Flag int,
							 src int,
							 tgt int,
							 ord int,
							 ssid int,
							 tsid int,
							 deptype int  )




	   IF OBJECT_ID('tempdb..#Discovered') IS NOT NULL DROP TABLE #Discovered
	   CREATE TABLE #Discovered (     
                          ID INT IDENTITY(1,1) NOT NULL PRIMARY KEY,
						  src int,
						  tgt int,
						  ord int,
						  ssid int,
						  tsid int,
						  deptype int )
					      

         IF OBJECT_ID('tempdb..#TempCycle') IS NOT NULL DROP TABLE #TempCycle
	    CREATE TABLE #TempCycle (     
                          ID INT IDENTITY(1,1) NOT NULL,
						  cyclejobid INT,
						  src int,
						  tgt int,
						  ord int,
						  ssid int,
						  tsid int,
						  deptype int )

         IF OBJECT_ID('tempdb..#PreCycle') IS NOT NULL DROP TABLE #PreCycle
	    CREATE TABLE #PreCycle (     
                          ID INT IDENTITY(1,1) NOT NULL PRIMARY KEY,
						  cyclejobid INT,
						  src int,
						  tgt int,
						  ord int,
						  ssid int,
						  tsid int,
						  deptype int )
	  
	  
         IF OBJECT_ID('tempdb..#Cycle') IS NOT NULL DROP TABLE #Cycle
	    CREATE TABLE #Cycle (     
                          ID INT IDENTITY(1,1) NOT NULL PRIMARY KEY,
						  cycleid INT,
						  cyclejobid INT,
						  src int,
						  tgt int,
						  ord int,
						  ssid int,
						  tsid int,
						  deptype int )
    
       CREATE NONCLUSTERED INDEX cidx61 ON #Cycle (cycleid ASC, ord ASC)
	   CREATE NONCLUSTERED INDEX cidx62 ON #Cycle (cyclejobid ASC) INCLUDE (src, tgt)


	    IF OBJECT_ID('tempdb..#Current_Stack') IS NOT NULL DROP TABLE #Current_Stack
		CREATE TABLE #Current_Stack (    
								ID INT IDENTITY(1,1) NOT NULL,
								src int,
								tgt int,
								ord int,
								ssid int,
								tsid int,
								deptype int)
	   CREATE NONCLUSTERED INDEX ncidx41 ON  #Current_Stack ( src, tgt, ord)

   

	    IF OBJECT_ID('tempdb..#Processed') IS NOT NULL DROP TABLE #Processed
	    CREATE TABLE #Processed (
							ID INT IDENTITY(1,1),
							src int,
							tgt int)

         CREATE NONCLUSTERED INDEX ncidx51 ON #Processed (src ASC, tgt ASC)


	   IF OBJECT_ID('tempdb..#PrePath') IS NOT NULL DROP TABLE #PrePath
	   CREATE TABLE #PrePath (    
						  ID INT IDENTITY(1,1) NOT NULL,
						  pathid int,
						  src int,
						  tgt int,
						  ord int,
						  ssid int,
						  tsid int,
						  deptype int )


        CREATE CLUSTERED INDEX cidx31 ON #PrePath (pathid ASC, ord ASC)
		CREATE NONCLUSTERED INDEX ncidx32 ON #PrePath (src ASC, tgt ASC)


	    IF OBJECT_ID('tempdb..#Path') IS NOT NULL DROP TABLE #Path
	   CREATE TABLE #Path ( 
						  pathtype int,
						  pathid int,
						  src int,
						  tgt int,
						  ord int,
						  ssid int,
						  tsid int,
						  deptype int )




	   INSERT INTO #Discovered (src, tgt, ord, ssid, tsid, deptype) 
	   SELECT  null, @StartJobID, 0, @StartSchid, @StartSchid, null



WHILE  (@maxiterations > @level AND @maxnodesnumber > @nodesnumber)
BEGIN


   BEGIN TRAN


				   -- get first job (tgt) for processing 
				   SELECT @src = src, @tgt = tgt, @ord = ord, @ssid = ssid, @tsid = tsid, @deptype =deptype FROM #Discovered WHERE ID = @id


				   TRUNCATE TABLE #TempDiscovered -- clean up temp stack


			        IF NOT EXISTS( SELECT 1 FROM #Processed WHERE ISNULL(src,-1) = ISNULL(@src,-1) AND ISNULL(tgt, -1) = ISNULL(@tgt,-1)) 		  
	                  BEGIN 
				    
													--reset current stack
													DELETE FROM #Current_Stack WHERE ord >= @ord


													-- add JobID (tgt) into Current Stack
												    INSERT INTO #Current_Stack (src, tgt, ord, ssid,  tsid, deptype)
												    SELECT  @src, @tgt, @ord, @ssid,  @tsid, @deptype



													-- jobid (tgt) is marked as processed
												    INSERT INTO #Processed (src, tgt) 
												    SELECT  @src, @tgt
													EXCEPT
												    SELECT src, tgt FROM #Processed

												   

												    -- store the current path if we have reached the EndJob
												    IF EXISTS ( SELECT 1
															 FROM  #Current_Stack 
															 WHERE tgt = @EndJobId -- if last inserted is our searched Job (End Job)
																    AND ID = (SELECT MAX(ID) FROM #Current_Stack) -- on the last position
															 )  
												    BEGIN		       
														  INSERT INTO #PrePath ( pathid, src, tgt, ord, ssid,  tsid, deptype)
														  SELECT @Level AS pathid, src, tgt, ord, ssid,  tsid, depType
														  FROM  #Current_Stack 	
												    END




												   -- prepare next level
												   -- get related jobs to @tgt (next level of processing)
												   -- TRUNCATE TABLE #TempDiscovered -- clean up temp stack

												   INSERT INTO #TempDiscovered (Flag, src, tgt, ord, ssid, tsid, depType) -- get jobs (tgt) for next step/processing
												   SELECT 1 AS Flag  -- discovered
														, t.src, t.tgt, t.ord, t.ssid, t.tsid, t.depType
												   FROM (
															  ----direct flow  
															 SELECT e.TriggeredBy_JobID AS src, 
																   e.JobID AS tgt, 
																   @ord + 1 AS ord, 
																   CASE WHEN e.inSCHID = 0 THEN -ABS(@tsid) 
																	   ELSE e.inSCHID 
																   END AS ssid, 
																   CASE WHEN e.outSCHID = 0 AND e.inSCHID = 0 THEN -ABS(@tsid)
																	   WHEN e.outSCHID = 0                   THEN -ABS(e.inSCHID)		  
																	   ELSE e.outSCHID 
																    END AS tsid,
																   -1 AS depType
															    FROM #CA7_JobsTriggeredByJobs e
															    WHERE    e.TriggeredBy_JobID = @tgt 
																	   AND e.TriggeredBy_JobID != @EndJobID
																	   AND ( ABS(@tsid) = ABS(e.inSCHID)
																		  OR (@tsid = 0 AND @StartSchid = 0 AND @ord<>0)
																		  OR (e.inSCHID = 0 AND (
																							 @ord <> 0 OR (
																											 (
																												SELECT COUNT(*) 
																												FROM CA7_SchedulesPerJob spj 
																												WHERE spj.JobID = @tgt 
																												    AND spj.SCHID = ABS(@tsid)
																												)
																												+ 
																												(
																												SELECT COUNT(*) 
																												FROM #CA7_JobsTriggeredByJobs jtj 
																												WHERE jtj.JobID = @tgt 
																													   AND   ISNULL(NULLIF(jtj.outSCHID,0), jtj.inSCHID) = ABS(@tsid)
																												) > 0
																										  )
																							 )
																			 )
																		  )

		              
																UNION

																-- dependency relation
																SELECT depe.DependentOn_JobID AS src,
																	  depe.JobID AS tgt, 
																	  @ord + 1 AS ord, 
																	  CASE WHEN depe.SCHID = 0 THEN -ABS(@tsid) 
																		  ELSE depe.SCHID 
																	  END AS ssid,-- ssid or tsid depending on how we interpret schid on dependency (also below in join)
																	  CASE WHEN depe.SCHID = 0 THEN -ABS(@tsid) 
																		  ELSE depe.SCHID 
																	  END AS tsid,--same id
																	  depe.DependencyTypeID as depType
																FROM #CA7_JobsDependentOnJobs depe 
																WHERE depe.DependentOn_JobID = @tgt
																	 AND depe.DependentOn_JobID != @EndJobID
																	 AND (   
																		   depe.SCHID = 0
																		   OR
																		   depe.SCHID = ABS(@tsid) -- ssid or tsid depending on how we interpret schid on dependency (also above in select)
																		)
									


													 ) t  
													 ORDER BY t.src
		

													-- Cycle Area

													 TRUNCATE TABLE #TempCycle

													 INSERT INTO #TempCycle (cyclejobid, src, tgt, ord, ssid, tsid, depType)
													 SELECT t.tgt AS cyclejobid , t.src, t.tgt, t.ord, t.ssid, t.tsid, t.depType
													 FROM #TempDiscovered t
														 INNER JOIN #Current_Stack c ON c.tgt = t.tgt  -- job that will produce loop / cycle
													 ORDER BY t.ID


													 SET @j = 1

													 -- if there are cycle candidates
													 WHILE (@j<= (SELECT MAX(ID) FROM #TempCycle))
													 BEGIN

														  SELECT @cyclejobid = cyclejobid FROM #TempCycle WHERE ID = @j -- get jobid that produce cycle
														  SELECT @cycleord = MAX(ord) FROM #Current_Stack WHERE tgt = @cyclejobid   -- get cycle start position
	                          

														 TRUNCATE TABLE #PreCycle

														 INSERT INTO #PreCycle (cyclejobid, src, tgt, ord, ssid, tsid, depType)
														 SELECT @cyclejobid, src, tgt, ord - ISNULL(@cycleord,0) AS ord, ssid, tsid, depType
														 FROM(
															 SELECT src, tgt, ord, ssid, tsid, depType
															 FROM #Current_Stack
															 WHERE ord >= @cycleord 
						 
															 UNION      
	  
															 SELECT src, tgt, ord, ssid, tsid, depType
															 FROM #TempCycle 
															 WHERE ID = @j
															 )s
														  ORDER BY ord 


														  -- check if the cycle wasn't already stored
														  IF (SELECT COUNT(*) 
															 FROM (
																    SELECT cyclejobid, src, tgt, ord 
																    FROM #PreCycle
																    EXCEPT
																    SELECT cyclejobid, src, tgt, ord 
																    FROM #Cycle
																)s
																)>0
														   BEGIN

														         SET @maxcycleid = ISNULL((SELECT MAX(ID) FROM  #Cycle), 0)

																INSERT INTO #Cycle (cycleid, cyclejobid, src, tgt, ord, ssid, tsid, depType) 
																SELECT  @maxcycleid as cycleid,  -- @level + @j AS cycleid, 
																       cyclejobid, src, tgt, ord, ssid, tsid, depType 
																FROM #PreCycle 
																ORDER BY ID

														   END
						    

														   SET @j = @j + 1
													END


												-- End Cycle Area

                               END
                         ELSE
					     BEGIN
					
						     -- partial path
							-- this node is already in a path so we can consider 
						    IF EXISTS( SELECT 1 FROM #PrePath WHERE ISNULL(src,-1) = ISNULL(@src,-1) AND ISNULL(tgt, -1) = ISNULL(@tgt,-1)) 		  
	                                 BEGIN 
				    
													--reset current stack
													DELETE FROM #Current_Stack WHERE ord >= @ord


													-- add JobID (tgt) into Current Stack
												    INSERT INTO #Current_Stack (src, tgt, ord, ssid,  tsid, deptype)
												    SELECT  @src, @tgt, @ord, @ssid,  @tsid, @deptype



												    -- insert partial path
												    INSERT INTO #PrePath ( pathid, src, tgt, ord, ssid,  tsid, deptype)
												    SELECT @Level AS pathid, src, tgt, ord, ssid,  tsid, depType
												    FROM  #Current_Stack 	
												   

						
						
						        END   
						END          




					    TRUNCATE TABLE #PreDiscovered

					  -- keep only unprocessed jobs
					   INSERT INTO #PreDiscovered (Flag, src, tgt, ord, ssid, tsid, depType)
					   SELECT s.Flag, s.src, s.tgt, s.ord, s.ssid, s.tsid, s.depType
					   FROM(   -- new jobs
							 SELECT t.ID, t.Flag
								    , t.src, t.tgt, t.ord, t.ssid, t.tsid, t.depType
							 FROM #TempDiscovered t
								 LEFT OUTER JOIN #Current_Stack c ON c.tgt = t.tgt  -- avoide cycle
							 WHERE c.ID IS NULL
							
							 UNION 
							 -- move unprocessed jobs (tgt) from waiting stack to temp stack for later processing
							 SELECT ID, 2 AS Flag  -- old jobs moved 
								    , src, tgt, ord, ssid,  tsid, deptype
							 FROM #Discovered
							 WHERE ID > @id
							 )s
					   ORDER BY s.Flag, s.ID


	


					  -- clean waiting stack
					  TRUNCATE TABLE #Discovered 

					  -- insert the jobs (tgt) into waiting stak  ( reordered -> new jobs in front) 
					  INSERT INTO #Discovered (src, tgt, ord, ssid, tsid, deptype) 
					  SELECT src, tgt, ord, ssid, tsid, deptype
					  FROM #PreDiscovered 
					  ORDER BY Flag, ID
		  

		             
 
       COMMIT TRAN  
 
              -- count number of nodes processed
                SET @nodesnumber = ISNULL(
								(SELECT COUNT(DISTINCT node)
								FROM
								(	
								    SELECT src, tgt 
								    FROM #Processed		     
								)y
								unpivot( node for tp in ([src],[tgt])) as UnpivotTable)
								, 0)



		   IF EXISTS(SELECT 1 FROM #Discovered)  --check if there are jobs to be processed
                 SET @level = @level + 1  
		   ELSE 
		       SET @level = @maxiterations -- exit if nothing to process


END




        -- A direct
     --add into final table direct pathid 
    INSERT INTO #Path(pathid, pathtype, src, tgt, ord, ssid,  tsid, deptype)
    SELECT pp.pathid, 0 AS pathtype, pp.src, pp.tgt, pp.ord, pp.ssid, pp.tsid, pp.depType 
    FROM #PrePath pp




    
    --DECLARE @maxpathid int
	SET @maxpathid = (SELECT MAX(pathid) FROM #PrePath)

	INSERT INTO #Path(pathid, pathtype, src, tgt, ord, ssid,  tsid, deptype)
	SELECT @maxpathid + cc.CycleID + 1 AS pathid, 1 AS pathtype, cc.src, cc.tgt, cc.ord, cc.ssid,  cc.tsid, cc.deptype
	FROM #cycle cc 
	     INNER JOIN (SELECT DISTINCT tgt FROM #PrePath ) pp 
		ON pp.tgt = cc.cyclejobid




SELECT pp.pathid, pp.src, pp.tgt, pp.ord, pp.ssid, pp.tsid, pp.depType 
--SELECT pp.pathid, pp.pathtype, pp.src, pp.tgt, pp.ord, pp.ssid, pp.tsid, pp.depType 
FROM #Path pp
ORDER BY pp.pathid, pp.ord




    RETURN

END 