@DIRECTION int, -- both
@VALID_FROM datetime,
@VALID_TO datetime,
@RESTRICT_APPS int, -- do not restrict
@MAXLEVELS int
AS
   BEGIN
       SET  @DIRECTION = COALESCE(@DIRECTION, 2)
       SET @RESTRICT_APPS = COALESCE(@RESTRICT_APPS, 0)
	   SET @MAXLEVELS  = COALESCE(@MAXLEVELS, 100)
	    
/*
 declare @MAXLEVELS int
 declare @VALID_FROM datetime
 declare @VALID_TO datetime
 declare @DIRECTION int
 declare @RESTRICT_APPS int
 
 Set @MAXLEVELS = 20
 Set @VALID_FROM = null --'2014-05-12T00:00:00.000'
 Set @VALID_TO = null --'2014-07-12T00:00:00.000'
 Set @DIRECTION = 0
 Set @RESTRICT_APPS = 0
 */

 DECLARE @LEVEL int
 
 --direction is 0 -> forward
 --             1 -> backward
 --             2 -> both
 IF @DIRECTION > 2 or @DIRECTION < 0 Set @DIRECTION = 2
 IF @MAXLEVELS > 100 Set @MAXLEVELS = 100
 
 IF @VALID_FROM = '' Set @VALID_FROM = null
 IF @VALID_TO = '' Set @VALID_TO = null
 
 --select * from #aids
 --select * from #jids
 
 set xact_abort on
 set NOCOUNT ON;
 
 create table #Discovered (
    srcJobNr varchar(5),
    srcAppId  int,
    tgtJobNr varchar(5),
    tgtAppId int,
    level int,
    DependencyDescription varchar(50),
    c int,
 )
 create table #DistinctApps (
    c int,
    appid int,
    applicationname varchar(16),
 )
 insert into #DistinctApps
    select COUNT(ApplicationName) as c, MIN(AppID) as AppID, ApplicationName
    from TWS_Applications where ApplicationType = 'A' and ApplicationStatus = 'A' --only active applications
    group by ApplicationName
 
 insert into #Discovered (srcJobNr, srcAppId, tgtJobNr, tgtAppId, level, DependencyDescription)
     select null, null, j.jobnr, j.appid, 0, null from #jobids j
     
 
 --select * from #DistinctApps where appid in (1,2,3)
 --select * from #Discovered
 --select * from TWS_Jobs
 --select * from TWS_Applications
 
 Set @LEVEL = 1
 while @@ROWCOUNT > 0 and @MAXLEVELS > @LEVEL
    begin
        Set @LEVEL = @LEVEL + 1
        insert into #Discovered (srcJobNr, srcAppId, tgtJobNr, tgtAppId, level, DependencyDescription, c)
        --forward
        select d.tgtJobNr, d.tgtAppId, e.JobNumber, e.JobAppID, (@LEVEL - 1), e.DependencyDescription, da.c
        from #Discovered d
                 inner join #DistinctApps as da on da.appid = d.tgtAppId
                 inner join TWS_Jobs as e on e.PredecessorJobNumber = d.tgtJobNr and d.level >= 0
                            and ((e.PredecessorApplication  is null and e.JobAppID = da.appid)
                                  or e.PredecessorApplication = da.applicationname)
                 inner join TWS_Applications oa on oa.AppID = e.JobAppID
                        and ((@VALID_FROM is null or oa.ValidFromDate >= @VALID_FROM)
                                and
                              (@VALID_TO is null or oa.ValidToDate <= @VALID_TO))
                        --only active applications
						and oa.ApplicationType = 'A' and oa.ApplicationStatus = 'A'
                        --id constraints for application      
                        and (@RESTRICT_APPS = 0 or
                              (e.JobAppID in (select appid from #appids)))
        where --direction choice
              (@DIRECTION = 0 or @DIRECTION = 2)
               --cycle stop
               and not exists (select 1 from #Discovered as dd
                    where e.PredecessorJobNumber = dd.srcJobNr and dd.srcAppId = e.JobAppId)
                    
        union
        --backward
        select d.tgtJobNr, d.tgtAppId, e.PredecessorJobNumber, da.appID, -(@LEVEL - 1), e.DependencyDescription, da.c
            from #Discovered d
                 inner join TWS_Jobs as e on e.JobNumber = d.tgtJobNr and d.tgtAppId = e.JobAppID and d.level <= 0
                 inner join #DistinctApps as da on
                        ((e.PredecessorApplication is null and e.JobAppID = da.AppID) --same application
                          or e.PredecessorApplication = da.ApplicationName
                        )
                 inner join TWS_Applications oa ON oa.AppID = da.appid
                        --date constraints for application
                        and ((@VALID_FROM is null or oa.ValidFromDate >= @VALID_FROM)
                                and
                              (@VALID_TO is null or oa.ValidToDate <= @VALID_TO))
                        --only active applications
						and oa.ApplicationType = 'A' and oa.ApplicationStatus = 'A'
                        --id constraints for application      
                        and (@RESTRICT_APPS = 0 or
                              (e.JobAppID in (select appid from #appids)))     
        where --direction choice
              (@DIRECTION = 1 or @DIRECTION = 2)
               --cycle stop
               and not exists (select 1 from #Discovered as dd
                    where e.JobNumber = dd.srcJobNr and dd.srcAppId = e.JobAppId)  
                          
 end    
 
 select #Discovered.srcJobNr,
     #Discovered.srcAppId,
     #Discovered.tgtJobNr,
     #Discovered.tgtAppId,
     #Discovered.level,
    -- TWS_Jobs.JobName as tgtJobName,
    -- TWS_Jobs.JobDescription as tgtJobDescription,
     #Discovered.DependencyDescription
    -- TWS_Applications.ApplicationName as tgtApplicationName,
    -- abs(#Discovered.level)
    , c
 from #Discovered
     --left join TWS_Jobs on #Discovered.tgtJobNr = TWS_Jobs.JobNumber AND #Discovered.tgtAppId = TWS_Jobs.JobAppID
     --left join TWS_Applications on #Discovered.tgtAppId = TWS_Applications.AppID
 order by level--abs(#Discovered.level)

 drop table #Discovered
 drop table #DistinctApps

end
