# cython: language_level=3

from enum import Enum, Flag, auto


class _DocEnum(Enum):
    def __new__(cls, value, doc=None):
        # calling super().__new__(value) here would fail
        self = object.__new__(cls)
        self._value_ = value
        if doc is not None:
            self.__doc__ = doc
            self.desc = doc
        return self


class Status(_DocEnum):
    """
    The status resulting from the solution process
    """
    Unkown = csleqp.SLEQP_STATUS_UNKNOWN, "Unknown state"
    Running = csleqp.SLEQP_STATUS_RUNNING, "Solver is running"
    Optimal = csleqp.SLEQP_STATUS_OPTIMAL, "An optimal solution was found"
    Infeasible = csleqp.SLEQP_STATUS_INFEASIBLE, "Problem was detected to be infeasible"
    Unbounded = csleqp.SLEQP_STATUS_UNBOUNDED, "Problem appears unbounded"
    AbortDeadpoint = csleqp.SLEQP_STATUS_ABORT_DEADPOINT, "Reached a dead point"
    AbortIter = csleqp.SLEQP_STATUS_ABORT_ITER, "Aborted after reaching iteration limit"
    AbortManual = csleqp.SLEQP_STATUS_ABORT_MANUAL, "Manual abort requested"
    AbortTime = csleqp.SLEQP_STATUS_ABORT_TIME, "Aborted after reaching time limit"


class DerivCheck(Flag):
    Skip = csleqp.SLEQP_DERIV_CHECK_SKIP
    FirstFunc = csleqp.SLEQP_DERIV_CHECK_FIRST_OBJ
    FirstCons = csleqp.SLEQP_DERIV_CHECK_FIRST_CONS
    First = csleqp.SLEQP_DERIV_CHECK_FIRST
    SecondFunc = csleqp.SLEQP_DERIV_CHECK_SECOND_OBJ
    SecondCons = csleqp.SLEQP_DERIV_CHECK_SECOND_CONS
    SecondExhaustive = csleqp.SLEQP_DERIV_CHECK_SECOND_EXHAUSTIVE
    SecondSimple = csleqp.SLEQP_DERIV_CHECK_SECOND_SIMPLE


class HessianEval(_DocEnum):
    """
    The evaluation method used for Hessian products
    """
    Exact = csleqp.SLEQP_HESS_EVAL_EXACT, "Exact evaluation"
    SR1 = csleqp.SLEQP_HESS_EVAL_SR1, "The SR1 quasi-Newton method"
    SimpleBFGS = csleqp.SLEQP_HESS_EVAL_SIMPLE_BFGS, "The BFGS method for convex functions"
    DampedBFGS = csleqp.SLEQP_HESS_EVAL_DAMPED_BFGS, "A damped BFGS method "


class Sizing(Enum):
    NoSizing = csleqp.SLEQP_BFGS_SIZING_NONE
    CenteredOL = csleqp.SLEQP_BFGS_SIZING_CENTERED_OL


class TRSolver(_DocEnum):
    """
    The trust-region solver used
    """
    TRlib = csleqp.SLEQP_TR_SOLVER_TRLIB, "The trlib implementation of the Generalized Lanczos method"
    CG = csleqp.SLEQP_TR_SOLVER_CG, "Steihaug's conjugate gradient method"
    LSQR = csleqp.SLEQP_TR_SOLVER_LSQR, "LSQR solver for LSQ functions"
    Auto = csleqp.SLEQP_TR_SOLVER_AUTO, "Automatically chosen"


class PolishingType(_DocEnum):
    """
    The polishing methods use
    """
    NoPolishing = csleqp.SLEQP_POLISHING_NONE, "No polishing"
    ZeroDual = csleqp.SLEQP_POLISHING_ZERO_DUAL, "Remove bounds and constraints with zero duals"
    Inactive = csleqp.SLEQP_POLISHING_INACTIVE, "Remove inactive bounds and constraints"


class StepRule(_DocEnum):
    """
    The step rule used
    """
    Direct = csleqp.SLEQP_STEP_RULE_DIRECT, "Direct"
    Window = csleqp.SLEQP_STEP_RULE_WINDOW, "Sliding window"
    MinStep = csleqp.SLEQP_STEP_RULE_MINSTEP, "Min-step"


class LineSearch(_DocEnum):
    """
    The linesearch used
    """
    Exact = csleqp.SLEQP_LINESEARCH_EXACT, "Exact line search"
    Approx = csleqp.SLEQP_LINESEARCH_APPROX, "Approximate line search"


