pbs/src/PBSlib.coffee

181 lines
5.8 KiB
CoffeeScript
Raw Permalink Normal View History

2015-04-09 10:59:08 +02:00
class PBS
2015-04-09 15:03:30 +02:00
constructor: (obj, @verbose, @errListener) ->
2015-03-13 21:03:11 +01:00
@days = []
2015-04-09 16:25:05 +02:00
@resources = []
2015-04-07 14:09:05 +02:00
@criticalPaths = []
2015-04-09 16:25:05 +02:00
@verbose = yes
2015-04-09 15:03:30 +02:00
if obj.push # is a list
@list = obj
else if obj.activities
@list = obj.activities
2015-04-09 16:25:05 +02:00
if obj.resources?.push? then @resources = obj.resources
2015-04-09 15:03:30 +02:00
else
@list = []
2015-04-09 16:25:05 +02:00
@err 'data is not an array nor a object with "activities" array'
2015-03-13 18:32:19 +01:00
log: (x...) ->
2015-04-09 10:59:08 +02:00
if @verbose
if chalk?
console.log chalk.bold "[ Pert ]", x...
else console.log "[ Pert ]", x...
err: (x...) ->
if chalk?
2015-04-09 15:03:30 +02:00
console.log chalk.bold chalk.red("[ Pert ]"), x...
else console.log "[ !Pert! ]", x...
2015-04-09 15:03:30 +02:00
if @errListener?.call? then @errListener x
2015-04-09 16:25:05 +02:00
compileResources: =>
@log 'compiling resources...'
if not @resources? then return
@resources.forEach (x) =>
@log 'processing resource', x
if x.assignedTo?.push? then x.assignedTo.forEach (i) =>
a = @toActivity i
a.assigned ?= []
a.assigned.push x.name or x.id
@list.forEach (x) =>
item = @toActivity x
if item.assigned?.push? then item.assigned.forEach (i) =>
res = @toResource i
if res
@log 'found', res, 'assigned to', item
res.assignedTo ?= []
res.assignedTo.push i
# Returns the highest number in an array of numbers
maxa: (l) -> return Math.max.apply null, l
# Find the activity with given id
2015-03-13 18:32:19 +01:00
toActivity: (id) =>
if !@list? then @err "list is", @list
item = {}
for i,x of @list
if x.id is id then item = x
return item
2015-04-09 16:25:05 +02:00
# Find the activity with given id
toResource: (id) =>
unless @resources?.push? then return
item = {}
for i,x of @resources
if x.id is id or x.name is id then item = x
return item
2015-03-13 18:32:19 +01:00
# Compute the item's end day
calculateEndDay: (item) =>
if !item.startDay?
2015-03-13 18:32:19 +01:00
@log "calculating start day of",item.id
item.startDay = @calculateStartDay item
@log "start day of",item.id,"is",item.startDay
item.endDay = item.startDay + item.duration
2015-03-13 18:32:19 +01:00
@log "end day of",item.id,"is",item.endDay
2015-03-13 21:03:11 +01:00
@insertDay item.endDay
return item.endDay
# Find out which day the activity starts
2015-03-13 18:32:19 +01:00
calculateStartDay: (item) =>
2015-03-13 21:03:11 +01:00
if !item.depends? or item.depends.length is 0
@insertDay 0
return item.startDay = 0
2015-03-13 18:32:19 +01:00
item.startDay = @maxa item.depends.map(@toActivity).map @calculateEndDay
@log "start day of",item.id,"is",item.startDay
# write max delay time to each depend
for j,x of item.depends
2015-03-13 18:32:19 +01:00
@log "checking permittedDelay to dependency", x, "of", item
i = @toActivity x
2015-03-16 11:44:08 +01:00
if !i.dependant? then i.dependant = [item.id]
else i.dependant.push item.id
if !i.permittedDelay?
2015-03-13 18:32:19 +01:00
i.permittedDelay = item.startDay - @calculateEndDay i
@log "written permittedDelay to dependency", x, "of", item, "as", i.permittedDelay
else @log "aborting permittedDelay: already calculated"
@log "permitted delay of",x,"is",i.permittedDelay
2015-03-13 21:03:11 +01:00
@insertDay item.startDay
return item.startDay
2015-04-07 13:36:07 +02:00
calculateDelays: (item) =>
if !item.dependant? or item.dependant.length is 0 then return no
olDelay = item.chainedDelay
2015-04-09 17:55:21 +02:00
if item.critical
@log item.id, 'is critical: no chained delays'
item.chainedDelay = 0
else
lowestFDelay = 0; fDelay = no; cDelay = 0
for j,i of item.dependant
x = @toActivity i
if !isNaN(x.permittedDelay) or x.permittedDelay < lowestFDelay or fDelay is no
@log "activity", i, "dependant on", item.id, "has the lowest delay for now ("+(x.permittedDelay or 0)+")"
lowestFDelay = x.permittedDelay or 0
cDelay = x.chainedDelay or 0
fDelay = yes
olDelay = item.chainedDelay
item.chainedDelay = lowestFDelay + cDelay
@log "chained delay of", item.id, "is", item.chainedDelay
2015-04-07 13:36:07 +02:00
return item.chainedDelay isnt olDelay
2015-04-07 14:09:05 +02:00
calculateCriticalPaths: (path) ->
@log "calculating path from",path
lastID = path[path.length - 1]
last = @toActivity lastID
2015-04-09 16:25:05 +02:00
if last.permittedDelay > 0
@log "dead end at", lastID, "because its delay is", last.permittedDelay
else if last.dependant? and last.dependant.length > 0
2015-04-07 14:09:05 +02:00
last.dependant.forEach (x) =>
ii = @toActivity x
delay = ii.permittedDelay or 0
if delay is 0
2015-04-09 16:25:05 +02:00
@log 'following path from', last.id, 'to', ii.id, 'because', ii, 'has', ii.permittedDelay, 'days of free delay'
@calculateCriticalPaths path.concat x
else
@log "dead end at", lastID, "-->", x, "because delay is", delay
2015-04-07 14:09:05 +02:00
else
path.forEach (x) => @toActivity(x).critical = yes
@log "calculated path", path
2015-04-07 14:09:05 +02:00
@criticalPaths.push path
# Find out which activity has the highest id
2015-03-13 18:32:19 +01:00
highestID: => return @maxa(@list.map (x) -> x.id)
2015-03-13 21:03:11 +01:00
# Insert a day to the list of days if it's not there already
insertDay: (day) =>
for d in @days
if day is d then return
@days.push day
2015-03-14 09:42:05 +01:00
setData: (data) ->
@list = data
return @
2015-03-16 11:44:08 +01:00
calculate: (options,cb) ->
2015-04-09 17:55:21 +02:00
# Calculate startDay, endDay, freeDelay
2015-04-07 13:36:07 +02:00
for x,i in @list
2015-04-09 17:55:21 +02:00
@log '('+i+'/'+@list.length+')'
2015-03-14 09:42:05 +01:00
@calculateEndDay x
2015-04-09 17:55:21 +02:00
# Calculate Critical Paths
for x,i in @list
if !x.depends? or x.depends.length is 0
@calculateCriticalPaths [x.id]
# Calculate chained Delays
2015-04-07 13:36:07 +02:00
finished = no; i = 0
while !finished
i++; finished = yes
for x,i in @list
if @calculateDelays x
finished = no
@log "Done calculating delays. Took", i, "iterations"
2015-04-09 17:55:21 +02:00
# Compile resource information
2015-04-09 16:25:05 +02:00
@compileResources()
2015-04-09 17:55:21 +02:00
# done
2015-04-09 16:25:05 +02:00
results =
activities: @list
days: @days
criticalPaths: @criticalPaths
resources: @resources || []
@log 'Done', results
2015-03-16 11:44:08 +01:00
if options?.json
if cb? then cb(JSON.stringify results)
JSON.stringify results
else
if cb? then cb(results)
results