#include <vtkm/cont/ColorTable.h>
#include <vtkm/cont/DataSet.h>
#include <vtkm/cont/Initialize.h>
#include <vtkm/filter/Contour.h>
#include <vtkm/cont/Initialize.h>
#include <vtkm/source/Tangle.h>

#include <vtkm/io/reader/VTKDataSetReader.h>
#include <vtkm/io/writer/VTKDataSetWriter.h>
#include <vtkm/rendering/Actor.h>
#include <vtkm/rendering/Light.h>
#include <vtkm/rendering/CanvasRayTracer.h>
#include <vtkm/rendering/MapperRayTracer.h>
#include <vtkm/rendering/Scene.h>
#include <vtkm/rendering/View3D.h>
#include <vtkm/rendering/Shader.h>

#include <vtkm/io/ImageReaderPNG.h> 
#include <vtkm/rendering/Texture2D.h> 

#include "shaderFunction.h"

int main(int argc, char** argv)
{
  auto opts = vtkm::cont::InitializeOptions::DefaultAnyDevice;
  vtkm::cont::InitializeResult config = vtkm::cont::Initialize(argc, argv, opts);

  //Loading .vtk File
  //vtkm::io::VTKDataSetReader reader("data/astro.vtk");
  //vtkm::io::VTKDataSetReader reader("data/plane.vtk");
  vtkm::io::VTKDataSetReader reader("data/astro_iso_1M_scaled.vtk");
  vtkm::cont::DataSet ds_from_file = reader.ReadDataSet();
  //ds_from_file.PrintSummary(std::cerr);

  //Creating Scene and adding Actor
  vtkm::rendering::Scene scene;
  vtkm::rendering::Actor actor(ds_from_file.GetCellSet(),
                               ds_from_file.GetCoordinateSystem(),
                               ds_from_file.GetField("node_sMD"));
  vtkm::cont::Field SecondaryField = ds_from_file.GetField("Normals"); 
  scene.AddActor(actor);

  //creating raytracer and adding normal field to it
  vtkm::rendering::MapperRayTracer mapper;
  mapper.SetRaytracerNormalField(SecondaryField);
  vtkm::rendering::CanvasRayTracer canvas(2048, 2048);

  //correct intialization of view3d to better conform to camera 
  vtkm::rendering::View3D view(scene, mapper, canvas);
  
  //get camera here
  vtkm::rendering::Camera &cam = view.GetCamera(); 
  vtkm::Vec3f_32 lat(0,0.0,0.0); 
  cam.SetLookAt(lat); 
  //vtkm::Vec3f_32 campos(3.0, 6.0, 8.0); 
  vtkm::Vec3f_32 campos(-1.5, 1.5, 16.0); 
  cam.SetPosition(campos);
  //cam.Print(); 


  //create light here

  vtkm::Vec3f_32 lightLookDir1(0.0, 0.0, 0.0); 
  vtkm::Vec3f_32 lightLookDir2(0.0, 0.0, -7.0); 

  vtkm::Vec3f_32 lightPos1(15.0, 5.0, 20.0);
  vtkm::Vec3f_32 lightPos2(-10.0, 1.0, 3.5);
  vtkm::Vec3f_32 lightPos3(20.0, 8.0, -6.5);
  vtkm::Vec3f_32 lightPos4(0.0, 18.0, 0.0);

  vtkm::Vec3f_32 color1(1.0, 1.0, 1.0);
  vtkm::Vec3f_32 color2(1.0, 0.715, 0.118);
  vtkm::Vec3f_32 color3(1.0, 0.146, 0.334);

  vtkm::rendering::Light light1(lightPos1, //light position
		                lightLookDir1,       //light lookDir
				color1,              //light color
				1.0f,               //light intensity
				false);             //light is directional

  vtkm::rendering::Light light2(lightPos2, //light position
		                lightLookDir1,      //light lookDir
				color1,             //light color
				1.0f,
			//	10.0f,               //light intensity
				false);             //light is directional

  
  vtkm::rendering::Light light3(lightPos3,             //light position
		                lightLookDir1,       //light lookDir
				color1,             //light color
				1.0f,
			//	25.0f,               //light intensity
				false);             //light is directional

  vtkm::rendering::Light light4(lightPos4,             //light position
		                lightLookDir1,       //light lookDir
				color1,             //light color
				1.0f,
			//	25.0f,               //light intensity
				false);             //light is directional
  scene.AddLight(light1);
  scene.AddLight(light2);
  scene.AddLight(light3);
  scene.AddLight(light4);

  //Setting the background and foreground colors; optional.
  view.SetBackgroundColor(vtkm::rendering::Color(1.0f, 1.0f, 1.0f));
  view.SetForegroundColor(vtkm::rendering::Color(0.0f, 0.0f, 0.0f));
  
  //test to see if include is working 
  //TO DELETE BUT TOO LAZY TO RE-EDIT ALL THIS BULLSHIT ATM
  //note requires this as a dependency to execute mapper function 
  //look in mapperRaytracer to see wtf i mean 
  mapper.SetShaderFunction(&testFunction); 

  //for goals when it will be the time to implement the shader
  vtkm::rendering::Shader PBR; 

  //Painting View
  view.Paint();

  //Saving View
  view.SaveAs("astroPretty2.ppm");

  return 0;
}
