/*
 *   Copyright 2003-2004 The Apache Software Foundation.
 *
 *   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.
 *
 *   @author Sanjaya Singharage
 *   @author Roshan Weerasuriya (roshan@jkcs.slt.lk, roshan@opensource.lk)
 *   @author Susantha Kumara (skumara@virtusa.com, susantha@opensource.lk)
 *
 */

// !!! This include file must be first thing in file !!!
#include "../platforms/PlatformAutoSense.hpp"

#include "WSDDDeployment.h"
#include "WSDDDocument.h"

#include <axis/GDefine.hpp>
#include "../common/AxisConfig.h"
#include "AxisWsddException.h"

#include "../common/AxisTrace.h"

AXIS_CPP_NAMESPACE_START


WSDDDeployment::
WSDDDeployment()
{
	logEntryEngine("WSDDDeployment::WSDDDeployment")

    m_DeployedServices = NULL;
    m_sAux = "";
    m_pTransportHandlers = NULL;
    m_GlobalResponseHandlers = NULL;
    m_GlobalRequestHandlers = NULL;
    m_DeplType = DT_DEPLOYMENT;
    m_pLibNameIdMap = new map<AxisString, int>;
    
	logExit()
}

WSDDDeployment::
~WSDDDeployment()
{
	logEntryEngine("WSDDDeployment::~WSDDDeployment")

    WSDDHandlerList::iterator iter;
    delete m_pTransportHandlers;

    if(m_GlobalRequestHandlers)
        for(iter=m_GlobalRequestHandlers->begin(); iter!=m_GlobalRequestHandlers->end(); iter++)
            delete (*iter);

    if(m_GlobalResponseHandlers)
        for(iter=m_GlobalResponseHandlers->begin(); iter!=m_GlobalResponseHandlers->end(); iter++)
            delete (*iter);

    WSDDServiceMap::iterator iter2;
    if(m_DeployedServices)
        for(iter2=m_DeployedServices->begin(); iter2!=m_DeployedServices->end(); iter2++)
            delete ((*iter2).second);

    delete m_DeployedServices;
    delete m_pLibNameIdMap;
    
	logExit()
}

const WSDDHandlerList* WSDDDeployment::
getGlobalRequestFlowHandlers()
{
    return m_GlobalRequestHandlers;
}

const WSDDHandlerList* WSDDDeployment::
getGlobalResponseFlowHandlers()
{
    return m_GlobalResponseHandlers;
}

int WSDDDeployment::
updateWSDD(const AxisChar* sWSDD)
{
    WSDDDocument* doc = new WSDDDocument(m_pLibNameIdMap);
    int rc = doc->updateDeployment(sWSDD, this);
    delete doc;
    
    if (AXIS_SUCCESS == rc)
        saveWSDD();
        
    return rc;        
}

int WSDDDeployment::
loadWSDD( const AxisChar * sWSDD)
{
	logEntryEngine("WSDDDeployment::loadWSDD")

    m_sWSDDPath = std::string( sWSDD);

    WSDDDocument *doc = new WSDDDocument( m_pLibNameIdMap);
    
    int rc = doc->getDeployment( sWSDD, this);

    delete doc;
    
    if (AXIS_FAIL == rc)
    {
    	 logThrowException("AxisWsddException - SERVER_WSDD_FILE_NOT_FOUND")

         throw AxisWsddException(SERVER_WSDD_FILE_NOT_FOUND);
    }
        
	logExitWithReturnCode(AXIS_SUCCESS)

    return AXIS_SUCCESS;
}

