//=-- ConfigRep.h - Classes for representing configuration files --*- C++ -*--=
//
//  This file defines the data structures used when loading .cfg files from 
//  the disk.  After calling LoadConfigFile, a dynamically structured 
//  configuration 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 CONFIGREP_H
#define CONFIGREP_H

#include "Object.h"
#include "MSString.h"
#include "SkelRep.h"
#include "ConfigFileSection.h"

class ConfigFileSection;
class MSFilename;

// LoadConfigFile - This is the public function that should be used to load 
// configuration files from the disk.
ConfigFileSection *LoadConfigFile(const MSFilename &Filename);


// ConfigFileStatement - Each statement in a configuration file consists of 
// a name (for example "input") and an expression that assigns it a value. 
// This class holds one link of a linked list of statements.
//
class ConfigFileStatement {
public :
  ConfigFileStatement(int lineNo, const CSString &element, VTExp *E, 
                      ConfigFileStatement *n) : Element(element) {
    Exp = E;
    Next = n;
    LineNo = lineNo;
  }

  void Print(VarTable &Variables) {
    cout << "  " << Element << " == " << Exp->Evaluate(Variables) << endl;

    if (Next)
      Next->Print(Variables);
  }

  void EvaluateFile(VarTable &Vars, VarTable &Statements, int *Lint);

public :
  int LineNo;
private :
  CSString Element;           // Element Name
  VTExp *Exp;                 // Element Value
  ConfigFileStatement *Next;  // Next Statement
};


class ConfigFileSection {
public :
  ConfigFileSection(int lineNo, const String &sectionName, 
                    ConfigFileStatement *SList, ConfigFileSection *n)
                        : SectionName(sectionName) {
    StmtList = SList;
    Next = n;
    LineNo = lineNo;
  }

  virtual ~ConfigFileSection() {
    delete StmtList;
    delete Next;
  }

  // EvaluateFile - Convert a dynamic ConfigFile data structure into the 
  // corresponding "flattened" CFileSection data structure.  The flattened
  // structure contains all of the statements in an evaluated hashtable form.
  // The dynamic structure here has all of the statements with their structure
  // intact.  The variables passed in here are inherited by all sections.
  //
  LinkedList<CFileSection> EvaluateFile(const VarTable &Variables, 
                                        int *Lint = 0);

  // LintTheme - Used to run "lint" on a theme.  This should check that all 
  // variables are defined and that the theme is ready for distribution...
  //
  int LintTheme(const VarTable &Variables) {
    int Result = 0;
    EvaluateFile(Variables, &Result);   // 1 == Lint the file...
    return Result;
  }

  // PostLoadFixupScan - This function is called immediately after all of the
  // config file is loaded.  This can be used by themes for example to load
  // their subtheme files...  Because the parser is not reentrant...
  //
  virtual void PostLoadFixupScan() { if (Next) Next->PostLoadFixupScan(); }

  // Print - Print out this section of the configuration file...
  //
  virtual void Print(VarTable &Variables) = 0;

  // GetNext() - Return the next node in the linked list of ConfigFileSections
  //
  inline ConfigFileSection *GetNext() { return Next; }

  // EvaluateSection - This function causes only the 'this' section to be added
  // to the specified linked list... if it's a theme, it should add all of the 
  // theme stuff too...
  //
  virtual void EvaluateSection(VarTable &Variables, 
                               LinkedList<CFileSection> &List,
                               int *Lint) = 0;
public :
  int LineNo;
protected:
  String SectionName;
  ConfigFileStatement *StmtList;
  ConfigFileSection   *Next;
};


// PlainConfigFileSection - This class holds one SECTION of the configuration 
// file.  Sections in the configuration file are delimited with [Theme:Name] 
// pairs.  The EvaluateFile method is used to flatten it out to a CFileSection 
// structure.
//
class PlainConfigFileSection : public ConfigFileSection {
public:
  PlainConfigFileSection(int LineNo, const String &SectionName, 
                         ConfigFileStatement *SList, ConfigFileSection *Next);

