/** 
 * @file lltoolplacer.cpp
 * @brief Tool for placing new objects into the world
 *
 * Copyright (c) 2001-$CurrentYear$, Linden Research, Inc.
 * $License$
 */

#include "llviewerprecompiledheaders.h"

// self header
#include "lltoolplacer.h"

// linden library headers
#include "llprimitive.h"

// viewer headers
#include "llbutton.h"
#include "llviewercontrol.h"
#include "llfirstuse.h"
#include "llfloatertools.h"
#include "llselectmgr.h"
#include "llstatusbar.h"
#include "lltoolcomp.h"
#include "lltoolmgr.h"
#include "llviewerobject.h"
#include "llviewerregion.h"
#include "llviewerwindow.h"
#include "llworld.h"
#include "viewer.h"
#include "llui.h"

//static 
LLPCode	LLToolPlacer::sObjectType = LL_PCODE_CUBE;

LLToolPlacer::LLToolPlacer()
:	LLTool( "Create" )
{
}

// Used by the placer tool to add copies of the current selection.
// Inspired by add_object().  JC
BOOL add_duplicate(S32 x, S32 y)
{
	LLVector3 ray_start_region;
	LLVector3 ray_end_region;
	LLViewerRegion* regionp = NULL;
	BOOL b_hit_land = FALSE;
	S32 hit_face = -1;
	LLViewerObject* hit_obj = NULL;
	BOOL success = raycast_for_new_obj_pos( x, y, &hit_obj, &hit_face, &b_hit_land, &ray_start_region, &ray_end_region, &regionp );
	if( !success )
	{
		make_ui_sound("UISndInvalidOp");
		return FALSE;
	}
	if( hit_obj && (hit_obj->isAvatar() || hit_obj->isAttachment()) )
	{
		// Can't create objects on avatars or attachments
		make_ui_sound("UISndInvalidOp");
		return FALSE;
	}


	// Limit raycast to a single object.  
	// Speeds up server raycast + avoid problems with server ray hitting objects
	// that were clipped by the near plane or culled on the viewer.
	LLUUID ray_target_id;
	if( hit_obj )
	{
		ray_target_id = hit_obj->getID();
	}
	else
	{
		ray_target_id.setNull();
	}

	gSelectMgr->selectDuplicateOnRay(ray_start_region,
										ray_end_region,
										b_hit_land,			// suppress raycast
										FALSE,				// intersection
										ray_target_id,
										gSavedSettings.getBOOL("CreateToolCopyCenters"),
										gSavedSettings.getBOOL("CreateToolCopyRotates"),
										FALSE);				// select copy

	if (regionp
		&& (regionp->getRegionFlags() & REGION_FLAGS_SANDBOX))
	{
		LLFirstUse::useSandbox();
	}

	return TRUE;
}


BOOL LLToolPlacer::placeObject(S32 x, S32 y, MASK mask)
{
	BOOL added = TRUE;
	
	if (gSavedSettings.getBOOL("CreateToolCopySelection"))
	{
		added = add_duplicate(x, y);
	}
	else
	{
		added = add_object( sObjectType, x, y, NO_PHYSICS );
	}

	// ...and go back to the default tool
	if (added && !gSavedSettings.getBOOL("CreateToolKeepSelected"))
	{
		gCurrentToolset->selectTool( gToolTranslate );
	}

	return added;
}

BOOL LLToolPlacer::handleHover(S32 x, S32 y, MASK mask)
{
	lldebugst(LLERR_USER_INPUT) << "hover handled by LLToolPlacer" << llendl;		
	gViewerWindow->getWindow()->setCursor(UI_CURSOR_TOOLCREATE);
	return TRUE;
}

void LLToolPlacer::handleSelect()
{
	gFloaterTools->setStatusText("Click in the world to create, shift-click to select");
}

void LLToolPlacer::handleDeselect()
{
	gFloaterTools->setStatusText("");
}

//////////////////////////////////////////////////////
// LLToolPlacerPanel

