

#include "Instance.h"




// Constructor
Instance::Instance(int numCustomers, int vehicleCapacity, const std::vector<int>& demand, const std::vector<float>& startTW, 
    const std::vector<float>& endTW, const std::vector<float>& serviceTime, const std::vector<std::vector<float>>& nodePositions)
    : numCustomers(numCustomers), vehicleCapacity(vehicleCapacity), demand(demand), startTW(startTW), endTW(endTW), serviceTime(serviceTime), nodePositions(nodePositions)
{

    numNodes = numCustomers + 1;

    // Check the size of the demand vector
    if (demand.size() != numNodes) {
        throw std::invalid_argument("Size of demand vector does not match number of customers!");
    }

    // Resize the distanceMatrix vector
    distanceMatrix.resize(numNodes, std::vector<float>(numNodes, 0.0f));

    // Calculate distance matrix
    for (int i = 0; i < numNodes; ++i) {
        for (int j = 0; j < numNodes; ++j) {
            distanceMatrix[i][j] = std::sqrt(std::pow(nodePositions[i][0] - nodePositions[j][0], 2) + std::pow(nodePositions[i][1] - nodePositions[j][1], 2));
        }
    }

    //Calaculate adj list
    for (int i = 0; i < numNodes; ++i) {
        adj.push_back(argsort(distanceMatrix[i]));
    }

    //Calaculate timeWindowWidth
    TW_Width.resize(numNodes);
    for (int i = 0; i < numNodes; ++i) {
        TW_Width[i] = endTW[i] - startTW[i];
    }

    // Check time windows
    for (int i = 1; i < numNodes; ++i) {
        if (endTW[i] + distanceMatrix[i][0] + serviceTime[i] > endTW[0]) {
            std::cout << "node " << endTW[0];
            throw std::invalid_argument("Time window end of customers need to be adjusted so that the depot is reached in time!");
        }
    }


}


Instance::Instance(std::string pathToInstance, bool isRoundingInteger)
{
    std::string line;

    // Read INPUT dataset
    std::ifstream inputFile(pathToInstance);
    if (inputFile.is_open())
    {
        getline(inputFile, line);
        getline(inputFile, line);
        getline(inputFile, line);

        // Read the vehicle information
        int vehicleNumber;
        getline(inputFile, line); // "NUMBER     CAPACITY"
        inputFile >> vehicleNumber >> vehicleCapacity;

        getline(inputFile, line);
        getline(inputFile, line);
        getline(inputFile, line);
        getline(inputFile, line);
        getline(inputFile, line);

        std::vector<double>x_coords = std::vector<double>();
        std::vector<double>y_coords = std::vector<double>();
        demand = std::vector<int>();
        startTW = std::vector<float>();
        endTW = std::vector<float>();
        serviceTime = std::vector<float>();

        int cust_no;
        float x_coord, y_coord;
        int cus_demand;
        float ready_time, due_date, service_time;

        while (std::getline(inputFile, line)) {
            if (line.empty()) continue; // Skip empty lines

            std::istringstream cust_stream(line);

            cust_stream >> cust_no >> x_coord >> y_coord >> cus_demand
                >> ready_time >> due_date >> service_time;

            x_coords.push_back(x_coord);
            y_coords.push_back(y_coord);
            demand.push_back(cus_demand);
            startTW.push_back(ready_time);
            endTW.push_back(due_date);
            serviceTime.push_back(service_time);
        }
        numNodes = x_coords.size();
        numCustomers = numNodes - 1;

        // Calculating 2D Euclidean Distance
        distanceMatrix = std::vector < std::vector< float > >(numCustomers + 1, std::vector <float>(numNodes));
        for (int i = 0; i <= numCustomers; i++)
        {
            for (int j = 0; j <= numCustomers; j++)
            {
                distanceMatrix[i][j] = std::sqrt(
                    (x_coords[i] - x_coords[j]) * (x_coords[i] - x_coords[j])
                    + (y_coords[i] - y_coords[j]) * (y_coords[i] - y_coords[j])
                );

                if (isRoundingInteger) distanceMatrix[i][j] = round(distanceMatrix[i][j]);
            }
        }

    }
    else
        throw std::string("Impossible to open instance file: " + pathToInstance);


    //Calaculate adj list
    for (int i = 0; i < numNodes; ++i) {
        adj.push_back(argsort(distanceMatrix[i]));
    }

    //Calaculate timeWindowWidth
    TW_Width.resize(numNodes);
    for (int i = 0; i < numNodes; ++i) {
        TW_Width[i] = endTW[i] - startTW[i];
    }

    // Check time windows
    for (int i = 1; i < numNodes; ++i) {
        if (endTW[i] + distanceMatrix[i][0] + serviceTime[i] > endTW[0]) {
            throw std::invalid_argument("Time window end of customers need to be adjusted so that the depot is reached in time!");
        }
    }

}



// Other necessary properties and methods of the Instance object
