

#include "Instance.h"




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

    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]));
    }

    //Calculate total prizes
    total_prizes = 0;
    for (int i = 1; i < numNodes; ++i) {
        total_prizes += prizes[i];
    }

}


Instance::Instance(std::string pathToInstance, bool isRoundingInteger)
{
    std::string content, content2, content3;
    double serviceTimeData = 0.;

    // Read INPUT dataset
    std::ifstream inputFile(pathToInstance);
    if (inputFile.is_open())
    {
        getline(inputFile, content);
        getline(inputFile, content);
        getline(inputFile, content);
        for (inputFile >> content; content != "NODE_COORD_SECTION"; inputFile >> content)
        {
            if (content == "DIMENSION") { inputFile >> content2 >> numCustomers; numCustomers--; } // Need to substract the depot from the number of nodes
            else if (content == "EDGE_WEIGHT_TYPE")	inputFile >> content2 >> content3;
            else if (content == "CAPACITY")	inputFile >> content2 >> vehicleCapacity;
            //else if (content == "DISTANCE") { inputFile >> content2 >> durationLimit; isDurationConstraint = true; }
            //else if (content == "SERVICE_TIME")	inputFile >> content2 >> serviceTimeData;
            else throw std::string("Unexpected data in input file: " + content);
        }
        if (numCustomers <= 0) throw std::string("Number of nodes is undefined");
        if (vehicleCapacity == 1.e30) throw std::string("Vehicle capacity is undefined");

        numNodes = numCustomers + 1;

        std::vector<double>x_coords = std::vector<double>(numNodes);
        std::vector<double>y_coords = std::vector<double>(numNodes);
        demand = std::vector<int>(numNodes);
        //service_time = std::vector<double>(nbClients + 1);

        // Reading node coordinates
        // depot must be the first element
        // 		- i = 0 in the for-loop below, or
        // 		- node_number = 1 in the .vrp file
        // customers are
        // 		- i = 1, 2, ..., nbClients in the for-loop below, or
        // 		- node_number = 2, 3, ..., nb_Clients in the .vrp file
        int node_number;
        for (int i = 0; i <= numCustomers; i++)
        {
            inputFile >> node_number >> x_coords[i] >> y_coords[i];
            if (node_number != i + 1) throw std::string("The node numbering is not in order.");
        }

        // Reading demand information
        inputFile >> content;
        if (content != "DEMAND_SECTION") throw std::string("Unexpected data in input file: " + content);
        for (int i = 0; i <= numCustomers; i++)
        {
            inputFile >> content >> demand[i];
            //service_time[i] = (i == 0) ? 0. : serviceTimeData;
        }

        // 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]);
            }
        }

        // Reading depot information (in all current instances the depot is represented as node 1, the program will return an error otherwise)
        inputFile >> content >> content2 >> content3 >> content3;
        if (content != "DEPOT_SECTION") throw std::string("Unexpected data in input file: " + content);
        if (content2 != "1") throw std::string("Expected depot index 1 instead of " + content2);
        if (content3 != "EOF") throw std::string("Unexpected data in input file: " + content3);
    }
    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]));
    }


}



// Other necessary properties and methods of the Instance object