// static
LLPCode LLToolPlacerPanel::sCube		= LL_PCODE_CUBE;
LLPCode LLToolPlacerPanel::sPrism		= LL_PCODE_PRISM;
LLPCode LLToolPlacerPanel::sPyramid		= LL_PCODE_PYRAMID;
LLPCode LLToolPlacerPanel::sTetrahedron	= LL_PCODE_TETRAHEDRON;
LLPCode LLToolPlacerPanel::sCylinder	= LL_PCODE_CYLINDER;
LLPCode LLToolPlacerPanel::sCylinderHemi= LL_PCODE_CYLINDER_HEMI;
LLPCode LLToolPlacerPanel::sCone		= LL_PCODE_CONE;
LLPCode LLToolPlacerPanel::sConeHemi	= LL_PCODE_CONE_HEMI;
LLPCode LLToolPlacerPanel::sTorus		= LL_PCODE_TORUS;
LLPCode LLToolPlacerPanel::sSquareTorus = LLViewerObject::LL_VO_SQUARE_TORUS;
LLPCode LLToolPlacerPanel::sTriangleTorus = LLViewerObject::LL_VO_TRIANGLE_TORUS;
LLPCode LLToolPlacerPanel::sSphere		= LL_PCODE_SPHERE;
LLPCode LLToolPlacerPanel::sSphereHemi	= LL_PCODE_SPHERE_HEMI;
LLPCode LLToolPlacerPanel::sTree		= LL_PCODE_LEGACY_TREE;
LLPCode LLToolPlacerPanel::sGrass		= LL_PCODE_LEGACY_GRASS;
LLPCode LLToolPlacerPanel::sTreeNew		= LL_PCODE_TREE_NEW;

S32			LLToolPlacerPanel::sButtonsAdded = 0;
LLButton*	LLToolPlacerPanel::sButtons[ TOOL_PLACER_NUM_BUTTONS ];

LLToolPlacerPanel::LLToolPlacerPanel(const std::string& name, const LLRect& rect)
	:
	LLPanel( name, rect )
{
	/* DEPRECATED - JC
	addButton( "UIImgCubeUUID",			"UIImgCubeSelectedUUID",		&LLToolPlacerPanel::sCube );
	addButton( "UIImgPrismUUID",		"UIImgPrismSelectedUUID",		&LLToolPlacerPanel::sPrism );
	addButton( "UIImgPyramidUUID",		"UIImgPyramidSelectedUUID",		&LLToolPlacerPanel::sPyramid );
	addButton( "UIImgTetrahedronUUID",	"UIImgTetrahedronSelectedUUID",	&LLToolPlacerPanel::sTetrahedron );
	addButton( "UIImgCylinderUUID",		"UIImgCylinderSelectedUUID",	&LLToolPlacerPanel::sCylinder );
	addButton( "UIImgHalfCylinderUUID",	"UIImgHalfCylinderSelectedUUID",&LLToolPlacerPanel::sCylinderHemi );
	addButton( "UIImgConeUUID",			"UIImgConeSelectedUUID",		&LLToolPlacerPanel::sCone );
	addButton( "UIImgHalfConeUUID",		"UIImgHalfConeSelectedUUID",	&LLToolPlacerPanel::sConeHemi );
	addButton( "UIImgSphereUUID",		"UIImgSphereSelectedUUID",		&LLToolPlacerPanel::sSphere );
	addButton( "UIImgHalfSphereUUID",	"UIImgHalfSphereSelectedUUID",	&LLToolPlacerPanel::sSphereHemi );
	addButton( "UIImgTreeUUID",			"UIImgTreeSelectedUUID",		&LLToolPlacerPanel::sTree );
	addButton( "UIImgGrassUUID",		"UIImgGrassSelectedUUID",		&LLToolPlacerPanel::sGrass );
	addButton( "ObjectTorusImageID",	"ObjectTorusActiveImageID",		&LLToolPlacerPanel::sTorus );
	addButton( "ObjectTubeImageID",		"ObjectTubeActiveImageID",		&LLToolPlacerPanel::sSquareTorus );
	*/
}

void LLToolPlacerPanel::addButton( const LLString& up_state, const LLString& down_state, LLPCode* pcode )
{
	const S32 TOOL_SIZE = 32;
	const S32 HORIZ_SPACING = TOOL_SIZE + 5;
	const S32 VERT_SPACING = TOOL_SIZE + 5;
	const S32 VPAD = 10;
	const S32 HPAD = 7;

	S32 row = sButtonsAdded / 4;
	S32 column = sButtonsAdded % 4; 

	LLRect help_rect = gSavedSettings.getRect("ToolHelpRect");

	// Build the rectangle, recalling the origin is at lower left
	// and we want the icons to build down from the top.
	LLRect rect;
	rect.setLeftTopAndSize(
		HPAD + (column * HORIZ_SPACING),
		help_rect.mBottom - VPAD - (row * VERT_SPACING),
		TOOL_SIZE,
		TOOL_SIZE );

	LLButton* btn = new LLButton(
		"ToolPlacerOptBtn",
		rect,
		up_state,
		down_state,
		"", &LLToolPlacerPanel::setObjectType,
		pcode,
		LLFontGL::sSansSerif);
	btn->setFollowsBottom();
	btn->setFollowsLeft();
	addChild(btn);

	sButtons[sButtonsAdded] = btn;
	sButtonsAdded++;
}

// static 
void	LLToolPlacerPanel::setObjectType( void* data )
{
	LLPCode pcode = *(LLPCode*) data;
	LLToolPlacer::setObjectType( pcode );
}
