////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// This is a part of the COM Serialization SDK VC++ Library.
//  
// Copyright 2009 BPM Microsystems
// 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//                                                                                                                    //
// $Header: //sesca/src/Winprog/COMSerializationSDK/VC++/HeaderLib/ComSerSdk/rcs/StaticVectorServer.h 1.2 2009/06/05 11:53:12 arturoc Exp $
//                                                                                                                    //
///////// 120 columns, Tab = Insert 3 Spaces ///////////////////////////////////////////////////////////////////////////

/**
   This header file defines the CStaticVectorServerBase class, as well as other related helper classes used in its
   implementation.

   The following is an attempt at an explanation of how we allow a variable number of template arguments and for
   each argument we require the user to provide an override of a SetVector() member function.

   1.) We define a template class named CStaticVectorServerBase that takes 18 template arguments, each of them
       defaulted to a single seperate type named "NoArg", and the class has no implementation.  You can see this
       class template declaration for yourself in the code below.  The purpose of this class is to provide a compiler
       error if a user specifies 0 template arguments (since it has no implementation), to allow the user to
       provide a variable number of template arguments, and to act as a primary template for a number of
       specializations.

   2.) We define 17 seperate specializations of the class described in #1 above.  Each of them take a different
       number of template arguments.  When the library-user specifies template arguments to CStaticVectorServerBase,
       they are actually instantiating one of these specializations.  You can see the list of all of these
       specializations below.  Notice that for each of them, we do not have to manually specify "NoArg" for any
       template arguments that are not set.  This is because the primary template (the one with no implementation)
       defaults them to "NoArg" for us.

   3.) Each specialization inherits from a template class named CSvsi.  The letters in its name stand for "Static
       Vector Server Implementation".  CSvsi accepts two template arguments: a static vector type, and another
       specialization of CStaticVectorServerBase.
       For the purposes of this explanation, we will refer to the number of template arguments that each specialization
       accepts as NumTemplateArgs.  The specialization that is provided as the second template argument to CSvsi
       is the one that takes a number of template arguments that is equal to NumTemplateArgs-1.

   4.) CSvsi is the class that declares the SetVector() member function as pure-virtual.  It specifies 
       its first template argument (which is a static vector type) as the parameter type that the SetVector() 
       pure-virtual requires.
       CSvsi is also defined to inherit from its second template argument.  That second template argument,
       as stated above, is a CStaticVectorServerBase specialization that does the same thing as the one that inherited
       from CSvsi.
       
       The CStaticVectorServerBase specialization that takes a single template argument is defined to inherit from
       a CSvsi template where, unlike all other specializations of CStaticVectorServerBase, the second template
       argument is not another specialziation but instead a class named CSvsiRoot.

       Not only does CSvsi specify the SetVector() pure-virtual, it also DEFINES another member function named
       SetVectors() (notice that its name is plural).  SetVectors() is defined in CSvsi to declare an instantiation
       of the static vector object, invoke its SetVector() pure-virtual with that instantiation, and then 
       invoke the base-class SetVectors() (plural).   This chain of calls that originates at one point
       in the heirarchy and ends at the other extreme is how we call all of the SetVector() (singular) pure-virtuals.

       The result is a class heirarchy that looks like this:
       ___________
      | CSvsiRoot |
       -----------
            ^
       _____|______________________________________________________
      | CSvsi (defines pure-virtual SetVector(CStaticVectorType1&))|    
       ------------------------------------------------------------
            ^
       _____|_________________________________________
      | CStaticVectorServerBase (1 arg specialization)|
       -----------------------------------------------
            ^
       _____|______________________________________________________
      | CSvsi (defines pure-virtual SetVector(CStaticVectorType2&))|    
       ------------------------------------------------------------
            ^
       _____|_________________________________________
      | CStaticVectorServerBase (2 arg specialization)|
       -----------------------------------------------
            ^
       _____|______________________________________________________
      | CSvsi (defines pure-virtual SetVector(CStaticVectorType3&))| 
       ------------------------------------------------------------
            ^
       _____|_________________________________________
      | CStaticVectorServerBase (3 arg specialization)|
       -----------------------------------------------
         etc
            
*/
#pragma once

