/*
 * Copyright 2010 Funambol, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/* $Id$ */

#include "common/Errors.h"
#include "treemanager/IMOTreeManager.h"
#include "treemanager/TreeManagerUtils.h"
#include "treemanager/ValidDMAccAvailableCommand.h"
#include "Logger/LoggerMacroses.h"


using namespace NS_DM_Client;
using namespace NS_DM_Client::NS_Communication;

const char* const c_LogName = "DMAccountCommand";

ValidDMAccAvailableCommand::ValidDMAccAvailableCommand(ProfileComponentsHolder &pch, IResultSink &rsink) : 
	DMAccountCommand(pch), m_resultSink(rsink)
{
}


bool ValidDMAccAvailableCommand::Execute()
{
	IMOTreeManager::ChildrenPaths accounts;
	
	if (TMUtils::IsDMAccNode(m_treeManager, URI_DMACC))
	{
		FStringBuffer uri(URI_DMACC);
		m_resultSink.SetResult(isValidAccount(uri));
	}
	else if (e_Ok == m_pch.GetMOTreeManager()->GetChildren(URI_DMACC, accounts, NULL))
	{
		bool brc = false;

		for (size_t i=0; i<accounts.size(); ++i)
		{
			String accname = accounts[i];
			FStringBuffer uriAccount0(URI_DMACC);
			uriAccount0.append("/").append(accname.c_str()); // this is uri ./DMAcc/X
			brc = isValidAccount(uriAccount0);
			if (brc)
			{
				// valid account is found. not continue
				GDLDEBUG("Valid account is found. URI '%s'. Stop searching.", uriAccount0.c_str());
				break;
			}
		}

		m_resultSink.SetResult(brc);
	}
	else
		m_resultSink.SetResult(false);
	
	return true;
}


bool ValidDMAccAvailableCommand::isValidAccount(FStringBuffer &uriAccount)
{
	GDLDEBUG("URI '%s'", uriAccount.c_str());
	
	if (isAbsentOrEmpty(uriAccount, "AppID") || 
		isAbsentOrEmpty(uriAccount, "ServerID") 
		//|| isAbsentOrEmpty(uriAccount, "Name") 
		)
	{
		GDLERROR("AppID or ServerID is not valid");
		return false;
	}
	
	FStringBuffer appID;
	if (!getLeafValue(uriAccount, "AppID", appID) || strcmp("w7", appID))
	{
		GDLERROR("AppID is not w7");
		return false;
	}
	
	if (!isValidAppAddr(uriAccount))
	{
		GDLERROR("AppAddr is not valid");
		return false;
	}

	FStringBuffer uriClientCred;
	if (!getAuthenticationNode(uriAccount, uriClientCred, CLCRED) ||
		!isValidAuthNode(uriClientCred))
	{
		GDLERROR("CLCRED is not valid");
		return false;
	}

	FStringBuffer uriServerCred;
	if (!getAuthenticationNode(uriAccount, uriServerCred, SRVCRED) ||
		!isValidAuthNode(uriServerCred))
	{
		GDLERROR("SRVCRED is not valid");
		return false;
	}

	GDLDEBUG("Account by URI '%s' is correct", uriAccount.c_str());
	return true;
}


bool ValidDMAccAvailableCommand::isAbsentOrEmpty(FStringBuffer &uri, const char *leafName)
{
	FStringBuffer outvalue;
	return leafName && (!getLeafValue(uri, leafName, outvalue) || outvalue.empty());
}


bool ValidDMAccAvailableCommand::isValidAuthNode(FStringBuffer &uri)
{
	bool isValid = //!isAbsentOrEmpty(uri, "AAuthData") && // AAuthData may be absent
				   !isAbsentOrEmpty(uri, "AAuthName") &&
				   !isAbsentOrEmpty(uri, "AAuthSecret");

	if (!isValid)
		return false;
		
	FStringBuffer authtype;
	if (getLeafValue(uri, "AAuthType", authtype) && !authtype.empty())
	{
		return  !strcmp("BASIC", authtype)  ||
				!strcmp("DIGEST", authtype) ||
				!strcmp("HMAC", authtype);
	}

	return false;
}


bool ValidDMAccAvailableCommand::isValidAppAddr(FStringBuffer &uriAccount)
{
	FStringBuffer uriServerNode;

	if (!getServerNode(uriAccount, uriServerNode) || uriServerNode.empty())
		return false;
	
	return !isAbsentOrEmpty(uriServerNode, "Addr") && !isAbsentOrEmpty(uriServerNode, "AddrType");
}
