"""
    filtering(;input::AbstractString="", featurelist::AbstractString="", samplelist::AbstractString="", thr1::Number=0.0, thr2::Number=0.0, direct1::AbstractString="+", direct2::AbstractString="+", outdir::AbstractString=".")

This function filters the genes by some standards such as mean or variance of the genes.

Input Arguments
---------
- `input` : A Julia Binary file generated by `csv2bin` function.
- `featurelist` : A row-wise summary data such as. The CSV files are generated by `csv2bin` function.
- `thr` : The threshold to reject low-signal feature.
- `outdir` : The directory specified the directory you want to save the result.

Output Files
---------
- `filtered.zst` : Filtered binary file.
"""
function filtering(;input::AbstractString="", featurelist::AbstractString="", samplelist::AbstractString="", thr1::Number=0.0, thr2::Number=0.0, direct1::AbstractString="+", direct2::AbstractString="+", outdir::AbstractString=".")
    # Feature selection
    if featurelist == "" && samplelist == ""
        error("At least featurelist or samplelist must be specified")
    end
    if featurelist != ""
        featurevec = readcsv(featurelist) # e.g., HVG_pval.csv
    else
        featurevec = Nothing
    end
    if samplelist != ""
        samplevec = readcsv(samplelist) # e.g., Sample_NoCounts.csv
    else
        samplevec = Nothing
    end

    # Setting
    if thr1 isa String
        thr1 = parse(Float64, thr1)
    end
    if thr2 isa String
        thr2 = parse(Float64, thr2)
    end
    N, M = nm(input)
    tmpN = zeros(UInt32, 1)
    tmpM = zeros(UInt32, 1)
    x = zeros(UInt32, M)
    outfile1 = joinpath(outdir, "filtered.zst")
    outfile2 = joinpath(outdir, "filteredFeature.csv")
    outfile3 = joinpath(outdir, "filteredSample.csv")

    # Search
    nr, nc, ix1, ix2 = rcfilter(input, featurevec, samplevec, thr1, thr2, direct1, direct2)
    nr = UInt32(nr)
    nc = UInt32(nc)

    # save
    writecsv(outfile2, ix1)
    writecsv(outfile3, ix2)
    open(outfile1, "w") do file1
        stream1 = ZstdCompressorStream(file1)
        write(stream1, nr) # by rcfilter
        write(stream1, nc) # by rcfilter
        open(input , "r") do file2
            stream2 = ZstdDecompressorStream(file2)
            read!(stream2, tmpN)
            read!(stream2, tmpM)
            progress = Progress(N)
            for n = 1:N
                next!(progress)
                read!(stream2, x)
                    if ix1[n] == 1
                        write(stream1, x[ix2])
                    end
            end
            close(stream2)
        end
        close(stream1)
    end
    print("\n")
end

function rcfilter(input, featurevec, samplevec, thr1, thr2, direct1, direct2)
    ncol = 0
    nrow = 0
    N, M = nm(input)
    idx1 = zeros(UInt32, N)
    idx2 = Int64[]
    tmpN = zeros(UInt32, 1)
    tmpM = zeros(UInt32, 1)
    # Row-wise filter
    if featurevec != Nothing
        open(input, "r") do file
            stream = ZstdDecompressorStream(file)
            read!(stream, tmpN)
            read!(stream, tmpM)
            for n = 1:N
                if direct1 == "+"
                    if featurevec[n] >= thr1
                        nrow += 1
                        idx1[n] = 1
                    end
                elseif direct1 == "-"
                    if featurevec[n] <= thr1
                        nrow += 1
                        idx1[n] = 1
                    end
                end
            end
            close(stream)
        end
    else
        nrow = N
        for n = 1:N
            idx1[n] = 1
        end
    end

    # Column-wise filter
    if samplevec != Nothing
        for m=1:M
            if direct2 == "+"
                if(samplevec[m] >= thr2)
                    ncol += 1
                    push!(idx2, m)
                end
            elseif direct2 == "-"
                if(samplevec[m] <= thr2)
                    ncol += 1
                    push!(idx2, m)
                end
            end
        end
    else
        ncol = M
        for m = 1:M
            push!(idx2, m)
        end
    end
    nrow, ncol, idx1, idx2
end
