using Graphs
using LinearAlgebra
using StatsBase

# Section 2.2
function distances(graph::String, x::Int64)::Array{Int64}
    g::SimpleGraph{Int64} = loadgraph("graphs/" * graph, "graph")
    d::Array{Int64} = gdistances(g, x)
    return d
end

# Section 2.2
function degrees_of_separation(graph::String)::Float64
    g::SimpleGraph{Int64} = loadgraph("graphs/" * graph, "graph")
    s::Int64 = 0
    for x::Int64 in vertices(g)
        d::Array{Int64} = gdistances(g, x)
        s = s + sum(d)
    end
    return s / (nv(g) * (nv(g) - 1))
end

# Section 2.3.3
function min_max_degree(graph::String)::Tuple{Int64,Int64}
    g::SimpleGraph{Int64} = loadgraph("graphs/" * graph, "graph")
    degree::Array{Int64} = degree_centrality(g, normalize=false)
    return minimum(degree), maximum(degree)
end

# Section 2.3.3
function distance_distribution(graph::String)::Array{Float64}
    g::SimpleGraph{Int64} = loadgraph("graphs/" * graph, "graph")
    dd::Array{Int64} = zeros(Int64, nv(g) - 1)
    for x::Int64 in vertices(g)
        dd = dd + counts(gdistances(g, x), 1:nv(g)-1)
    end
    return dd / (nv(g) * (nv(g) - 1))
end

# Section 2.3.3
function degrees_of_separation(dd::Array{Float64})::Float64
    last_distance::Int64 = findlast(x -> x > 0, dd)
    return dot(1:last_distance, dd[1:last_distance])
end

# Section 2.3.3
function distance_distribution(graph::String, k::Int64)::Array{Float64}
    g::SimpleGraph{Int64} = loadgraph("graphs/" * graph, "graph")
    dd::Array{Int64} = zeros(Int64, nv(g) - 1)
    for _ in 1:k
        dd = dd + counts(gdistances(g, rand(1:nv(g))), 1:nv(g)-1)
    end
    return dd / (k * (nv(g) - 1))
end

# Section 2.5.2
# Write to the author for having the graphs
function imdb_degrees_separation(f_year::Int64, l_year::Int64, step::Int64)::Array{Float64}
    ds::Array{Float64} = zeros(1 + (l_year - f_year) ÷ step)
    for year in f_year:step:l_year
        graph::String = "imdb/imdb$year.lg"
        g::SimpleGraph{Int64} = loadgraph("graphs/" * graph, "graph")
        k::Int64 = 100 * trunc(log2(nv(g)))
        dd::Array{Float64} = distance_distribution(graph, k)
        ds[1+(year-f_year)÷step] = degrees_of_separation(dd)
    end
    return ds
end
