/**********************************************************************
 *
 * action.h -- 
 * 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 ACTION_H
#define ACTION_H

#include "gsdlconf.h"
#include "text_t.h"
#include "cgiargs.h"
#include "display.h"
#include "recptproto.h"
#include "browserclass.h"
#include "securitytools.h"

#if defined(GSDL_USE_OBJECTSPACE)
#  include <ospace\std\iostream>
#elif defined(GSDL_USE_IOS_H)
#  include <iostream.h>
#else
#  include <iostream>
#endif


class action {
protected:
  cgiargsinfoclass argsinfo;
  text_t gsdlhome;
  text_t collecthome;
  text_t dbhome;

public:
  action ();
  virtual ~action ();

  // configure should be called once for each configuration line
  virtual void configure (const text_t &key, const text_tarray &cfgline);

  // init should be called after all the configuration is done but
  // before any other methods are called
  virtual bool init (ostream &logout);

  // returns the "a" argument value that will specify this action
  // this name should be short but does not have to be one character
  // long
  virtual text_t get_action_name ();

  // check_cgiargs should be called before get_cgihead_info, 
  // define_external_macros, and do_action. If an error is found
  // a message will be written to logout, if the error is severe
  // then the function will return false and no page content
  // should be produced based on the arguments.
  virtual bool check_cgiargs (cgiargsinfoclass &argsinfo, cgiargsclass &args, 
			      recptprotolistclass *protos, ostream &logout);

  // check_external_cgiargs should be called after check_cgiargs
  // for all actions. It should only be used to override some other
  // normal behaviour, for example, producing a login page when
  // the requested page needs authentication.
  virtual bool check_external_cgiargs (cgiargsinfoclass &argsinfo,
				       cgiargsclass &args,
				       outconvertclass &outconvert,
				       const text_t &saveconf,
				       ostream &logout);

  // 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, recptprotolistclass *protos,
				 response_t &response, text_t &response_data, 
				 ostream &logout);
  
  // uses_display should return true if the receptionist should return
  // true if the display class is needed to output the page content.
  // The default is to return true.
  virtual bool uses_display (cgiargsclass &args);

  // define all the macros which are related to pages generated
  // by this action
  virtual void define_internal_macros (displayclass &disp, cgiargsclass &args, 
				       recptprotolistclass *protos, ostream &logout);

  // define all the macros which might be used by other actions
  // to produce pages. These macros should be well documented.
  virtual void define_external_macros (displayclass &disp, cgiargsclass &args, 
				       recptprotolistclass *protos, ostream &logout);

  // returns false if there was an error which prevented the action
  // from outputing anything.
  virtual bool do_action (cgiargsclass &args, recptprotolistclass *protos, 
			  browsermapclass *browsers, displayclass &disp, 
			  outconvertclass &outconvert, ostream &textout, 
			  ostream &logout);

  // return true if the specified top classifier is handled by this action
  virtual bool is_my_classifier(const text_t& topcl) { return false; }

  // getargsinfo should be called after all configuration files
  // have been read
  cgiargsinfoclass *getargsinfo() {return &argsinfo;};
};


// The actionptr function does not 'own' the action. The 
// action should be deleted by the code which created it.
class actionptr {
public:
  action *a;

  actionptr () {a=NULL;}
};

bool operator==(const actionptr &x, const actionptr &y);
bool operator<(const actionptr &x, const actionptr &y);

typedef map<text_t, actionptr, lttext_t> actionptrmap;

// contains a list of actions indexed by their name
class actionmapclass {
protected:
  actionptrmap actionptrs;

public:
  // type support for actionptrmap
  typedef actionptrmap::iterator iterator;
  typedef actionptrmap::const_iterator const_iterator;
  typedef actionptrmap::reference reference;
  typedef actionptrmap::const_reference const_reference;
  typedef actionptrmap::size_type size_type;

  typedef actionptrmap::difference_type difference_type;
  typedef actionptrmap::const_reverse_iterator const_reverse_iterator;
  typedef actionptrmap::reverse_iterator reverse_iterator;
  
  // basic container support
  iterator begin () {return actionptrs.begin();}
  const_iterator begin () const {return actionptrs.begin();}
  iterator end () {return actionptrs.end();}
  const_iterator end () const {return actionptrs.end();}

  void erase(iterator pos) {actionptrs.erase(pos);}
  void erase(iterator first, iterator last) {actionptrs.erase(first, last);}
  actionmapclass &operator=(const actionmapclass &x) {actionptrs=x.actionptrs;return *this;}

  bool empty () const {return actionptrs.empty();}
  size_type size() const {return actionptrs.size();}


  // added functionality
  void clear () {actionptrs.erase(actionptrs.begin(),actionptrs.end());}

  // theaction remains the property of the calling code but
  // should not be deleted until it is removed from this list.
  void addaction (action *theaction);

  // getaction will return NULL if the action could not be found
  action *getaction (const text_t &key);
};


#endif
