//-----------------------------------------------------------
// Copyright Christian Arnault LAL-Orsay CNRS
// arnault@lal.in2p3.fr
// Modified by Grigory Rybkin
// See the complete license in cmt_license.txt "http://www.cecill.info". 
//-----------------------------------------------------------

#ifndef __cmt_generator_h__
#define __cmt_generator_h__

#include "cmt_parser.h"
#include "cmt_constituent.h"
#include "cmt_language.h"
#include "cmt_awk.h"

class Packager : public FAwk
{
public:
  void begin ();
  void filter (const cmt_string& line);
  cmt_string& package_name ();
private:
  cmt_string m_package_name;
};

class SourceFile
{
public:
  void set (const cmt_string name, Language& language, const cmt_string output);
  cmt_string name () const;
  Language& language () const;
  cmt_string output () const;

private:
  cmt_string m_name;
  Language* m_language;
  cmt_string m_output;
};

/**
   Base class for all specific generators.
   The Generator command driver will operate on specialized classes of CmtGenerator
*/
class CmtGenerator
{
public:

  CmtGenerator ();

  void reset ();
  bool prepare_output (const cmt_string& package,
                       const Constituent& constituent,
		       const cmt_string& file = "");
  void commit (const cmt_string& name);
  static void check (const cmt_string& name);
  void terminate ();

  void fill_names_outputs ();
  void fill_outputs ();

  //  void prepare_use_context ();

  void set_full_name (cmt_string& full_name, cmt_string& file);
  void filter_path (cmt_string& text);
  int get_all_files (const cmt_string& full_name,
		     const cmt_vector<cmt_regexp>& exclude_exprs, 
		     const cmt_vector<cmt_regexp>& select_exprs, 
		     CmtSystem::cmt_string_vector& files);


public:
  cmt_string m_PACKINCLUDES;
  bool m_PACKOS9;

  cmt_string m_GENERATOR;

  bool is_library;
  bool is_application;

  cmt_string srcdir;
  cmt_string docdir;
  cmt_string cmtdir;
  cmt_string incdir;
  cmt_string src;
  cmt_string doc;
  cmt_string inc;
  cmt_string mgr;
  cmt_string cmt;
  cmt_string protos;
  cmt_string protonames;
  cmt_string os9sources;

  cmt_vector<SourceFile> m_source_files;

  cmt_string m_bin;
  cmt_string m_output_file_name;
  FILE* m_output_file;

  Constituent* m_constituent;

  Variable m_CONSTITUENT;
  Variable m_LINKMACRO;
  Variable m_DEPENDENCIESOPTS;
  Variable m_DOCPATH;
  Variable m_PACKAGEPATH;
  Variable m_PACKAGEPREFIX;
  Variable m_PACKAGE;
  Variable m_VERSION;
  Variable m_MGRSTYLE;
  Variable m_TITLE;
  Variable m_GROUP;
  Variable m_CONSTITUENTSUFFIX;
  Variable m_LIBRARYSUFFIX;
  Variable m_USER;
  Variable m_DATE;
  Variable m_PROTOTARGET;
  Variable m_OBJS;
  Variable m_CLASSES;
  Variable m_PROTOSTAMPS;
  Variable m_NAME;
  Variable m_FILEPATH;
  Variable m_FILESUFFIX;
  Variable m_SUFFIX;
  Variable m_FILENAME;
  Variable m_LINE;
  Variable m_ADDINCLUDE;
  Variable m_FULLNAME;
  Variable m_DIRNAME;
  Variable m_OUTPUTNAME;
  Variable m_ALLOS9SOURCES;
  Variable m_NODEBUGUSELINKOPTS;
  Variable m_DEBUGUSELINKOPTS;
  Variable m_USEINCLUDES;
  Variable m_HASTARGETTAG;
  Variable m_HASDEPENDENCIES;
  Variable m_HASPROTOTYPES;
  Variable m_ISCHECKGROUP;
};

class InGenerator
{
 public:
  InGenerator (bool usecmt, bool pedantic);
  int build (const Constituent& constituent, ostream& out = cout);
  
 private:
  InGenerator ();

 private:
  class Buffer
  {
  public:
    Buffer ();
    void set_names (const CmtSystem::cmt_string_vector& names);
    int print (ostream& s);
    void set_uses (bool usecmt);
    void set_pedantic (bool pedantic);
  private:
    virtual int initialize () = 0;

  protected:
    CmtSystem::cmt_string_vector m_names;
    ostringstream m_buffer;
    bool m_initialized;
    bool m_usecmt;
    bool m_pedantic;
  };
  
  class Languages : public Buffer
  {
  private:
    int initialize ();
  };
  
  class Fragments : public Buffer
  {
  private:
    int initialize ();
  };
  
 private:
  Fragments m_common;
  Fragments m_application;
  Fragments m_application_library;
  Fragments m_library;
  Fragments m_document;
  Languages m_languages;
  bool m_usecmt;
  bool m_pedantic;
};

/**
   Generic command interface to be used by the cmt command driver.
 */
class Generator
{
public:
    // Build the MSDEV workspace file
  static int build_msdev_workspace (const Constituent::ConstituentVector& constituents);

    // Build the MSDEV project file (one per constituent)
  static int build_msdev (const Constituent& constituent);

    // Build the VSNET workspace file
  static int build_vsnet_workspace (const Constituent::ConstituentVector& constituents);

    // Build the VSNET project file (one per constituent)
  static int build_vsnet (const Constituent& constituent);

     // Build the Make setup file
  static void build_make_setup (const cmt_string& package);

    // Build the constituents.make file
  static void build_constituents_makefile (const cmt_string& package,
					   const cmt_string& file = "");
					   //					   const CmtSystem::cmt_string_vector& arguments);

    // Build the makefile fragment for one constituent
  static int build_constituent_makefile (const Constituent& constituent,
					 bool& dependencies,
					 const cmt_string& file = "");
  static void build_constituent_makefile (const CmtSystem::cmt_string_vector& arguments);
  static int build_constituent_infile (const Constituent& constituent,
				       const cmt_string& outdir = "",
				       bool usecmt = true);

  static int build_library_links_infile (const cmt_string& outdir = "");

  static int build_dependencies_infile (const Constituent* constituent,
					const cmt_string& outdir = "",
					bool usecmt = true);

  static void build_default_makefile ();

    // Build the packages (N)Make file
  static void build_packages_makefile (const cmt_string& package,
				       const cmt_string& file = "");

    // Build the dependencies for one module
  static void build_dependencies (const CmtSystem::cmt_string_vector& arguments);

    // Build prototype file for one module
  static void build_prototype (const cmt_string& file_name);

    // Build README.html file
  static void build_readme (const CmtSystem::cmt_string_vector& arguments);

    // Build def files for Windows shared libraries
  //  static void build_windefs (const cmt_string& library_name);
  static void build_windefs (const CmtSystem::cmt_string_vector& arguments);
};

#endif
