/* 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_WINDOW_HPP_
#define _NMM_WINDOW_HPP_ _NMM_WINDOW_HPP_

#include "nmm/nmm_prefix.hpp"

#include "Workspace.hpp"
#include "interfaces/IWindowImpl.hpp"

#include "nmm/comm/NMMObject.hpp"
#include "nmm/utils/scaler/VideoScaler.hpp"


#include <pthread.h>

namespace NMM {
  class Widget;
  class OSDManagerNode;

  class Window : public IWindowImpl {
  private:
    OSDManagerNode* manager;
    
  protected:
    pthread_mutex_t mutex;
    
    Widget* vc;			// Needed to call draw function of a Widget
    workspace_t workspace;	// workspace to pass to the draw functions
    
    int         id;             // window ID
    int	        xpos;		// x pos. of upper left corner of window
    int         ypos;		// y pos. of upper left corner of window
    bool        updateflag;	// indicates, if window should be redrawn
    bool        hidden;		// indicates, if window is hidden
    
    /**
    * Creates workspace (in rgba format)
    * \param width width of workspace
    * \param height height of workspace
    * \returns true if workspace could be created, false otherwise
    */
    virtual bool createWorkSpace( int width, int height );

    /**
    * deletes created workspace
    */
    virtual void deleteWorkSpace();

    /**
    * \returns status of update flag (true or false)
    */
    bool getUpdateFlag();

    /**
    * set update flag
    * \param b true, if window should be redrawn within next get-call
    */
    void setUpdateFlag( bool b );
    
  public:
    Window(OSDManagerNode* manager);
    virtual ~Window();
    
    /**
     * IWindow interface.
     * These methods are called locally and are therefore public.
     * (better design would be to have two sets of methods)
     */
    virtual nmm_int32 getWindowID() const;
    virtual void setPosition(const nmm_uint32& x, const nmm_uint32& y);
    virtual void getPosition(nmm_uint32& x, nmm_uint32& y) const;
    virtual void setDimension(const nmm_uint32& w, const nmm_uint32& h);
    virtual void getDimension(nmm_uint32& w, nmm_uint32& h) const;
    virtual void update();
    virtual nmm_bool getVisible() const;
    virtual void setVisible(const nmm_bool& value);
    virtual void setScaleFactor( const nmm_double& scale_x, const nmm_double& scale_y ) = 0;
    virtual void setContent(const IWidget& value);
    virtual IWidget* getContent() const;
    
    int getID() const { return id; }
    void setID(int id) { this->id = id; }
    
    /**
     * Creates a window.
     * @param w witdh of the window
     * @param h height of the window
     * @return true, if window could be created succesfully
     */
    bool create( int w, int h );

    /**
     * Deletes the created window.
     */
    void remove();
    
    /**
     * Put widget in a window.
     * @param vc pointer to a widget
     */
    void setContentInternal( Widget* vc );
    
    /**
     * Get widget in a window.
     * @param vc pointer to a widget
     */
    Widget* getContentInternal() const;
    
    /**
     * Lock the window, so that no update() can be done
     */
    void lock();

    /**
     * allow update() call again
     */
    void unlock();

    /**
    * test if window is hidden
    * \returns true if window is hidden
    */
    bool isHidden();

    /**
    * hides the window
    */
    void hide();

    /**
    * makes window visible
    */
    void unHide();

    /**
    * \returns pointer to rgba pixel data of the window, x,y contain the x and y position of the window
    *                                                    w, h contains with and height of the window
    * \returns NULL, if window should not be drawn (window deleted or hidden)
    */
    virtual unsigned char* get( int* x, int* y, int* w, int *h );

  };

  class WindowYV12A: public Window {
  protected:
    workspace_t    yv12a_workspace;
    VideoScaler    scaler;
    unsigned char* scaled_data;
    bool           scale_factor_changed;
    double         scale_factor_x;
    double         scale_factor_y;

    /**
    * Creates workspace (in YV12A format)
    * \param width width of workspace
    * \param height height of workspace
    * \returns true if workspace could be created, false otherwise
    */
    bool createWorkSpace( int width, int height );

    /**
    * deletes created workspace
    */
    void deleteWorkSpace();

    /**
    * converts rgba bitmap to yv12a
    * \param yuv_buffer pointer to destination buffer (make sure enough buffer space is allocated)
    * \param rgb_buffer pointer to rgba bitmap
    * \param width width of the bitmap
    * \param height height of the bitmap
    */
    void convertRGBAtoYV12A( unsigned char* yuv_buffer, unsigned char* rgbbuffer, int width, int height );


  public:
    WindowYV12A(OSDManagerNode* manager);
    virtual ~WindowYV12A();

    /**
    *   - if necessary, converts rgba window to yv12a
    *   - returns information about the window
    * \returns pointer to yv12a pixel data, x,y contain the x and y position of the window
    *          w, h contains with and height of the window
    * \returns NULL, if window should not be drawn (window deleted or hidden)
    */
    unsigned char* get( int* x, int* y, int* w, int *h );

    /**
    * set scale factor
    * this has influence to the get method
    * before data is delivered, the workspace is scaled
    * \param scale_x scale factor that is multiplied with width and x coordinate
    * \param scale_y scale factor that is multiplied with height and y coordinate
    */
    void setScaleFactor( const nmm_double& scale_x, const nmm_double& scale_y );

  };
} // NMM

#include "nmm/nmm_suffix.hpp"

#endif //_NMM_WINDOW_HPP_
