source(paste0(wd.path, "/parameters.R"))
### initializations
assign_initial_values()

### main execution loop
print(Sys.time())
while(TRUE){
  vehicle.number = length(truck.routes)
  iteration = iteration + 1
  temp.counter = temp.counter + 1
  sol.feasibility = FALSE
  cost.found.in.last.move = 10e5
  current.cost = sum(route.costs)
  
  ### move application part
  destruction.degree = choose_destruction_degree("random-equal")
  move.res = choose_move(drone.routes, destruction.degree, include.drone)
  move.operator = move.res[[1]]
  vehicles = move.res[[2]]
  result = apply_move(move.operator, vns.parameter,
                        truck.routes, drone.routes, vehicles, destruction.degree)
  
  ### update part
  candidate.truck.routes = result[[1]]
  candidate.drone.routes = result[[2]]
  evaluate_move_result(candidate.truck.routes, candidate.drone.routes, vehicles)
  
  incumbent.sol = FALSE
  if(sol.feasibility){
    #solution approval or not
    cost.change = current.cost - cost.found.in.last.move
    if(cost.change >= 0 || runif(1) < exp(1)^(cost.change/temperature)){
      truck.routes = candidate.truck.routes
      drone.routes = candidate.drone.routes
      schedule = nsch
      current.cost = cost.found.in.last.move
      drone.vector = c(drone.vector,
                       sum(sapply(drone.routes, function(x) sum(x[,2]!=0))))
      cost.vector = c(cost.vector, current.cost-noise)
      #incumbent solution update
      if(cost.found.in.last.move < incumbent.cost){
        incumbent_sol_update(save.sols)
      }
      last.operator = move.operator
    }
  }

  # adjustment of simulated annealing parameters
  if(temp.counter >= temperature.length){
    temperature = round(temperature * cooling.ratio, 2)
    temp.counter = 0
    temperature.length = min(max.temperature.length,
                             round(temperature.length * (1 + TL.factor)))
  }
  
  if(!incumbent.sol){
    # if no incumbent or feasible solution is found in last iteration
    not.improving.turns = not.improving.turns + 1
    improve_strategy()
  }
  
  # update probabilities by move success
  if(sum(moves.used.in.segment) >= 100){
    update_after_segment()
  }
  
  # starting of drone assignments
  if(!include.drone){
    if((not.improving.turns == 200 ||
       (difftime(Sys.time(), starting.time, units = "mins") >= time.limit/4))){
      vrptr = truck.routes
      include_drone_delivery()
      # rr = add_drone_route(truck.routes, drone.routes)
      # truck.routes = rr[[1]]
      # drone.routes = rr[[2]]
      # plot_dronetruck(truck.routes, drone.routes)
    }
  }
  
  # time-limit stopping condition
  if(not.improving.turns == iteration.limit){
    print("iteration limit")
    print(paste("number of moves applied:  ", iteration))
    print(paste("number of changes applied:", total.changes))
    print(paste("time passed:",
                round(difftime(Sys.time(), starting.time, units = "secs"))))
    break()
  }else if((difftime(Sys.time(), starting.time, units = "mins") >= time.limit)){
    print("time limit")
    print(paste("number of moves applied:   ", iteration))
    print(paste("number of changes applied: ", total.changes))
    print(paste("not-improving-tours passed:", not.improving.turns))
    break()
  }
  last.move.operator = move.operator
}
