/*
  SESSION-SERVICES.hpp  -  accessing Proc-Layer internal session implementation services

  Copyright (C)         Lumiera.org
    2008,               Hermann Vosseler <Ichthyostega@web.de>

  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.

*/


/** @file session-services.hpp
 ** A mechanism for exposing and accessing implementation level
 ** services of the session. While any client code should always
 ** use the public Session API, some implementation level facilities
 ** within Proc-Layer need to cooperate with a wider SessionImpl API.
 ** On the other hand, we don't want to create coupling between the
 ** mentioned Proc internals and the session implementation. Another
 ** concern addressed by this mechanism is to assure consistency
 ** across all those implementation APIs. New APIs can be added
 ** just by extending a template definition and will automatically
 ** participate in the session management mechanisms, because any
 ** access is routed through the top level Session PImpl.
 ** 
 ** \par structure of session implementation-level services
 ** 
 ** Assumed any part of the Proc implementation needs to cooperate
 ** with the session implementation; the necessary link has to be
 ** abstracted into an implementation level API. Typically, this
 ** API provides an static access function, which is to be implemented
 ** "somewhere else", so the Proc implementation isn't required to 
 ** include anything of the session implementation level
 ** 
 ** In order to actually provide such a service, an specialisation of
 ** the ServiceAccessPoint template has to be defined, which may mix in
 ** the service API and implement it directly on top of SessionImpl.
 ** Note, mixing in the API isn't required -- alternatively the API might
 ** be completely bridged through the mentioned static access functions
 ** (i.e. such would be kind of an generic API, relying on convention
 ** rather than on a vtable)
 ** 
 ** When the SessManagerImpl creates the concrete session object,
 ** it doesn't use the bare SessionImpl class; rather, an inheritance
 ** chain is formed, starting with SessionImpl and stacking any of the
 ** configured ServiceAccessPoint instantiations on top of it. Thus,
 ** the public session access gets the concrete implementation of the
 ** Session API (through the vtable), while any service level access
 ** can use the corresponding service API directly. Service APIs have
 ** to care to avoid name clashes though.
 ** 
 ** The implementation of all the service API access functions is
 ** bundled within session-service.cpp -- where the full compound
 ** of SessionImpl and the ServiceAccessPoint specialisations has
 ** to be visible.
 ** 
 ** @see session-service-access-test.cpp simplified inline demo definition of this setup
 ** @see session.hpp public session API
 ** @see session-impl.hpp definition of ServiceAccessPoint specialisations
 ** @see session-impl.cpp session implementation internals
 **
 */


#ifndef MOBJECT_SESSION_SESSION_SERVICES_H
#define MOBJECT_SESSION_SESSION_SERVICES_H

#include "proc/mobject/session.hpp"
#include "lib/meta/generator.hpp"




namespace proc {
namespace mobject {
namespace session {
  
  using lib::meta::InstantiateChained;
  using lib::meta::Types;
  
  
  /**
   * Access point to a single implementation-level API.
   * For each concrete service to provide, an specialisation
   * of this template is assumed to exist which inherits from
   * IMPL; it will be used in an inheritance-chain on top of
   * SessionImpl and thus can access the latter (= session
   * implementation API) just through its parent class IMPL
   */
  template<class API, class IMPL>
  struct ServiceAccessPoint;
  
  
  /**
   * Collection of configured implementation-level services
   * to provide by the Session. An instance of this template
   * is created on top of SessionImpl, configured such as
   * to inherit from all the concrete services to be
   * exposed for use by Proc-Lyer's internals.
   * 
   * @param APIS  sequence of API types to implement
   * @param FRONT type of the frontend used for access
   * @param SESS  the basic session implementation 
   */
  template< typename APIS
          , class FRONT
          , class SESS
          >
  class SessionServices
    : public InstantiateChained< typename APIS::List    // for each of the API types...
                               , ServiceAccessPoint    //  instantiate a service implementation
                               , SESS                 //   and stack all these on top of SessionImpl
                               >
    {
    public:
      static FRONT& current;                      ///< intended to be hard-wired to SessManagerImpl singleton 
      
      /** access an service by explicit downcast.
       *  @warning this function is dangerous; never store the
       *           returned reference, as the referred object 
       *           might go away due to session close/reset/load
       */
      template<class API>
      API& get() { return *this; }
    };
  
  
  
}}} // namespace proc::mobject::session
#endif
