#
# bugpred-fishing.R, 19 Jul 26
#
# Data from:
# Do Bugs Propagate? An Empirical Analysis of Temporal Correlations Among Software Bugs
# Xiaodong Gu, Yo-Sub Han, Sunghun Kim, Hongyu Zhang


# This code runs in each of the four directories within data/


# library("colorspace")
library("plyr")
library("geepack")


# par(bty="l")
# par(las=1)
# par(pch="+")
# pal_col=rainbow(2)


read_metrics=function(ver_str)
{
if (ver_str== "0.0.0")
   return(NULL)

metinfo=read.csv(paste0("metrics", ver_str, ".txt"), header=FALSE, sep=" ")

# The first column is the file index
# Convert to a matrix ordered by file index
# geeglm does not handle NA's, so have to use a numeric value
met_stat = matrix(-1, nrow = numfile, ncol = ncol(metinfo)-1)
met_stat[metinfo$V1, ]=as.matrix(metinfo[, -1])

return(as.data.frame(met_stat))
}


# Count fixed faults in graph neighbourhood
cnt_graph_bugs=function(ver_num, graph_str="callgraph")
{
# version string
ver_str=reldates$V1[ver_num]

graphinfo=read.csv(paste0(graph_str, ver_str, ".txt"), header=FALSE, sep=" ")

graph=as.matrix(graphinfo)

nei_bug=rep(NA, numfile)

# The Matlab code is is much more long winded.
for (fn in 1:numfile)
   nei_bug[fn]=sum(bug_stat[which(graph[fn, ] > 0), ver_num] > 0)

return(data.frame(ver_num, nei_bug))
}


fit_gee_mod=function(graph_str)
{
callgraph_bugs=adply(1:numrel, .mar=1, cnt_graph_bugs, graph_str)

nei_prev_bug=subset(callgraph_bugs, ver_num != numrel)$nei_bug
nei_curr_bug=subset(callgraph_bugs, ver_num != 1)$nei_bug

# The Matlab code uses these names, and even increments the values by +1
# a=nei_prev_bug
# b=ego_prev_bug
# c=nei_curr_bug
noc=metrics$V1
noa=metrics$V2
loc=metrics$V25

y=(ego_curr_bug > 0)

# The subset used in the Matlab code is
# ego_curr_bug>=0 & nei_prev_bug<5;
# There are instances where loc == 0
gee_mod=geeglm(y ~ loc+noa + nei_prev_bug+ego_prev_bug,
			subset=(ego_curr_bug >= 0) & (loc > 0),
			id = id,
			waves = time,
			family = binomial(link = "logit"),
			corstr = "exchangeable")
return(gee_mod)
}


graphtypes=c("callgraph", "hiegraph", "cochgraph")

reldates=read.csv("bugs/release_date_revision.csv", header=FALSE)
buginfo=read.csv("bugstat.txt", sep=" ", header=FALSE)
# buginfo[buginfo == -1]=NA

agraph=read.csv(paste0("callgraph", reldates$V1[2], ".txt"), header=FALSE)
numfile=nrow(agraph) # Quickest way to get the number of files

numrel=nrow(reldates)-1

# The first column is the file index
# Convert to a matrix ordered by file index
bug_stat = matrix(-1, nrow = numfile, ncol = numrel)
bug_stat[buginfo$V1, ]=as.matrix(buginfo[, -1])

metrics=adply(reldates$V1[-1], .mar=1, read_metrics)

# Merge every column into a single vector
# All but the last is a previous of a current
ego_prev_bug=as.vector(bug_stat[ , -numrel])
# The first has no previous
ego_curr_bug=as.vector(bug_stat[ , -1])

id=rep(1:numfile, times=numrel-1)
time=rep(1:(numrel-1), each=numfile)

call_mod=fit_gee_mod("callgraph")
summary(call_mod)

hie_mod=fit_gee_mod("hiegraph")
summary(hie_mod)

coch_mod=fit_gee_mod("cochgraph")
summary(coch_mod)




bug_mod=glm(y ~ loc+noc+noa+a+b+c, family=binomial,
			subset=(nei_prev_bug < 5))
summary(bug_mod)