#include "Detail/Server.h"
#include "StaticVector.h"
#include "Constants.h"

namespace ComSerSdk
{
namespace Detail
{

/**
   Svsi = "Static Vector Server Impl".  Declares a pure-virtual "SetVectors" (notice it's plural) member function,
   and overrides CServerCommonBase's GetSerialData() to invoke the SetVectors pure-virtual.  The SetVectors
   pure-virtual is overriden in the CSvsi concrete of this class to invoke the SetVector() pure-virtual that it
   declared with an instance of its static vector, and then invoke its base class' SetVectors (plural).

*/
class CSvsiRoot : public CServerCommonBase
{
   /**
      /override
      Invokes the SetVectors() (plural) pure-virtual to let it begin the chain of calls to all of the library-user's
      SetVector() overrides.
   */
   virtual HRESULT DoGetSerialData(BSTR sCurrentNumber, IDispatch ** ppoDictionaryAsIDispatch)
   {
      std::string sNextHandle;

      // Obviously, this invokes the SetVectors() override of the most-derived class; that is, the concrete at the
      // very bottom of the heirarchy.  But it is defined in that most-derived, and also in all classes in between,
      // to, after it's done, allow its base-class' SetVectors to be invoked.
      //
      SetVectors(std::string(_bstr_t(sCurrentNumber)), sNextHandle);

      PutItem(Dictionary(), _variant_t("NextHandle"), _variant_t(sNextHandle.c_str()), COMSERSDK_CODELOCATION);
      *ppoDictionaryAsIDispatch = Dictionary();
      return S_OK;
   }

   virtual HRESULT DoGetSocketSerialData(BSTR sCurrentNumber, 
                                         long lSite,
                                         long lSocket, 
                                         BSTR sSiteId,
                                         BSTR sAdapter,
                                         BSTR sSocketId,
                                         IDispatch ** ppoDictionaryAsIDispatch)
   {
      return DoGetSerialData(sCurrentNumber, ppoDictionaryAsIDispatch);
   }

   virtual HRESULT DoGetSerialAddresses(IDispatch ** ppoDictionaryAsIDispatch)
   {
      Scripting::IDictionaryPtr spoDictionary = CServerBase::CreateDictionary();
      //CVectorAddrSetter oAddrSetter(spoDictionary);
      //SetVectorAddrs(oAddrSetter);
      *ppoDictionaryAsIDispatch = spoDictionary.Detach();
      return S_OK;
   }

public:

   /**
      The pure-virtual overriden by CSvsi so that it can instantiate its static vector type, pass it to its
      SetVector() (singular) pure-virtual, and then defer the rest of the execution to its base class.
      Even though this is pure-virtual, we'll give it a body that does nothing to allow the invokation of it
      that the single-vector version of CSvsi does to not result in an unnecessary compile error.
   */
   virtual void SetVectors(const std::string & sCurrentHandle, std::string & sNextHandle) = 0{};

};

/**
   Svsi = "Static Vector Server Impl"
*/
template<class TVector, class TBase>
class CSvsi : public TBase
{
   /**
      To be overriden by the library-user so that they can place their logic to specify the data portion of the
      vector object passed in.
   */
   virtual void SetVector(const std::string & sCurrentHandle, std::string & sNextHandle, TVector &) = 0;

protected:
   
   /**
      /override
      Here we instantiate the static vector, pass it to the library-user's SetVector() override, and then invoke
      our base-class' SetVectors(), which will do the exact same thing with its static vector.
   */
   virtual void SetVectors(const std::string & sCurrentHandle, std::string & sNextHandle)
   {
      Detail::CExceptionPtr spoVectorDestructorException;

      CreateAndSetVector(sCurrentHandle, sNextHandle, spoVectorDestructorException);
      
      if(spoVectorDestructorException.get())
      {
         spoVectorDestructorException->Throw();
      }

      TBase::SetVectors(sCurrentHandle, sNextHandle);
   }


private:

