#pragma once
#include "poly_match.h"
#include <stdexcept>
#include <fstream>
#include <cassert>

namespace maps {
namespace wiki {
namespace autocart {

class Model {
public:
    virtual double predict(const AffineResult& result) const = 0;
};

class LinearModel : public Model {
    std::vector<double> weights;
public:
    LinearModel(const char* model_file_path) {
        std::ifstream model_file(model_file_path);

        if (!model_file) {
            throw std::logic_error("File with model not found (should be in data/linear.param)");
        }

        double weight;
        while (model_file >> weight) {
            weights.push_back(weight);
        }

        assert(weights.size() == 6);
    }

    double predict(const AffineResult& result) const override {
        AffineTransform transform = result.transform;
        double sum = weights[0] * fabs(transform.shift_x)
                   + weights[1] * fabs(transform.shift_y)
                   + weights[2] * fabs(transform.theta)
                   + weights[3] * fabs(1. - transform.scale)
                   + weights[4] * fabs(result.residual)
                   + weights[5];
        return 1. / (1. + exp(-sum));
    }
};

double calc_metric(const Polygon& poly_real, const Polygon& poly_gen,
                   const OptimizationParams& params, Model* model) {
    AffineResult result = find_affine(poly_real, poly_gen, params);
    return model->predict(result);
}



} // namespace autocart
} // namespace wiki
} // namespace maps
