struct Assays
    count::NamedArray
    norm_count::NamedArray
    scaled_count::NamedArray
    feature_data::DataFrame
    var_features::Array{String,1}
    name::String
end

struct Reductions
    name::String
    cell_coordinates::DataFrame
    feature_coordinates::DataFrame
    key::String
    standard_deviation::Array{Float32,1}
    assay_used::String
    misc::AbstractArray
end
 
struct Pissaro
    assays::Dict{String, Assays}
    reductions::Dict{String, Reductions}
    cell_data::DataFrame
    default_assay::String    
    default_ident::String
end

function Base.show(io::IO, m::Pissaro) 
    println("A PissaroObject with:")
    println(length(m.assays), " assays")
    println(nrow(m.cell_data), " cells")
    println("active assay: ", m.default_assay, " with ", size(m.assays[m.default_assay].count)[1], " features")
end

function Base.show(io::IO, m::Assays) 
    print("assay ", m.name)
end

function GetCount(X::Pissaro; assay::String = X.default_assay, named::Bool = true)
    if named
        GetAssay(X, assay = assay).count
    else    
        GetAssay(X, assay = assay).count.array
    end
end

function GetNormCount(X::Pissaro; assay::String = X.default_assay, named::Bool = true)
    if named
        GetAssay(X, assay = assay).norm_count
    else    
        GetAssay(X, assay = assay).norm_count.array
    end
end

function GetScaledCount(X::Pissaro; assay::String = X.default_assay, named::Bool = true)
    if named
        GetAssay(X, assay = assay).scaled_count
    else    
        GetAssay(X, assay = assay).scaled_count.array
    end    
end

function GetFeatureData(X::Pissaro; assay::String = X.default_assay)
    GetAssay(X, assay = assay).feature_data
end

function GetAssay(X::Pissaro; assay::String = X.default_assay)
    in(assay, keys(X.assays)) ? X.assays[assay] : error(assay, " assay not present in PissaroObject")
end

function GetVariableFeatures(X::Pissaro; assay::String = X.default_assay)
    GetAssay(X, assay = assay).var_features
end
