/*
 * Copyright 2009 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 <base/util/utils.h>
#include <Utils.h>
#include <serverexchange/ConnectionInfo.h>
#include <Logger/LoggerMacroses.h>

using namespace NS_DM_Client::NS_Communication;

static const char * c_LogName = "ConnectionInfo";

ConnectionInfo::ConnectionInfo() :
    m_messageID(0),
    m_isAuthenticated(false),
    m_isDevInfSent(false),
    m_isInLOMode(false),
    m_isWaitingAuthentication(false), 
    m_isWaitingForNextChunk(false),
    m_askNextChunkAlertCmdID(NULL), m_sessionURL(NULL), m_serverID(NULL), 
    m_nextNonce(NULL), m_nonce(NULL),
    m_messageIDText(NULL), m_lastServerMessageID(NULL),
    m_sessionID(NULL)
{
    m_messageIDText = Funambol::stringdup("1");
    m_lastServerMessageID = Funambol::stringdup("");
    acconfig.setUsername("");
    acconfig.setPassword("");
    acconfig.setProxyHost("");
    acconfig.setProxyUsername("");
    acconfig.setProxyPassword("");
    acconfig.setClientAuthType("");
    acconfig.setServerAuthType("");
    acconfig.setServerPWD("");
    acconfig.setServerID("");
    acconfig.setServerNonce("");
    acconfig.setClientNonce("");
    acconfig.setUserAgent("");
}


ConnectionInfo::~ConnectionInfo()
{
    SAFE_DELETE_ARR(m_askNextChunkAlertCmdID);
    SAFE_DELETE_ARR(m_sessionURL);
    SAFE_DELETE_ARR(m_nextNonce);
    SAFE_DELETE_ARR(m_nonce);
    SAFE_DELETE_ARR(m_messageIDText);
    SAFE_DELETE_ARR(m_lastServerMessageID);
    SAFE_DELETE_ARR(m_sessionID);
    SAFE_DELETE_ARR(m_serverID);
}


void ConnectionInfo::SetAuthenticated(bool b)
{
    m_isAuthenticated = b;
    if (b)
        m_isWaitingAuthentication = false;
    else
    {
        ResetMessageID();
        m_isDevInfSent = false;
    }
}


void ConnectionInfo::ResetMessageID()
{
    m_messageID = 0;
}


char * ConnectionInfo::GetNextMessageID()
{
    SAFE_DELETE_ARR(m_messageIDText);

    m_messageID++;

    char bf[64];
    __sprintf(bf, "%d", m_messageID);
    m_messageIDText = Funambol::stringdup(bf);

    return m_messageIDText;
}


void ConnectionInfo::SetWaitingAuthentication(bool b)
{
    m_isWaitingAuthentication = b;
    if (b)
        m_isAuthenticated = false;
}


void ConnectionInfo::SetLastServerMessageID(const char *theID)
{
    SAFE_DELETE_ARR(m_lastServerMessageID);
    if (theID)
        m_lastServerMessageID = Funambol::stringdup(theID);
    else
        m_lastServerMessageID = Funambol::stringdup("");
}


void ConnectionInfo::SetNextChunkAlertCmdID(const char *theID)
{
    SAFE_DELETE_ARR(m_askNextChunkAlertCmdID);
    if (theID)
        m_askNextChunkAlertCmdID = Funambol::stringdup(theID);
    else
        m_askNextChunkAlertCmdID = Funambol::stringdup("");
}


const char * ConnectionInfo::GetNextNonce()
{
    SAFE_DELETE_ARR(m_nonce);
    m_nonce = Funambol::stringdup(m_nextNonce);

    Funambol::NextNonce *pNonce = CreateNonce();
    const char *nonce64 = pNonce->getValueAsBase64(); // result created with new []
    m_nextNonce = const_cast<char*>(nonce64);

    return m_nonce;
}


void ConnectionInfo::SetSessionURL(const char *url)
{
    SAFE_DELETE_ARR(m_sessionURL);
    m_sessionURL = Funambol::stringdup(url);
}


const char * ConnectionInfo::GetSessionURL()
{
    return m_sessionURL;
}


void ConnectionInfo::SetServerID(const char *sid)
{
    SAFE_DELETE_ARR(m_serverID);
    m_serverID = Funambol::stringdup(sid);
}


void ConnectionInfo::SetSessionID(const char *sid)
{
    SAFE_DELETE_ARR(m_sessionID);
    m_sessionID = Funambol::stringdup(sid);
}



void ConnectionInfo::SwitchToSessionType(const char *name)
{
    if (name && strlen(name))
    {
        if (!initialClientSessionType.size())
            initialClientSessionType = acconfig.getClientAuthType();
        acconfig.setClientAuthType(name);
        state.reconnectInstantly = true;
    }
}


bool ConnectionInfo::IsServerCredValid(Funambol::Cred *cred)
{
    if (cred && cred->getData() && cred->getFormat() && cred->getType())
    {
        const char *data   = cred->getData();
        const char *format = cred->getFormat();
        const char *type   = cred->getType();
        
        if (!strcmp(AUTH_TYPE_BASIC, type) && !strcmp("b64", format))
        {
            Funambol::Authentication auth(AUTH_TYPE_BASIC, acconfig.getServerID(), acconfig.getServerPWD());
            return !strcmp(cred->getData(), auth.getData());
        }
        else if (!strcmp(AUTH_TYPE_MD5, type) && !strcmp("b64", format))
        {
            char *localmd5 = Funambol::MD5CredentialData(acconfig.getServerID(), acconfig.getServerPWD(), acconfig.getServerNonce());
            GDLDEBUG("Local md5 calc: %s", localmd5);
//          GDLDEBUG("on auth data: ['%s' '%s' '%s']", acconfig.getServerID(), acconfig.getServerPWD(), acconfig.getServerNonce());
            
            bool res = localmd5 && data && !strcmp(localmd5, data);
            SAFE_DELETE_ARR(localmd5);
            return res;
        }
        else
            GDLERROR("Unsupported cred type received: %s", type);
    }
    return false;
}


void ConnectionInfo::Reset()
{
    state.abortConnection = false;
    state.hasLOSending = false;
    state.connectionFinished = true;
    state.reconnectInstantly = false;
    state.repeatAuthentication = false;
    m_messageID = 0;

    SetSessionID(NULL);
}
