/////////////////////////////////////////////////////////////////////////////
// Name:        wx/valnum.h
// Purpose:     Numeric validator classes.
// Author:      Vadim Zeitlin based on the submission of Fulvio Senore
// Created:     2010-11-06
// Copyright:   (c) 2010 wxWidgets team
//              (c) 2011 Vadim Zeitlin <vadim@wxwidgets.org>
// Licence:     wxWindows licence
/////////////////////////////////////////////////////////////////////////////

#ifndef _WX_VALNUM_H_
#define _WX_VALNUM_H_

#include "wx/defs.h"

#if wxUSE_VALIDATORS

#include "wx/textentry.h"
#include "wx/validate.h"

// This header uses std::numeric_limits<>::min/max, but these symbols are,
// unfortunately, often defined as macros and the code here wouldn't compile in
// this case, so preventively undefine them to avoid this problem.
#undef min
#undef max

#include <limits>

// Bit masks used for numeric validator styles.
enum wxNumValidatorStyle
{
    wxNUM_VAL_DEFAULT               = 0x0,
    wxNUM_VAL_THOUSANDS_SEPARATOR   = 0x1,
    wxNUM_VAL_ZERO_AS_BLANK         = 0x2,
    wxNUM_VAL_NO_TRAILING_ZEROES    = 0x4,
    wxNUM_VAL_SIGN_PLUS             = 0x8,
    wxNUM_VAL_SIGN_SPACE           = 0x10,
};

// ----------------------------------------------------------------------------
// Base class for all numeric validators.
// ----------------------------------------------------------------------------

class WXDLLIMPEXP_CORE wxNumValidatorBase : public wxValidator
{
public:
    // Change the validator style. Usually it's specified during construction.
    void SetStyle(int style) { m_style = style; }


    // Override base class method to not do anything but always return success:
    // we don't need this as we do our validation on the fly here.
    virtual bool Validate(wxWindow * WXUNUSED(parent)) override { return true; }

    // Override base class method to check that the window is a text control or
    // combobox.
    virtual void SetWindow(wxWindow *win) override;

protected:
    wxNumValidatorBase(int style)
    {
        m_style = style;
    }

    wxNumValidatorBase(const wxNumValidatorBase& other) : wxValidator(other)
    {
        m_style = other.m_style;
    }

    bool HasFlag(wxNumValidatorStyle style) const
    {
        return (m_style & style) != 0;
    }

    // Get the text entry of the associated control. Normally shouldn't ever
    // return nullptr (and will assert if it does return it) but the caller should
    // still test the return value for safety.
    wxTextEntry *GetTextEntry() const;

    // Convert wxNUM_VAL_THOUSANDS_SEPARATOR, wxNUM_VAL_NO_TRAILING_ZEROES,
    // wxNUM_VAL_SIGN_PLUS, and wxNUM_VAL_SIGN_SPACE
    // bits of our style to the corresponding wxNumberFormatter::Style values.
    int GetFormatFlags() const;

    // Return the string which would result from inserting the given character
    // at the specified position.
    wxString GetValueAfterInsertingChar(wxString val, int pos, wxChar ch) const
    {
        val.insert(pos, ch);
        return val;
    }

    // Return true if this control allows negative numbers in it.
    //
    // If it doesn't, we don't allow entering "-" at all.
    virtual bool CanBeNegative() const = 0;

private:
    // Check whether the specified character can be inserted in the control at
    // the given position in the string representing the current controls
    // contents.
    //
    // Notice that the base class checks for '-' itself so it's never passed to
    // this function.
    virtual bool IsCharOk(const wxString& val, int pos, wxChar ch) const = 0;

    // Return the canonical form of the number corresponding to the contents of
    // the string: if the input string is invalid, return a string representing
    // some valid value.
    virtual wxString NormalizeString(const wxString& s) const = 0;


    // Event handlers.
    void OnChar(wxKeyEvent& event);
    void OnKillFocus(wxFocusEvent& event);


    // Determine the current insertion point and text in the associated control.
    void GetCurrentValueAndInsertionPoint(wxString& val, int& pos) const;

    // Return true if pressing a '-' key is acceptable for the current control
    // contents and insertion point. This is used by OnChar() to handle '-' and
    // relies on CanBeNegative() implementation in the derived class.
    bool IsMinusOk(const wxString& val, int pos) const;


    // Combination of wxVAL_NUM_XXX values.
    int m_style;


    wxDECLARE_EVENT_TABLE();

    wxDECLARE_NO_ASSIGN_CLASS(wxNumValidatorBase);
};

