module Segmenter
    export Segment

    struct Segment
        type::Symbol
        x_start::Int
        x_end::Int
        value::Any
    end

    Base.length(segment::Segment) = segment.x_end - segment.x_start + 1

    function segment(type, y; segment_by_value = false)
        x_start = 1
        segments = []
        while true
            idx = findfirst(x->x !== nothing, y[x_start:end])
            idx !== nothing || break
            x_start += idx - 1

            x_end = findfirst(x->(segment_by_value ? x != y[x_start] : x === nothing), y[x_start:end])
            if x_end === nothing
                x_end = length(y) - x_start + 1
            else
                x_end -= 1
            end
            x_end += x_start - 1

            value = (segment_by_value ? y[x_start] : y[x_start:x_end])

            push!(segments, Segment(type, x_start, x_end, value))

            x_end != length(y) || break
            x_start = x_end + 1
        end
        return segments
    end

    function consolidate_segments(segments)
        idx = 1
        consolidated = []
        segments_to_merge = [idx]
        while idx <= length(segments)
            while true
                idx += 1
                idx <= length(segments) && segments[idx].x_start - segments[idx-1].x_end == 1 || break # is contiguous
                push!(segments_to_merge, idx)
            end

            if length(segments_to_merge) > 1
                x_start = segments[segments_to_merge[1]].x_start
                x_end = segments[segments_to_merge[end]].x_end
                value = zeros(length(x_start:x_end))
                for j in segments_to_merge
                    copyto!(value, segments[j].x_start - x_start + 1, [segments[j].value for i in 1:length(segments[j])], 1)
                end
                push!(consolidated, Segment(segments[segments_to_merge[1]].type, x_start, x_end, value))
            else
                push!(consolidated, segments[idx-1])
            end

            segments_to_merge = [idx]
        end
        return consolidated
    end
end
