// This may look like C code, but it's really -*- C++ -*-
/*
 * Copyright (C) 2013 Emweb bvba, Leuven, Belgium.
 *
 * See the LICENSE file for terms of use.
 */

#ifndef WSERVERGLWIDGET
#define WSERVERGLWIDGET

#include <Wt/WAbstractGLImplementation>

namespace Wt {

class WMemoryResource;
class WRasterImage;

class WServerGLWidgetImpl;

class WServerGLWidget : public WAbstractGLImplementation {
public:
  WServerGLWidget(WGLWidget *glInterface);

  ~WServerGLWidget();

  void debugger();
  
  void activeTexture(WGLWidget::GLenum texture);

  void attachShader(WGLWidget::Program program, WGLWidget::Shader shader);

  void bindAttribLocation(WGLWidget::Program program, unsigned index, const std::string &name);

  void bindBuffer(WGLWidget::GLenum target, WGLWidget::Buffer buffer);

  void bindFramebuffer(WGLWidget::GLenum target, WGLWidget::Framebuffer buffer);

  void bindRenderbuffer(WGLWidget::GLenum target, WGLWidget::Renderbuffer buffer);

  void bindTexture(WGLWidget::GLenum target, WGLWidget::Texture texture);

  void blendColor(double red, double green, double blue, double alpha);

  void blendEquation(WGLWidget::GLenum mode);

  void blendEquationSeparate(WGLWidget::GLenum modeRGB,
			     WGLWidget::GLenum modeAlpha);

  void blendFunc(WGLWidget::GLenum sfactor, WGLWidget::GLenum dfactor);

  void blendFuncSeparate(WGLWidget::GLenum srcRGB,
			 WGLWidget::GLenum dstRGB,
			 WGLWidget::GLenum srcAlpha,
			 WGLWidget::GLenum dstAlpha);

  void bufferData(WGLWidget::GLenum target, WGLWidget::ArrayBuffer res,
		  unsigned bufferResourceOffset,
		  unsigned bufferResourceSize,
		  WGLWidget::GLenum usage);

  void bufferData(WGLWidget::GLenum target, WGLWidget::ArrayBuffer res,
		  WGLWidget::GLenum usage);

  void bufferSubData(Wt::WGLWidget::GLenum target, unsigned offset,
		     WGLWidget::ArrayBuffer res);

  void bufferSubData(Wt::WGLWidget::GLenum target, unsigned offset,
		     WGLWidget::ArrayBuffer res, unsigned bufferResourceOffset,
		     unsigned bufferResourceSize);

  void bufferData(WGLWidget::GLenum target, int size, WGLWidget::GLenum usage);

  void bufferDatafv(WGLWidget::GLenum target, const FloatBuffer &buffer, WGLWidget::GLenum usage, bool binary);

#ifdef WT_TARGET_JAVA
  void bufferDatafv(WGLWidget::GLenum target, const FloatNotByteBuffer &buffer, WGLWidget::GLenum usage);
#endif

  void bufferDataiv(WGLWidget::GLenum target, IntBuffer &buffer, WGLWidget::GLenum usage,
		    WGLWidget::GLenum type);

  void bufferSubDatafv(WGLWidget::GLenum target, unsigned offset,
		       const FloatBuffer &buffer, bool binary);

#ifdef WT_TARGET_JAVA
  void bufferSubDatafv(WGLWidget::GLenum target, unsigned offset,
		       const FloatNotByteBuffer &buffer);
#endif

  void bufferSubDataiv(WGLWidget::GLenum target,
		       unsigned offset, IntBuffer &buffer, 
		       WGLWidget::GLenum type);

  void clear(WFlags<WGLWidget::GLenum> mask);

  void clearColor(double r, double g, double b, double a);

  void clearDepth(double depth);

  void clearStencil(int s);

  void colorMask(bool red, bool green, bool blue, bool alpha);

  void compileShader(WGLWidget::Shader shader);

  void copyTexImage2D(WGLWidget::GLenum target, int level,
		      WGLWidget::GLenum internalFormat,
		      int x, int y,
		      unsigned width, unsigned height, 
		      int border);

  void copyTexSubImage2D(WGLWidget::GLenum target, int level,
			 int xoffset, int yoffset,
			 int x, int y,
			 unsigned width, unsigned height);

  WGLWidget::Buffer createBuffer();

  WGLWidget::ArrayBuffer createAndLoadArrayBuffer(const std::string &url);

  WGLWidget::Framebuffer createFramebuffer();

  WGLWidget::Program createProgram();

  WGLWidget::Renderbuffer createRenderbuffer();

  WGLWidget::Shader createShader(WGLWidget::GLenum shader);

  WGLWidget::Texture createTexture();

  WGLWidget::Texture createTextureAndLoad(const std::string &url);

  WPaintDevice* createPaintDevice(const WLength& width,
				  const WLength& height);

