//=-- SkelRep.h - Classes for representing skeleton files ---------*- C++ -*--=
//
//  This file defines the data structures used when loading skel files from 
//  the disk.  After calling LoadSkelFile, a dynamically structured skel file
//  is loaded.  This structure has all of the expression forms still intact, 
//  so Evaluating it with different files can return a different resultant 
//  structure.
//
//=---------------------------------------------------------------------------=
//  This file is copyright (c) 1997-2000 Chris Lattner
//=---------------------------------------------------------------------------=

#ifndef SKELREP_H
#define SKELREP_H

#include <iostream.h>
#include <stdio.h>
#include <string.h>
#include "MSString.h"
#include "Table.h"
#include "VarTable.h"

class Date;
class SkelData;

const SkelData *GetSkelFile(const char *Filename);

//=---------------------------------------------------------------------------=
//  Subclasses of VTExp that are used to implement loading of Skel files...
//=---------------------------------------------------------------------------=

class SkelVarExp : public VTExp {
public :
  SkelVarExp(int LineNo, const char *VarNam) : VTExp(LineNo, InternalTy) {
    VarName = VarNam;
  }

  VTExp *Evaluate(VarTable &Vars, int *Lint = 0);

private :
  CSString VarName;
};

class SkelBinExp : public VTExp {
public :
  enum OpTypes {
    Plus, Equals, NEquals, And, Or
  };

  SkelBinExp(int LineNo, OpTypes op, VTExp *left, VTExp *right);

  VTExp *Evaluate(VarTable &Vars, int *Lint = 0);

protected :
  ~SkelBinExp();

private:
  VTExp *Left, *Right;
  OpTypes Op;
};

class SkelUnaryExp : public VTExp {
public :
  enum OpTypes {
    Not
  };

  SkelUnaryExp(int LineNo, OpTypes op, VTExp *subExp);

  VTExp *Evaluate(VarTable &Vars, int *Lint = 0);

protected :
  ~SkelUnaryExp();

private:
  VTExp *SubExp;
  OpTypes Op;
};


class SkelFunctionExp : public VTExp {
public:
  SkelFunctionExp(int LineNo, VTExp *Function, VTListExp *ParamList);
  VTExp *Evaluate(VarTable &Vars, int *Lint = 0);
protected:
  ~SkelFunctionExp();
private:
  VTListExp *Params;
  VTExp *Function;
};


//=---------------------------------------------------------------------------=
//   SkelSettingList class...  Host list of fields and the expressions that 
//   are their value.  This is used for MSInsert and MSPlugin tags...
//=---------------------------------------------------------------------------=

class SkelSettingList {
public:
  SkelSettingList(int lineNo, const char *field, VTExp *exp, 
                  SkelSettingList *next) 
    : Field(field) {
    Exp = exp;
    Next = next;
    LineNo = lineNo;
  }

  ~SkelSettingList() {
    Exp->UnRef();
    delete Next;
  }

  // Add settings to table... convert the linked list of settings into a more
  // easily addressable hash table...
  //
  void AddSettingsToTable(VarTable &ParamTab, VarTable &Vars, int *Lint = 0) {
    SkelSettingList *CurNode = this;

    while (CurNode) {
      ParamTab[CurNode->Field] = CurNode->Exp->Evaluate(Vars, Lint);
      CurNode = CurNode->Next;
    }
  }

public :
  int LineNo;

private :
  CSString Field;
  VTExp *Exp;
  SkelSettingList *Next; 
};


//=---------------------------------------------------------------------------=
//   SkelData class and subclasses...
//=---------------------------------------------------------------------------=

class SkelData {
public :
  SkelData(int lineNo, SkelData *N) { Next = N; LineNo = lineNo; }

  virtual ~SkelData() {
    delete Next;
  }

  void DoScanForPlugins(int UpdateFreq, VarTable &Variables) const {
    for (const SkelData *Link = this; Link; Link = Link->Next) 
      Link->ScanForPlugins(UpdateFreq, Variables);
  }

  void DoOutputFile(ostream &OutFile, int UpdateFreq,
                    VarTable &Variables, int *Lint) const {
    for (const SkelData *Link = this; Link; Link = Link->Next)
      Link->OutputFile(OutFile, UpdateFreq, Variables, Lint);
  }

public :
  int LineNo;

protected:
  virtual void ScanForPlugins(int, VarTable &) const {}
  virtual void OutputFile(ostream &OutFile, int UpdateFreq, 
                          VarTable &Variables, int *Lint) const = 0;

  SkelData *Next;  
};


//=---------------------------------------------------------------------------=
//   SkelRawData class
//=---------------------------------------------------------------------------=

class SkelRawData : public SkelData {
public :
  SkelRawData(int LineNo, const char *RD, SkelData *N) : SkelData(LineNo, N) {
    RawData = RD;
  }

protected:
  void OutputFile(ostream &OutFile, int UpdateFreq, VarTable &Vars, 
                  int *Lint) const;

private :
  String RawData;
};


//=---------------------------------------------------------------------------=
//   SkelInsertData class   (MSInsert Tag)
//=---------------------------------------------------------------------------=

class SkelInsertData : public SkelData {
public :
  SkelInsertData(int LineNo, VTExp *E, SkelSettingList *L, SkelData *N);
  ~SkelInsertData();

  // Used by the SkelVarExp to insert $(MS.Date:Numeric) for example...
  static int IsValidToken(const CSString &Token);
  static String EvaluateToken(const CSString &Token, 
                              const Table<CSString,VTExp*> &ParamList,
                              int UpdateFreq, int *Lint);

protected:
  void OutputFile(ostream &OutFile, int UpdateFreq, VarTable &Vars, 
                  int *Lint) const;

private :
  static String EvalDate(Date &OutputDate, String Format);
  static void InitializeBuiltinLookup();

  enum BuiltIns {  // BuiltIn's currently recognized...
    Version=1, ElapsedSeconds, MagicStatsURL, cDate, UpdateDate, 
    YesterdayDate, TomorrowDate, NextMonth, LastMonth, MSCopyright, MSBuiltInURL
  };

  static int BILRefCount;  // When comes back to zero, remove lookup table.
  static Table <CSString, int> *BuiltInLookup;

  VTExp *InsertExp;
  SkelSettingList *Settings;
};


//=---------------------------------------------------------------------------=
//   SkelPluginData class   (MSPlugin Tag)
//=---------------------------------------------------------------------------=

class SkelPluginData : public SkelData {
public :
  SkelPluginData(int LineNo, char *Name, SkelSettingList *L, SkelData *N);
  ~SkelPluginData();

protected:
  void OutputFile(ostream &OutFile, int UpdateFreq, VarTable &Vars, 
                  int *Lint) const;
  void ScanForPlugins(int UpdateFreq, VarTable &Vars) const;

private:
  CSString PluginName;
  SkelSettingList *Settings;
};


//=---------------------------------------------------------------------------=
//   SkelIfThenElseData class   (MSIF/MSELSEIF/MSELSE/MSENDIF Tags)
//=---------------------------------------------------------------------------=

class SkelIfThenElseData : public SkelData {
public :
  SkelIfThenElseData(int LineNo, VTExp *exp, SkelData *ThenC, 
                     SkelData *ElseC, SkelData *N);
  ~SkelIfThenElseData();

protected:
  void OutputFile(ostream &OutFile, int UpdateFreq, VarTable &Vars, 
                  int *Lint) const;
  void ScanForPlugins(int UpdateFreq, VarTable &Vars) const;

private :
  VTExp *Exp;
  SkelData *Then, *Else;
};

#endif
