/*
_____       _    _    Corso   Italia,  178
(_|__   .  (_   |_|_  56125           Pisa
(_|_) |)|(()_)()| |   tel.  +39  050 46380
  |   |               picosoft@picosoft.it

 Copyright (C) Picosoft s.r.l. 1995-2002

 This program is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation; either version 2, or (at your option)
 any later version.

 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with this program; if not, write to the Free Software
 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

*/
# ifndef express_h
# define express_h "$Id: express.h 5.1 1999/12/15 16:44:37 picoSoft Exp $"

# include "stmtattr.h"

# include "lex.h"
# include "token.h"
# include "pstack.h"
# include "piteratr.h"
# include "dberror.h"

class StackItem : public PObject {
   char deleteSa;
public:
   toknum type;
   StmtAttr *sa;
   PBool isParam;
   StackItem(toknum t) {
      deleteSa = PFalse;
      type = t;
      sa = 0;
      isParam = PFalse;
   }
   StackItem(StmtAttr *exsa, PBool param = PFalse) {
      deleteSa = PFalse;
      type = (toknum)0;
      sa = exsa;
      isParam = param;
   }
   StackItem(const DataBase &d, const Token &t) {
      deleteSa = PTrue;
      type = (toknum)0;
      sa = new StmtAttr (d, t);
      isParam = PFalse;
   }
   StackItem(const StackItem &a) {
      *this = a;
      isParam = PFalse;
   }
   ~StackItem() {
      if (deleteSa)
         delete sa;
   }
   StackItem & operator=(const StackItem &a) {
      type = a.type;
      deleteSa = a.deleteSa;
      if (deleteSa)
         sa = new StmtAttr (*(a.sa));
      else
         sa = a.sa;
      return *this;
   }
};

PLIST(StackItem);
class ExprItemSStack;
class CFieldList;
PTSTACK(StackItem);
                             
class Expression : public PObject
{
public:
# ifdef WIN32
   typedef StmtAttr * (SqlParser::*Method)(const PString & name, 
                                           PString & table, StmtRel **sr, toknum bi);
# else
   typedef StmtAttr * (PObject::*Method)(const PString & name, 
                                           PString & table, StmtRel **sr, toknum bi);
# endif
private:
   PCLASS(Expression, PObject)
   PString name;
   StackItemList stack;
   StmtAttrList DbField;
   StmtAttrList DistField;
   PBool parsing;
   SqlParser *parent;
   toknum aggregate;
   StmtAttr * value;
   StmtAttr * aggrValue;
   const PBool parseAggregate;
   Method findAttr;
   Error Start (Lex &l);
   Error Parenthesis (Lex &l);
   Error Args (Lex &l, int nArgs);
   Error ConvertArgs (Lex &l);
   Error Item (Lex &l, PStack(StackItem) &localStack);
   StmtAttr * UserName (Lex &l, Token *t);
   Error Function (Lex &l, PStack(StackItem) &localStack);
   Error ArithmOp (Lex &l, PStack(StackItem) &localStack);
   Error Alias (Lex &l);
   StmtAttr * DistinctFunction (Lex &l);
   void reduce (Token *lookAhead, PStack(StackItem) &localStack);
   PBool check1Args (ExprItemSStack & s, char op);
   PBool check2Args (ExprItemSStack & s, char op);
   void Eval ();
   void PrintError (ErrNum e, const PString & submess, int syserr = 0) {
      if (parent != 0)
         ::PrintError (0, 0, parent, e, submess, syserr);
      else
         ::PrintError (0, 0, 0, e, submess, syserr);
   }
public:
   Expression (SqlParser &s, Lex &l, Method findAttr, PBool aggr);
   Expression (SqlParser *s, StmtAttr *sa);
   Expression (const DataBase &d, const Token &t);
   Expression (Expression &ex);
   ~Expression ();
   PBool isOk () { return parsing; }
   void setName (const PString &n) { name = n; }
   PString getName () { return name; }
   PBool hasDistField () {
      return DistField.GetItemNum() > 0;
   }
   StmtAttrList & getDistField () {
      return DistField;
   }
   StmtAttrList & getStmtAttr () {
      return DbField;
   }
   PBool Compare (Expression *ex, toknum op, PBool checkOnly) {
      if (checkOnly)
         return getAggrValue()->Compare (ex->getAggrValue(), op, checkOnly);
      else
         return getValueUpdated()->Compare(ex->getValueUpdated(), op, checkOnly);
   }
   StmtAttr * getValue () {
      return value;
   }
   StmtAttr * getValueUpdated ();
   StmtAttr * getAggrValue () {
      return aggrValue;
   }
   StmtAttr * getAggrValueUpdated (unsigned long i) {
      if (aggrValue != value)
         aggrValue->Aggregate (i, getValueUpdated());
      else
         Eval();
      return aggrValue;
   }
   toknum getAggregate() { return aggregate; }
   Attribute * getAttr() {
      return aggrValue->getAttr();
   }
   StmtRel * GetStmtParent() {
      return aggrValue->GetStmtParent ();
   }
   Error verify (int & numeric, PBool isFormal);
   // per debug
   StackItemList * getStack () { return &stack; }
   void toString (PString &result);
   unsigned int getHighestStmtRelOrder();
   PBool isDbExpr() { return DbField.GetItemNum() > 0; }
};

PLIST(Expression);
PITERATOR(Expression);

class OrderItem
{
public:
   StmtAttr * sa;
   PBool desc;
   Expression *ex;
   OrderItem() {
      sa = (StmtAttr *) 0;
      desc = PFalse;
      ex = (Expression *) 0;
   }
};

PCOPYLIST(OrderItem);
# endif
