#cython: language_level=3

cdef class WorkingSet:
  """
  The working set associated with an iterate, containing
  the states of all variables and constraints.
  """
  cdef csleqp.SleqpWorkingSet* working_set

  cdef dict __dict__

  cdef _release(self):
    if self.working_set:
      csleqp_call(csleqp.sleqp_working_set_release(&self.working_set))

  cdef _set_working_set(self, csleqp.SleqpWorkingSet* working_set):
    self._release()

    csleqp_call(csleqp.sleqp_working_set_capture(working_set))

    self.working_set = working_set

  @property
  def num_vars(self) -> int:
    """
    The total number of (active or inactive) variables in the working set
    """
    cdef csleqp.SleqpProblem* problem

    problem = csleqp.sleqp_working_set_problem(self.working_set)

    return csleqp.sleqp_problem_num_vars(problem)

  @property
  def num_cons(self) -> int:
    """
    The total number of (active or inactive) constraints in the working set
    """
    cdef csleqp.SleqpProblem* problem

    problem = csleqp.sleqp_working_set_problem(self.working_set)

    return csleqp.sleqp_problem_num_cons(problem)

  @property
  def num_active_vars(self) -> int:
    """
    The total number of active (lower or upper or both)
    variables in the working set
    """
    assert self.working_set

    return csleqp.sleqp_working_set_num_active_vars(self.working_set)

  @property
  def num_active_cons(self) -> int:
    """
    The total number of active (lower or upper or both)
    constraints in the working set
    """
    assert self.working_set

    return csleqp.sleqp_working_set_num_active_cons(self.working_set)

  def var_state(self, int i) -> ActiveState:
    """
    State of variable i
    """
    assert self.working_set

    state = csleqp.sleqp_working_set_var_state(self.working_set,
                                               i)

    return ActiveState(state)

  def cons_state(self, int i) -> ActiveState:
    """
    State of constraint i
    """
    assert self.working_set

    state = csleqp.sleqp_working_set_cons_state(self.working_set,
                                                i)

    return ActiveState(state)

  def __str__(self):
    str_val = "Active set, variables: {0}, constraints: {1}\n".format(self.num_vars,
                                                                      self.num_cons)

    str_val += "\n".join(("State of variable {0}: {1}".format(j, str(self.var_state(j)))
                          for j in range(self.num_vars)))

    str_val += "\n"

    str_val += "\n".join(("State of constraint {0}: {1}".format(i, str(self.cons_state(i)))
                          for i in range(self.num_cons)))

    return str_val

  @property
  def size(self) -> int:
    """
    Size of the working set, i.e., number of active variables
    and active constraints
    """
    assert self.working_set

    return csleqp.sleqp_working_set_size(self.working_set)

  def __dealloc__(self):
    self._release()
