/****************************************************************************
    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
****************************************************************************/


// RPNStackEval.h: interface for the CRPNStackEval class.
//
//////////////////////////////////////////////////////////////////////

#if !defined(AFX_RPNSTACKEVAL_H__72CBB513_CB04_11D6_B261_00300511F21B__INCLUDED_)
#define AFX_RPNSTACKEVAL_H__72CBB513_CB04_11D6_B261_00300511F21B__INCLUDED_

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


#include <stack>
#include <map>
#include <vector>
#include <iostream>
#include <fstream>
#include "FuncObject.h"
#include "fnlist_impl.h"
#include "DataStack.h"

namespace Kalkulon{
/////////////////////////////////////////////////////////////////////
// useful shortcuts
typedef unsigned char		U08;
typedef unsigned short		U16;
typedef unsigned int		U32;
typedef signed char			S08;
typedef signed short		S16;
typedef signed int			S32;


// use of cast functions to avoid too aggressive optimization (e.g. VC++8)
inline U32 cast_u32(double d)
{
   S32 s32dummy;
   if(d>=0)
      return static_cast<U32>(d);
   else
      return static_cast<U32>(s32dummy=static_cast<S32>(d));
}
inline U08 cast_u08(double d)
{
    return static_cast<U08>(cast_u32(d));
}
inline U16 cast_u16(double d)
{
   return static_cast<U16>(cast_u32(d));
}

inline S32 cast_s32(double d)
{
   U32 u32dummy;
   if(d>=0)
      return static_cast<S32>(u32dummy=static_cast<U32>(d));
   else
      return static_cast<S32>(d);
}
inline S08 cast_s08(double d)
{
   return static_cast<S08>(cast_u32(d));
}
inline S16 cast_s16(double d)
{
   return static_cast<S16>(cast_u32(d));
}



#ifdef USE_WIN32_LIB
    typedef __declspec( dllimport ) int  (* LPGETLASTERROR) ();
    typedef __declspec( dllimport ) const char *  (* LPGETERRORMESSAGE) ();
#endif
/////////////////////////////////////////////////////////////////////

const char OUT_STR[]  = "out";
const char OUT_LIST[] = "outl";




class Callback
{
public:
    virtual ~Callback() {}

    // override to print from with-in Kalkulon core
    virtual void print(const char * str, bool lf) {}
    // override for event processing in UI, this function is called repeatly in eval()
    virtual void processEvents() {}
};


class CRPNStackEval
{
public:
    typedef std::map< std::string, DataObject > symbols_t;
    typedef std::map< std::string, FuncObject > functions_t;

    CRPNStackEval();
    virtual ~CRPNStackEval();

    DataObject	eval(RPNStack_t& rpn_stack_, unsigned int uid = (unsigned int)-1, RPNStack_t::iterator *pIt = 0);
    DataObject  parseEval(const std::string& expr);
    void		clearAll();
    int			load(const char* file);
    int			getOutIdx() {return out_idx;}
    static int	SetRecursionLimit(int new_limit);	// sets new recursion limit for evaluator, returns old value, BEWARE: bigger values may lead to stack overflow!

    // if CRPNStackEval::eval() is run in an own thread the caller can interrupt the calculation by calling BreakSig()
    // BEWARE: Kalkulon core is not thread safe at all! The caller is responsible for proper handling of calls to eval(), BreakSig(), ...
    void		BreakSig(bool set = true) {breaksig=set;}


    DataObject  ForEach1(std::vector<DataObject>* plist, RPNStack_t* purefunc);
    DataObject  ForEach2(std::vector<DataObject>* plist1, std::vector<DataObject>* plist2, RPNStack_t* purefunc);
    DataObject  Table(double start, double end, double delta, RPNStack_t* ppurefunc);
    DataObject  Fold(std::vector<DataObject>* plist, const DataObject& first, RPNStack_t* ppurefunc);
    DataObject  FoldList(std::vector<DataObject>* plist, const DataObject& first, RPNStack_t* ppurefunc);

  //////////////////////////////////////////////////////////////
  // methods for persisting CRPNStackEval state
  bool serialize(const std::string& filename) const;
  bool deserialize(const std::string& filename);
  //

    Callback*	callbackOb;
    symbols_t   symbols;
    functions_t functions;

private:

    static const unsigned int CALLBACK_INTERVAL;
    static const int SERIALIZATION_MAGICPATTERN;
    static const int SERIALIZATION_VERSION;

    CDataStack datastack;
    RPNStack_t::iterator rpnIter;

    std::vector< symbols_t* > symbols_list;
    int out_idx;	// counter for out1, out2 ...
    bool breaksig;
    static int recursion_limit;

    void		func(Token &tok);
    bool		call_fn(Token &tok, const fn_list_t&);
    bool		call_userfn(Token &tok);
    bool		eval_purefn(Token &tok);

    DataObject* getIndexedDob(DataObject *pdob, int dim);

    bool tryDeserialize(std::istream &is);
    void trySerialize(std::ostream &os) const;


#ifdef USE_WIN32_LIB
    HINSTANCE hDLL;
    bool				FnDllValid;
    const fn_list_t*	FnDll_fn_list;

    LPGETLASTERROR    GetLastError;
    LPGETERRORMESSAGE GetErrorMessage;

#endif

};
}


#endif // !defined(AFX_RPNSTACKEVAL_H__72CBB513_CB04_11D6_B261_00300511F21B__INCLUDED_)


