/* Network-Integrated Multimedia Middleware (NMM)
 * http://www.motama.com/nmm.html
 *  
 * Copyright (C) 2006-2007
 * Motama GmbH, Saarbruecken, Germany
 * http://www.motama.com
 *  
 * This file is part of NMM. 
 * 
 * NMM 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; only version 2 of the License.      
 * 
 * NMM 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 NMM; if not, write to the Free Software Foundation,    
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 */

#ifndef NMM_XSHMMANAGER_HPP
#define NMM_XSHMMANAGER_HPP NMM_XSHMMANAGER_HPP

#include "nmm/nmm_prefix.hpp"


#include <X11/Xlib.h>
#include <X11/extensions/XShm.h>

namespace NMM {

  class ShmBufferManager;

  /**
   * This is a class for mastering kernel shared memory (SHM).
   */
  class ShmManager {

  private:
    //! The pointer to the ShmBufferManager, which should offer the
    //  shared memory, may be NULL if no ShmBufferManager should offer
    //  it.
    ShmBufferManager* buffermanager;

    //! The id of the shared memory segment.
    int shmid;

    //! The starting address of the shared memory segment. 
    char* shmaddr;

    //! The size of the buffers generated from the shared memory
    //  segment.
    unsigned int buffer_size;

    //! number of buffers generated from the shared memory segment,
    //  is 1 if ShmBufferManager is not used
    unsigned int shared_memory_pages;

  protected:
    
    /**
     * This method computes the end of the shared memory segment.
     * \return A Pointer to the address directly behind the shared
     *         memory segment.
     */
    const char* getShmEnd() const;

  public:

    /**
     * Constructor:
     * \param manager A pointer to a ShmBufferManager or NULL if no
     *                ShmBufferManager should be used
     * \param pages The ammount of shared memory pages to be
     *              allocated/attached.
     */
    ShmManager(ShmBufferManager* manager, unsigned int shared_pages);

    /**
     * Destructor
     */
    virtual ~ShmManager();

    /**
     * This method seta the internal buffermanager to new one
     * \param manager new ShmBufferManager or NULL if no shared buffer
     *                manager should be used
     * \param pages number of pages that should be allocated with the
     *              shared memory segment
     */
    void updateMemoryManager(ShmBufferManager* manager, unsigned int pages);

    /**
     * This method attaches a shared memory segment of size
     * (size * shared_memory_pages)
     * \param size The size of one buffer/page of the shared memory
     *             segment.
     * \returns true iff the memory could be successfully
     *          allocated/attached.
     */
    virtual bool attachMemory(const int size);

    /**
     * This method detaches the previously (in attachMemory())
     * attached/allocated shared memory segment.
     */
    virtual void detachMemory();

    /**
     * this method tests if the given data pointer lies within the
     * shared memory segment and copies its content eventually to a
     * shared memory segment.
     * \param data The pointer to test if it is within the shared
     *             memory segment.
     * \returns A Pointer with the same content as data, which is
     *          guarenteed to be in the shared memory segment.
     */
    char* getMem(char* data) const;

    /**
     * This method returns the ID of the shared memory segment.
     * \returns The shared memory ID.
     */
    int getID();
    
    /**
     * This method returns the starting address of the shared memory
     * segment.
     * \returns The shared memory starting address.
     */
    char* getShm();

    /**
     * This method tests if a given data pointer is within the shared
     * memory segment.
     * \param data A pointer to test if it lies within the shared
     *             memory segment.
     * \returns true iff the data pointer is within the shared memory
     *          segment.
     */
    bool isSharedMemory(const char* data) const;
  };



  /**
   * This is a class for mastering shared memory for the XShm
   * extension.
   */
  class XShmManager
    : public ShmManager {

  private:
    //! The XShm segment info needed for all XShm calls.
    XShmSegmentInfo xshminfo;

    //! The X Display to which the shared memory segment is attached.
    Display* attached_display;

  public:

    /**
     * Constructor:
     * \param manager A pointer to a ShmBufferManager or NULL if no
     *                ShmBufferManager should be used
     * \param pages The ammount of shared memory pages to be
     *              allocated/attached.
     */
    XShmManager(ShmBufferManager* manager, unsigned int shared_pages);

    /**
     * Destructor.
     */
    ~XShmManager();

    /**
     * Disabled reimplementation from ShmManager.
     * \returns always false as the method
     *          "XShmManager::allocateMemory(Display*, const int)"
     *          should be used!
     */
    bool attachMemory(const int) { return false; }

    /**
     * This method attaches a shared memory segment of size
     * (size * shared_memory_pages) to the given X Display.
     * \param display The X Display to attach the shared memory
     *                segment to.
     * \param size The size of one buffer/page of the shared memory
     *             segment.
     * \returns true iff the memory could be successfully
     *          allocated/attached.
     */
    bool attachMemory(Display* display, const int size);

    // reimplementation from ShmManager
    void detachMemory();

    /**
     * This method returns the XShm info struct to use in XShm calls.
     * \returns A pointer to a allocated/initialized XShmSegmentInfo
     *          struct.
     */
    XShmSegmentInfo* getInfo();

    /**
     * This method tests the given Display for support for the XShm
     * extension.
     * \param display The Display to query for XShm extension.
     * \returns true iff the Display supports XShm.
    */
    static bool queryDisplay(Display* display);
  };

}

#include "nmm/nmm_suffix.hpp"

#endif //NMM_XSHMMANAGER_HPP