namespace wxPrivate
{

// This is a helper class used by wxIntegerValidator and wxFloatingPointValidator
// below that implements Transfer{To,From}Window() adapted to the type of the
// variable.
//
// The template argument B is the name of the base class which must derive from
// wxNumValidatorBase and define LongestValueType type and {To,As}String()
// methods i.e. basically be one of wx{Integer,Number}ValidatorBase classes.
//
// The template argument T is just the type handled by the validator that will
// inherit from this one.
template <class B, typename T>
class wxNumValidator : public B
{
public:
    typedef B BaseValidator;
    typedef T ValueType;

    typedef typename BaseValidator::LongestValueType LongestValueType;

    wxCOMPILE_TIME_ASSERT
    (
        sizeof(ValueType) <= sizeof(LongestValueType),
        UnsupportedType
    );

    void SetMin(ValueType min)
    {
        m_min = min;
    }

    ValueType GetMin() const
    {
        return m_min;
    }

    void SetMax(ValueType max)
    {
        m_max = max;
    }

    ValueType GetMax() const
    {
        return m_max;
    }

    void SetRange(ValueType min, ValueType max)
    {
        SetMin(min);
        SetMax(max);
    }

    void GetRange(ValueType& min, ValueType& max) const
    {
        min = GetMin();
        max = GetMax();
    }

    virtual bool TransferToWindow()  override
    {
        if ( m_value )
        {
            wxTextEntry * const control = BaseValidator::GetTextEntry();
            if ( !control )
                return false;

            control->SetValue(NormalizeValue(static_cast<LongestValueType>(*m_value)));
        }

        return true;
    }

    virtual bool TransferFromWindow() override
    {
        if ( m_value )
        {
            wxTextEntry * const control = BaseValidator::GetTextEntry();
            if ( !control )
                return false;

            const wxString s(control->GetValue());
            LongestValueType value;
            if ( s.empty() && BaseValidator::HasFlag(wxNUM_VAL_ZERO_AS_BLANK) )
                value = 0;
            else if ( !BaseValidator::FromString(s, &value) )
                return false;

            if ( !this->IsInRange(value) )
                return false;

            *m_value = static_cast<ValueType>(value);
        }

        return true;
    }

protected:
    wxNumValidator(ValueType *value, int style)
        : BaseValidator(style),
          m_value(value)
    {
    }

    // Implement wxNumValidatorBase virtual method which is the same for
    // both integer and floating point numbers.
    virtual wxString NormalizeString(const wxString& s) const override
    {
        // If empty value is handled as zero, just return it as is for
        // consistency with TransferFromWindow() and NormalizeValue().
        if ( s.empty() && BaseValidator::HasFlag(wxNUM_VAL_ZERO_AS_BLANK) )
            return wxString();

        LongestValueType value;
        if ( !BaseValidator::FromString(s, &value) )
        {
            // We don't have any valid number at all, just arbitrarily decide
            // to return the minimum value.
            value = static_cast<LongestValueType>(m_min);
        }
        else if ( !this->IsInRange(value) )
        {
            // We do have a value, but it's out of range: clamp it to the
            // closest limit.
            if ( value > static_cast<LongestValueType>(m_max) )
                value = static_cast<LongestValueType>(m_max);
            else
                value = static_cast<LongestValueType>(m_min);
        }

        return NormalizeValue(value);
    }

    virtual bool CanBeNegative() const override { return m_min < 0; }


    // This member is protected because it can be useful to the derived classes
    // in their Transfer{From,To}Window() implementations.
    ValueType * const m_value;

private:
    // Just a helper which is a common part of TransferToWindow() and
    // NormalizeString(): returns string representation of a number honouring
    // wxNUM_VAL_ZERO_AS_BLANK flag.
    wxString NormalizeValue(LongestValueType value) const
    {
        // We really want to compare with the exact 0 here, so disable gcc
        // warning about doing this.
        wxGCC_WARNING_SUPPRESS(float-equal)

        wxString s;
        if ( value != 0 || !BaseValidator::HasFlag(wxNUM_VAL_ZERO_AS_BLANK) )
            s = this->ToString(value);

        wxGCC_WARNING_RESTORE(float-equal)

        return s;
    }

    // Minimal and maximal values accepted (inclusive).
    ValueType m_min, m_max;

    wxDECLARE_NO_ASSIGN_DEF_COPY(wxNumValidator);
};

} // namespace wxPrivate

// ----------------------------------------------------------------------------
// Validators for integer numbers.
// ----------------------------------------------------------------------------

// Base class for integer numbers validator. This class contains all non
// type-dependent code of wxIntegerValidator<> and always works with values of
// type LongestValueType. It is not meant to be used directly, please use
// wxIntegerValidator<> only instead.
class WXDLLIMPEXP_CORE wxIntegerValidatorBase : public wxNumValidatorBase
{
protected:
    // Define the type we use here, it should be the maximal-sized integer type
    // we support to make it possible to base wxIntegerValidator<> for any type
    // on it.
    typedef wxLongLong_t LongestValueType;
    typedef wxULongLong_t ULongestValueType;

