////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// 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/VectorServer.h 1.2 2009/06/05 11:53:39 arturoc Exp $
//                                                                                                                    //
///////// 120 columns, Tab = Insert 3 Spaces ///////////////////////////////////////////////////////////////////////////

/**
   This header file defines the CVectorServerBase class as well as other related classes.
*/

#pragma once

#include "Detail/Vector.h"
#include "Detail/Server.h"
#include "ScriptingRuntime.h"
#include "Exception.h"

namespace ComSerSdk
{

/**
   Type of vector used by the library user when they define a vector "server class".
   Consult the COM Serialization SDK documentation for details.
*/
class CLockedVector : public Detail::CVectorBase
{
   /**
      Only CVectorSetter can instantiate us.
   */
   friend class CVectorSetter;

   /**
      Configures this instance with the arguments, defering vector configuration to the base class.
   */
   CLockedVector(unsigned long long ullAddress,
                 unsigned uSize,
                 Scripting::IDictionaryPtr & spoDictionary,
                 std::auto_ptr<Detail::CException> & spoVectorDestructorException):
      Detail::CVectorBase(ullAddress, uSize, spoDictionary, spoVectorDestructorException)
   {}

   /**
      Disable these.
   */
   CLockedVector();
   CLockedVector & operator = (const CLockedVector &);
};

class CVectorAddrs : public Detail::CVectorBase
{
   /**
      Only CVectorServerBase can instantiate us.
   */
   friend class CVectorAddrSetter;

   /**
      Configures this instance with the arguments, defering vector configuration to the base class.
   */
   CVectorAddrs(unsigned long long ullAddress,
                unsigned uSize,
                Scripting::IDictionaryPtr & spoDictionary,
                std::auto_ptr<Detail::CException> & spoVectorDestructorException):
      Detail::CVectorBase(ullAddress, uSize, spoDictionary, spoVectorDestructorException)
   {}

   /**
      Disable these.
   */
   CVectorAddrs();
   CVectorAddrs & operator = (const CVectorAddrs &);
};

class CVectorAddrSetter
{
public:
    void Add(unsigned long long ullAddress, unsigned uSize)
    {
       std::ostringstream oStrm;
       oStrm << ullAddress;
       const std::string sAddr = oStrm.str();

       std::ostringstream oStrm2;
       oStrm2 << uSize;
       const std::string sSize = oStrm2.str();
       /*
       Scripting::IDictionaryPtr & spoDictionary,
                    _variant_t oKey,
                    const _variant_t & oItem,
                    const CCodeLocation & oCodeLocation
                    */
       PutItem(m_spoDictionary, 
               sAddr.c_str(),
               sSize.c_str(),
               COMSERSDK_CODELOCATION);
    }
private:

    /**
      Only CVectorServerBase can create an instance of this class.
   */
   friend class CVectorServerBase;
   
   /**
      Configures this instance with the dictionary object to configure the vectors with in Lock().
   */
   explicit CVectorAddrSetter(Scripting::IDictionaryPtr & spoDictionary):
      m_spoDictionary(spoDictionary)
   {}

   Scripting::IDictionaryPtr & m_spoDictionary;
   std::auto_ptr<Detail::CException> m_spoVectorDestructorException;

   /**
      Disable these.
   */
   CVectorAddrSetter();
   CVectorAddrSetter(const CVectorAddrSetter &);
   CVectorAddrSetter & operator = (const CVectorAddrSetter &);
};

/**
   Instances of these are constructed by the library and used as an argument to the library-user's SetVectors()
   override of their CVectorServerBase concrete.  The library-user then calls the Lock() member function of this class
   to specify vectors to modify the data pattern with.
   Consult the COM Serialization SDK documentation for details.
*/
class CVectorSetter
{
public:

   /**
      Create a vector to modify the data pattern with based on the arguments passed in.
      Consult the COM Serialization SDK documentation for details.
   */
   CLockedVector Lock(unsigned long long ullAddress, unsigned uSize)
   {
      ThrowVectorDestructorExceptionIfSet();
      return CLockedVector(ullAddress, uSize, m_spoDictionary, m_spoVectorDestructorException);
   }

private:

   /**
      Only CVectorServerBase can create an instance of this class.
   */
   friend class CVectorServerBase;
   
   /**
      Configures this instance with the dictionary object to configure the vectors with in Lock().
   */
   explicit CVectorSetter(Scripting::IDictionaryPtr & spoDictionary):
      m_spoDictionary(spoDictionary)
   {}

   /**
      the dictionary object to configure the vectors with in Lock().
   */
   Scripting::IDictionaryPtr & m_spoDictionary;

   /**
      Holds a cloned exception that may have occcurred during the destruction of a vector.
   */
   std::auto_ptr<Detail::CException> m_spoVectorDestructorException;

   /**
      Helper that throws an exception that may have occurred during the destruction of a vector.
   */
   void ThrowVectorDestructorExceptionIfSet()
   {
      if(m_spoVectorDestructorException.get())
      {
         m_spoVectorDestructorException->Throw();
      }
   }