  virtual ~PlainConfigFileSection() {
  }

  // Print - Print out this section of the configuration file...
  //
  virtual void Print(VarTable &Variables) {
    cout << "[" << SectionName << "]\n";
    if (StmtList) StmtList->Print(Variables);
    if (Next)  Next->Print(Variables);
  }

  // EvaluateSection - This function causes only the 'this' section to be added
  // to the specified linked list... if it's a theme, it should add all of the 
  // theme stuff too...
  //
  virtual void EvaluateSection(VarTable &Variables, 
                               LinkedList<CFileSection> &List, int *Lint);
private :
  MSFilename Path;
};


class ThemeConfigFileSection : public ConfigFileSection {
public :
  ThemeConfigFileSection(int LineNo, const CSString &themeName, 
                         ConfigFileStatement *SList, 
                         ConfigFileSection *N) 
           : ConfigFileSection(LineNo, themeName, SList, N), 
             ThemeName(themeName) {
    ThemeConfigFile = 0;
  }

  ~ThemeConfigFileSection() {
  }

  // PostLoadFixupScan - This function is called immediately after all of the
  // config file is loaded.  This is used here to load the theme file this 
  // section is refering to.  Because the parser is not reentrant, we cannot
  // load it from the constructor...
  //
  virtual void PostLoadFixupScan();

  // Print - Print out this section of the configuration file...
  //
  virtual void Print(VarTable &Variables) {
    cout << "[[" << ThemeName << "]]\n";
    if (StmtList) StmtList->Print(Variables);
    if (Next)  Next->Print(Variables);
  }

  // EvaluateSection - This function causes only the 'this' section to be added
  // to the specified linked list... if it's a theme, it should add all of the 
  // theme stuff too...
  //
  virtual void EvaluateSection(VarTable &Variables, 
                               LinkedList<CFileSection> &List, int *Lint);

protected :
  CSString ThemeName;

  // Set by the PostLoadFixupScan() function...
  String ThemeURL, ThemePath;
  ConfigFileSection *ThemeConfigFile;
};


class VarDefaultsConfigFileSection : public ConfigFileSection {
public :
  VarDefaultsConfigFileSection(int LineNo, 
                         ConfigFileStatement *SList, ConfigFileSection *N) 
           : ConfigFileSection(LineNo, "VariableDefaults", SList, N) {
  }

  ~VarDefaultsConfigFileSection() {
  }

  // Print - Print out this section of the configuration file...
  //
  virtual void Print(VarTable &Variables) {
    cout << "[" << SectionName << "]\n";
    if (StmtList) StmtList->Print(Variables);
    if (Next) Next->Print(Variables);
  }

  // EvaluateSection - This function causes only the 'this' section to be added
  // to the specified linked list... if it's a theme, it should add all of the 
  // theme stuff too...
  //
  virtual void EvaluateSection(VarTable &Variables, 
                               LinkedList<CFileSection> &List, int *Lint);
};


class GlobalConfigFileSection : public ConfigFileSection {
public :
  GlobalConfigFileSection(int LineNo, ConfigFileStatement *SList, 
                          ConfigFileSection *N) ;

  ~GlobalConfigFileSection() {
  }

  // Print - Print out this section of the configuration file...
  //
  virtual void Print(VarTable &Variables) {
    cout << "[" << SectionName << "]\n";
    if (StmtList)
      StmtList->Print(Variables);

    if (Next) 
      Next->Print(Variables);
  }

  // EvaluateSection - This function causes only the 'this' section to be added
  // to the specified linked list... if it's a theme, it should add all of the 
  // theme stuff too...
  //
  virtual void EvaluateSection(VarTable &Variables, 
                               LinkedList<CFileSection> &List, int *Lint);
};

#endif
