/**********************************************************************
 *
 * receptionist.h -- a web interface for the gsdl
 * Copyright (C) 1999  The New Zealand Digital Library Project
 *
 * A component of the Greenstone digital library software
 * from the New Zealand Digital Library Project at the
 * University of Waikato, New Zealand.
 *
 * 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 of the License, 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 RECEPTIONIST_H
#define RECEPTIONIST_H

#include "gsdlconf.h"
#include "text_t.h"
#include "cgiargs.h"
#include "display.h"
#include "browserclass.h"
#include "recptproto.h"
#include "converter.h"
#include "cfgread.h"
#include "action.h"
#include "cnfgable.h"

// the MACROPRECEDENCE macro is used as a default. override
// it using something like:
//
// macroprecedence c,l
//
// in your configuration file
#ifndef MACROPRECEDENCE
#define MACROPRECEDENCE "c,l"
#endif


struct collectioninfo_t {
  void clear ();
  collectioninfo_t () {clear();}

  text_t gsdl_gsdlhome;
  text_t gsdl_collecthome;
  text_t gsdl_dbhome;

  bool info_loaded;
  ColInfoResponse_t info;
};

struct languageinfo_t {
  void clear();
  languageinfo_t () {clear();}

  text_t longname;
  text_t defaultencoding;
};

typedef map<text_t, collectioninfo_t, lttext_t> colinfo_tmap;
typedef map<text_t, languageinfo_t, lttext_t> languageinfo_tmap;

enum events_t {Disabled, CollectorEvents, AllEvents};
enum ldformat_t {LocalTime, UTCTime, Absolute};

struct recptconf {
   text_t gsdlhome;
   text_t collecthome;
   text_t dbhome;   // will equal gsdlhome if not set
   text_t collection; // will equal "" in 'general' mode
   text_t collectdir; // will equal gsdlhome in 'general' mode
   colinfo_tmap collectinfo;
   text_t httpprefix;
  text_t httpweb; // will be set to httpprefix/web if not set
   text_t gwcgi;
   text_tset macrofiles;
   text_t saveconf;
   bool usecookiesForUID;  // true if we want to save user id as a cookie
  bool usecookiesForE; // true if want to save the e arg as a cookie instead of passing it round as an arg
   bool logcgiargs;  // true if we want to log cgi arguments
   
   ldformat_t LogDateFormat;
   
   text_t maintainer; // email address of maintainer
   text_t MailServer; // SMTP mail server to use when sending event messages by email
                     // defaults to mail.maintainer-domain
   events_t LogEvents;
   events_t EmailEvents;
   bool EmailUserEvents;

   bool    site_auth;   // Complete site authentication, useful to lockout site for example.
   text_t  site_group;  // Similar to the auth_groups functionality, infact exactly the same
   
   text_t HomePageType; 
   int HomePageCols;
   
   text_tmap pageparams;
   text_t macroprecedence;
   
   languageinfo_tmap languages;
   
   // encodings is just a simple mapping from encoding longnames to
   // shortnames.  It's useful for now for creating the pulldown menu of
   // encodings on the preferences page but isn't intended to be permanent.
   text_tmap encodings;
   
   void clear ();
   recptconf () {clear();}
  
};

class receptionist : public configurable {
protected:

   recptconf configinfo;
   
   cgiargsinfoclass argsinfo;
   actionmapclass actions;
   browsermapclass browsers;
   recptprotolistclass protocols;
   displayclass disp;
   convertinfoclass converters;
   ColInfoResponse_t collectinfo;
   
   // prepare_page sets up page parameters, sets display macros
   // and opens the page ready for output 
   virtual void prepare_page (action *a, cgiargsclass &args, 
			      outconvertclass &outconvert, 
			     ostream &logout);
   
   virtual void translate_OIDs (cgiargsclass &args, recptproto *collectproto,
				ostream &logout);
   
   bool get_uid_cookie (text_t &cookie, text_tmap &fcgienv);
   bool has_uid_cookie (text_tmap &fcgienv);
  bool get_named_cookie (text_t &cookie, const text_t cookie_name, text_tmap &fcgienv);
  
   // get the default encoding for the given language - if it fails for any
   // reason, return ""
   text_t get_default_encoding (const text_t &language);
   
   virtual void define_general_macros (cgiargsclass &args, outconvertclass &outconvert, 
				       ostream &logout);
   
   virtual bool append_logstr (const text_t &filename, const text_t &logstr,
                               ostream &logout);

   virtual void configure_encoding (const text_tarray &cfgline);
   
 public:
   receptionist ();
   virtual ~receptionist() {}

#ifdef _APACHE_MOD
   bool loaded;
#endif   
   // add_action makes another action available to the receptionist
   // the action remains the property of the calling code and that
   // code should destroy the action after the recptionist has been
   // destroyed.
   void add_action (action *theaction);
   actionmapclass *get_actionmap_ptr () {return &actions;}
   
   // add_browser makes another browser available to the receptionist
   // the browser remains the property of the calling code and that
   // code should destroy it after the recptionist has been
   // destroyed.
   void add_browser (browserclass *thebrowser);
   browsermapclass *get_browsermap_ptr () {return &browsers;}
   void setdefaultbrowser (const text_t &browsername);
   
   // add_protocol makes another protocol available to the receptionist
   // without any protocols, no collections will be available. The
   // protocols remain the property of the calling code.
   void add_protocol (recptproto *theprotocol) {protocols.addrecptproto(theprotocol);}
   recptprotolistclass *get_recptprotolist_ptr () {return &protocols;}
   
   // add_converter makes another converter available to the receptionist.
   // Converters are needed to display pages using different encodings.
   // The converters remain the property of the calling code.
   void add_converter (const text_t &name, inconvertclass *inconverter,
		       rzwsoutconvertclass *outconverter) {
      converters.add_converter(name, inconverter, outconverter);}
   convertinfoclass *get_convertinfo_ptr () {return &converters;}
   
   
   // configure should be called for each line in the
  // configuration files to configure the receptionist and everything
  // it contains. The configuration should take place after everything
  // has been added but before the initialisation.
  virtual void configure (const text_t &key, const text_tarray &cfgline);
  virtual void configure (const text_t &key, const text_t &value);
  const recptconf &get_configinfo () const {return configinfo;}
  cgiargsinfoclass *get_cgiargsinfo_ptr () {return &argsinfo;}
  

  // init should be called after all the actions, protocols, and
  // converters have been added to the receptionist and after everything
  // has been configured but before any pages are created.
  // It returns true on success and false on failure. If false is
  // returned getpage should not be called (without producing
  // meaningless output), instead an error page should be
  // produced by the calling code.
  virtual bool init (ostream &logout);
  
  // There are two ways to produce a page. You can either call parse_cgi_args,
  // get_cgihead_info, and produce_content or you can just call parse_cgi_args and
  // produce_cgi_page (which will be satisfactory in most cases). You might want to call
  // parse_cgi_args, get_cgihead_info, and produce_content when you want to
  // interface directly with a web server for which the standard header is inappropriate.

  // parse_cgi_args parses cgi arguments into an argument class.
  // This function should be called for each page request. It returns false
  // if there was a major problem with the cgi arguments.
  virtual bool parse_cgi_args (const text_t &argstr, 
			       fileupload_tmap &fileuploads,
			       cgiargsclass &args, 
			       ostream &logout, text_tmap &fcgienv);

  virtual bool log_cgi_args (cgiargsclass &args, ostream &logout, text_tmap &fcgienv);

  text_t expandmacros (const text_t &astring, cgiargsclass &args, 
		       ostream &logout);

  // produce_cgi_page will call get_cgihead_info and 
  // produce_content in the appropriate way to output a cgi header and
  // the page content (if needed). If a page could not be created it
  // will return false
  virtual bool produce_cgi_page (cgiargsclass &args, ostream &contentout, 
				 ostream &logout, text_tmap &fcgienv);
  
  // get_cgihead_info determines the cgi header information for
  // a set of cgi arguments. If response contains location then
  // response_data contains the redirect address. If reponse
  // contains content then reponse_data contains the content-type.
  // Note that images can now be produced by the receptionist.
  virtual void get_cgihead_info (cgiargsclass &args, response_t &response,
				 text_t &response_data, ostream &logout,
				 text_tmap &fcgienv);
  virtual void get_cgihead_info (cgiargsclass &args, text_tmap &headers,
				 ostream &logout, text_tmap &fcgienv);

  // produce the page content
  virtual bool produce_content (cgiargsclass &args, ostream &contentout,
				ostream &logout);
  
  // returns the compressed argument ("e") corresponding to the argument
  // list. This can be used to save preferences between sessions.
  virtual text_t get_compressed_arg (cgiargsclass &args, ostream &logout);

  // gets collection info from cache if found or 
  // calls collection server (and updates cache)
  // returns NULL if there's an error
  ColInfoResponse_t *get_collectinfo_ptr (recptproto *collectproto, 
					  const text_t &collection, 
					  ostream &logout);

  void uncache_collection (const text_t &collection);
  
protected:
  // will read in all the macro files. If one is not found an
  // error message will be written to logout and the method will
  // return false.
  virtual bool read_macrofiles (ostream &logout);
  
  virtual void read_collection_macrofiles (const text_t& collection, ostream &logout);

  // check_mainargs will check all the main arguments. If a major
  // error is found it will return false and no cgi page should
  // be created using the arguments.
  virtual bool check_mainargs (cgiargsclass &args, ostream &logout);
};


#endif
