/******************************************************************************
 *
 * 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.
 *
 */
#ifdef PSP_ENABLE_PYTHON

#include <perspective/base.h>
#include <perspective/binding.h>
#include <perspective/python/base.h>
#include <perspective/python/context.h>

namespace perspective {
namespace binding {

/******************************************************************************
 *
 * Context API
 */

template <>
std::shared_ptr<t_ctx0>
make_context(std::shared_ptr<Table> table, std::shared_ptr<t_schema> schema,
    std::shared_ptr<t_view_config> view_config, const std::string& name) {
    auto columns = view_config->get_columns();
    auto filter_op = view_config->get_filter_op();
    auto fterm = view_config->get_fterm();
    auto sortspec = view_config->get_sortspec();
    auto computed_columns = view_config->get_computed_columns();

    auto cfg = t_config(columns, fterm, filter_op, computed_columns);
    auto ctx0 = std::make_shared<t_ctx0>(*(schema.get()), cfg);
    ctx0->init();
    ctx0->sort_by(sortspec);

    auto pool = table->get_pool();
    auto gnode = table->get_gnode();
    pool->register_context(gnode->get_id(), name, ZERO_SIDED_CONTEXT,
        reinterpret_cast<std::uintptr_t>(ctx0.get()));

    return ctx0;
}

template <>
std::shared_ptr<t_ctx1>
make_context(std::shared_ptr<Table> table, std::shared_ptr<t_schema> schema,
    std::shared_ptr<t_view_config> view_config, const std::string& name) {
    auto row_pivots = view_config->get_row_pivots();
    auto aggspecs = view_config->get_aggspecs();
    auto filter_op = view_config->get_filter_op();
    auto fterm = view_config->get_fterm();
    auto sortspec = view_config->get_sortspec();
    auto row_pivot_depth = view_config->get_row_pivot_depth();
    auto computed_columns = view_config->get_computed_columns();

    auto cfg = t_config(row_pivots, aggspecs, fterm, filter_op, computed_columns);
    auto ctx1 = std::make_shared<t_ctx1>(*(schema.get()), cfg);

    ctx1->init();
    ctx1->sort_by(sortspec);

    auto pool = table->get_pool();
    auto gnode = table->get_gnode();
    pool->register_context(gnode->get_id(), name, ONE_SIDED_CONTEXT,
        reinterpret_cast<std::uintptr_t>(ctx1.get()));

    if (row_pivot_depth > -1) {
        ctx1->set_depth(row_pivot_depth - 1);
    } else {
        ctx1->set_depth(row_pivots.size());
    }

    return ctx1;
}

template <>
std::shared_ptr<t_ctx2>
make_context(std::shared_ptr<Table> table, std::shared_ptr<t_schema> schema,
    std::shared_ptr<t_view_config> view_config, const std::string& name) {
    bool column_only = view_config->is_column_only();
    auto row_pivots = view_config->get_row_pivots();
    auto column_pivots = view_config->get_column_pivots();
    auto aggspecs = view_config->get_aggspecs();
    auto filter_op = view_config->get_filter_op();
    auto fterm = view_config->get_fterm();
    auto sortspec = view_config->get_sortspec();
    auto col_sortspec = view_config->get_col_sortspec();
    auto row_pivot_depth = view_config->get_row_pivot_depth();
    auto column_pivot_depth = view_config->get_column_pivot_depth();
    auto computed_columns = view_config->get_computed_columns();

    t_totals total = sortspec.size() > 0 ? TOTALS_BEFORE : TOTALS_HIDDEN;

    auto cfg = t_config(
        row_pivots, column_pivots, aggspecs, total, fterm, filter_op, computed_columns, column_only);
    auto ctx2 = std::make_shared<t_ctx2>(*(schema.get()), cfg);

    ctx2->init();

    auto pool = table->get_pool();
    auto gnode = table->get_gnode();
    pool->register_context(gnode->get_id(), name, TWO_SIDED_CONTEXT,
        reinterpret_cast<std::uintptr_t>(ctx2.get()));

    if (row_pivot_depth > -1) {
        ctx2->set_depth(t_header::HEADER_ROW, row_pivot_depth - 1);
    } else {
        ctx2->set_depth(t_header::HEADER_ROW, row_pivots.size());
    }

    if (column_pivot_depth > -1) {
        ctx2->set_depth(t_header::HEADER_COLUMN, column_pivot_depth - 1);
    } else {
        ctx2->set_depth(t_header::HEADER_COLUMN, column_pivots.size());
    }

    if (sortspec.size() > 0) {
        ctx2->sort_by(sortspec);
    }

    if (col_sortspec.size() > 0) {
        ctx2->column_sort_by(col_sortspec);
    }

    return ctx2;
}

} //namespace binding
} //namespace perspective

#endif