#include "route.h"

#include <maps/wikimap/mapspro/libs/masstransit/masstransit.h>
#include <maps/wikimap/mapspro/libs/masstransit/time_zone.h>

namespace maps::wiki::masstransit {

namespace {

std::string
operatorRole(FtType ftType)
{
    switch (ftType) {
        case FtType::TransportBusRoute:
        case FtType::TransportTrolleybusRoute:
        case FtType::TransportMinibusRoute:
            return role::ASSIGNED_BUS;

        case FtType::TransportTramRoute:
            return role::ASSIGNED_TRAM;

        case FtType::TransportWaterwayRoute:
            return role::ASSIGNED_WATERWAY;

        case FtType::TransportMetroLine:
        case FtType::TransportMetroCableLine:
        case FtType::TransportMetroTramLine:
        case FtType::TransportMetroMonorailLine:
        case FtType::TransportMetroBusLine:
        case FtType::TransportMetroFunicularLine:
            return role::ASSIGNED_METRO;

        default:
            throw maps::RuntimeError() << "Unsupported route ft_type: "
                << static_cast<typename std::underlying_type<FtType>::type>(ftType);
    }
}

const std::string COLOR_PREFIX = "color=";

std::string
style(const std::string& color)
{
    if (color.empty()) {
        return color;
    }
    return COLOR_PREFIX + color;
}

} // namespace

YmapsdfRouteHandler::YmapsdfRouteHandler(Masstransit& masstransit)
    : YmapsdfObjectHandler(masstransit, masstransit.routes)
{ }

std::vector<FtType>
YmapsdfRouteHandler::ftTypes() const
{
    return {
        FtType::TransportBusRoute,
        FtType::TransportTrolleybusRoute,
        FtType::TransportTramRoute,
        FtType::TransportMinibusRoute,
        FtType::TransportMetroLine,
        FtType::TransportWaterwayRoute,
        FtType::TransportMetroCableLine,
        FtType::TransportMetroTramLine,
        FtType::TransportMetroMonorailLine,
        FtType::TransportMetroBusLine,
        FtType::TransportMetroFunicularLine
    };
}

StringVector
YmapsdfRouteHandler::attrs() const
{
    return {attr::COLOR};
}

StringVector
YmapsdfRouteHandler::rolesToMasters() const
{
    return {
        role::ASSIGNED_METRO,
        role::ASSIGNED_BUS,
        role::ASSIGNED_TRAM,
        role::ASSIGNED_WATERWAY
    };
}

void
YmapsdfRouteHandler::addObject(const pqxx::row& tuple)
{
    auto route = std::make_shared<Route>();

    const auto ftType = getAttr<FtType>(tuple, ymapsdf::FT_TYPE_ID);
    route->routeId = getAttr<DBID>(tuple, ymapsdf::ID);
    route->ftType = ftType;
    route->operatorId = getAttr<DBID>(tuple, operatorRole(ftType), 0);
    route->name = getAttr<std::string>(tuple, ymapsdf::NAME, "");
    const auto color = getAttr<std::string>(tuple, attr::COLOR, "");
    route->style = style(color);

    const auto mtrId = getAttr<std::string>(tuple, ymapsdf::SOURCE_ID, std::to_string(route->routeId));
    idMap().add(route->routeId, mtrId, MtrType::Route);

    insert(route->routeId, route);
}

MtrRouteHandler::MtrRouteHandler(Masstransit& masstransit)
    : MtrObjectHandler(masstransit, masstransit.routes)
{ }

void
MtrRouteHandler::writeObject(StreamMap& ostreams, const Object& object)
{
    const auto& route = dynamic_cast<const Route&>(object);
    auto& ostream = ostreams[fileNames().front()];

    const auto& operatorPoint = masstransit_.operators[route.operatorId].point;

    ostream
        << idMap().getMtrId(route.routeId) << FIELD_SEPARATOR
        << toString(route.ftType) << FIELD_SEPARATOR
        << route.name << FIELD_SEPARATOR
        << route.style << FIELD_SEPARATOR
        << route.uri << FIELD_SEPARATOR
        << timeZoneName(operatorPoint) << std::endl;
}

} // namespace maps::wiki::masstransit
