/****************************************************************************
    Kalkulon - A programmable calculator for programmers

    This file is part of the Kalkulon core.

    If you find this source code useful, your are encouraged to use it in your own projects.
    Please give me credit!

    COPYRIGHT by Juergen Holetzeck 2003 - 2008
    e-mail:		contact@kalkulon.de
    homepage:	www.kalkulon.de
****************************************************************************/



// DataObject.h:
//
//////////////////////////////////////////////////////////////////////

#if !defined(AFX_DATAOBJECT_H__E4652240_9F67_11D7_BEF2_86D72C36037F__INCLUDED_)
#define AFX_DATAOBJECT_H__E4652240_9F67_11D7_BEF2_86D72C36037F__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#include <string>
#include <vector>
#include <list>
#include <iostream>

namespace Kalkulon{
// forward declaration to avoid including of "Token.h"
struct Token;
typedef std::list<Token> RPNStack_t;

namespace serialize
{
  void put(std::ostream& os, const RPNStack_t& rpnStack);
  RPNStack_t getRPNStack_t(std::istream& is);
}


//////////////////////////////////////////////////////////////////////////////
// internal types of RPNStackEval exceptions
struct ErrMathInternal
{
    std::string name;
    std::string reason;
  ErrMathInternal(std::string n, std::string r) {name=n; reason=r;}
};
//////////////////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////////////////////
// DataObject
struct DataObject
{
    //////////////////////////////////////////////////////////////
    // supported types
    enum DataObjectId
    {
        UNKNOWN,
        FNUMBER,
        STRING,
        LIST,
        PUREFUNC,
        MESSAGE	// same as void
    };
    //////////////////////////////////////////////////////////////

    //////////////////////////////////////////////////////////////
    // constructors
    DataObject() : did(UNKNOWN), fnum_value(0), ptr_compound_value(nullptr){}
    DataObject(double d) : did(FNUMBER), fnum_value(d), ptr_compound_value(nullptr){}
    DataObject(const std::string& str, DataObjectId e=STRING) : did(e), ptr_compound_value(new std::string(str)){KALKULON_ASSERT(did==STRING || did==MESSAGE);}
    DataObject(DataObjectId e);

    // copy and move ctor
    DataObject(const DataObject& rhs);
    DataObject(DataObject&& rhs) NOEXCEPT;
    DataObject& operator=  (const DataObject& rhs);
    DataObject& operator=  (DataObject&& rhs) NOEXCEPT;

    // destructor
    ~DataObject() {if(nullptr != ptr_compound_value) deleteCompound();}

    //////////////////////////////////////////////////////////////


  //////////////////////////////////////////////////////////////
  // methods for persisting DataObject state
  void serialize(std::ostream& os) const;
  static DataObject deserialize(std::istream& is);
  //

    //////////////////////////////////////////////////////////////
    // conversions
    operator double() const;

    // operators
    DataObject  operator+  (const DataObject& rhs) const;
    bool  operator== (const DataObject& rhs) const;
    bool  operator!= (const DataObject& rhs) const;
    DataObject& operator[] (size_t idx);
    const DataObject& operator[] (size_t idx) const;
    //////////////////////////////////////////////////////////////


    //////////////////////////////////////////////////////////////
    // formatting of output
    enum FormStyle
    {
        PLAIN        = 0x0000,
        QUOTEDSTRING = 0x0001,
        FULLFORM     = 0x0002
    };

    // returns DataObject as formatted string with style 'FormStyle'
    std::string formattedString(unsigned int style = QUOTEDSTRING) const;
    // returns dob 'PLAIN' formatted
    operator std::string() const;
    // sprintf for DOBs
    std::string sprintf(const std::string& format, bool single_number=false) const;

    // change number format to user specified 'sprintf string'
    static std::string setNumberFormat(const std::string& s)
        { std::string old_format(format_number); format_number=s; return old_format;}
    //////////////////////////////////////////////////////////////

    //////////////////////////////////////////////////////////////
    // DataObject's value types
  inline DataObjectId				getDid() const			{return did;}
  inline std::string*             getPtrStrValue() const	{KALKULON_ASSERT(did==STRING || did==MESSAGE); return static_cast<std::string*> (ptr_compound_value);}
  inline std::vector<DataObject>* getPtrListValue() const	{KALKULON_ASSERT(did==LIST); return static_cast<std::vector<DataObject>*> (ptr_compound_value);}
  inline RPNStack_t*				getPtrRPNStack() const	{KALKULON_ASSERT(did==PUREFUNC); return static_cast<RPNStack_t*> (ptr_compound_value);}
    //////////////////////////////////////////////////////////////

    //////////////////////////////////////////////////////////////
    // data members
    private:
        // object identifier
        DataObjectId		did;

        // object value is either number or pointer to compound value like list etc.
        double				fnum_value;
        void*				ptr_compound_value;

        // printf format string for displaying numbers
        static std::string			format_number;

        // type safe delete of ptr_compound_value
        void deleteCompound();

    public:
        static const std::string STD_FORMAT;
    //////////////////////////////////////////////////////////////

};
}


//////////////////////////////////////////////////////////////////////////////
// returns DataObject as formatted string with style 'QUOTEDSTRING'
std::ostream& operator<< (std::ostream& out, Kalkulon::DataObject& data);
//////////////////////////////////////////////////////////////////////////////


#endif // !defined(AFX_DATAOBJECT_H__E4652240_9F67_11D7_BEF2_86D72C36037F__INCLUDED_)
