#include <vtkRenderer.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkSphereSource.h>
#include <vtkPolyDataMapper.h>
#include <vtkActor.h>
#include <vtkHardwareSelector.h>
#include <vtkSelection.h>
#include <vtkSelectionNode.h>
#include <vtkDataSetAttributes.h>
#include <vtkCommand.h>
#include <vtkProperty.h>

class SelectCommand : public vtkCommand
{
public:
	vtkRenderer* ren;
	vtkRenderWindow* renWin;
	vtkHardwareSelector* selector;
	vtkPolyData* polyData;

	vtkSphereSource* markPoint;
	vtkActor* markActor;

	SelectCommand(vtkRenderer* ren, vtkRenderWindow* renWin)
	{
		this->ren = ren;
		this->renWin = renWin;

		this->markPoint = vtkSphereSource::New();
		this->markPoint->SetRadius(0.02);
		this->markPoint->SetThetaResolution(32);
		this->markPoint->SetPhiResolution(32);
		vtkPolyDataMapper* markMapper = vtkPolyDataMapper::New();
		markMapper->SetInputConnection(this->markPoint->GetOutputPort());
		this->markActor = vtkActor::New();
		this->markActor->SetMapper(markMapper);
		markMapper->FastDelete();
		this->markActor->SetPickable(false);
		this->markActor->GetProperty()->SetColor(1, 0, 0);
		this->markActor->VisibilityOff();
		this->ren->AddActor(this->markActor);

		this->selector = vtkHardwareSelector::New();
		this->selector->SetRenderer(this->ren);
		this->selector->SetFieldAssociation(vtkDataObject::FIELD_ASSOCIATION_POINTS);

		this->renWin->GetInteractor()->AddObserver(vtkCommand::MouseMoveEvent, this);
	}

	virtual void Execute(vtkObject* caller, unsigned long eventId, void* callData)
	{
		if (this->renWin == NULL)
			return;
		
		this->markActor->VisibilityOff();

		vtkRenderWindowInteractor* interactor = this->renWin->GetInteractor();
		assert(interactor != NULL);
		int x = 0;
		int y = 0;
		interactor->GetEventPosition(x, y);

		int tolerance = 3;
		this->selector->SetArea(x - tolerance, y - tolerance, x + tolerance, y + tolerance);
		vtkSelection* selection = this->selector->Select();
		if (selection->GetNumberOfNodes() > 0)
		{
			vtkSelectionNode* node = selection->GetNode(0);
			vtkDataSetAttributes* datasetAttrs = node->GetSelectionData();
			for (int i = 0; i < datasetAttrs->GetNumberOfArrays(); ++i)
				std::cout << datasetAttrs->GetArrayName(i) << std::endl;
			for (int i = 0; i < datasetAttrs->GetArray(0)->GetNumberOfTuples(); ++i)
			{
				int id = datasetAttrs->GetArray(0)->GetComponent(i, 0);
				std::cout << id << std::endl;
				if (id >= this->polyData->GetNumberOfPoints())
					continue;

				double* pt = this->polyData->GetPoint(id);
				this->markPoint->SetCenter(pt);
				this->markActor->VisibilityOn();
			}
		}

		this->renWin->Render();
	}
};

void TestHardwareSelector()
{
	vtkSphereSource* sphereSource = vtkSphereSource::New();
	sphereSource->SetRadius(0.6);
	sphereSource->SetPhiResolution(32);
	sphereSource->SetThetaResolution(32);

	vtkPolyDataMapper* mapper = vtkPolyDataMapper::New();
	mapper->SetInputConnection(sphereSource->GetOutputPort());

	vtkActor* actor = vtkActor::New();
	actor->SetMapper(mapper);

	vtkRenderer* ren = vtkRenderer::New();
	vtkRenderWindow* renWin = vtkRenderWindow::New();
	renWin->AddRenderer(ren);
	vtkRenderWindowInteractor* iren = vtkRenderWindowInteractor::New();
	renWin->SetInteractor(iren);

	ren->AddActor(actor);
	renWin->Render();

	SelectCommand* cmd = new SelectCommand(ren, renWin);
	cmd->polyData = sphereSource->GetOutput();

	iren->Initialize();
	iren->Start();
}