/* ***** BEGIN LICENSE BLOCK *****
 * Source last modified: $Id: CHXClientEngineSymbian.cpp,v 1.1.2.3 2004/07/09 01:49:38 hubbe Exp $
 * 
 * Portions Copyright (c) 1995-2004 RealNetworks, Inc. All Rights Reserved.
 * 
 * The contents of this file, and the files included with this file,
 * are subject to the current version of the RealNetworks Public
 * Source License (the "RPSL") available at
 * http://www.helixcommunity.org/content/rpsl unless you have licensed
 * the file under the current version of the RealNetworks Community
 * Source License (the "RCSL") available at
 * http://www.helixcommunity.org/content/rcsl, in which case the RCSL
 * will apply. You may also obtain the license terms directly from
 * RealNetworks.  You may not use this file except in compliance with
 * the RPSL or, if you have a valid RCSL with RealNetworks applicable
 * to this file, the RCSL.  Please see the applicable RPSL or RCSL for
 * the rights, obligations and limitations governing use of the
 * contents of the file.
 * 
 * Alternatively, the contents of this file may be used under the
 * terms of the GNU General Public License Version 2 or later (the
 * "GPL") in which case the provisions of the GPL are applicable
 * instead of those above. If you wish to allow use of your version of
 * this file only under the terms of the GPL, and not to allow others
 * to use your version of this file under the terms of either the RPSL
 * or RCSL, indicate your decision by deleting the provisions above
 * and replace them with the notice and other provisions required by
 * the GPL. If you do not delete the provisions above, a recipient may
 * use your version of this file under the terms of any one of the
 * RPSL, the RCSL or the GPL.
 * 
 * This file is part of the Helix DNA Technology. RealNetworks is the
 * developer of the Original Code and owns the copyrights in the
 * portions it created.
 * 
 * This file, and the files included with this file, is distributed
 * and made available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY
 * KIND, EITHER EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS
 * ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET
 * ENJOYMENT OR NON-INFRINGEMENT.
 * 
 * Technology Compatibility Kit Test Suite(s) Location:
 *    http://www.helixcommunity.org/content/tck
 * 
 * Contributor(s):
 * 
 * ***** END LICENSE BLOCK ***** */

#include "CHXClientEngineSymbian.h"
#include "hxassert.h"
#include "safestring.h"
#include "dllpath.h"
#include "hxwintyp.h"

#include "globals/hxglobalptr.h"
#include "hxglobalmgr_imp.h"
#include "hxglobalmgr_inst.h"

#include "symbian_dll_map.h"
#include "symbian_dll_map_inst.h"

#include <utf.h>
#include <coemain.h>
#include <f32file.h>

#define MAX_PATH    256

// for HXSymbianDLLMapInstance
static void
DestroyDLLMap(void* pObj)
{
    SymbianDLLMapImp* pDM = reinterpret_cast<SymbianDLLMapImp*>(pObj);
    delete pDM;
}

/*!
  @function CreateGlobalManager
  @abstract Create the global manager for handling global data in DLLs
*/
static void
CreateGlobalManager()
{
    HXGlobalManagerImp* pGM = new HXGlobalManagerImp();
    if (pGM)
    {
	HXGlobalManInstance::SetInstance(pGM);
    }
}

/*!
  @function DestroyGlobalManager
  @abstract Destroy the global manager
*/
static void
DestroyGlobalManager()
{
    // destroy the global manager
    HXGlobalManagerImp* pGM =
	static_cast<HXGlobalManagerImp*>( HXGlobalManInstance::GetInstance() );
    if (pGM)
    {
	pGM->Shutdown();
	HX_DELETE(pGM);
	HXGlobalManInstance::SetInstance(0);
    }
}

