#include "object_predicates.h"
#include <maps/wikimap/mapspro/services/editor/src/configs/config.h>
#include <maps/wikimap/mapspro/services/editor/src/objects/object.h>

namespace maps
{
namespace wiki
{

void
IsPartOfSimpleContourObject::setSimple(TOid oid)
{
    results_.insert({oid, ContourObjectStructure::Simple});
}

void
IsPartOfSimpleContourObject::setNotSimple(TOid oid)
{
    results_.insert({oid, ContourObjectStructure::NotSimple});
}

IsPartOfSimpleContourObject::ContourObjectStructure
IsPartOfSimpleContourObject::result(TOid oid) const
{
    auto it = results_.find(oid);
    return
        it == results_.end()
        ? ContourObjectStructure::Unknown
        : it->second;
}

bool
IsPartOfSimpleContourObject::operator ()(const GeoObject* obj)
{
    auto currentResult = result(obj->id());
    if (currentResult != ContourObjectStructure::Unknown) {
        return currentResult == ContourObjectStructure::Simple;
    }
    const auto& contourObjectsDefs = cfg()->editor()->contourObjectsDefs();
    const GeoObject* element = nullptr;
    const GeoObject* contour = nullptr;
    auto contourObjectPartType = contourObjectsDefs.partType(obj->categoryId());
    const RelativesLimit limit { 1, RelativesLimit::PerRole};
    switch (contourObjectPartType) {
        case ContourObjectsDefs::PartType::LinearElement :
            element = obj;
            break;
        case ContourObjectsDefs::PartType::Contour :
            {
                //If contour object passed, get it's element
                //and report NotSimple if element is not single
                contour = obj;
                const auto& contourDef = contourObjectsDefs.contourDef(obj->categoryId());
                auto elements = contour->slaveRelations().range(contourDef.contour.linearElement.roleId, limit);
                if (!elements || elements->size() != 1) {
                    setNotSimple(contour->id());
                    return false;
                }
                element = elements->begin()->relative();
                break;
            }
        default :
            return false;
    }
    //Get contours (_fc) objects owning the element
    //If it is not single, report NotSimple
    const auto& contourDef = contourObjectsDefs.contourDef(obj->categoryId());
    auto contours = element->masterRelations().range(contourDef.contour.linearElement.roleId, limit);
    if (!contours || contours->size() != 1) {
        setNotSimple(element->id());
        return false;
    }
    contour = contours->begin()->relative();
    //Continue with returned contour and check it's relations
    //If many or none elments in it - report NotSimple
    auto elements = contour->slaveRelations().range(contourDef.contour.linearElement.roleId, limit);
    if (!elements || elements->size() != 1) {
        setNotSimple(contour->id());
        setNotSimple(element->id());
        return false;
    }
    //If contour contained by many contour objects, report not simole
    auto contourObjs = contour->masterRelations().range(contourDef.contour.roleId, limit);
    if (!contourObjs || contourObjs->size() != 1) {
        setNotSimple(contour->id());
        setNotSimple(element->id());
        return false;
    }
    const auto* contourObj = contourObjs->begin()->relative();
    //Continue with single contour object and check how many
    //contour does it contain
    auto slaveContours = contourObj->slaveRelations().range(contourDef.contour.roleId, limit);
    if (!slaveContours || slaveContours->size() != 1) {
        setNotSimple(contour->id());
        setNotSimple(element->id());
        return false;
    }
    setSimple(contour->id());
    setSimple(element->id());
    return true;
}

}//wiki
}//maps
