void FSLSLBridge :: startCreation()
{
	////are we already in conversation with a bridge?
	////must have already received a URL call from a bridge.
	//if (mpBridge != NULL) 
	//{
	//	return;
	//}

	//if bridge object doesn't exist - create and attach it, update script.
	LLUUID catID = findFSCategory();

	LLViewerInventoryItem* fsBridge = findInvObject(mCurrentFullName, catID, LLAssetType::AT_OBJECT);
	if (fsBridge == NULL)
	{
		initCreationStep();
	}
	else
	{
		//TODO need versioning - see isOldBridgeVersion()
		mpBridge = fsBridge;
		if (!isItemAttached(mpBridge->getUUID()))
			LLAttachmentsMgr::instance().addAttachment(mpBridge->getUUID(), BRIDGE_POINT, FALSE, TRUE);			
	}
}
void FSLSLBridge::initBridge()
{
	if (!gSavedSettings.getBOOL("UseLSLBridge"))
	{
		return;
	}

	if (gSavedSettings.getBOOL("NoInventoryLibrary"))
	{
		llwarns << "Asked to create bridge, but we don't have a library. Aborting." << llendl;
		reportToNearbyChat(LLTrans::getString("fsbridge_no_library"));
		mBridgeCreating = false;
		return;
	}

	LLUUID catID = findFSCategory();
	LLUUID libCatID = findFSBridgeContainerCategory();

	//check for inventory load
	// AH: Use overloaded LLInventoryFetchDescendentsObserver to check for load of
	// bridge and bridge rock category before doing anything!
	uuid_vec_t cats;
	cats.push_back(catID);
	cats.push_back(libCatID);
	FSLSLBridgeInventoryObserver *bridgeInventoryObserver = new FSLSLBridgeInventoryObserver(cats);
	gInventory.addObserver(bridgeInventoryObserver);
	bridgeInventoryObserver->startFetch();
}
void FSLSLBridge::cleanUpBridgeFolder(std::string nameToCleanUp)
{
	llinfos << "Cleaning leftover scripts and bridges for folder " << nameToCleanUp << llendl;
	
	if (!isBridgeValid())
	{
		llwarns << "Bridge no valid" << llendl;
		return;
	}

	LLUUID catID = findFSCategory();
	LLViewerInventoryCategory::cat_array_t cats;
	LLViewerInventoryItem::item_array_t items;

	//find all bridge and script duplicates and delete them
	//NameCollectFunctor namefunctor(mCurrentFullName);
	NameCollectFunctor namefunctor(nameToCleanUp);
	gInventory.collectDescendentsIf(catID, cats, items, FALSE, namefunctor);

	for (S32 iIndex = 0; iIndex < items.count(); iIndex++)
	{
		const LLViewerInventoryItem* itemp = items.get(iIndex);
		if (!itemp->getIsLinkType() && (itemp->getUUID() != mpBridge->getUUID()))
		{
			gInventory.purgeObject(itemp->getUUID());
		}
	}
	gInventory.notifyObservers();
}
bool FSLSLBridge :: lslToViewer(std::string message, LLUUID fromID, LLUUID ownerID)
{
	if (!gSavedSettings.getBOOL("UseLSLBridge"))
		return false;

	llinfos << message << llendl;

	std::string tag = message.substr(0,11);

	if (tag == "<bridgeURL>")
	{
		// get the content of the message, between <tag> and </tag>
		mCurrentURL = message.substr(tag.length(), message.length() - ((tag.length() * 2) + 1));
		llinfos << "New URL is: " << mCurrentURL << llendl;
		
		if (mpBridge == NULL)
		{
			LLUUID catID = findFSCategory();
			LLViewerInventoryItem* fsBridge = findInvObject(mCurrentFullName, catID, LLAssetType::AT_OBJECT);

			if (fsBridge != NULL)
				mpBridge = fsBridge;
		}
		return viewerToLSL("URL Confirmed", new FSLSLBridgeRequestResponder());
	}
	return false;
}
void FSLSLBridge :: initBridge()
{
	if (!gSavedSettings.getBOOL("UseLSLBridge"))
		return;

	LLUUID catID = findFSCategory();

	//check for inventory load
	FSLSLBridgeInventoryObserver *bridgeInventoryObserver = new FSLSLBridgeInventoryObserver(catID);
	gInventory.addObserver(bridgeInventoryObserver);
}
void FSLSLBridge :: createNewBridge() 
{
	//check if user has a bridge
	LLUUID catID = findFSCategory();

	//attach the Linden rock from the library (will resize as soon as attached)
	LLUUID libID = gInventory.getLibraryRootFolderID();
	LLViewerInventoryItem* libRock = findInvObject(LIB_ROCK_NAME, libID, LLAssetType::AT_OBJECT);
	//shouldn't happen but just in case
	if (libRock != NULL)
	{
		//copy the library item to inventory and put it on 
		LLPointer<LLInventoryCallback> cb = new FSLSLBridgeRezCallback();
		copy_inventory_item(gAgent.getID(),libRock->getPermissions().getOwner(),libRock->getUUID(),catID,mCurrentFullName,cb);
	}
}
void FSLSLBridge :: create_script_inner(LLViewerObject* object)
{
	LLUUID catID = findFSCategory();

	LLPointer<LLInventoryCallback> cb = new FSLSLBridgeScriptCallback();
	create_inventory_item(gAgent.getID(), 
							gAgent.getSessionID(),
							catID,	//LLUUID::null, 
							LLTransactionID::tnull, 
							mCurrentFullName, 
							mCurrentFullName, 
							LLAssetType::AT_LSL_TEXT, 
							LLInventoryType::IT_LSL,
							NOT_WEARABLE, 
							mpBridge->getPermissions().getMaskNextOwner(), 
							cb);

}
// Gets called by the Init, when inventory loaded.
void FSLSLBridge::startCreation()
{
	if (!isAgentAvatarValid())
	{
		llwarns << "AgentAvatar is not valid" << llendl;
		return;
	}

	llinfos << "startCreation called. gInventory.isInventoryUsable=" << gInventory.isInventoryUsable() << llendl;

	//if bridge object doesn't exist - create and attach it, update script.
	LLUUID catID = findFSCategory();

	LLViewerInventoryItem* fsBridge = findInvObject(mCurrentFullName, catID, LLAssetType::AT_OBJECT);

	//detach everything else
	detachOtherBridges();

	if (fsBridge == NULL)
	{
		llinfos << "Bridge not found in inventory, creating new one..." << llendl;
		initCreationStep();
	}
	else
	{
		//TODO need versioning - see isOldBridgeVersion()
		mpBridge = fsBridge;
		if (!isItemAttached(mpBridge->getUUID()))
		{
			if (!LLAppearanceMgr::instance().getIsInCOF(mpBridge->getUUID()))
			{
				//Is this a valid bridge - wear it. 
				LLAttachmentsMgr::instance().addAttachment(mpBridge->getUUID(), BRIDGE_POINT, FALSE, TRUE);	
				llinfos << "Bridge not attached but found in inventory, reattaching..." << llendl;
				//from here, the attach shoould report to ProcessAttach and make sure bridge is valid.
			}
			else
			{
				llinfos << "Bridge not found but in CoF. Waiting for automatic attach..." << llendl;
			}
		}
	}
}
//
//Bridge initialization
//
void FSLSLBridge :: recreateBridge()
{
	if (!gSavedSettings.getBOOL("UseLSLBridge"))
		return;

	LLUUID catID = findFSCategory();

	LLViewerInventoryItem* fsBridge = findInvObject(mCurrentFullName, catID, LLAssetType::AT_OBJECT);
	if (fsBridge != NULL)
	{
		if (get_is_item_worn(fsBridge->getUUID()))
		{
			LLVOAvatarSelf::detachAttachmentIntoInventory(fsBridge->getUUID());
		}
	}
	if (mpBridge != NULL)
		mpBridge = NULL; //the object itself will get cleaned up when new one is created.

	initCreationStep();
}
void FSLSLBridge::detachOtherBridges()
{
	LLUUID catID = findFSCategory();
	LLViewerInventoryCategory::cat_array_t cats;
	LLViewerInventoryItem::item_array_t items;

	LLViewerInventoryItem* fsBridge = findInvObject(mCurrentFullName, catID, LLAssetType::AT_OBJECT);

	//detach everything except current valid bridge - if any
	gInventory.collectDescendents(catID,cats,items,FALSE);

	for (S32 iIndex = 0; iIndex < items.count(); iIndex++)
	{
		const LLViewerInventoryItem* itemp = items.get(iIndex);
		if (get_is_item_worn(itemp->getUUID()) &&
			((fsBridge == NULL) || (itemp->getUUID() != fsBridge->getUUID())))
		{
			LLVOAvatarSelf::detachAttachmentIntoInventory(itemp->getUUID());
		}
	}
}
void FSLSLBridge::processDetach(LLViewerObject* object, const LLViewerJointAttachment* attachment)
{
	llinfos << "Entering processDetach" << llendl;

	if (gAgentAvatarp.isNull() || (!gAgentAvatarp->isSelf()) || (attachment == NULL) || (attachment->getName() != "Bridge"))
	{
		llwarns << "Couldn't detach bridge, object has wrong name or avatar wasn't self." << llendl;
		return;
	}

	LLViewerInventoryItem* fsObject = gInventory.getItem(object->getAttachmentItemID());
	if (fsObject == NULL) //just in case
	{
		llwarns << "Couldn't detach bridge. inventory object was NULL." << llendl;
		return;
	}
	//is it in the right place?
	LLUUID catID = findFSCategory();
	if (catID != fsObject->getParentUUID())
	{
		//that was in the wrong place. It's not ours.
		llwarns << "Bridge seems to be the wrong inventory category. Aborting detachment." << llendl;
		return;
	}
	if (mpBridge != NULL && mpBridge->getUUID() == fsObject->getUUID()) 
	{
		mpBridge = NULL;
		reportToNearbyChat(LLTrans::getString("fsbridge_detached"));
		mIsFirstCallDone = false;
		if (mBridgeCreating)
		{
			reportToNearbyChat(LLTrans::getString("fsbridge_warning_not_finished"));
			mBridgeCreating = false; //in case we interrupted the creation
		}
	}

	llinfos << "processDetach Finished" << llendl;
}
//
//Bridge initialization
//
void FSLSLBridge::recreateBridge()
{
	if (!gSavedSettings.getBOOL("UseLSLBridge"))
	{
		return;
	}

	if (gSavedSettings.getBOOL("NoInventoryLibrary"))
	{
		llwarns << "Asked to create bridge, but we don't have a library. Aborting." << llendl;
		reportToNearbyChat(LLTrans::getString("fsbridge_no_library"));
		mBridgeCreating = false;
		return;
	}

	if (mBridgeCreating)
	{
		llwarns << "Bridge creation already in progress, aborting new attempt." << llendl;
		reportToNearbyChat(LLTrans::getString("fsbridge_already_creating"));
		return;
	}

	LLUUID catID = findFSCategory();

	LLViewerInventoryItem* fsBridge = findInvObject(mCurrentFullName, catID, LLAssetType::AT_OBJECT);
	if (fsBridge != NULL)
	{
		if (get_is_item_worn(fsBridge->getUUID()))
		{
			LLVOAvatarSelf::detachAttachmentIntoInventory(fsBridge->getUUID());
		}
	}
	// clear the stored bridge ID - we are starting over.
	mpBridge = 0; //the object itself will get cleaned up when new one is created.

	initCreationStep();
}
void FSLSLBridge::createNewBridge()
{
	//check if user has a bridge
	LLUUID catID = findFSCategory();

	//attach the Linden rock from the library (will resize as soon as attached)
	LLUUID libID = gInventory.getLibraryRootFolderID();
	LLViewerInventoryItem* libRock = findInvObject(LIB_ROCK_NAME, libID, LLAssetType::AT_OBJECT);
	//shouldn't happen but just in case
	if (libRock != NULL)
	{
		//copy the library item to inventory and put it on 
		LLPointer<LLInventoryCallback> cb = new FSLSLBridgeRezCallback();
		llinfos << "Cloning a new Bridge container from the Library..." << llendl;
		copy_inventory_item(gAgent.getID(), libRock->getPermissions().getOwner(), libRock->getUUID(), catID, mCurrentFullName, cb);
	}
	else
	{
		llwarns << "Bridge container not found in the Library!" << llendl;
		// AH: Set to false or we won't be able to start another bridge creation
		// process in this session!
		mBridgeCreating = false;
	}
}
void FSLSLBridge::processAttach(LLViewerObject* object, const LLViewerJointAttachment* attachment)
{
	llinfos << "Entering processAttach, checking the bridge container - gInventory.isInventoryUsable=" << gInventory.isInventoryUsable()<< llendl;

	if ((!gAgentAvatarp->isSelf()) || (attachment->getName() != "Bridge"))
	{
		llwarns << "Bridge not created. Our bridge container attachment isn't named correctly." << llendl;
		if (mBridgeCreating)
		{
			reportToNearbyChat(LLTrans::getString("fsbridge_failure_creation_bad_name"));
			mBridgeCreating = false; //in case we interrupted the creation
		}
		return;
	}

	LLViewerInventoryItem* fsObject = gInventory.getItem(object->getAttachmentItemID());
	if (fsObject == NULL) //just in case
	{
		llwarns << "Bridge container is still NULL in inventory. Aborting." << llendl;
		if (mBridgeCreating)
		{
			reportToNearbyChat(LLTrans::getString("fsbridge_failure_creation_null"));
			mBridgeCreating = false; //in case we interrupted the creation
		}
		return;
	}
	if (mpBridge == NULL) //user is attaching an existing bridge?
	{
		//is it the right version?
		if (fsObject->getName() != mCurrentFullName)
		{
			LLVOAvatarSelf::detachAttachmentIntoInventory(fsObject->getUUID());
			llwarns << "Attempt to attach to bridge point an object other than current bridge" << llendl;
			reportToNearbyChat(LLTrans::getString("fsbridge_failure_attach_wrong_object"));
			if (mBridgeCreating)
			{
				mBridgeCreating = false; //in case we interrupted the creation
			}
			return;
		}
		//is it in the right place?
		LLUUID catID = findFSCategory();
		if (catID != fsObject->getParentUUID())
		{
			//the object is not where we think it is. Kick it off.
			LLVOAvatarSelf::detachAttachmentIntoInventory(fsObject->getUUID());
			llwarns << "Bridge container isn't in the correct inventory location. Detaching it and aborting." << llendl;
			if (mBridgeCreating)
			{
				reportToNearbyChat(LLTrans::getString("fs_bridge_failure_attach_wrong_location"));
				mBridgeCreating = false; //in case we interrupted the creation
			}
			return;
		}
		mpBridge = fsObject;
	}

	lldebugs << "Bridge container is attached, mpBridge not NULL, avatar is self, point is bridge, all is good." << llendl;


	if (fsObject->getUUID() != mpBridge->getUUID())
	{
		//something odd just got attached to bridge?
		llwarns << "Something unknown just got attached to bridge point, detaching and aborting." << llendl;
		if (mBridgeCreating)
		{
			reportToNearbyChat(LLTrans::getString("fsbridge_failure_attach_point_in_use"));
			mBridgeCreating = false; //in case we interrupted the creation
		}
		LLVOAvatarSelf::detachAttachmentIntoInventory(mpBridge->getUUID());
		return;
	}
	lldebugs << "Bridge container found is the same bridge we saved, id matched." << llendl;

	if (!mBridgeCreating) //just an attach. See what it is
	{
		// AH: We need to request objects inventory first before we can
		// do anything with it!
		llinfos << "Requesting bridge inventory contents..." << llendl;
		object->registerInventoryListener(this, NULL);
		object->requestInventory();
	}
	else
	{
		configureBridgePrim(object);
	}
}
bool FSLSLBridge::lslToViewer(std::string message, LLUUID fromID, LLUUID ownerID)
{
	if (!gSavedSettings.getBOOL("UseLSLBridge"))
	{
		return false;
	}

	lldebugs << message << llendl;
	
	//<FS:TS> FIRE-962: Script controls for built-in AO
	if ((message[0]) != '<')
	{
		return false; 		// quick exit if no leading <
	}
	S32 closebracket = message.find('>');
	S32 firstblank = message.find(' ');
	S32 tagend;
	if (closebracket == std::string::npos)
	{
		tagend = firstblank;
	}
	else if (firstblank == std::string::npos)
	{
		tagend = closebracket;
	}
	else
	{
		tagend = (closebracket < firstblank) ? closebracket : firstblank;
	}
	if (tagend == std::string::npos)
	{
		return false;
	}
	std::string tag = message.substr(0, tagend + 1);
	std::string ourBridge = gSavedPerAccountSettings.getString("FSLSLBridgeUUID");
	//</FS:TS> FIRE-962
	
	bool status = false;
	if (tag == "<bridgeURL>")
	{

		// brutish parsing
		S32 urlStart  = message.find("<bridgeURL>") + 11;
		S32 urlEnd    = message.find("</bridgeURL>");
		S32 authStart = message.find("<bridgeAuth>") + 12;
		S32 authEnd   = message.find("</bridgeAuth>");
		S32 verStart  = message.find("<bridgeVer>") + 11;
		S32 verEnd    = message.find("</bridgeVer>");
		std::string bURL = message.substr(urlStart,urlEnd - urlStart);
		std::string bAuth = message.substr(authStart,authEnd - authStart);
		std::string bVer = message.substr(verStart,verEnd - verStart);

		// Verify Version
		// todo

		// Verify Authorization
		if (ourBridge != bAuth)
		{
			llwarns << "BridgeURL message received from ("<< bAuth <<") , but not from our registered bridge ("<< ourBridge <<"). Ignoring." << llendl;
			// Failing bridge authorization automatically kicks off a bridge rebuild. This correctly handles the
			// case where a user logs in from multiple computers which cannot have the bridgeAuth ID locally 
			// synchronized.
			
			
			// If something that looks like our current bridge is attached but failed auth, detach and recreate.
			LLUUID catID = findFSCategory();
			LLViewerInventoryItem* fsBridge = findInvObject(mCurrentFullName, catID, LLAssetType::AT_OBJECT);
			if (fsBridge != NULL)
			{
				if (get_is_item_worn(fsBridge->getUUID()))
				{
					LLVOAvatarSelf::detachAttachmentIntoInventory(fsBridge->getUUID());
					//This may have been an unfinished bridge. If so - stop the process before recreating.
					if (mBridgeCreating)
						mBridgeCreating = false;
					recreateBridge();
					return true; 
				}
			}
			
			// If something that didn't look like our current bridge failed auth, don't recreate, it might interfere with a bridge creation in progress
			// or normal bridge startup.  Bridge creation isn't threadsafe yet.
			return true;
		}

		// Save the inworld UUID of this attached bridge for later checking
		mBridgeUUID = fromID;
		
		// Get URL
		mCurrentURL = bURL;
		llinfos << "New Bridge URL is: " << mCurrentURL << llendl;
		
		if (mpBridge == NULL)
		{
			LLUUID catID = findFSCategory();
			LLViewerInventoryItem* fsBridge = findInvObject(mCurrentFullName, catID, LLAssetType::AT_OBJECT);
			mpBridge = fsBridge;
		}

		status = viewerToLSL("URL Confirmed", new FSLSLBridgeRequestResponder());
		//updateBoolSettingValue("UseLSLFlightAssist");
		if (!mIsFirstCallDone)
		{
			//on first call from bridge, confirm that we are here
			//then check options use
			updateBoolSettingValue("UseLSLFlightAssist");
			updateBoolSettingValue("FSPublishRadarTag");
			mIsFirstCallDone = true;
		}
		return true;
	}
	
	//<FS:TS> FIRE-962: Script controls for built-in AO
	if (fromID != mBridgeUUID)
	{
		return false;		// ignore if not from the bridge
	}
	if (tag == "<clientAO ")
	{
		status = true;
		S32 valuepos = message.find("state=") + 6;
		if (valuepos != std::string::npos)
		{
			if (message.substr(valuepos, 2) == "on")
			{
				gSavedPerAccountSettings.setBOOL("UseAO", TRUE);
			}
			else if (message.substr(valuepos, 3) == "off")
			{
				gSavedPerAccountSettings.setBOOL("UseAO", FALSE);
			}
		}
	}
	//</FS:TS> FIRE-962
	return status;
}