# Insert in Pyomo model (script) after "solve" command:

# if (results.solver.termination_condition == pyo.TerminationCondition.infeasibleOrUnbounded):
#     debug(instance)

# ---------------------------------------------------------------------------------------------------------------------

# Debugging function starts here:

import gurobipy as gr
import pyomo.environ as pe
import xlsxwriter


# debug-function
def debug(model):
    # write an instance for the model and for the debugger
    model.write("instance.mps", io_options={"symbolic_solver_labels": True})

    model.write("debug_instance.mps")

    # Count iterations in while-loop
    count = 0
    count_iter = 0

    # create the solver_parameters for writing our IIS into an ilp-file
    dopt = pe.SolverFactory('gurobi_persistent')
    dopt.set_instance(model)
    solver_parameters = "ResultFile=model.ilp"
    dopt.solve(model, options_string=solver_parameters)

    B = []
    Sets = []
    B2 = []
    K = []
    K1 = {}
    Index_Sets = {}
    Index = {}

    for c in model.component_objects(pe.Constraint):
        lowb = len(B)
        for i in c._index:
            if (c.dim() > 1):
                temp = []
                for se in c._implicit_subsets:
                    temp.append(se.getname())
                Index_Sets[c[i]] = str(temp)
                Sets.append(temp)
            else:
                Index_Sets[c[i]] = str(c.index_set())
                Sets.append(c.index_set())
            B2.append(c[i])
            K.append(c.getname())
            K1[c[i]] = c.getname()
            Index[c[i]] = i

    Name = {}

    for k in B2:
        try:
            Name[dopt.get_linear_constraint_attr(k, "ConstrName")] = k
        except AttributeError:
            Name[dopt.get_quadratic_constraint_attr(k, "QCName")] = k

    xlsx = xlsxwriter.Workbook("list.xlsx")
    xsheet = xlsx.add_worksheet()

    bold = xlsx.add_format({"bold": True})

    merge_format = xlsx.add_format({
        "bold": 1,
        "align": "center"})

    merge_format2 = xlsx.add_format({
        "bold": 1,
        "align": "center",
        "valign": "vcenter",
        "bottom": 6})

    new_iis_border = xlsx.add_format({
        "top": 6
    })

    border = xlsx.add_format()
    border.set_top(2)

    border2 = xlsx.add_format()
    border2.set_bottom(2)

    xsheet.merge_range("A1:A2", "IIS", merge_format2)

    xsheet.set_column("B:B", 20)
    xsheet.set_column("C:C", 30)
    xsheet.set_column("D:D", 20)
    xsheet.merge_range("B1:B2", "Constraint", merge_format2)
    xsheet.merge_range("C1:C2", "Set Objects", merge_format2)
    xsheet.merge_range("D1:D2", "Index", merge_format2)

    while True:

        new_iis = True
        b_constraint = None
        b_border = False
        count_iter += 1

        iismodel = gr.read("model.ilp")
        iismodel.setParam('OutputFlag', 0)
        I1 = iismodel.getConstrs()
        I2 = iismodel.getQConstrs()
        I = I1 + I2
        ix = len(I)

        if ix != 0:
            # iterate over the number of constraints of the IIS
            for i in range(0, ix, 1):
                # c -> i-th constraint of IIS
                c = I[i]
                try:
                    pyomo_c = Name[c.ConstrName]
                    pyomo_cn = pyomo_c.getname()
                except:
                    pyomo_c = Name[c.QCName]
                    pyomo_cn = pyomo_c.getname()
                lhs = iismodel.getRow(c)
                try:
                    rhs = c.RHS
                except AttributeError:
                    rhs = c.QCRHS

                # print the i-th constraint including constraint name, lhs and rhs
                print("\n" + str(count) + " : CONSTRAINT: " + pyomo_cn + "\nLHS: " + str(
                    lhs) + "\nRHS: " + str(rhs) + "\n")  # D.get(c.ConstrName)

                # xlsxwriter

                # b_constraint -> check whether a constraint has changed
                if new_iis:
                    br = new_iis_border
                else:
                    br = None
                if b_constraint is None or b_constraint != K1[pyomo_c]:
                    b_constraint = K1[pyomo_c]
                    b_border = True
                    xsheet.write("B" + str(count + 3), K1[pyomo_c], br if new_iis else border)
                    xsheet.write("C" + str(count + 3), Index_Sets[pyomo_c], br if new_iis else border)

                xsheet.write("A" + str(count + 3), str(count_iter), new_iis_border) if new_iis else None
                xsheet.write("D" + str(count + 3), str(Index[pyomo_c]), border if b_border and not new_iis else br)

                b_border = False
                new_iis = False

                count += 1
                # remove constraint c from model
                dopt.remove_constraint(pyomo_c)
        # try to solve the new instance (excluding the constraints from the IIL)
        solver_parameters = "ResultFile=model.ilp"
        dopt.options['NonConvex'] = 2  # MIQCP
        dopt.options['threads'] = 4
        results = dopt.solve(model, options_string=solver_parameters, keepfiles=True, tee=True)
        # check if our model is feasible -> break from loop
        if results.solver.termination_condition == pe.TerminationCondition.optimal:
            xlsx.close()
            break
# ---------------------------------------------------------------------------------------------------------------------