    wxIntegerValidatorBase(int style)
        : wxNumValidatorBase(style)
    {
        wxASSERT_MSG( !(style & wxNUM_VAL_NO_TRAILING_ZEROES),
                      "This style doesn't make sense for integers." );
        wxASSERT_MSG(!(style & wxNUM_VAL_SIGN_PLUS) ||
                        !(style & wxNUM_VAL_SIGN_SPACE),
                        "Sign prefix conflict.");
    }

    // Default copy ctor is ok.

    // Provide methods for wxNumValidator use.
    wxString ToString(LongestValueType value) const;
    bool FromString(const wxString& s, LongestValueType *value) const;

    virtual bool IsInRange(LongestValueType value) const = 0;

    // Check whether the value is in the extended range allowed on input.
    //
    // Notice that the minimal and maximal values that have to be accepted on
    // input may differ from the actually defined range to allow entering
    // a temporarily invalid number because otherwise it would not be possible
    // to enter any digits in an initially empty control limited to the values
    // between "10" and "20".
    virtual bool IsInInputRange(LongestValueType value) const = 0;

    // Implement wxNumValidatorBase pure virtual method.
    virtual bool IsCharOk(const wxString& val, int pos, wxChar ch) const override;

private:
    wxDECLARE_NO_ASSIGN_DEF_COPY(wxIntegerValidatorBase);
};

// Validator for integer numbers. It can actually work with any integer type
// (short, int or long and long long if supported) and their unsigned versions
// as well.
template <typename T>
class wxIntegerValidator
    : public wxPrivate::wxNumValidator<wxIntegerValidatorBase, T>
{
public:
    typedef T ValueType;

    typedef
        wxPrivate::wxNumValidator<wxIntegerValidatorBase, T> Base;
    typedef
        wxIntegerValidatorBase::LongestValueType LongestValueType;

    // Ctor for an integer validator.
    //
    // Sets the range appropriately for the type, including setting 0 as the
    // minimal value for the unsigned types.
    wxIntegerValidator(ValueType *value = nullptr, int style = wxNUM_VAL_DEFAULT)
        : Base(value, style)
    {
        this->SetMin(std::numeric_limits<ValueType>::min());
        this->SetMax(std::numeric_limits<ValueType>::max());
    }

  // Ctor for an integer validator.
  //
  // Sets the range to the specified interval [min, max].
  wxIntegerValidator(ValueType *value,
                     ValueType min,
                     ValueType max,
                     int style = wxNUM_VAL_DEFAULT)
      : Base(value, style)
  {
    this->SetMin(min);
    this->SetMax(max);
  }

    wxNODISCARD virtual wxObject *Clone() const override { return new wxIntegerValidator(*this); }

    virtual bool IsInRange(LongestValueType value) const override
    {
        return IsValueInRange( value, this->GetMin(), this->GetMax() );
    }

    virtual bool IsInInputRange(LongestValueType value) const override
    {
        ValueType min = wxMin( 1, this->GetMin() );
        ValueType max = wxMax( 0, this->GetMax() );

        return IsValueInRange( value, min, max );
    }

private:
    bool IsValueInRange(LongestValueType value, ValueType min, ValueType max ) const
    {
        // LongestValueType is used as a container for the values of any type
        // which can be used in type-independent wxIntegerValidatorBase code,
        // but we need to use the correct type for comparisons, notably for
        // comparing unsigned values correctly, so cast to this type and check
        // that we don't lose precision while doing it.
        const ValueType valueT = static_cast<ValueType>(value);
        if ( static_cast<LongestValueType>(valueT) != value )
        {
            // The conversion wasn't lossless, so the value must not be exactly
            // representable in this type and so is definitely not in range.
            return false;
        }

        return min <= valueT && valueT <= max;
    }

    wxDECLARE_NO_ASSIGN_DEF_COPY(wxIntegerValidator);
};

// Helper function for creating integer validators which allows to avoid
// explicitly specifying the type as it deduces it from its parameter.
template <typename T>
inline wxIntegerValidator<T>
wxMakeIntegerValidator(T *value, int style = wxNUM_VAL_DEFAULT)
{
    return wxIntegerValidator<T>(value, style);
}

// ----------------------------------------------------------------------------
// Validators for floating point numbers.
// ----------------------------------------------------------------------------