/*!
  @function AllocPath
  @abstract Given a 16-bit descriptor, convert to utf8 in alloc'ed char array
*/
static char* 
AllocPath(const TDesC& pathDes)
{
    char* pPath = NULL;

    RFs fs;
    fs.Connect();
    TFindFile find(fs);
    if (KErrNone == find.FindByDir(pathDes, _L("")))
    {
	TBuf8<KMaxFileName> utf8Path;
	CnvUtfConverter::ConvertFromUnicodeToUtf8(utf8Path, find.File());

	pPath = new char[utf8Path.Length() + 1];

	strcpy(pPath, (const char*)utf8Path.PtrZ());
    }
    fs.Close();
    return pPath;
}


/*!
  @const kClientCoreLocation
  @abstract Literal path to client core
*/
_LIT(kClientCoreLocation, "\\system\\apps\\realplayer\\lib\\clntcore.dll");

/*!
  @const kRealPlayerLocation
  @abstract Literal path to install dir for RealPlayer
*/
_LIT(kRealPlayerLocation, "\\system\\apps\\realplayer");

/*!
  @const kCreateEngine
  @abstract symbol name for the client engine creation func
*/
const char* const kCreateEngine = "CreateEngine";


/*!
  @const kCloseEngine
  @abstract symbol name for the client engine destruction func
*/
const char* const kCloseEngine = "CloseEngine";

/*!
  @const kClientCoreDll
  @abstract the name of the helix client core shared library on unix
*/
const char* const kClientCoreDll = "clntcore.dll";

/*!
  @const kSetDll
  @abstract symbol name for the client engine's dll search path function
*/
const char* const kSetDll = "SetDLLAccessPath";

/*!
  @const kDllTypes
  @abstract names of common dll locations used by SetDLLAccessPath
*/
const char* const kDllTypes[] =
{
    "DT_Common", "DT_Plugins", "DT_Codecs"
};

/*!
  @const kDllDirs
  @abstract names of common dll directories used by SetDLLAccessPath
*/
const char* const kDllDirs[] =
{
    "lib", "lib", "lib"
};

/*!
  @const kNumDllTypes
  @abstract number of dll location names used by SetDLLAccessPath
*/
const UINT32 kNumDllTypes = sizeof(kDllTypes) / sizeof(*kDllTypes);


ENABLE_DLLACCESS_PATHS(hxclient);


/*!
  @function CreatePlatformClientEngine
  @abstract create and return a new CHXClientEngineSymbian
*/
CHXClientEngine* CreatePlatformClientEngine(void)
{
    return new CHXClientEngineSymbian;
}

//typedef HX_RESULT (HXEXPORT_PTR FPRMSETDLLACCESSPATH) (const char*);


/*!
  @function ~CHXClientEngineSymbian
  @abstract destructor
  @discussion unloads the client core
*/
CHXClientEngineSymbian::~CHXClientEngineSymbian(void)
{
    UnloadClientCore();

    DestroyGlobalManager();
}


/*!
  @function CHXClientEngineSymbian
  @abstract constructor
*/
CHXClientEngineSymbian::CHXClientEngineSymbian(void)
    : m_pICoreEngine(NULL)
{
    CreateGlobalManager();
}

/*!
  @function LoadClientCore
  @abstract load and initialize the helix client engine
*/
HX_RESULT
CHXClientEngineSymbian::LoadClientCore(void)
{
    HX_RESULT res = HXR_OK;

    if (!m_dllHXCore.isOpen())
    {
	char* pCore = NULL;

	pCore = AllocPath(kClientCoreLocation);

	if (pCore && m_dllHXCore.open(pCore, 0) == DLLAccess::DLL_OK)
	{
	    res = HXR_OK;
	}
	else
	{
	    res = HXR_FAIL;
	}

	delete [] pCore;
    }

    return res;
}