  void cullFace(WGLWidget::GLenum mode);

  void deleteBuffer(WGLWidget::Buffer buffer);

  void deleteFramebuffer(WGLWidget::Framebuffer buffer);

  void deleteProgram(WGLWidget::Program program);

  void deleteRenderbuffer(WGLWidget::Renderbuffer buffer);

  void deleteShader(WGLWidget::Shader shader);

  void deleteTexture(WGLWidget::Texture texture);

  void depthFunc(WGLWidget::GLenum func);

  void depthMask(bool flag);

  void depthRange(double zNear, double zFar);

  void detachShader(WGLWidget::Program program, WGLWidget::Shader shader);

  void disable(WGLWidget::GLenum cap);

  void disableVertexAttribArray(WGLWidget::AttribLocation index);

  void drawArrays(WGLWidget::GLenum mode, int first, unsigned count);

  void drawElements(WGLWidget::GLenum mode, unsigned count,
		    WGLWidget::GLenum type, unsigned offset);

  void enable(WGLWidget::GLenum cap);

  void enableVertexAttribArray(WGLWidget::AttribLocation index);

  void finish();
  void flush();

  void framebufferRenderbuffer(WGLWidget::GLenum target,
			       WGLWidget::GLenum attachment,
			       WGLWidget::GLenum renderbuffertarget,
			       WGLWidget::Renderbuffer renderbuffer);

  void framebufferTexture2D(WGLWidget::GLenum target,
			    WGLWidget::GLenum attachment,
			    WGLWidget::GLenum textarget,
			    WGLWidget::Texture texture, int level);

  void frontFace(WGLWidget::GLenum mode);

  void generateMipmap(WGLWidget::GLenum target);

  WGLWidget::AttribLocation getAttribLocation(WGLWidget::Program program, const std::string &attrib);

  WGLWidget::UniformLocation getUniformLocation(WGLWidget::Program program, const std::string location);

  void hint(WGLWidget::GLenum target, WGLWidget::GLenum mode);

  void lineWidth(double width);

  void linkProgram(WGLWidget::Program program);

  void pixelStorei(WGLWidget::GLenum pname, int param);

  void polygonOffset(double factor, double units);

  void renderbufferStorage(WGLWidget::GLenum target, WGLWidget::GLenum internalformat, 
			   unsigned width, unsigned height);

  void sampleCoverage(double value, bool invert);

  void scissor(int x, int y, unsigned width, unsigned height);

  void shaderSource(WGLWidget::Shader shader, const std::string &src);

  void stencilFunc(WGLWidget::GLenum func, int ref, unsigned mask);

  void stencilFuncSeparate(WGLWidget::GLenum face,
			   WGLWidget::GLenum func, int ref,
			   unsigned mask);

  void stencilMask(unsigned mask);

  void stencilMaskSeparate(WGLWidget::GLenum face, unsigned mask);

  void stencilOp(WGLWidget::GLenum fail, WGLWidget::GLenum zfail,
		 WGLWidget::GLenum zpass);

  void stencilOpSeparate(WGLWidget::GLenum face, WGLWidget::GLenum fail,
			 WGLWidget::GLenum zfail, WGLWidget::GLenum zpass);

  void texImage2D(WGLWidget::GLenum target, int level, WGLWidget::GLenum internalformat, 
		  unsigned width, unsigned height, int border, WGLWidget::GLenum format);

  void texImage2D(WGLWidget::GLenum target, int level,
		  WGLWidget::GLenum internalformat,
		  WGLWidget::GLenum format, WGLWidget::GLenum type,
		  WImage *image);

  void texImage2D(WGLWidget::GLenum target, int level,
		  WGLWidget::GLenum internalformat,
		  WGLWidget::GLenum format, WGLWidget::GLenum type,
		  WVideo *video);

  void texImage2D(WGLWidget::GLenum target, int level, WGLWidget::GLenum internalformat,
		  WGLWidget::GLenum format, WGLWidget::GLenum type, std::string imgFilename);

  void texImage2D(WGLWidget::GLenum target, int level, WGLWidget::GLenum internalformat,
		  WGLWidget::GLenum format, WGLWidget::GLenum type,
		  WPaintDevice *paintdevice);

  void texImage2D(WGLWidget::GLenum target, int level,
		  WGLWidget::GLenum internalformat,
		  WGLWidget::GLenum format, WGLWidget::GLenum type,
		  WGLWidget::Texture texture);

  void texParameteri(WGLWidget::GLenum target,
		     WGLWidget::GLenum pname,
		     WGLWidget::GLenum param);

  void uniform1f(const WGLWidget::UniformLocation &location, double x);

  void uniform1fv(const WGLWidget::UniformLocation &location,
		  const WT_ARRAY float *value);

  void uniform1fv(const WGLWidget::UniformLocation &location,
		  const WGLWidget::JavaScriptVector &v);

