//
// This source code resides at www.jaeckel.org/ImpliedNormalVolatility.7z .
//
// ======================================================================================
// Copyright © 2022 Peter Jäckel.
//
// Permission to use, copy, modify, and distribute this software is freely granted,
// provided that this notice is preserved.
//
// WARRANTY DISCLAIMER
// The Software is provided "as is" without warranty of any kind, either express or implied,
// including without limitation any implied warranties of condition, uninterrupted use,
// merchantability, fitness for a particular purpose, or non-infringement.
// ======================================================================================
//

#ifndef XLOPER_H
#define XLOPER_H

#ifdef _MSC_VER
#define _CRT_SECURE_NO_WARNINGS
#endif

#include <windows.h>
#include "XLCall.h"
#include <string>

//
// Undocumented feature:
//
//   When Excel returns an xlOper of type 0x1000, which is strictly speaking illegal,
//   the returned xlOper contains a wide char string in Pascal encoding. Wide char, in
//   this context means that every character is two bytes long. ASCII characters are
//   encoded with the ASCII code first, followed by a zero (I am not sure if this depends
//   on the Endian convention of the hardware, though). So, the first two bytes, cast into
//   an unsigned short, tell you how many (two byte) characters follow. Excel surmounts
//   the 255 character limitation in this way.
//
//   Note that (xltypeWideCharStr&xltypeType) == 0x0000 !
//
#define xltypeWideCharStr        0x1000

// All bits that are mutually exclusive
#define xltypeType       0x0FFF

// Note that the type list below is restricted to what we use and support.
enum XLType {
    XLTypeNum            = xltypeNum,
    XLTypeStr            = xltypeStr,
    XLTypeBool           = xltypeBool,
    XLTypeErr            = xltypeErr,
    XLTypeMulti          = xltypeMulti,
    XLTypeMissing        = xltypeMissing,
    XLTypeNil            = xltypeNil,
    XLTypeInt            = xltypeInt
};


//
// A class that is bitwise identical to XLOPER.
//

class XLOper4 : public xloper {

public:

    XLOper4(const char *);
    XLOper4(const wchar_t * s);	
    XLOper4(const std::string &);
    XLOper4(double);
    XLOper4(bool);
    XLOper4(int);
    XLOper4(XLType);
    XLOper4(); // Nil
    ~XLOper4();
    XLOper4* toExcel(); // Sets the xlbitDLLFree free in the xltype field and returns this.

};


//
// A class that is bitwise identical to XLOPER12.
//

class XLOper12 : public xloper12 {

public:

    XLOper12(const char *);
    XLOper12(const wchar_t * s);	
    XLOper12(const std::string &);
    XLOper12(double);
    XLOper12(bool);
    XLOper12(int);
    XLOper12(XLType);
    XLOper12(); // Nil
    ~XLOper12();
    XLOper12* toExcel(); // Sets the xlbitDLLFree free in the xltype field and returns this.

};

//
// A polymorphic class that either is an XLOper4 or XLOper12 depending on the value of XLOper::APIVersion.
//
class XLOper {

public:

    enum APIVersionType {
        APIVersionUndefined = 0,
        APIVersion4 = 4,
        APIVersion12 = 12
    };

    static APIVersionType APIVersion;

    union {
        struct xloper    o4;
        struct xloper12 o12;
    };

    XLOper(const char *);
    XLOper(const wchar_t * s);	
    XLOper(const std::string &);
    XLOper(double);
    XLOper(bool);
    XLOper(int);
    XLOper(XLType);
    XLOper(); // Nil
    ~XLOper();

    XLType type() const;

    const char* type_name() const;

    XLOper* toExcel(); // Sets the xlbitDLLFree free in the xltype field and returns this.

    operator std::string()  const;

    static char xloper_code(); // 'P' in API version 4, and 'Q' in API version 12.

    static std::string replace_xloper_codes(const char *codes); // '?' -> 'P' in API version 4, and 'Q' in API version 12.

    static const XLOper Missing; // This one is special. It appears as a missing xloper type for both API versions.

};

template <class T> XLOper* toExcel(const T&t){ return (new XLOper(t))->toExcel(); }

#endif // XLOPER_H
