///////////////////////////////////////////////////////////////////////////////
// Name:        wx/anystr.h
// Purpose:     wxAnyStrPtr class declaration
// Author:      Vadim Zeitlin
// Created:     2009-03-23
// Copyright:   (c) 2008 Vadim Zeitlin <vadim@wxwidgets.org>
// Licence:     wxWindows licence
///////////////////////////////////////////////////////////////////////////////

#ifndef _WX_ANYSTR_H_
#define _WX_ANYSTR_H_

#include "wx/string.h"

// ----------------------------------------------------------------------------
// wxAnyStrPtr
//
// Notice that this is an internal and intentionally not documented class. It
// is only used by wxWidgets itself to ensure compatibility with previous
// versions and shouldn't be used by user code. When you see a function
// returning it you should just know that you can treat it as a string pointer.
// ----------------------------------------------------------------------------

// This is a helper class convertible to either narrow or wide string pointer.
// It is similar to wxCStrData but, unlike it, can be null which is required to
// represent the return value of wxDateTime::ParseXXX() methods for example.
//
// NB: this class is fully inline and so doesn't need to be DLL-exported
class wxAnyStrPtr
{
public:
    // ctors: this class must be created from the associated string or using
    // its default ctor for an invalid nullptr-like object; notice that it is
    // immutable after creation.

    // ctor for invalid pointer
    wxAnyStrPtr()
        : m_str(nullptr)
    {
    }

    // ctor for valid pointer into the given string (whose lifetime must be
    // greater than ours and which should remain constant while we're used)
    wxAnyStrPtr(const wxString& str, const wxString::const_iterator& iter)
        : m_str(&str),
          m_iter(iter)
    {
    }

    // default copy ctor is ok and so is default dtor, in particular we do not
    // free the string


    // various operators meant to make this class look like a superposition of
    // char* and wchar_t*

    // this one is needed to allow boolean expressions involving these objects,
    // e.g. "if ( FuncReturningAnyStrPtr() && ... )" (unfortunately using
    // unspecified_bool_type here wouldn't help with ambiguity between all the
    // different conversions to pointers)
    operator bool() const { return m_str != nullptr; }

    // at least VC7 also needs this one or it complains about ambiguity
    // for !anystr expressions
    bool operator!() const { return !((bool)*this); }


#ifndef wxNO_IMPLICIT_WXSTRING_ENCODING
    // and these are the conversions operator which allow to assign the result
    // of FuncReturningAnyStrPtr() to either char* or wxChar* (i.e. wchar_t*)
    operator const char *() const
    {
        if ( !m_str )
            return nullptr;

        // check if the string is convertible to char at all
        //
        // notice that this pointer points into wxString internal buffer
        // containing its char* representation and so it can be kept for as
        // long as wxString is not modified -- which is long enough for our
        // needs
        const char *p = m_str->c_str().AsChar();
        if ( *p )
        {
            // find the offset of the character corresponding to this iterator
            // position in bytes: we don't have any direct way to do it so we
            // need to redo the conversion again for the part of the string
            // before the iterator to find its length in bytes in current
            // locale
            //
            // NB: conversion won't fail as it succeeded for the entire string
            p += strlen(wxString(m_str->begin(), m_iter).mb_str());
        }
        //else: conversion failed, return "" as we can't do anything else

        return p;
    }
#endif // wxNO_IMPLICIT_WXSTRING_ENCODING

    operator const wchar_t *() const
    {
        if ( !m_str )
            return nullptr;

        // no complications with wide strings (as long as we discount
        // surrogates as we do for now)
        //
        // just remember that this works as long as wxString keeps an internal
        // buffer with its wide char representation, just as with AsChar()
        // above
        return m_str->c_str().AsWChar() + (m_iter - m_str->begin());
    }

    // Because the objects of this class are only used as return type for
    // functions which can return nullptr we can skip providing dereferencing
    // operators: the code using this class must test it for null first and if
    // it does anything else with it has to assign it to either char* or
    // wchar_t* itself, before dereferencing.
    //
    // IOW this
    //
    //      if ( *FuncReturningAnyStrPtr() )
    //
    // is invalid because it could crash. And this
    //
    //      const char *p = FuncReturningAnyStrPtr();
    //      if ( p && *p )
    //
    // already works fine.

private:
    // the original string and the position in it we correspond to, if the
    // string is null this object is null pointer-like
    const wxString * const m_str;
    const wxString::const_iterator m_iter;

    wxDECLARE_NO_ASSIGN_DEF_COPY(wxAnyStrPtr);
};

#endif // _WX_ANYSTR_H_