/*!
b  @function InitDLLAccessPaths
  @abstract initialize DLLAccess paths
  @discussion DLLAccess is a class used in Helix to easily load dlls and
  access their symbols.  The client engine typically expects to find certain
  types of dlls (eg: codecs, plugins) in certain locations.  The
  SetDLLAccessPath function is called to set these locations.
  InitDLLAccessPaths sets these locations to some reasonable defaults.
*/
HX_RESULT
CHXClientEngineSymbian::InitDLLAccessPaths(void)
{
    HX_RESULT res = LoadClientCore();

    if (SUCCEEDED(res))
    {
	FPSETDLLACCESSPATH pfnSetDll;
	pfnSetDll = (FPSETDLLACCESSPATH)m_dllHXCore.getSymbol(kSetDll);
	if (pfnSetDll)
	{
	    char* pDllHome = AllocPath(kRealPlayerLocation);

	    if (pDllHome)
	    {
		char paths[MAX_PATH * kNumDllTypes];

		int nLen = sizeof(paths) / sizeof(char);
		char* pPath = paths;
		for (unsigned int i = 0; i != kNumDllTypes; ++i)
		{
		    int nSize = SafeSprintf(pPath, nLen,
					    "%s=%s\\%s",
					    kDllTypes[i],
					    pDllHome,
					    kDllDirs[i]);

		    nSize++; // Skip over the '\0'                
		    pPath += nSize;
		    nLen -= nSize;
		
		    HX_ASSERT(nLen >= 0);
		}
		pPath++;
		*pPath = 0;
	    
		pfnSetDll(paths);
	    }
	    else
	    {
		res = HXR_FAIL;
	    }

	    delete [] pDllHome;
	}
    }
    return res;
}


/*!
  @function OnCreateClientEngine
  @abstract create and return an IHXClientEngine
*/
IHXClientEngine*
CHXClientEngineSymbian::OnCreateClientEngine(HX_RESULT* pResult)
{
    *pResult = HXR_OK;
    if (!m_pICoreEngine)
    {
	// Install ISymbianDLLMap object. 
	// This object is used by DLLAccess to reference count each DLL. This
	// map keeps track of when a library will actually be unloaded by the OS
	// and arranges for the DLLs globals to get cleaned up before the DLL is
	// unloaded.
	SymbianDLLMapImp* pDM = new SymbianDLLMapImp;
	if (pDM)
	{
	    HXSymbianDLLMapInstance::SetInstance(pDM, &DestroyDLLMap);
	}

	*pResult = InitDLLAccessPaths();
	if (SUCCEEDED(*pResult))
	{
	    FPRMCREATEENGINE pCreateEngine =
		(FPRMCREATEENGINE)m_dllHXCore.getSymbol(kCreateEngine);
	    if (pCreateEngine)
	    {
		*pResult = pCreateEngine(&m_pICoreEngine);
		// If engine was not created, we should receive a reason.
		HX_ASSERT((NULL != m_pICoreEngine) || (FAILED(*pResult)));
	    }
	    else
	    {
		*pResult = HXR_COULDNOTINITCORE;
	    }
	}
    }
    return m_pICoreEngine;
}


/*!
  @function GetClientEngine
  @abstract return the IHXClientEngine
*/
IHXClientEngine*
CHXClientEngineSymbian::GetClientEngine(void)
{
    return m_pICoreEngine;
}


/*!
  @function OnCloseClientEngine
  @abstract destroy the IHXClientEngine and unload the client core
*/
void
CHXClientEngineSymbian::OnCloseClientEngine(void)
{
    if (m_pICoreEngine)
    {
	HX_ASSERT(m_dllHXCore.isOpen());
	FPRMCLOSEENGINE pCloseEngine =
	    (FPRMCLOSEENGINE)m_dllHXCore.getSymbol(kCloseEngine);
	if (pCloseEngine)
	{
	    pCloseEngine(m_pICoreEngine);
	}
	m_pICoreEngine = NULL;
    }
}


/*!
  @function UnloadClientCore
  @abstract shutdown the engine and unload the client core dll
*/
void
CHXClientEngineSymbian::UnloadClientCore(void)
{
    if (m_dllHXCore.isOpen())
    {
	OnCloseClientEngine();
	
	m_dllHXCore.close();
    }
}

