#ifndef K3DSDK_RIB_GRAMMAR_H
#define K3DSDK_RIB_GRAMMAR_H

// K-3D
// Copyright (c) 1995-2004, Timothy M. Shead
//
// Contact: tshead@k-3d.com
//
// This program 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; either
// version 2 of the License, or (at your option) any later version.
//
// This program 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 this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

#include <boost/spirit/core.hpp>
#include <boost/spirit/utility/loops.hpp>
#include <boost/spirit/utility/confix.hpp>
#include <boost/spirit/utility/escape_char.hpp>
#include <iostream>
#include <vector>
#include <string>

namespace k3d
{

namespace ri
{

using namespace boost::spirit;

struct rtint_grammar :
	public grammar<rtint_grammar>
{
	template <typename ScannerT>
	struct definition
	{
		definition(rtint_grammar const& self)
		{
			first = (
				rtint = int_p
			);
		}

		subrule<0> rtint;

		rule<ScannerT> first;
		rule<ScannerT> const& start() const { return first; }
	};
};
struct rtfloat_grammar :
	public grammar<rtfloat_grammar>
{
	template <typename ScannerT>
	struct definition
	{
		definition(rtfloat_grammar const& self)
		{
			first = (
				rtfloat = real_p
			);
		}

		subrule<0> rtfloat;

		rule<ScannerT> first;
		rule<ScannerT> const& start() const { return first; }
	};
};
struct rtstring_grammar :
	public grammar<rtstring_grammar>
{
	template <typename ScannerT>
	struct definition
	{
		definition(rtstring_grammar const& self)
		{
			first = (
				rtstring = QUOTES >> lexeme_d[ *(anychar_p - QUOTES) ] >> QUOTES
				,
				QUOTES = ch_p('"')
			);
		}

		subrule<0> rtstring;
		subrule<1> QUOTES;

		rule<ScannerT> first;
		rule<ScannerT> const& start() const { return first; }
	};
};
struct rtint_array_grammar :
	public grammar<rtint_array_grammar>
{
	template <typename ScannerT>
	struct definition
	{
		definition(rtint_array_grammar const& self)
		{
			first = (
				rtint_array = ch_p('[') >> *rtint >> ch_p(']')
			);
		}

		subrule<0> rtint_array;

		rule<ScannerT> first;
		rule<ScannerT> const& start() const { return first; }

		rtint_grammar rtint;
	};
};
struct rtfloat_array_grammar :
	public grammar<rtfloat_array_grammar>
{
	template <typename ScannerT>
	struct definition
	{
		definition(rtfloat_array_grammar const& self)
		{
			first = (
				rtfloat_array = ch_p('[') >> *rtfloat >> ch_p(']')
			);
		}

		subrule<0> rtfloat_array;

		rule<ScannerT> first;
		rule<ScannerT> const& start() const { return first; }

		rtfloat_grammar rtfloat;
	};
};
struct rtstring_array_grammar :
	public grammar<rtstring_array_grammar>
{
	template <typename ScannerT>
	struct definition
	{
		definition(rtstring_array_grammar const& self)
		{
			first = (
				rtstring_array = ch_p('[') >> *rtstring >> ch_p(']')
			);
		}

		subrule<0> rtstring_array;

		rule<ScannerT> first;
		rule<ScannerT> const& start() const { return first; }

		rtstring_grammar rtstring;
	};
};


struct bytestream_grammar :
	public grammar<bytestream_grammar>
{
	template <typename ScannerT>
	struct definition
	{
		definition(bytestream_grammar const& self)
		{
			rtpair = pair1 | pair2 | pair3 | pair4 | pair5 | pair6;
			pair1 = rtstring >> rtint;
			pair2 = rtstring >> rtint_array;
			pair3 = rtstring >> rtfloat;
			pair4 = rtstring >> rtfloat_array;
			pair5 = rtstring >> rtstring;
			pair6 = rtstring >> rtstring_array;

			rtparameters = *rtpair;

			file = version >> *request;

			version = str_p("version") >> rtfloat;

			request = request1 | request2 | request3 | request4 | request5 | request6;

			request1 = str_p("Attribute") >> rtstring >> rtparameters
				| str_p("Bound") >> (repeat_p(6)[rtfloat] | rtfloat_array)
				| str_p("Color") >> ((rtfloat >> rtfloat >> rtfloat) | rtfloat_array)
				| str_p("ColorSamples") >> rtfloat_array >> rtfloat_array
				| str_p("Declare") >> rtstring >> rtstring
				| str_p("DetailRange") >> (repeat_p(4)[rtfloat] | rtfloat_array);

			request2 = str_p("Detail") >> (repeat_p(6)[rtfloat] | rtfloat_array)
				| str_p("Display") >> rtstring >> rtstring >> rtstring >> rtparameters
				| str_p("GeometricApproximation") >> rtstring >> (rtfloat | rtfloat_array)
				| str_p("Illuminate") >> rtint >> rtint
				| str_p("Matte") >> rtint
				| str_p("ObjectInstance") >> rtint;

			request3 = str_p("Opacity") >> ((rtfloat >> rtfloat >> rtfloat) | rtfloat_array)
				| str_p("Option") >> rtstring >> rtparameters
				| str_p("Orientation") >> rtstring
				| str_p("RelativeDetail") >> rtfloat
				| str_p("ReverseOrientation")
				| str_p("Sides") >> rtint
				| str_p("TextureCoordinates") >> (repeat_p(8)[rtfloat] | rtfloat_array);

			request4 = attribute
				| camera
				| errors
				| frame;

			request5 = geometry
				| motion
				| object
				| shaders;

			request6 = solid
				| textures
				| transform
				| transformations
				| world
				;

			camera = camera1 | camera2 | camera3 | camera4;

			camera1 = str_p("Clipping") >> rtfloat >> rtfloat
				| str_p("CropWindow") >> rtfloat >> rtfloat >> rtfloat >> rtfloat
				| str_p("DepthOfField") >> rtfloat >> rtfloat >> rtfloat
				| str_p("Exposure") >> rtfloat >> rtfloat;

			camera2 = str_p("Format") >> rtint >> rtint >> rtfloat
				| str_p("FrameAspectRatio") >> rtfloat
				| str_p("Hider") >> rtstring >> rtparameters
				| str_p("PixelFilter") >> rtstring >> rtfloat >> rtfloat;

			camera3 = str_p("PixelSamples") >> rtfloat >> rtfloat
				| str_p("PixelVariance") >> rtfloat
				| str_p("Projection") >> rtstring >> rtparameters
				| str_p("Quantize") >> rtstring >> rtint >> rtint >> rtint >> rtfloat;

			camera4 = str_p("ScreenWindow") >> rtfloat >> rtfloat >> rtfloat >> rtfloat
				| str_p("ShadingInterpolation") >> rtstring
				| str_p("ShadingRate") >> rtfloat
				| str_p("Shutter") >> rtfloat >> rtfloat
				;

/*
			frame = str_p("FrameBegin") >> rtint >> *request >> str_p("FrameEnd");

			world = str_p("WorldBegin") >> *request >> str_p("WorldEnd");

			transform = str_p("TransformBegin") >> *request >> str_p("TransformEnd");

			attribute = str_p("AttributeBegin") >> *request >> str_p("AttributeEnd");

			solid = str_p("SolidBegin") >> *request >> str_p("SolidEnd");

			object = str_p("ObjectBegin") >> rtint >> *request >> str_p("ObjectEnd");

			motion = str_p("MotionBegin") >> rtfloat_array >> *request >> str_p("MotionEnd");
*/

			frame = str_p("FrameBegin") >> rtint
				| str_p("FrameEnd")
				;

			world = str_p("WorldBegin")
				| str_p("WorldEnd")
				;

			transform = str_p("TransformBegin")
				| str_p("TransformEnd")
				;

			attribute = str_p("AttributeBegin")
				| str_p("AttributeEnd")
				;

			solid = str_p("SolidBegin") >> rtstring
				| str_p("SolidEnd")
				;

			object = str_p("ObjectBegin") >> rtint
				| str_p("ObjectEnd")
				;

			motion = str_p("MotionBegin") >> rtfloat_array
				| str_p("MotionEnd")
				;

			shaders = shaders1 | shaders2 | shaders3;

			shaders1 = str_p("AreaLightSource") >> rtstring >> rtint >> rtparameters
				| str_p("Atmosphere") >> rtstring >> rtparameters
				| str_p("Deformation") >> rtstring >> rtparameters;
			shaders2 = str_p("Displacement") >> rtstring >> rtparameters
				| str_p("Exterior") >> rtstring >> rtparameters
				| str_p("Imager") >> rtstring >> rtparameters;
			shaders3 = str_p("Interior") >> rtstring >> rtparameters
				| str_p("LightSource") >> rtstring >> rtint >> rtparameters
				| str_p("Surface") >> rtstring >> rtparameters
				;

			geometry = geometry1 | geometry2 | geometry3 | geometry4 | geometry5;

			geometry1 = str_p("Polygon") >> rtparameters
				| str_p("GeneralPolygon") >> rtint_array >> rtparameters
				| str_p("Curves") >> rtstring >> rtint_array >> rtstring >> rtparameters
				| str_p("Blobby") >> rtint >> rtint_array >> rtfloat_array >> rtstring_array >> rtparameters;
			geometry2 = str_p("Procedural") >> rtstring >> rtstring >> rtfloat_array >> rtparameters
				| str_p("Points") >> rtparameters

				| str_p("PointsPolygons") >> rtint_array >> rtint_array >> rtparameters
				| str_p("PointsGeneralPolygons") >> rtint_array >> rtint_array >> rtint_array >> rtparameters;
				/* basis */
			geometry3 = str_p("Patch") >> rtstring >> rtparameters
				| str_p("PatchMesh") >> rtstring >> rtint >> rtstring >> rtint >> rtstring >> rtparameters
				| str_p("NUPatch") >> rtint >> rtint >> rtfloat_array >> rtfloat >> rtfloat >> rtint >> rtint >> rtfloat_array >> rtfloat >> rtfloat >> rtparameters
				| str_p("TrimCurve") >> rtint_array >> rtint_array >> rtfloat_array >> rtfloat_array >> rtfloat_array >> rtint_array >> rtfloat_array >> rtfloat_array >> rtfloat_array;

			geometry4 = str_p("Sphere") >> repeat_p(4)[rtfloat] >> rtparameters
				| str_p("Cone") >> repeat_p(3)[rtfloat] >> rtparameters
				| str_p("Cylinder") >> repeat_p(4)[rtfloat] >> rtparameters
				| str_p("Hyperboloid") >> (repeat_p(7)[rtfloat] | rtfloat_array) >> rtparameters;
			geometry5 = str_p("Paraboloid") >> repeat_p(4)[rtfloat] >> rtparameters
				| str_p("Disk") >> repeat_p(3)[rtfloat] >> rtparameters
				| str_p("Torus") >> repeat_p(5)[rtfloat] >> rtparameters
				| str_p("Geometry") >> rtstring >> rtparameters
				| str_p("SubdivisionMesh") >> (rtstring >> rtint_array >> rtint_array | rtstring >> rtint_array >> rtint_array >> rtstring_array >> rtint_array >> rtint_array >> rtfloat_array) >> rtparameters
				;

			transformations = transformations1 | transformations2;

			transformations1 = str_p("Identity")
				| str_p("Transform") >> rtfloat_array
				| str_p("ConcatTransform") >> rtfloat_array
				| str_p("Perspective") >> rtfloat
				| str_p("Translate") >> repeat_p(3)[rtfloat];

			transformations2 = str_p("Rotate") >> repeat_p(4)[rtfloat]
				| str_p("Scale") >> repeat_p(3)[rtfloat]
				| str_p("Skew") >> (repeat_p(7)[rtfloat] | rtfloat_array)
				| str_p("CoordinateSystem") >> rtstring
				| str_p("CoordSysTransform") >> rtstring
				| str_p("TransformPoints")
				;

			errors = str_p("ErrorHandler") >> rtstring
				| str_p("ErrorIgnore")
				| str_p("ErrorPrint")
				| str_p("ErrorAbort")
				;

			textures = str_p("MakeTexture") >> repeat_p(5)[rtstring] >> rtfloat >> rtfloat >> rtparameters
				| str_p("MakeBump") >> repeat_p(5)[rtstring] >> rtfloat >> rtfloat >> rtparameters
				| str_p("MakeLatLongEnvironment") >> repeat_p(3)[rtstring] >> rtfloat >> rtfloat >> rtparameters
				| str_p("MakeCubeFaceEnvironment") >> repeat_p(7)[rtstring] >> rtfloat >> rtstring >> rtfloat >> rtfloat >> rtparameters
				| str_p("MakeShadow") >> rtstring >> rtstring >> rtparameters
				;
		}

		rule<ScannerT> const& start() const { return file; }

		rtint_grammar rtint;
		rtfloat_grammar rtfloat;
		rtstring_grammar rtstring;
		rtint_array_grammar rtint_array;
		rtfloat_array_grammar rtfloat_array;
		rtstring_array_grammar rtstring_array;

		rule<ScannerT> rtpair, rtparameters;
		rule<ScannerT> pair1, pair2, pair3, pair4, pair5, pair6;
		rule<ScannerT> file, version, request, request1, request2, request3, request4, request5, request6, request7, request8, request9, request10, request11, shaders, shaders1, shaders2, shaders3, geometry, geometry1, geometry2, geometry3, geometry4, geometry5, transformations, transformations1, transformations2, textures, errors;
		rule<ScannerT> frame, world, transform, attribute, solid, object, motion, camera, camera1, camera2, camera3, camera4;
	};
};

} // namespace ri

} // namespace k3d

#endif // !K3DSDK_RIB_GRAMMAR