int WSDDDeployment::
saveWSDD()
{
    int Status = AXIS_FAIL;
    /* TODO we have to rename the existing server.wsdd to server.wsdd.old
     * and if anything went wrong we have to rename it back to server.wsdd
     */
    FILE* file = fopen(m_sWSDDPath.c_str(), "w");
    if(!file) 
        return AXIS_FAIL;
        
    do
    {
        if (fputs("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n", file) < 0) 
            break;
            
        if (fputs("<deployment xmlns=\"http://xml.apache.org/axis/wsdd/"
                    "\" xmlns:C=\"http://xml.apache.org/axis/wsdd/providers/C\" xmlns:"
                    "CPP=\"http://xml.apache.org/axis/wsdd/providers/CPP\">\n",
                file) < 0) 
            break;
            
        if (fputs("\t<globalConfiguration>\n", file) < 0) 
            break;
            
        WSDDHandlerList::iterator iter;
        if(m_GlobalRequestHandlers)
        {
            if (fputs("\t\t<requestFlow>\n", file) < 0) 
                break;
                
            for(iter=m_GlobalRequestHandlers->begin(); iter!=m_GlobalRequestHandlers->end(); iter++)
                (*iter)->updateWSDD(file, 3);

            if (fputs("\t\t</requestFlow>\n", file) < 0) 
                break;
        }

        if(m_GlobalResponseHandlers)
        {
            if (fputs("\t\t<responseFlow>\n", file) < 0) 
                break;
                
            for(iter=m_GlobalResponseHandlers->begin(); iter!=m_GlobalResponseHandlers->end(); iter++)
                (*iter)->updateWSDD(file, 3);

            if (fputs("\t\t</responseFlow>\n", file) < 0) 
                break;
        }

        if (fputs("\t</globalConfiguration>\n", file) < 0) 
            break;

        if(m_pTransportHandlers)
            m_pTransportHandlers->updateWSDD(file, 3);

        WSDDServiceMap::iterator iter2;
        if(m_DeployedServices)
            for(iter2=m_DeployedServices->begin(); iter2!=m_DeployedServices->end(); iter2++)
                ((*iter2).second)->updateWSDD(file, 1);
        
        if (fputs("</deployment>", file) < 0) 
            break;
    } 
    while(0);
    
    fflush(file);
    fclose(file);
    if (AXIS_SUCCESS != Status)
    {
        /*TODO use the previous server.wsdd file itself. Undo renaming*/
    }
    return AXIS_SUCCESS;
}


const WSDDService* WSDDDeployment::
getService(const AxisChar* sServiceName)
{
	logSetFunctionNameEngine("WSDDDeployment::getService")
	
    WSDDServiceMap::iterator iter;
    if (!m_DeployedServices) 
        return NULL;
        
    try
    {
        iter = m_DeployedServices->find(sServiceName);
        if (iter != m_DeployedServices->end())
            return (*iter).second;
        else
           return NULL;
    }
    catch(exception& e)
    {
        e = e;

   	    logThrowExceptionWithData("AxisWsddException - SERVER_WSDD_EXCEPTION", e.what())

        throw AxisWsddException(SERVER_WSDD_EXCEPTION);
    }
}

const WSDDServiceMap* WSDDDeployment::
getWSDDServiceMap() const
{
    return m_DeployedServices;
}

const AxisChar* WSDDDeployment::
getLibName(int nLibId)
{
    for (map<AxisString, int>::iterator it = m_pLibNameIdMap->begin();
         it != m_pLibNameIdMap->end(); it++)
    {
        if ((*it).second == nLibId)
            return (*it).first.c_str();
    }
    
    return NULL;
}

int WSDDDeployment::
addService(WSDDService* pService)
{
	logEntryEngine("WSDDDeployment::addService")

    if (!m_DeployedServices) 
        m_DeployedServices = new WSDDServiceMap;
    
    if (m_DeployedServices->find(pService->getServiceName()) != m_DeployedServices->end())
    {
    	logWarning("The service already exists and the attempt to re-deploy is ignored.")
    }
    else
        (*m_DeployedServices)[pService->getServiceName()] = pService;

	logExitWithReturnCode(AXIS_SUCCESS)

    return AXIS_SUCCESS;
}        