  void uniform1i(const WGLWidget::UniformLocation &location, int x);

  void uniform1iv(const WGLWidget::UniformLocation &location, 
		  const WT_ARRAY int *value);

  void uniform2f(const WGLWidget::UniformLocation &location, double x, double y);

  void uniform2fv(const WGLWidget::UniformLocation &location, 
		  const WT_ARRAY float *value);

  void uniform2fv(const WGLWidget::UniformLocation &location,
		  const WGLWidget::JavaScriptVector &v);

  void uniform2i(const WGLWidget::UniformLocation &location, int x, int y);

  void uniform2iv(const WGLWidget::UniformLocation &location, 
		  const WT_ARRAY int *value);

  void uniform3f(const WGLWidget::UniformLocation &location,
		 double x, double y, double z);

  void uniform3fv(const WGLWidget::UniformLocation &location, 
		  const WT_ARRAY float *value);

  void uniform3fv(const WGLWidget::UniformLocation &location,
		  const WGLWidget::JavaScriptVector &v);

  void uniform3i(const WGLWidget::UniformLocation &location, int x, int y, int z);

  void uniform3iv(const WGLWidget::UniformLocation &location, 
		  const WT_ARRAY int *value);

  void uniform4f(const WGLWidget::UniformLocation &location,
		 double x, double y, double z, double w);

  void uniform4fv(const WGLWidget::UniformLocation &location, 
		  const WT_ARRAY float *value);

  void uniform4fv(const WGLWidget::UniformLocation &location,
		  const WGLWidget::JavaScriptVector &v);

  void uniform4i(const WGLWidget::UniformLocation &location, int x, int y, 
		 int z, int w);

  void uniform4iv(const WGLWidget::UniformLocation &location, 
		  const WT_ARRAY int *value);

  void uniformMatrix2fv(const WGLWidget::UniformLocation &location,
			bool transpose, 
			const WT_ARRAY double *value);

  void uniformMatrix2(const WGLWidget::UniformLocation &location,
		      const WGenericMatrix<double, 2, 2> &m);

  void uniformMatrix3fv(const WGLWidget::UniformLocation &location,
			bool transpose, 
			const WT_ARRAY double *value);

  void uniformMatrix3(const WGLWidget::UniformLocation &location,
		      const WGenericMatrix<double, 3, 3> &m);

  void uniformMatrix4fv(const WGLWidget::UniformLocation &location,
			bool transpose,
			const WT_ARRAY double *value);

  void uniformMatrix4(const WGLWidget::UniformLocation &location,
		      const WGenericMatrix<double, 4, 4> &m);

  void uniformMatrix4(const WGLWidget::UniformLocation &location,
		      const WGLWidget::JavaScriptMatrix4x4 &m);

  void useProgram(WGLWidget::Program program);

  void validateProgram(WGLWidget::Program program);

  void vertexAttrib1f(WGLWidget::AttribLocation location, double x);

  void vertexAttrib2f(WGLWidget::AttribLocation location, double x, double y);

  void vertexAttrib3f(WGLWidget::AttribLocation location, double x, double y, 
		      double z);

  void vertexAttrib4f(WGLWidget::AttribLocation location,
		      double x, double y, double z, double w);
  
  void vertexAttribPointer(WGLWidget::AttribLocation location, int size,
			   WGLWidget::GLenum type, bool normalized,
			   unsigned stride, unsigned offset);
  
  void viewport(int x, int y, unsigned width, unsigned height);

  void clearBinaryResources();

  void initJavaScriptMatrix4(WGLWidget::JavaScriptMatrix4x4 &jsm);

  void setJavaScriptMatrix4(WGLWidget::JavaScriptMatrix4x4 &jsm,
			    const WGenericMatrix<double, 4, 4> &m);

  void initJavaScriptVector(WGLWidget::JavaScriptVector &jsv);

  void setJavaScriptVector(WGLWidget::JavaScriptVector &jsv,
			   const std::vector<float> &v);

  void setClientSideMouseHandler(const std::string& handlerCode);

  void setClientSideLookAtHandler(const WGLWidget::JavaScriptMatrix4x4 &m,
				  double centerX, double centerY, double centerZ,
				  double uX, double uY, double uZ,
				  double pitchRate, double yawRate);

  void setClientSideWalkHandler(const WGLWidget::JavaScriptMatrix4x4 &m,
				double frontStep, double rotStep);

  JsArrayType arrayType() const;

  void injectJS(const std::string& jsString) {}

  std::string glObjJsRef(const std::string& jsRef);

  void restoreContext(const std::string &jsRef) {}

  void render(const std::string& jsRef, WFlags<RenderFlag> flags);

private:
  WServerGLWidgetImpl *impl_;
  WRasterImage *raster_;
  WMemoryResource *memres_;

  std::stringstream js_;

};

}

#endif
