/******************************************************************************
 *
 * Copyright (c) 2019, the Perspective Authors.
 *
 * This file is part of the Perspective library, distributed under the terms of
 * the Apache License 2.0.  The full license can be found in the LICENSE file.
 *
 */

#include <perspective/first.h>
#include <perspective/data_slice.h>

namespace perspective {

template <typename CTX_T>
t_data_slice<CTX_T>::t_data_slice(std::shared_ptr<CTX_T> ctx,
    t_uindex start_row, t_uindex end_row, t_uindex start_col, t_uindex end_col,
    t_uindex row_offset, t_uindex col_offset,
    const std::vector<t_tscalar>& slice,
    const std::vector<std::vector<t_tscalar>>& column_names)
    : m_ctx(ctx)
    , m_start_row(start_row)
    , m_end_row(end_row)
    , m_start_col(start_col)
    , m_end_col(end_col)
    , m_row_offset(row_offset)
    , m_col_offset(col_offset)
    , m_slice(slice)
    , m_column_names(column_names) {
    m_stride = m_end_col - m_start_col;
}

template <typename CTX_T>
t_data_slice<CTX_T>::t_data_slice(std::shared_ptr<CTX_T> ctx,
    t_uindex start_row, t_uindex end_row, t_uindex start_col, t_uindex end_col,
    t_uindex row_offset, t_uindex col_offset,
    const std::vector<t_tscalar>& slice,
    const std::vector<std::vector<t_tscalar>>& column_names,
    const std::vector<t_uindex>& column_indices)
    : m_ctx(ctx)
    , m_start_row(start_row)
    , m_end_row(end_row)
    , m_start_col(start_col)
    , m_end_col(end_col)
    , m_row_offset(row_offset)
    , m_col_offset(col_offset)
    , m_slice(slice)
    , m_column_names(column_names)
    , m_column_indices(column_indices) {
    m_stride = m_end_col - m_start_col;
}

template <typename CTX_T>
t_data_slice<CTX_T>::~t_data_slice() {}

// Public API
template <typename CTX_T>
t_tscalar
t_data_slice<CTX_T>::get(t_uindex ridx, t_uindex cidx) const {
    ridx += m_row_offset;
    t_uindex idx = get_slice_idx(ridx, cidx);
    t_tscalar rv;
    if (idx >= m_slice.size()) {
        rv.clear();
    } else {
        rv = m_slice.operator[](idx);
    }
    return rv;
}

template <typename CTX_T>
std::vector<t_tscalar>
t_data_slice<CTX_T>::get_pkeys(t_uindex ridx, t_uindex cidx) const {
    std::pair<t_uindex, t_uindex> pair{ridx, cidx};
    std::vector<std::pair<t_uindex, t_uindex>> vec{pair};
    return m_ctx->get_pkeys(vec);
}

template <typename CTX_T>
std::vector<t_tscalar>
t_data_slice<CTX_T>::get_column_slice(t_uindex cidx) const {
    std::vector<t_tscalar> column_data;
    column_data.reserve(m_end_row);

    for (t_uindex ridx = 0; ridx < m_end_row; ++ridx) {
        ridx += m_row_offset;
        t_tscalar value = get(ridx, cidx);
        column_data.push_back(value);
    }

    return column_data;
}

template <typename CTX_T>
std::vector<t_tscalar>
t_data_slice<CTX_T>::get_row_path(t_uindex ridx) const {
    return m_ctx->unity_get_row_path(ridx);
}

template <typename CTX_T>
t_uindex
t_data_slice<CTX_T>::num_rows() const {
    return m_end_row - m_start_row;
}

// Getters
template <typename CTX_T>
std::shared_ptr<CTX_T>
t_data_slice<CTX_T>::get_context() const {
    return m_ctx;
}

template <typename CTX_T>
const std::vector<t_tscalar>&
t_data_slice<CTX_T>::get_slice() const {
    return m_slice;
}

template <typename CTX_T>
const std::vector<std::vector<t_tscalar>>&
t_data_slice<CTX_T>::get_column_names() const {
    return m_column_names;
}

template <typename CTX_T>
const std::vector<t_uindex>&
t_data_slice<CTX_T>::get_column_indices() const {
    return m_column_indices;
}

template <typename CTX_T>
bool
t_data_slice<CTX_T>::is_column_only() const {
    return false;
}

template <>
bool
t_data_slice<t_ctx2>::is_column_only() const {
    auto config = m_ctx->get_config();
    return config.is_column_only();
}

template <typename CTX_T>
t_uindex
t_data_slice<CTX_T>::get_stride() const {
    return m_stride;
}

template <typename CTX_T>
t_uindex
t_data_slice<CTX_T>::get_row_offset() const {
    return m_row_offset;
}

template <typename CTX_T>
t_uindex
t_data_slice<CTX_T>::get_col_offset() const {
    return m_col_offset;
}

template <typename CTX_T>
t_get_data_extents
t_data_slice<CTX_T>::get_data_extents() const {
    auto nrows = m_ctx->get_row_count();
    auto ncols = m_ctx->get_column_count();
    t_get_data_extents ext = sanitize_get_data_extents(
        nrows, ncols, m_start_row, m_end_row, m_start_col, m_end_col);
    return ext;
}

// Private
template <typename CTX_T>
t_uindex
t_data_slice<CTX_T>::get_slice_idx(t_uindex ridx, t_uindex cidx) const {
    t_uindex idx = (ridx - m_start_row) * m_stride + (cidx - m_start_col);
    return idx;
}

// Explicitly instantiate data slice for each context
template class t_data_slice<t_ctxunit>;
template class t_data_slice<t_ctx0>;
template class t_data_slice<t_ctx1>;
template class t_data_slice<t_ctx2>;
} // end namespace perspective