/*******************************************************************************
 * Copyright (C) 2014  Stefan Schroeder
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 3.0 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public 
 * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
 ******************************************************************************/
package jsprit.instance.reader;


import jsprit.core.problem.VehicleRoutingProblem;
import jsprit.core.problem.VehicleRoutingProblem.FleetSize;
import jsprit.core.problem.job.Service;
import jsprit.core.problem.solution.route.activity.TimeWindow;
import jsprit.core.problem.vehicle.Vehicle;
import jsprit.core.problem.vehicle.VehicleImpl;
import jsprit.core.problem.vehicle.VehicleTypeImpl;
import jsprit.core.util.Coordinate;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;


public class LuiShenReader {

	private static Logger logger = LogManager.getLogger(LuiShenReader.class);
	
	private final VehicleRoutingProblem.Builder vrpBuilder;

	private double coordProjectionFactor = 1;

	public LuiShenReader(VehicleRoutingProblem.Builder vrpBuilder) {
		super();
		this.vrpBuilder = vrpBuilder;
	}
	
	/**
	 * Reads input files to build Liu Shen problem.
	 * 
	 * <p>The instance-file is a solomon file. The vehicle-file is a
	 * txt-file that has the following columns:
	 * <p>Vehicle;Capacity;Cost_a;Cost_b;Cost_c
	 * <p>Concrete vehicleType:
	 * <p>A;100;300;60;30
	 * 
	 * <p>In the example above, the vehicle-type with typeId A has
	 * a capacity of 100, and fixed costs of 100 in cost scenario "a",
	 * 300 in "b" and 30 in "c". 

	 * @param instanceFile is a solomon-instance-file
	 * @param vehicleFile
	 * @param costScenario is either "a", "b" or "c"
	 */
	public void read(String instanceFile, String vehicleFile, String costScenario){
		vrpBuilder.setFleetSize(FleetSize.INFINITE);
		BufferedReader reader = getReader(instanceFile);
		int counter = 0;
		String line = null;
		while((line = readLine(reader)) != null){
			line = line.replace("\r", "");
			line = line.trim();
			String[] tokens = line.split(" +");
			counter++;
			if(counter > 9){
                if(tokens.length < 7) continue;
				Coordinate coord = makeCoord(tokens[1],tokens[2]);
				String customerId = tokens[0];
				int demand = Integer.parseInt(tokens[3]);
				double start = Double.parseDouble(tokens[4])*coordProjectionFactor ;
				double end = Double.parseDouble(tokens[5])*coordProjectionFactor;
				double serviceTime = Double.parseDouble(tokens[6])*coordProjectionFactor;
				if(counter == 10){
					createVehicles(vehicleFile,costScenario,customerId,coord,start,end);
				}
				else{
					Service service = Service.Builder.newInstance("" + counter).addSizeDimension(0, demand).setCoord(coord).setLocationId(customerId).setServiceTime(serviceTime)
							.setTimeWindow(TimeWindow.newInstance(start, end)).build();
					vrpBuilder.addJob(service);
				}
			}
		}
		close(reader);
	}

	private void createVehicles(String vehicleFileName, String costScenario, String locationId, Coordinate coord, double start, double end) {
		BufferedReader reader = getReader(vehicleFileName);
		
		int costScenarioColumn = getCostScenarioColumn(costScenario);
		int vehicleIdColumn = 0;
		int capacityColumn = 1;
		
		
		
		boolean firstLine = true;
		String line = null;
		while((line = readLine(reader)) != null){
			if(firstLine){
				firstLine = false;
				continue;
			}
			String[] tokens = line.split(";");
			String vehicleId = tokens[vehicleIdColumn];
			int capacity = Integer.parseInt(tokens[capacityColumn]);
			int fixCost = Integer.parseInt(tokens[costScenarioColumn]);
			
			VehicleTypeImpl.Builder typeBuilder = VehicleTypeImpl.Builder.newInstance(vehicleId).addCapacityDimension(0, capacity);
			typeBuilder.setFixedCost(fixCost).setCostPerDistance(1.0);
			
			VehicleTypeImpl type = typeBuilder.build();
			
			Vehicle reprVehicle = VehicleImpl.Builder.newInstance(vehicleId).setEarliestStart(start).setLatestArrival(end).
					setStartLocationId(locationId).setStartLocationCoordinate(coord).setType(type).build();
			
			vrpBuilder.addVehicle(reprVehicle);
			
		}
		close(reader);	
	}
	
	private int getCostScenarioColumn(String costScenario) {
		if(costScenario.equals("a")){
			return 2;
		}
		else if(costScenario.equals("b")){
			return 3;
		}
		else if(costScenario.equals("c")){
			return 4;
		}
		throw new IllegalStateException("costScenario " + costScenario + " not known");
	}
	
	public void setCoordProjectionFactor(double coordProjectionFactor) {
		this.coordProjectionFactor = coordProjectionFactor;
	}

	private void close(BufferedReader reader)  {
		try {
			reader.close();
		} catch (IOException e) {
			e.printStackTrace();
			logger.error(e);
			System.exit(1);
		}
	}

	private String readLine(BufferedReader reader) {
		try {
			return reader.readLine();
		} catch (IOException e) {
			e.printStackTrace();
			logger.error(e);
			System.exit(1);
			return null;
		}
	}
	
	private Coordinate makeCoord(String xString, String yString) {
		double x = Double.parseDouble(xString);
		double y = Double.parseDouble(yString);
		return new Coordinate(x*coordProjectionFactor,y*coordProjectionFactor);
	}

	private BufferedReader getReader(String solomonFile) {
		BufferedReader reader = null;
		try {
			reader = new BufferedReader(new FileReader(solomonFile));
		} catch (FileNotFoundException e1) {
			e1.printStackTrace();
			logger.error(e1);
			System.exit(1);
		}
		return reader;
	}
}
