CLOUDACCESSID = "<ENTER-CLOUDACCESSID>"
CLOUDKEY = "<ENTER-CLOUDKEY>"
CLOUDPOOL = "<ENTER-CLOUDPOOL>"

print(
    "#################################################################################"
)
print("                       Cloud REST API Sample")
import gurobipy as gp
import requests
import json
import time
import sys

env = None
model = None

# curl -X POST "https://cloud.gurobi.com/api/v2/pools/<pool name>/machines" -H  "accept: application/json" -H
# "X-GUROBI-ACCESS-ID: <access code> -H  "X-GUROBI-SECRET-KEY: <secret key>"
urlCloud = "https://cloud.gurobi.com/api/v2/"

print("1. Make sure the Cloud Pool is started...")
response = requests.post(
    urlCloud + "pools/" + CLOUDPOOL + "/machines",
    headers={
        "Content-Type": "application/json",
        "Accept": "application/json",
        "X-GUROBI-ACCESS-ID": CLOUDACCESSID,
        "X-GUROBI-SECRET-KEY": CLOUDKEY,
    },
)

print("2. TODO: Run code to prepare your data here ...")
categories, minNutrition, maxNutrition = gp.multidict(
    {
        "calories": [1800, 2200],
        "protein": [91, gp.GRB.INFINITY],
        "fat": [0, 65],
        "sodium": [0, 1779],
    }
)
foods, cost = gp.multidict(
    {
        "hamburger": 2.49,
        "chicken": 2.89,
        "hot dog": 1.50,
        "fries": 1.89,
        "macaroni": 2.09,
        "pizza": 1.99,
        "salad": 2.49,
        "milk": 0.89,
        "ice cream": 1.59,
    }
)
# Nutrition values for the foods
nutritionValues = {
    ("hamburger", "calories"): 410,
    ("hamburger", "protein"): 24,
    ("hamburger", "fat"): 26,
    ("hamburger", "sodium"): 730,
    ("chicken", "calories"): 420,
    ("chicken", "protein"): 32,
    ("chicken", "fat"): 10,
    ("chicken", "sodium"): 1190,
    ("hot dog", "calories"): 560,
    ("hot dog", "protein"): 20,
    ("hot dog", "fat"): 32,
    ("hot dog", "sodium"): 1800,
    ("fries", "calories"): 380,
    ("fries", "protein"): 4,
    ("fries", "fat"): 19,
    ("fries", "sodium"): 270,
    ("macaroni", "calories"): 320,
    ("macaroni", "protein"): 12,
    ("macaroni", "fat"): 10,
    ("macaroni", "sodium"): 930,
    ("pizza", "calories"): 320,
    ("pizza", "protein"): 15,
    ("pizza", "fat"): 12,
    ("pizza", "sodium"): 820,
    ("salad", "calories"): 320,
    ("salad", "protein"): 31,
    ("salad", "fat"): 12,
    ("salad", "sodium"): 1230,
    ("milk", "calories"): 100,
    ("milk", "protein"): 8,
    ("milk", "fat"): 2.5,
    ("milk", "sodium"): 125,
    ("ice cream", "calories"): 330,
    ("ice cream", "protein"): 8,
    ("ice cream", "fat"): 10,
    ("ice cream", "sodium"): 180,
}


# Return a boolean thatis true when the server is ready:
def waitForPoolReady():
    ctr = 0
    bReady = False
    while ctr < 120 and bReady == False:
        time.sleep(1)
        ctr = ctr + 1  # <-- Avoid looping forever, just to be safe
        response = requests.get(
            urlCloud + "pools/" + CLOUDPOOL + "/machines",
            headers={
                "Content-Type": "application/json",
                "Accept": "application/json",
                "X-GUROBI-ACCESS-ID": CLOUDACCESSID,
                "X-GUROBI-SECRET-KEY": CLOUDKEY,
            },
        )
        if response.status_code == 200:
            state = ""
            serverInfo = json.loads(response.content)
            try:
                state = serverInfo["computeServers"][0]["state"]
                print("   state = " + state)
                if state == "running" or state == "idle":
                    bReady = True
            except Exception as e:
                break
        else:
            break
    return bReady


bReady = False
if response.status_code == 200:
    bReady = True
    print("   pool is ready ... ")
else:
    if response.status_code == 202:
        print("   pool is starting ... ")
        #########
        # You can  this step. Then the following Env call will block until the pool is running.
        bReady = waitForPoolReady()
        #########
    else:
        print("   error starting pool. Error status returned from post request.")
        sys.exit(-1)

if bReady != True:
    print("   failed to start pool.")
    sys.exit(-1)

print("3. Define the model:")
options = {
    "CloudAccessID": CLOUDACCESSID,
    "CloudSecretKey": CLOUDKEY,
    "CloudPool": CLOUDPOOL,
}
with gp.Env(params=options) as env, gp.Model(env=env) as model:
    buy = model.addVars(foods, name="buy")
    model.setObjective(buy.prod(cost), gp.GRB.MINIMIZE)
    model.addConstrs(
        (
            gp.quicksum(nutritionValues[f, c] * buy[f] for f in foods)
            == [minNutrition[c], maxNutrition[c]]
            for c in categories
        ),
        "_",
    )
    print("4. Solve the model:")
    model.optimize()
    print("5. TODO: Do something with the solution here.")
print("All done.")