   /**
      Disable these.
   */
   CVectorSetter();
   CVectorSetter(const CVectorSetter &);
   CVectorSetter & operator = (const CVectorSetter &);
};

/**
   The base of library-user-defined vector "server classes".
   Consult the COM Serialization SDK documentation for details.
*/
class CVectorServerBase : public Detail::CServerCommonBase
{
   /**
      Library-user overrides this to implement their data-pattern-modification logic for a device in a job session.
      Consult the COM Serialization SDK documentation for details.
   */
   virtual void SetVectors(const std::string & sCurrentHandle,
                           std::string & sNextHandle,
                           ComSerSdk::CVectorSetter & oVectorSetter) = 0;

   //virtual void SetVectors(const std::string & sCurrentHandle,
   //                         std::string & sNextHandle,
   //                         long lSite, 
   //                         long lSocket, 
   //                         const std::string & sSiteId,
   //                         const std::string & sAdapter,
   //                         const std::string & sSocketId,
   //                         ComSerSdk::CVectorSetter & oVectorSetter){}

   /**
      /override
      Here we call the library user's SetVectors() override, as well as do appropriate pre and post-processing.
   */
   virtual HRESULT DoGetSerialData(BSTR sCurrentNumber, IDispatch ** ppoDictionaryAsIDispatch)
   {
      return DoGetSocketSerialData(sCurrentNumber, -1, -1, NULL, NULL, NULL, ppoDictionaryAsIDispatch);
   }

   virtual void SetVectorAddrs(CVectorAddrSetter & oAddrSetter){};

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

   virtual HRESULT InvokeSetVectors(BSTR sCurrentNumber,
                                   long lSite,
                                   long lSocket,
                                   BSTR sSiteId,
                                   BSTR sAdapter,
                                   BSTR sSocketId,
                                   IDispatch ** ppoDictionaryAsIDispatch,
                                   std::string & sNextHandle,
                                   CVectorSetter & oSetter)
   {
      SetVectors(std::string(_bstr_t(sCurrentNumber)), sNextHandle, oSetter);
      return S_OK;
   }

   /**
      /override
      Here we call the library user's SetVectors() override, as well as do appropriate pre and post-processing.
   */
   virtual HRESULT DoGetSocketSerialData(BSTR sCurrentNumber,
                                         long lSite,
                                         long lSocket,
                                         BSTR sSiteId,
                                         BSTR sAdapter,
                                         BSTR sSocketId,
                                         IDispatch ** ppoDictionaryAsIDispatch)
   {
      CVectorSetter oSetter(Dictionary());
      std::string sNextHandle;

      //if(-1 == lSite)
      //{
      //   SetVectors(std::string(_bstr_t(sCurrentNumber)), sNextHandle, oSetter);
      //}
      //else
      //{
      //   SetVectors(std::string(_bstr_t(sCurrentNumber)),
      //              sNextHandle,
      //              lSite,
      //              lSocket,
      //              std::string(_bstr_t(sSiteId)),
      //              std::string(_bstr_t(sAdapter)),
      //              std::string(_bstr_t(sSocketId)),
      //              oSetter);
      //}

      const HRESULT hResult = InvokeSetVectors(sCurrentNumber,
                                               lSite,
                                               lSocket,
                                               sSiteId,
                                               sAdapter,
                                               sSocketId,
                                               ppoDictionaryAsIDispatch,
                                               sNextHandle,
                                               oSetter);

      if(FAILED(hResult)) return hResult;

      oSetter.ThrowVectorDestructorExceptionIfSet();
      Detail::PutItem(Dictionary(),
                      _variant_t("NextHandle"),
                      _variant_t(sNextHandle.c_str()),
                      COMSERSDK_CODELOCATION);
      *ppoDictionaryAsIDispatch = Dictionary();

      return S_OK;
   }
};

class CSocketVectorServerBase : public CVectorServerBase
{
    virtual void SetVectors(const std::string & sCurrentHandle,
                            std::string & sNextHandle,
                            long lSite, 
                            long lSocket,
                            const std::string & sSiteId,
                            const std::string & sAdapter,
                            const std::string & sSocketId,
                            ComSerSdk::CVectorSetter & oVectorSetter) = 0;

    virtual void SetVectors(const std::string & sCurrentHandle,
                           std::string & sNextHandle,
                           ComSerSdk::CVectorSetter & oVectorSetter)
    {
       throw ComSerSdk::CLibraryException(
          "Assertion failed: CSocketVectorServerBase::SetVectors(const std::string&,std::string&,ComSerSdk::CVectorSetter&) should not be invoked",
                                            COMSERSDK_CODELOCATION);
    }


    virtual void OnRetry(const std::string & sHandle, unsigned uSite, unsigned uSocket)
    {
              throw ComSerSdk::CLibraryException("Assertion failed: CSocketVectorServerBase::OnRetry(const std::string&,unsigned,unsigned) should not be invoked",
                                            COMSERSDK_CODELOCATION);
    }

    virtual HRESULT InvokeSetVectors(BSTR sCurrentNumber,
                                   long lSite,
                                   long lSocket,
                                   BSTR sSiteId,
                                   BSTR sAdapter,
                                   BSTR sSocketId,
                                   IDispatch ** ppoDictionaryAsIDispatch,
                                   std::string & sNextHandle,
                                   CVectorSetter & oSetter)
   {
      SetVectors(std::string(_bstr_t(sCurrentNumber)),
                        sNextHandle,
                        lSite,
                        lSocket,
                        std::string(_bstr_t(sSiteId)),
                        std::string(_bstr_t(sAdapter)),
                        std::string(_bstr_t(sSocketId)),
                        oSetter);
      return S_OK;
   }
};

}