int WSDDDeployment::
addHandler(bool bGlobal, bool bRequestFlow, WSDDHandler* pHandler, AXIS_PROTOCOL_TYPE protocol)
{
	logEntryEngine("WSDDDeployment::addHandler")
	
	if (pHandler)
	{
		logDebugArg4("Adding handler %s, global=%s, request=%s, response=%s", 
				     pHandler->getLibName(), 
				     bGlobal ? "yes" : "no",
				     bRequestFlow ? "yes" : "no", 
				     bRequestFlow ? "no"  : "yes")
	}

    if (bGlobal)
    {
        if (bRequestFlow)
        {
            if(!m_GlobalRequestHandlers) 
                m_GlobalRequestHandlers = new WSDDHandlerList;
            m_GlobalRequestHandlers->push_back(pHandler);
        }
        else
        {
            if(!m_GlobalResponseHandlers) 
                m_GlobalResponseHandlers = new WSDDHandlerList;
            m_GlobalResponseHandlers->push_back(pHandler);
        }
    }
    else /* transport */
    {
        if (!m_pTransportHandlers) 
            m_pTransportHandlers = new WSDDTransport();
        m_pTransportHandlers->addHandler(bRequestFlow, protocol, pHandler);
    }
	
	logExitWithReturnCode(AXIS_SUCCESS)

    return AXIS_SUCCESS;
}

const WSDDHandlerList* WSDDDeployment::
getTransportRequestFlowHandlers(AXIS_PROTOCOL_TYPE protocol)
{
    if (!m_pTransportHandlers) 
        return NULL;
    return m_pTransportHandlers->getRequestFlowHandlers(protocol);
}

const WSDDHandlerList* WSDDDeployment::
getTransportResponseFlowHandlers(AXIS_PROTOCOL_TYPE protocol)
{
    if (!m_pTransportHandlers) 
        return NULL;
    return m_pTransportHandlers->getResponseFlowHandlers(protocol);
}

int WSDDDeployment::
removeService(WSDDService* pService)
{
    if (m_DeployedServices && 
        (m_DeployedServices->find(pService->getServiceName()) != m_DeployedServices->end()))
    {
        WSDDService* pTheService = (*m_DeployedServices)[pService->getServiceName()];
        m_pLibNameIdMap->erase(pTheService->getLibName());
        m_DeployedServices->erase(pService->getServiceName());
        delete pTheService;    
        delete pService;
        return AXIS_SUCCESS;
    }
    return AXIS_NO_SUCH_SERVICE;
}

int WSDDDeployment::
removeHandler(bool bGlobal, bool bRequestFlow, WSDDHandler* pHandler, AXIS_PROTOCOL_TYPE protocol)
{
    m_pLibNameIdMap->erase(pHandler->getLibName());
    if (bGlobal)
    {
        WSDDHandlerList* pTempList = bRequestFlow ? m_GlobalRequestHandlers : m_GlobalResponseHandlers;
        if(pTempList)
            for (WSDDHandlerList::iterator itr=pTempList->begin(); itr != pTempList->end(); itr++)
                if (strcmp((*itr)->getLibName(), pHandler->getLibName()) == 0)
                {
                    pTempList->remove(*itr);
                    delete (*itr);
                    delete pHandler;
                    return AXIS_SUCCESS;
                }
    }
    else /* transport */
    {
        if (!m_pTransportHandlers) 
            return AXIS_NO_SUCH_HANDLER;
        return m_pTransportHandlers->removeHandler(bRequestFlow, protocol, pHandler);
    }
    
    return AXIS_NO_SUCH_HANDLER;    
}

DEPLOYMENTTYPE WSDDDeployment::
getDeploymentType() const
{
    return m_DeplType;
}

void WSDDDeployment::
setDeploymentType(DEPLOYMENTTYPE nType)
{
    m_DeplType = nType;
}

AXIS_CPP_NAMESPACE_END