class ParametricCauchy(_DocEnum):
    """
    The parametric Cauchy type to be used
    """
    Disabled = csleqp.SLEQP_PARAMETRIC_CAUCHY_DISABLED, "Disable parametric Cauchy"
    Coarse = csleqp.SLEQP_PARAMETRIC_CAUCHY_COARSE, "Coarse parametric Cauchy"
    Fine = csleqp.SLEQP_PARAMETRIC_CAUCHY_FINE, "Fine parametric Cauchy"


class InitialTRChoice(_DocEnum):
    """
    Choice for initial trust radius
    """
    Narrow = csleqp.SLEQP_INITIAL_TR_CHOICE_NARROW, "Narrow"
    Wide = csleqp.SLEQP_INITIAL_TR_CHOICE_WIDE, "Wide"


class AugJacMethod(_DocEnum):
    """
    Augmented Jacobian type
    """
    Auto = csleqp.SLEQP_AUG_JAC_AUTO, "Auto"
    Standard = csleqp.SLEQP_AUG_JAC_STANDARD, "Standard"
    Reduced = csleqp.SLEQP_AUG_JAC_REDUCED, "Reduced"
    Direct = csleqp.SLEQP_AUG_JAC_DIRECT, "Direct"


class ValueReason(_DocEnum):
    """
    The reason for setting a new function value
    """
    NoReason = csleqp.SLEQP_VALUE_REASON_NONE, "No reason given"
    Init = csleqp.SLEQP_VALUE_REASON_INIT, "Initialization"
    CheckingDeriv = csleqp.SLEQP_VALUE_REASON_CHECKING_DERIV, "Derivative check"
    AcceptedIterate = csleqp.SLEQP_VALUE_REASON_ACCEPTED_ITERATE, "Accepted a trial iterate"
    TryingIterate = csleqp.SLEQP_VALUE_REASON_TRYING_ITERATE, "Trying out a trial iterate"
    TryingSOCIterate = csleqp.SLEQP_VALUE_REASON_TRYING_SOC_ITERATE, "Trying a second-order correction"
    RejectedIterate = csleqp.SLEQP_VALUE_REASON_REJECTED_ITERATE, "Rejected an iterate restoring the previous"


class ActiveState(_DocEnum):
    """
    The state of a variable or constraint in the working set
    """
    Inactive = csleqp.SLEQP_INACTIVE, "Variable or constraint is inactive"
    ActiveLower = csleqp.SLEQP_ACTIVE_LOWER, "Variable or constraint is active at its lower bound"
    ActiveUpper = csleqp.SLEQP_ACTIVE_UPPER, "Variable or constraint is active at its upper bound"
    ActiveBoth = csleqp.SLEQP_ACTIVE_BOTH, "Variable or constraint is active at both bounds (which must coincide)"


class DualEstimationType(_DocEnum):
    """
    The type of dual estimation used
    """
    LP = csleqp.SLEQP_DUAL_ESTIMATION_TYPE_LP, "Dual variables of the LP"
    LSQ = csleqp.SLEQP_DUAL_ESTIMATION_TYPE_LSQ, "Least-squares estimation"


class SolverEvent(Enum):
    AcceptedIterate = csleqp.SLEQP_SOLVER_EVENT_ACCEPTED_ITERATE
    PerformedIteration = csleqp.SLEQP_SOLVER_EVENT_PERFORMED_ITERATION
    Finished = csleqp.SLEQP_SOLVER_EVENT_FINISHED


class SolverState(Enum):
    TrustRadius = auto()
    LPTrustRadius = auto()
    ScaledFuncVal = auto()
    ScaledMeritVal = auto()
    ScaledFeasRes = auto()
    ScaledStatRes = auto()
    ScaledSlackRes = auto()
    PenaltyParameter = auto()
    MinRayleigh = auto()
    MaxRayleigh = auto()
    LastStepOnBoundary = auto()
    Iteration = auto()
    LastStepType = auto()
    ScaledStatResiduals = auto()
    ScaledFeasResiduals = auto()
    ScaledConsSlackResiduals = auto()
    ScaledVarSlackResiduals = auto()


class StepType(Enum):
    NoStep = csleqp.SLEQP_STEPTYPE_NONE
    Accepted = csleqp.SLEQP_STEPTYPE_ACCEPTED
    AcceptedFull = csleqp.SLEQP_STEPTYPE_ACCEPTED_FULL
    AcceptedSOC = csleqp.SLEQP_STEPTYPE_ACCEPTED_SOC
    Rejected = csleqp.SLEQP_STEPTYPE_REJECTED
