
#include <Hapy/Parser.h>
#include <Hapy/Rules.h>

#include <functional>
#include <iostream>
#include <vector>
#include <string>

namespace k3d
{

namespace ri
{

using namespace Hapy;

Rule rtint("rtint", 1);
Rule rtfloat("rtfloat", 2);
Rule rtstring("rtstring", 3);
Rule rtint_array("rtint_array", 4);
Rule rtfloat_array("rtfloat_array", 5);
Rule rtstring_array("rtstring_array", 6);

Rule rtpair("rtpair", 7);
Rule rtparameters("rtparameters", 8);

Rule version("version", 9);
Rule file("file", 10);
Rule request("request", 11);

Rule camera("camera", 12);
Rule frame("frame", 13);
Rule world("world", 14);
Rule transform("transform", 15);
Rule attribute("attribute", 16);
Rule solid("solid", 17);
Rule object("object", 18);
Rule motion("motion", 19);
Rule shaders("shaders", 20);
Rule geometry("geometry", 21);
Rule transformations("transformations", 22);
Rule errors("errors", 23);
Rule textures("textures", 24);

Rule comment("comment", 25);


void parse()
{
	rtint = !char_r('-') >> +digit_r;
	rtint.verbatim(true);
	rtfloat = !char_r('-') >> *digit_r >> !(char_r('.') >> +digit_r);
	rtfloat.verbatim(true);
	rtstring = quoted_r(anychar_r, char_r('"'));
	rtstring.verbatim(true);

	rtint_array = quoted_r(rtint, char_r('['), char_r(']'));
	rtfloat_array = quoted_r(rtfloat, char_r('['), char_r(']'));
	rtstring_array = quoted_r(rtstring, char_r('['), char_r(']'));

	rtpair = rtstring >> rtint
		| rtstring >> rtint_array
		| rtstring >> rtfloat
		| rtstring >> rtfloat_array
		| rtstring >> rtstring
		| rtstring >> rtstring_array
		;

	rtparameters = *rtpair;

	version = "version" >> rtfloat;

	file = *comment >> version >> *request >> end_r;


	request = comment
		| "Attribute" >> rtstring >> rtparameters
		| "Bound" >> ((rtfloat >> rtfloat >> rtfloat >> rtfloat >> rtfloat >> rtfloat) | rtfloat_array)
		| "Color" >> ((rtfloat >> rtfloat >> rtfloat) | rtfloat_array)
		| "ColorSamples" >> rtfloat_array >> rtfloat_array
		| "Declare" >> rtstring >> rtstring
		| "DetailRange" >> ((rtfloat >> rtfloat >> rtfloat >> rtfloat) | rtfloat_array)
		| "Detail" >> ((rtfloat >> rtfloat >> rtfloat >> rtfloat >> rtfloat >> rtfloat) | rtfloat_array)
		| "Display" >> rtstring >> rtstring >> rtstring >> rtparameters
		| "GeometricApproximation" >> rtstring >> (rtfloat | rtfloat_array)
		| "Illuminate" >> rtint >> rtint
		| "Matte" >> rtint
		| "ObjectInstance" >> rtint
		| "Opacity" >> ((rtfloat >> rtfloat >> rtfloat) | rtfloat_array)
		| "Option" >> rtstring >> rtparameters
		| "Orientation" >> rtstring
		| "RelativeDetail" >> rtfloat
		| "ReverseOrientation"
		| "Sides" >> rtint
		| "TextureCoordinates" >> ((rtfloat >> rtfloat >> rtfloat >> rtfloat >> rtfloat >> rtfloat) | rtfloat_array)
		| attribute
		| camera
		| errors
		| frame
		| geometry
		| motion
		| object
		| shaders
		| solid
		| transform
		| transformations
		| world
		;

	camera = "Clipping" >> rtfloat >> rtfloat
		| "CropWindow" >> rtfloat >> rtfloat >> rtfloat >> rtfloat
		| "DepthOfField" >> rtfloat >> rtfloat >> rtfloat
		| "Exposure" >> rtfloat >> rtfloat
		| "Format" >> rtint >> rtint >> rtfloat
		| "FrameAspectRatio" >> rtfloat
		| "Hider" >> rtstring >> rtparameters
		| "PixelFilter" >> rtstring >> rtfloat >> rtfloat
		| "PixelSamples" >> rtfloat >> rtfloat
		| "PixelVariance" >> rtfloat
		| "Projection" >> rtstring >> rtparameters
		| "Quantize" >> rtstring >> rtint >> rtint >> rtint >> rtfloat
		| "ScreenWindow" >> rtfloat >> rtfloat >> rtfloat >> rtfloat
		| "ShadingInterpolation" >> rtstring
		| "ShadingRate" >> rtfloat
		| "Shutter" >> rtfloat >> rtfloat
		;

	frame = "FrameBegin" >> rtint
		| "FrameEnd"
		;

	world = "WorldBegin" >> *request >> "WorldEnd"
		;

	transform = "TransformBegin" >> *request >> "TransformEnd"
		;

	attribute = "AttributeBegin" >> *request >> "AttributeEnd"
		;

	solid = "SolidBegin" >> rtstring
		| "SolidEnd"
		;

	object = "ObjectBegin" >> rtint
		| "ObjectEnd"
		;

	motion = "MotionBegin" >> rtfloat_array
		| "MotionEnd"
		;

	shaders = "AreaLightSource" >> rtstring >> rtint >> rtparameters
		| "Atmosphere" >> rtstring >> rtparameters
		| "Deformation" >> rtstring >> rtparameters
		| "Displacement" >> rtstring >> rtparameters
		| "Exterior" >> rtstring >> rtparameters
		| "Imager" >> rtstring >> rtparameters
		| "Interior" >> rtstring >> rtparameters
		| "LightSource" >> rtstring >> rtint >> rtparameters
		| "Surface" >> rtstring >> rtparameters
		;

	geometry = "Polygon" >> rtparameters
		| "GeneralPolygon" >> rtint_array >> rtparameters
		| "Curves" >> rtstring >> rtint_array >> rtstring >> rtparameters
		| "Blobby" >> rtint >> rtint_array >> rtfloat_array >> rtstring_array >> rtparameters
		| "Procedural" >> rtstring >> rtstring >> rtfloat_array >> rtparameters
		| "Points" >> rtparameters
		| "PointsPolygons" >> rtint_array >> rtint_array >> rtparameters
		| "PointsGeneralPolygons" >> rtint_array >> rtint_array >> rtint_array >> rtparameters
		/* basis */
		| "Patch" >> rtstring >> rtparameters
		| "PatchMesh" >> rtstring >> rtint >> rtstring >> rtint >> rtstring >> rtparameters
		| "NUPatch" >> rtint >> rtint >> rtfloat_array >> rtfloat >> rtfloat >> rtint >> rtint >> rtfloat_array >> rtfloat >> rtfloat >> rtparameters
		| "TrimCurve" >> rtint_array >> rtint_array >> rtfloat_array >> rtfloat_array >> rtfloat_array >> rtint_array >> rtfloat_array >> rtfloat_array >> rtfloat_array
		| "Sphere" >> rtfloat >> rtfloat >> rtfloat >> rtfloat >> rtparameters
		| "Cone" >> rtfloat >> rtfloat >> rtfloat >> rtparameters
		| "Cylinder" >>  rtfloat >> rtfloat >> rtfloat >> rtfloat >> rtparameters
		| "Hyperboloid" >> ((rtfloat >> rtfloat >> rtfloat >> rtfloat >> rtfloat >> rtfloat >> rtfloat) | rtfloat_array) >> rtparameters
		| "Paraboloid" >> rtfloat >> rtfloat >> rtfloat >> rtfloat >> rtparameters
		| "Disk" >> rtfloat >> rtfloat >> rtfloat >> rtparameters
		| "Torus" >> rtfloat >> rtfloat >> rtfloat >> rtfloat >> rtfloat >> rtparameters
		| "Geometry" >> rtstring >> rtparameters
		| "SubdivisionMesh" >> ( rtstring >> rtint_array >> rtint_array | rtstring >> rtint_array >> rtint_array >> rtstring_array >> rtint_array >> rtint_array >> rtfloat_array) >> rtparameters
		;

	transformations = "Identity"
		| "Transform" >> rtfloat_array
		| "ConcatTransform" >> rtfloat_array
		| "Perspective" >> rtfloat
		| "Translate" >> rtfloat >> rtfloat >> rtfloat
		| "Rotate" >> rtfloat >> rtfloat >> rtfloat >> rtfloat
		| "Scale" >> rtfloat >> rtfloat >> rtfloat
		| "Skew" >> ((rtfloat >> rtfloat >> rtfloat >> rtfloat >> rtfloat >> rtfloat >> rtfloat) | rtfloat_array)
		| "CoordinateSystem" >> rtstring
		| "CoordSysTransform" >> rtstring
		| "TransformPoints"
		;

	errors = "ErrorHandler" >> rtstring
		| "ErrorIgnore"
		| "ErrorPrint"
		| "ErrorAbort"
		;

	textures = "MakeTexture" >> *rtstring >> rtfloat >> rtfloat >> rtparameters
		| "MakeBump" >> *rtstring >> rtfloat >> rtfloat >> rtparameters
		| "MakeLatLongEnvironment" >> *rtstring >> rtfloat >> rtfloat >> rtparameters
		| "MakeCubeFaceEnvironment" >> *rtstring >> rtfloat >> rtstring >> rtfloat >> rtfloat >> rtparameters
		| "MakeShadow" >> rtstring >> rtstring >> rtparameters
		;

	comment = char_r('#') >> *anychar_r >> eol_r;
	comment.verbatim(true);
}

} // namespace ri

} // namespace k3d


int expressions(const Hapy::Pree& expr)
{
	const Hapy::Pree &alt = expr[0];
	switch(alt.rid())
		{
		}
}

void interpret(const Hapy::Pree& result)
{
	const Hapy::Pree& exs = result[0];
	std::for_each(exs.begin(), exs.end(), std::ptr_fun(&expressions));
}


// Here's a simple example of how to use the grammar:

int main()
{
	k3d::ri::parse();

	std::string buffer;
	std::copy(std::istreambuf_iterator<char>(std::cin), std::istreambuf_iterator<char>(), std::back_inserter(buffer));

	k3d::ri::file.trim(*Hapy::space_r);

	Hapy::Parser parser;
	parser.grammar(k3d::ri::file);

	if(!parser.parse(buffer))
	{
		std::cerr << parser.result().location() << " -> parsing failed" << std::endl;
		exit(2);
	}

	parser.result().pree.print(std::cout << "parsing succeeded" << std::endl);

	interpret(parser.result().pree);

	return 0;
}


