#include <osmium/osm.hpp>

#include "format.hpp"
#include "input-handler.hpp"
#include "osmdata.hpp"

input_handler_t::input_handler_t(osmium::Box const &bbox, bool append,
                                 osmdata_t const *osmdata)
: m_data(osmdata), m_bbox(bbox), m_append(append)
{}

void input_handler_t::node(osmium::Node const &node)
{
    if (m_type != osmium::item_type::node) {
        m_type = osmium::item_type::node;
        m_data->flush();
    }

    if (node.deleted()) {
        if (!m_append) {
            throw std::runtime_error{"Input file contains deleted objects but "
                                     "you are not in append mode."};
        }
        m_data->node_delete(node.id());
    } else {
        // if the node is not valid, then node.location.lat/lon() can throw.
        // we probably ought to treat invalid locations as if they were
        // deleted and ignore them.
        if (!node.location().valid()) {
            fmt::print(
                stderr,
                "WARNING: Node {} (version {}) has an invalid location and has "
                "been ignored. This is not expected to happen with recent "
                "planet files, so please check that your input is correct.\n",
                node.id(), node.version());

            return;
        }

        if (!m_bbox.valid() || m_bbox.contains(node.location())) {
            if (m_append) {
                m_data->node_modify(node);
            } else {
                m_data->node_add(node);
            }
            m_progress.add_node(node.id());
        }
    }
}

void input_handler_t::way(osmium::Way &way)
{
    if (m_type != osmium::item_type::way) {
        m_type = osmium::item_type::way;
        m_data->flush();
    }

    if (way.deleted()) {
        if (!m_append) {
            throw std::runtime_error{"Input file contains deleted objects but "
                                     "you are not in append mode."};
        }
        m_data->way_delete(way.id());
    } else {
        if (m_append) {
            m_data->way_modify(&way);
        } else {
            m_data->way_add(&way);
        }
    }
    m_progress.add_way(way.id());
}

void input_handler_t::relation(osmium::Relation const &rel)
{
    if (m_type != osmium::item_type::relation) {
        m_type = osmium::item_type::relation;
        m_data->flush();
    }

    if (rel.deleted()) {
        if (!m_append) {
            throw std::runtime_error{"Input file contains deleted objects but "
                                     "you are not in append mode."};
        }
        m_data->relation_delete(rel.id());
    } else {
        if (rel.members().size() > 32767) {
            return;
        }
        if (m_append) {
            m_data->relation_modify(rel);
        } else {
            m_data->relation_add(rel);
        }
    }
    m_progress.add_rel(rel.id());
}