   /**
      Helper for instantiating a static vector and passing it to the library-user's SetVector() override.  The only
      reason to have this function is so that the static vector is created and destroyed in its scope, which optimizes
      memory usage.
   */
   void CreateAndSetVector(const std::string & sCurrentHandle,
                           std::string & sNextHandle,
                           Detail::CExceptionPtr & spoVectorDestructorException)
   {
      TVector oVec(Dictionary(), spoVectorDestructorException);
      SetVector(sCurrentHandle, sNextHandle, oVec);
   }
};


/**
   Type used to act as the CStaticVectorServerBase class' template argument default value.
*/
struct NoArg{};

}// end namespace Detail

/**
   The primary template.  Specializations are immediately below.
*/
template<
      typename T0  = Detail::NoArg, typename T1  = Detail::NoArg, typename T2  = Detail::NoArg,
      typename T3  = Detail::NoArg, typename T4  = Detail::NoArg, typename T5  = Detail::NoArg,
      typename T6  = Detail::NoArg, typename T7  = Detail::NoArg, typename T8  = Detail::NoArg,
      typename T9  = Detail::NoArg, typename T10 = Detail::NoArg, typename T11 = Detail::NoArg,
      typename T12 = Detail::NoArg, typename T13 = Detail::NoArg, typename T14 = Detail::NoArg,
      typename T15 = Detail::NoArg, typename T16 = Detail::NoArg, typename T17 = Detail::NoArg,
      typename T18 = Detail::NoArg, typename T19 = Detail::NoArg
    >
class CStaticVectorServerBase;

/**
  CStaticVectorServerBase specializations.  Implementations are forwarded to their templated base classes.
*/

template<class T0>
class CStaticVectorServerBase<T0> : 
   public Detail::CSvsi<T0, Detail::CSvsiRoot>{};

template<class T0, class T1>
class CStaticVectorServerBase<T1,                         T0> : 
   public Detail::CSvsi<      T1, CStaticVectorServerBase<T0>>{};

template<class T0, class T1, class T2>
class CStaticVectorServerBase<T2,                         T1,T0> : 
   public Detail::CSvsi<      T2, CStaticVectorServerBase<T1,T0>>{};

template<class T0, class T1, class T2, class T3>
class CStaticVectorServerBase<T3,                         T2,T1,T0> : 
   public Detail::CSvsi<      T3, CStaticVectorServerBase<T2,T1,T0>>{};

template<class T0, class T1, class T2, class T3, class T4>
class CStaticVectorServerBase<T4,                         T3,T2,T1,T0> : 
   public Detail::CSvsi<      T4, CStaticVectorServerBase<T3,T2,T1,T0>>{};

template<class T0, class T1, class T2, class T3, class T4, class T5>
class CStaticVectorServerBase<T5,                         T4,T3,T2,T1,T0> : 
   public Detail::CSvsi<      T5, CStaticVectorServerBase<T4,T3,T2,T1,T0>>{};

template<class T0, class T1, class T2, class T3, class T4, class T5, class T6>
class CStaticVectorServerBase<T6,                         T5,T4,T3,T2,T1,T0> : 
   public Detail::CSvsi<      T6, CStaticVectorServerBase<T5,T4,T3,T2,T1,T0>>{};

template<class T0, class T1, class T2, class T3, class T4, class T5, class T6, class T7>
class CStaticVectorServerBase<T7,                         T6,T5,T4,T3,T2,T1,T0> : 
   public Detail::CSvsi<      T7, CStaticVectorServerBase<T6,T5,T4,T3,T2,T1,T0>>{};

template<class T0, class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8>
class CStaticVectorServerBase<T8,                         T7,T6,T5,T4,T3,T2,T1,T0> : 
   public Detail::CSvsi<      T8, CStaticVectorServerBase<T7,T6,T5,T4,T3,T2,T1,T0>>{};

template<class T0, class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class T9>
class CStaticVectorServerBase<T9,                         T8,T7,T6,T5,T4,T3,T2,T1,T0> : 
   public Detail::CSvsi<      T9, CStaticVectorServerBase<T8,T7,T6,T5,T4,T3,T2,T1,T0>>{};

template<class T0, class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class T9,
         class T10>
class CStaticVectorServerBase<T10,                         T9,T8,T7,T6,T5,T4,T3,T2,T1,T0> : 
   public Detail::CSvsi<      T10, CStaticVectorServerBase<T9,T8,T7,T6,T5,T4,T3,T2,T1,T0>>{};

template<class T0, class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class T9,
         class T10, class T11>
class CStaticVectorServerBase<T11,                         T10,T9,T8,T7,T6,T5,T4,T3,T2,T1,T0> : 
   public Detail::CSvsi<      T11, CStaticVectorServerBase<T10,T9,T8,T7,T6,T5,T4,T3,T2,T1,T0>>{};

template<class T0, class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class T9,
         class T10, class T11, class T12>
class CStaticVectorServerBase<T12,                         T11,T10,T9,T8,T7,T6,T5,T4,T3,T2,T1,T0> : 
   public Detail::CSvsi<      T12, CStaticVectorServerBase<T11,T10,T9,T8,T7,T6,T5,T4,T3,T2,T1,T0>>{};

template<class T0, class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class T9,
         class T10, class T11, class T12, class T13>
class CStaticVectorServerBase<T13,                         T12,T11,T10,T9,T8,T7,T6,T5,T4,T3,T2,T1,T0> : 
   public Detail::CSvsi<      T13, CStaticVectorServerBase<T12,T11,T10,T9,T8,T7,T6,T5,T4,T3,T2,T1,T0>>{};

template<class T0, class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class T9,
         class T10, class T11, class T12, class T13, class T14>
class CStaticVectorServerBase<T14,                         T13,T12,T11,T10,T9,T8,T7,T6,T5,T4,T3,T2,T1,T0> : 
   public Detail::CSvsi<      T14, CStaticVectorServerBase<T13,T12,T11,T10,T9,T8,T7,T6,T5,T4,T3,T2,T1,T0>>{};

template<class T0, class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class T9,
         class T10, class T11, class T12, class T13, class T14, class T15>
class CStaticVectorServerBase<T15,                         T14,T13,T12,T11,T10,T9,T8,T7,T6,T5,T4,T3,T2,T1,T0> : 
   public Detail::CSvsi<      T15, CStaticVectorServerBase<T14,T13,T12,T11,T10,T9,T8,T7,T6,T5,T4,T3,T2,T1,T0>>{};

template<class T0, class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class T9,
         class T10, class T11, class T12, class T13, class T14, class T15, class T16>
class CStaticVectorServerBase<T16,                         T15,T14,T13,T12,T11,T10,T9,T8,T7,T6,T5,T4,T3,T2,T1,T0> : 
   public Detail::CSvsi<      T16, CStaticVectorServerBase<T15,T14,T13,T12,T11,T10,T9,T8,T7,T6,T5,T4,T3,T2,T1,T0>>{};

template<class T0, class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class T9,
         class T10, class T11, class T12, class T13, class T14, class T15, class T16, class T17>
class CStaticVectorServerBase<T17,                         T16,T15,T14,T13,T12,T11,T10,T9,T8,T7,T6,T5,T4,T3,T2,T1,T0> : 
   public Detail::CSvsi<      T17, CStaticVectorServerBase<T16,T15,T14,T13,T12,T11,T10,T9,T8,T7,T6,T5,T4,T3,T2,T1,T0>>{};

template<class T0, class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class T9,
         class T10, class T11, class T12, class T13, class T14, class T15, class T16, class T17, class T18>
class CStaticVectorServerBase<T18,T17,T16,T15,T14,T13,T12,T11,T10,T9,T8,T7,T6,T5,T4,T3,T2,T1,T0> : 
   public Detail::CSvsi<T18, CStaticVectorServerBase<T17,T16,T15,T14,T13,T12,T11,T10,T9,T8,T7,T6,T5,T4,T3,T2,T1,T0>>{};

}// end namespace ComSerSdk