// Similar to wxIntegerValidatorBase, this class is not meant to be used
// directly, only wxFloatingPointValidator<> should be used in the user code.
class WXDLLIMPEXP_CORE wxFloatingPointValidatorBase : public wxNumValidatorBase
{
public:
    // Set precision i.e. the number of digits shown (and accepted on input)
    // after the decimal point. By default this is set to the maximal precision
    // supported by the type handled by the validator.
    void SetPrecision(unsigned precision) { m_precision = precision; }

    // Set multiplier applied for displaying the value, e.g. 100 if the value
    // should be displayed in percents, so that the variable containing 0.5
    // would be displayed as 50.
    void SetFactor(double factor) { m_factor = factor; }

protected:
    // Notice that we can't use "long double" here because it's not supported
    // by wxNumberFormatter yet, so restrict ourselves to just double (and
    // float).
    typedef double LongestValueType;

    wxFloatingPointValidatorBase(int style)
        : wxNumValidatorBase(style)
    {
        m_factor = 1.0;
    }

    // Default copy ctor is ok.

    // Provide methods for wxNumValidator use.
    wxString ToString(LongestValueType value) const;
    bool FromString(const wxString& s, LongestValueType *value) const;

    virtual bool IsInRange(LongestValueType value) const = 0;

    // Check whether the value is in the extended range allowed on input.
    //
    // Notice that the minimal and maximal values that have to be accepted on
    // input may differ from the actually defined range to allow entering
    // a temporarily invalid number because otherwise it would not be possible
    // to enter any digits in an initially empty control limited to the values
    // between "10" and "20".
    virtual bool IsInInputRange(LongestValueType value) const = 0;

    // Implement wxNumValidatorBase pure virtual method.
    virtual bool IsCharOk(const wxString& val, int pos, wxChar ch) const override;

private:
    // Maximum number of decimals digits after the decimal separator.
    unsigned m_precision;

    // Factor applied for the displayed the value.
    double m_factor;

    wxDECLARE_NO_ASSIGN_DEF_COPY(wxFloatingPointValidatorBase);
};

// Validator for floating point numbers. It can be used with float, double or
// long double values.
template <typename T>
class wxFloatingPointValidator
    : public wxPrivate::wxNumValidator<wxFloatingPointValidatorBase, T>
{
public:
    typedef T ValueType;
    typedef wxPrivate::wxNumValidator<wxFloatingPointValidatorBase, T> Base;
    typedef wxFloatingPointValidatorBase::LongestValueType LongestValueType;


    // Ctor using implicit (maximal) precision for this type.
    wxFloatingPointValidator(ValueType *value = nullptr,
                             int style = wxNUM_VAL_DEFAULT)
        : Base(value, style)
    {
        DoSetMinMax();

        this->SetPrecision(std::numeric_limits<ValueType>::digits10);
    }

    // Ctor specifying an explicit precision.
    wxFloatingPointValidator(int precision,
                      ValueType *value = nullptr,
                      int style = wxNUM_VAL_DEFAULT)
        : Base(value, style)
    {
        DoSetMinMax();

        this->SetPrecision(precision);
    }

    wxNODISCARD virtual wxObject *Clone() const override
    {
        return new wxFloatingPointValidator(*this);
    }

    virtual bool IsInRange(LongestValueType value) const override
    {
        const ValueType valueT = static_cast<ValueType>(value);

        return this->GetMin() <= valueT && valueT <= this->GetMax();
    }

    virtual bool IsInInputRange(LongestValueType value) const override
    {
        const ValueType valueT = static_cast<ValueType>(value);

        ValueType min = wxMin( 0, this->GetMin() );
        ValueType max = wxMax( 0, this->GetMax() );

        return min <= valueT && valueT <= max;
    }

private:
    void DoSetMinMax()
    {
        // NB: Do not use min(), it's not the smallest representable value for
        //     the floating point types but rather the smallest representable
        //     positive value.
        this->SetMin(-std::numeric_limits<ValueType>::max());
        this->SetMax( std::numeric_limits<ValueType>::max());
    }
};

// Helper similar to wxMakeIntValidator().
//
// NB: Unfortunately we can't just have a wxMakeNumericValidator() which would
//     return either wxIntegerValidator<> or wxFloatingPointValidator<> so we
//     do need two different functions.
template <typename T>
inline wxFloatingPointValidator<T>
wxMakeFloatingPointValidator(T *value, int style = wxNUM_VAL_DEFAULT)
{
    return wxFloatingPointValidator<T>(value, style);
}

template <typename T>
inline wxFloatingPointValidator<T>
wxMakeFloatingPointValidator(int precision, T *value, int style = wxNUM_VAL_DEFAULT)
{
    return wxFloatingPointValidator<T>(precision, value, style);
}

#endif // wxUSE_VALIDATORS

#endif // _WX_VALNUM_H_
