/*
* Copyright (c) 2005 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of "Eclipse Public License v1.0"
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
*
* Description:  Layout configuration data retrieval and access
*
*/


#include "AknLayoutConfig.h"
#include <eikenv.h>
#include <AknPanic.h>
#include <aknpriv.rsg>
#include <barsread.h>
#include <barsc2.h>
#include "AknLib.h"
#include <AknLayoutConsts.h>
#include "AknLayoutConfigInternal.h"
#include <CdlTypes.h>
#include <AknCapServerClient.h>

NONSHARABLE_CLASS(CAknLayoutConfigWsiniParser) : public CBase
	{
public:
	static void GetConfigL(SAknLayoutConfig& aConfig, 
						   RArray<SAknScreenModeInfo>& aScreenInfoArray, 
						   RArray<SHardwareStateInfo>& aHardwareStateArray);

private:
	CAknLayoutConfigWsiniParser(SAknLayoutConfig& aConfig, 
								RArray<SAknScreenModeInfo>& aScreenInfoArray, 
								RArray<SHardwareStateInfo>& aHardwareStateArray);
	~CAknLayoutConfigWsiniParser();
	void GetConfigL();
	HBufC* GetWsiniLC();
	void ParseWsiniL(const TDesC& aWsini);
	void ParseLineL(const TText* aKwStart, const TText* aKwEnd, const TText* aLineEnd);

	SHardwareStateInfo& HardwareStateL(TInt aStateNumber);
	SAknScreenModeInfo& ScreenModeL(TInt aScreenMode);
	TInt ParseIntL(TPtrC& aLine);
	TInt ParseKeycodeL(TPtrC& aLine);
	TAknPrivSoftkeyLocation ParseSoftkeyLocationL(TPtrC& aLine);
	TInt ScreenStyleHash(TPtrC& aLine);

private:
#define WSINI_PARSE_FUNC(name) static void Call##name(CAknLayoutConfigWsiniParser* aSelf, TPtrC& aLine) { aSelf->name(aLine); } void name(TPtrC& aLine);
	WSINI_PARSE_FUNC(HardwareStateKeycodeL)
	WSINI_PARSE_FUNC(HardwareStateScreenModeL)
	WSINI_PARSE_FUNC(HardwareStateAltScreenModeL)
	WSINI_PARSE_FUNC(ScreenModeSoftkeyLocationL)
	WSINI_PARSE_FUNC(ScreenModeStyleNameL)

private:
	struct SParseEntry
		{
		const TText16* iKeyword;
		TInt iKeywordLen;
		void (*iFunc)(CAknLayoutConfigWsiniParser* aSelf, TPtrC& aLine);
		};
	static const SParseEntry iParseTable[];

private:
	SAknLayoutConfig& iConfig;
	RArray<SAknScreenModeInfo>& iScreenInfoArray;
	RArray<SHardwareStateInfo>& iHardwareStateArray;
	};

//
// CAknLayoutConfig::TScreenMode
//
EXPORT_C const TPixelsTwipsAndRotation& CAknLayoutConfig::TScreenMode::PixelsTwipsAndRotation() const
	{
	return iInfo.iPixelsTwipsAndRotation;
	}

CAknLayoutConfig::TScreenMode::TScreenMode(const SAknScreenModeInfo& aInfo)
: TAknScreenMode(aInfo)
	{
	}

EXPORT_C TAknPrivSoftkeyLocation CAknLayoutConfig::TScreenMode::SoftkeyLocation() const
	{
	return iInfo.iSoftkeyLocation;
	}

EXPORT_C TInt CAknLayoutConfig::TScreenMode::ScreenStyleHash() const
	{
	return iInfo.iScreenStyleHash;
	}


//
// CAknLayoutConfig::TScreenModeArray
//
EXPORT_C CAknLayoutConfig::TScreenMode CAknLayoutConfig::TScreenModeArray::At(TInt aIndex) const
	{
	__ASSERT_ALWAYS(0 <= aIndex && aIndex < iInfo.iNumScreenModes, Panic(EAknPanicLayoutConfigBadScreenModeIndex));
	return TScreenMode(iInfo.iScreenModes[aIndex]);
	}

EXPORT_C CAknLayoutConfig::TScreenMode CAknLayoutConfig::TScreenModeArray::Find(TInt aModeNumber) const
	{
	for (TInt ii=0; ii<iInfo.iNumScreenModes; ii++)
		{
		if (iInfo.iScreenModes[ii].iModeNumber == aModeNumber)
			return TScreenMode(iInfo.iScreenModes[ii]);
		}
	return TScreenMode(iInfo.iScreenModes[0]);
	}

CAknLayoutConfig::TScreenModeArray::TScreenModeArray(const SAknLayoutConfig& aInfo)
: TAknScreenModes(aInfo)
	{
	}


//
// CAknLayoutConfig::THardwareState
//
EXPORT_C TInt CAknLayoutConfig::THardwareState::StateNumber() const
	{
	return iInfo.iStateNum;
	}

EXPORT_C TInt CAknLayoutConfig::THardwareState::KeyCode() const
	{
	return iInfo.iKeyCode;
	}

EXPORT_C TInt CAknLayoutConfig::THardwareState::ScreenMode() const
	{
	return iInfo.iScreenMode;
	}

EXPORT_C TInt CAknLayoutConfig::THardwareState::AlternateScreenMode() const
	{
	return iInfo.iAltScreenMode;
	}

CAknLayoutConfig::THardwareState::THardwareState(const SHardwareStateInfo& aInfo)
: iInfo(aInfo)
	{
	}


//
// CAknLayoutConfig::THardwareStateArray
//
EXPORT_C TInt CAknLayoutConfig::THardwareStateArray::Count() const
	{
	return iInfo.iNumHardwareStates;
	}

EXPORT_C CAknLayoutConfig::THardwareState CAknLayoutConfig::THardwareStateArray::At(TInt aIndex) const
	{
	__ASSERT_ALWAYS(0 <= aIndex && aIndex < iInfo.iNumHardwareStates, Panic(EAknPanicLayoutConfigBadHardwareStateIndex));
	return THardwareState(iInfo.iHardwareStates[aIndex]);
	}

EXPORT_C CAknLayoutConfig::THardwareState CAknLayoutConfig::THardwareStateArray::Find(TInt aStateNumber) const
	{
	for (TInt ii=0; ii<iInfo.iNumHardwareStates; ii++)
		{
		if (iInfo.iHardwareStates[ii].iStateNum == aStateNumber)
			return THardwareState(iInfo.iHardwareStates[ii]);
		}
	return THardwareState(iInfo.iHardwareStates[0]);
	}

CAknLayoutConfig::THardwareStateArray::THardwareStateArray(const SAknLayoutConfig& aInfo)
: iInfo(aInfo)
	{
	}


//
// CAknLayoutConfig
//
EXPORT_C CAknLayoutConfig::TScreenModeArray CAknLayoutConfig::ScreenModes() const
	{
	return TScreenModeArray(*iData);
	}

EXPORT_C CAknLayoutConfig::THardwareStateArray CAknLayoutConfig::HardwareStates() const
	{
	return THardwareStateArray(*iData);
	}

CAknLayoutConfig::CAknLayoutConfig()
	{
	}

CAknLayoutConfig::~CAknLayoutConfig()
	{
	delete iBuf;
	}

EXPORT_C CAknLayoutConfig* CAknLayoutConfig::NewL()
	{
	CAknLayoutConfig* self = new(ELeave) CAknLayoutConfig;
	CleanupStack::PushL(self);

	RAknUiServer aknUiServer;
	CleanupClosePushL(aknUiServer);
	User::LeaveIfError(aknUiServer.Connect());
	HBufC8* configBuf = aknUiServer.GetPackedConfigL();
	CleanupStack::PopAndDestroy(&aknUiServer);

	// ownership of configBuf immediately transferred to self
	self->ConstructL(configBuf);
	CleanupStack::Pop(self);
	return self;
	}

#define UNPACK_CHECK(b) __ASSERT_ALWAYS(b, Panic(EAknPanicLayoutConfigUnpackFail))

void CAknLayoutConfig::ConstructL(HBufC8* aBuf)
	{
	iBuf = aBuf;
	
	// unpack & validate data
	TInt size = iBuf->Size();
	// basic structure
	UNPACK_CHECK(size >= sizeof(SAknLayoutConfig));
	iData = (SAknLayoutConfig*)iBuf->Ptr();

	// check total size
	UNPACK_CHECK(
		size == 
		(
			sizeof(SAknLayoutConfig) + 
			(iData->iNumScreenModes * sizeof(SAknScreenModeInfo)) +
			(iData->iNumHardwareStates * sizeof(SHardwareStateInfo))
		));

	// check and unpack screen modes, iScreenModes is an offset before unpacking
	UNPACK_CHECK((TUint32)iData->iScreenModes == sizeof(SAknLayoutConfig));
	iData->iScreenModes = (SAknScreenModeInfo*)((TUint8*)iData + (TUint32)iData->iScreenModes);
	
	// check iNumScreenModes (we've already checked it fits in size)
	UNPACK_CHECK(iData->iNumScreenModes >= 0);

	// check and unpack hardware states, iHardwareStates is an offset before unpacking
	UNPACK_CHECK((TUint32)iData->iHardwareStates == (sizeof(SAknLayoutConfig) + sizeof(SAknScreenModeInfo)*iData->iNumScreenModes));
	iData->iHardwareStates = (SHardwareStateInfo*)((TUint8*)iData + (TUint32)iData->iHardwareStates);

	// check iNumHardwareStates (we've already checked it fits in size)
	UNPACK_CHECK(iData->iNumHardwareStates >= 0);
	}

HBufC8* CAknLayoutConfig::CreatePackedBufL()
	{
	// set up structures to collect the config info
	SAknLayoutConfig config = { 0, NULL, 0, NULL };
	
	RArray<SAknScreenModeInfo> screenInfoArray;
	CleanupClosePushL(screenInfoArray);
	
	RArray<SHardwareStateInfo> hardwareStateArray;
	CleanupClosePushL(hardwareStateArray);

	// get the config info
	TRAP_IGNORE(GetConfigL(config, screenInfoArray, hardwareStateArray));
	
	// calculate how much space is needed for the config info
	TInt screenModesSize = sizeof(SAknScreenModeInfo) * screenInfoArray.Count();
	TInt hardwareStatesSize = sizeof(SHardwareStateInfo) * hardwareStateArray.Count();
	TInt bufSize = sizeof(SAknLayoutConfig) + screenModesSize + hardwareStatesSize;
	
	// create the buffer space
	HBufC8* buf = HBufC8::NewLC(bufSize);
	TPtr8 des(buf->Des());
	
	// pack the info for transport
	config.iScreenModes = (SAknScreenModeInfo*)sizeof(SAknLayoutConfig);
	config.iHardwareStates = (SHardwareStateInfo*)(sizeof(SAknLayoutConfig) + screenModesSize);
	
	// put the info into the buffer
	des.Append(TPckgC<SAknLayoutConfig>(config));
	if (screenModesSize)
		des.Append(TPtrC8((TText8*)&screenInfoArray[0], screenModesSize));
	if (hardwareStatesSize)
		des.Append(TPtrC8((TText8*)&hardwareStateArray[0], hardwareStatesSize));
	
	// tidy up and return
	CleanupStack::Pop(buf);
	CleanupStack::PopAndDestroy(2); // hardwareStateArray and screenInfoArray
	
	return buf;
	}

#ifdef _DEBUG
void DebugLayoutConfigLeaves(TAny*)
	{
	User::Panic(_L("LayoutConfigLeave"), 0);
	}
#endif

void CAknLayoutConfig::GetConfigL(SAknLayoutConfig& aConfig, 
								  RArray<SAknScreenModeInfo>& aScreenInfoArray, 
								  RArray<SHardwareStateInfo>& aHardwareStateArray)
	{
#ifdef _DEBUG
	CleanupStack::PushL(TCleanupItem(DebugLayoutConfigLeaves, 0));
#endif

	CEikonEnv* eikonEnv = CEikonEnv::Static();
	CResourceFile* resFile = CResourceFile::NewLC(eikonEnv->FsSession(), CAknLibrary::PrivateResourceFile(), 0, 0);
	resFile->ConfirmSignatureL();
	
	TAknPrivSoftkeyLocation landscapeSofkey = GetLandscapeSoftkeyLocationFromAknPrivL(resFile);
	GetScreenModesFromWservL(aConfig, aScreenInfoArray, landscapeSofkey);

	CAknLayoutConfigWsiniParser::GetConfigL(aConfig, aScreenInfoArray, aHardwareStateArray);
	if (aHardwareStateArray.Count() == 0)
		{
		// got no info from wsini, so look up AknPriv
		GetScreenMapFromAknPrivL(resFile, aScreenInfoArray, aHardwareStateArray);
		GetKeyMapFromAknPrivL(resFile, aHardwareStateArray);
		}
	aConfig.iNumHardwareStates = aHardwareStateArray.Count();

	CleanupStack::PopAndDestroy(resFile);
	
#ifdef _DEBUG
	CleanupStack::Pop(); 	// TCleanupItem(DebugLayoutConfigLeaves, 0)
#endif
	}

void CAknLayoutConfig::GetScreenMapFromAknPrivL(CResourceFile* aResFile,
												RArray<SAknScreenModeInfo>& aScreenInfoArray, 
											    RArray<SHardwareStateInfo>& aHardwareStateArray)
	{
    ::CleanupClosePushL(aScreenInfoArray);
    ::CleanupClosePushL(aHardwareStateArray);
	// get state screen map
#if defined(__WINS__)
    TInt screenMapResource = R_AKNPRIV_HARDWARE_STATE_SCREEN_MAP_EMUL;
#else
    TInt screenMapResource = R_AKNPRIV_HARDWARE_STATE_SCREEN_MAP;
#endif

	// open the resource table for the hardware state <-> screen map
	TResourceReader reader;
	reader.SetBuffer(aResFile->AllocReadLC(screenMapResource));

	// Read the entires
	TInt numScreenModes = aScreenInfoArray.Count();
	TInt count = reader.ReadInt16();
	aHardwareStateArray.ReserveL(count);
	for (TInt ii=0; ii<count; ii++)
		{
		SHardwareStateInfo hwInfo;
		Mem::FillZ(&hwInfo, sizeof(hwInfo));
		
		hwInfo.iStateNum = reader.ReadInt16();
		
		TInt width = reader.ReadInt16();
		TInt height = reader.ReadInt16();
		TSize size(width, height);
		CFbsBitGc::TGraphicsOrientation rotation = static_cast<CFbsBitGc::TGraphicsOrientation>(reader.ReadInt16());
		CFbsBitGc::TGraphicsOrientation altRotation = static_cast<CFbsBitGc::TGraphicsOrientation>(reader.ReadInt16());
		TSize altSize(height, width);
		if ((rotation % CFbsBitGc::EGraphicsOrientationRotated180) == 
			(altRotation % CFbsBitGc::EGraphicsOrientationRotated180))
			altSize = size;
		
		// find a matching screen number
		for (TInt jj=0; jj<numScreenModes; jj++)
			{
			SAknScreenModeInfo& screenMode = aScreenInfoArray[jj];
			if (screenMode.iPixelsTwipsAndRotation.iPixelSize == size && screenMode.iPixelsTwipsAndRotation.iRotation == rotation)
				hwInfo.iScreenMode = screenMode.iModeNumber;
			if (screenMode.iPixelsTwipsAndRotation.iPixelSize == altSize && screenMode.iPixelsTwipsAndRotation.iRotation == altRotation)
				hwInfo.iAltScreenMode = screenMode.iModeNumber;
			}
			
		aHardwareStateArray.AppendL(hwInfo);
		}

	CleanupStack::PopAndDestroy(); // reader's HBufC
	CleanupStack::Pop(&aHardwareStateArray);
	CleanupStack::Pop(&aScreenInfoArray);
	}
	
void CAknLayoutConfig::GetKeyMapFromAknPrivL(CResourceFile* aResFile,
											 RArray<SHardwareStateInfo>& aHardwareStateArray)
	{
    ::CleanupClosePushL(aHardwareStateArray);
	// get the state key map
#if defined(__WINS__)
    TInt hwMapResource = R_AKNPRIV_HARDWARE_STATE_KEY_MAP_EMUL;
#else
    TInt hwMapResource = R_AKNPRIV_HARDWARE_STATE_KEY_MAP;
#endif

	TResourceReader reader;
	reader.SetBuffer(aResFile->AllocReadLC(hwMapResource));

    TInt count = reader.ReadInt16();
    for (TInt ii=0; ii<count; ii++)
        {
        TInt key = (TUint32)reader.ReadUint16();
        TInt state = reader.ReadInt16();
		for (TInt jj=0; jj<aHardwareStateArray.Count(); jj++)
			{
			SHardwareStateInfo& hwInfo = aHardwareStateArray[jj];
			if (hwInfo.iStateNum == state)
				hwInfo.iKeyCode = key;
			}
        }

    CleanupStack::PopAndDestroy(); // reader's HBufC
    CleanupStack::Pop(&aHardwareStateArray);
	}

TAknPrivSoftkeyLocation CAknLayoutConfig::GetLandscapeSoftkeyLocationFromAknPrivL(CResourceFile* aResFile)
	{
#if defined(__WINS__)
    TInt skResource = R_AKNPRIV_SOFTKEY_LOCATION_LANDSCAPE_ROTATED90_EMUL;
#else
    TInt skResource = R_AKNPRIV_SOFTKEY_LOCATION_LANDSCAPE_ROTATED90;
#endif

	TResourceReader reader;
	reader.SetBuffer(aResFile->AllocReadLC(skResource));
	TAknPrivSoftkeyLocation softKeyLocation = (TAknPrivSoftkeyLocation)reader.ReadInt16();

    CleanupStack::PopAndDestroy(); // reader's HBufC
    
    return softKeyLocation;
	}

TBool IsLandscape(const TSize& aSize)
	{
	return aSize.iWidth > aSize.iHeight;
	}

void CAknLayoutConfig::GetScreenModesFromWservL(SAknLayoutConfig& aConfig,
												RArray<SAknScreenModeInfo>& aScreenInfoArray, 
												TAknPrivSoftkeyLocation aLandscapeSoftkeyLocation)
	{
	::CleanupClosePushL(aScreenInfoArray);
	CEikonEnv* eikonEnv = CEikonEnv::Static();
	CWsScreenDevice* dev = eikonEnv->ScreenDevice();

	TInt numScreenModes = dev->NumScreenModes();
	aConfig.iNumScreenModes = numScreenModes;
	aScreenInfoArray.ReserveL(numScreenModes);
	for (TInt ii=0; ii<numScreenModes; ii++)
		{
		SAknScreenModeInfo screenMode;
		screenMode.iModeNumber = ii;
		screenMode.iScreenStyleHash = 0;
		dev->GetScreenModeSizeAndRotation(ii, screenMode.iPixelsTwipsAndRotation);
		if (IsLandscape(screenMode.iPixelsTwipsAndRotation.iPixelSize))
			{
			screenMode.iSoftkeyLocation = aLandscapeSoftkeyLocation;
	        // side-swapping logic moved from CAknEnv::StatusPaneResIdForCurrentLayout
	        if (screenMode.iPixelsTwipsAndRotation.iRotation == CFbsBitGc::EGraphicsOrientationRotated270)
	            {
	            if (aLandscapeSoftkeyLocation == EAknPrivSoftkeyLocationRight)
	                screenMode.iSoftkeyLocation = EAknPrivSoftkeyLocationLeft;
	            else if (aLandscapeSoftkeyLocation == EAknPrivSoftkeyLocationLeft)
	                screenMode.iSoftkeyLocation = EAknPrivSoftkeyLocationRight;
	            }
			}
		else
			{
			screenMode.iSoftkeyLocation = EAknPrivSoftkeyLocationBottom;
			}
    	screenMode.iDisplayMode = dev->GetScreenModeDisplayMode(ii);
		aScreenInfoArray.AppendL(screenMode);
		}
	CleanupStack::Pop(&aScreenInfoArray);
	}

//
// CAknLayoutConfigWsiniParser
//
#define WSINI_PARSE_ENTRY(keyword, func) { _S(keyword), sizeof(keyword)-1, &CAknLayoutConfigWsiniParser::Call##func }
const CAknLayoutConfigWsiniParser::SParseEntry CAknLayoutConfigWsiniParser::iParseTable[] = 
	{
	WSINI_PARSE_ENTRY("S60_HWSTATE_KEYCODE", HardwareStateKeycodeL),		//S60_HWSTATE_KEYCODEn <KeyCode>
	WSINI_PARSE_ENTRY("S60_HWSTATE_SCREENMODE", HardwareStateScreenModeL),		//S60_HWSTATE_SCREENMODEn <ScreenModeNumber>
	WSINI_PARSE_ENTRY("S60_HWSTATE_ALT_SCREENMODE", HardwareStateAltScreenModeL),		//S60_HWSTATE_ALT_SCREENMODEn <ScreenModeNumber>
	WSINI_PARSE_ENTRY("S60_SCR_SOFTKEY_LOCATION", ScreenModeSoftkeyLocationL),		//S60_SCR_SOFTKEY_LOCATIONn <Location>
	WSINI_PARSE_ENTRY("S60_SCR_STYLE_NAME", ScreenModeStyleNameL),		//S60_SCR_STYLE_NAMEn <ScreenStyleName>
	};

void CAknLayoutConfigWsiniParser::GetConfigL(SAknLayoutConfig& aConfig, 
											 RArray<SAknScreenModeInfo>& aScreenInfoArray, 
											 RArray<SHardwareStateInfo>& aHardwareStateArray)
	{
	CAknLayoutConfigWsiniParser* self = new(ELeave) CAknLayoutConfigWsiniParser(aConfig, aScreenInfoArray, aHardwareStateArray);
	CleanupStack::PushL(self);
	self->GetConfigL();
	CleanupStack::PopAndDestroy();
	}

CAknLayoutConfigWsiniParser::CAknLayoutConfigWsiniParser(SAknLayoutConfig& aConfig, 
														 RArray<SAknScreenModeInfo>& aScreenInfoArray, 
														 RArray<SHardwareStateInfo>& aHardwareStateArray)
: iConfig(aConfig), iScreenInfoArray(aScreenInfoArray), iHardwareStateArray(aHardwareStateArray)	
	{
	}
	
CAknLayoutConfigWsiniParser::~CAknLayoutConfigWsiniParser()
	{
	}
	
void CAknLayoutConfigWsiniParser::GetConfigL()
	{
	HBufC* wsini = GetWsiniLC();
	ParseWsiniL(*wsini);
	CleanupStack::PopAndDestroy(wsini);
	}

void CAknLayoutConfigWsiniParser::HardwareStateKeycodeL(TPtrC& aLine)
	{
	//S60_HWSTATE_KEYCODEn <KeyCode>
	TInt stateNumber = ParseIntL(aLine);
	TInt keyCode = ParseKeycodeL(aLine);
	HardwareStateL(stateNumber).iKeyCode = keyCode;
	}

void CAknLayoutConfigWsiniParser::HardwareStateScreenModeL(TPtrC& aLine)
	{
	//S60_HWSTATE_SCREENMODEn <ScreenModeNumber>
	TInt stateNumber = ParseIntL(aLine);
	TInt modeNumber = ParseIntL(aLine) - 1;		// -1 to translate between wsini & CWsScreenDevice mode numbers
	HardwareStateL(stateNumber).iScreenMode = modeNumber;
	}

void CAknLayoutConfigWsiniParser::HardwareStateAltScreenModeL(TPtrC& aLine)
	{
	//S60_HWSTATE_ALT_SCREENMODEn <ScreenModeNumber>
	TInt stateNumber = ParseIntL(aLine);
	TInt modeNumber = ParseIntL(aLine) - 1;		// -1 to translate between wsini & CWsScreenDevice mode numbers
	HardwareStateL(stateNumber).iAltScreenMode = modeNumber;
	}

void CAknLayoutConfigWsiniParser::ScreenModeSoftkeyLocationL(TPtrC& aLine)
	{
	//S60_SCR_SOFTKEY_LOCATIONn <Location>
	TInt modeNumber = ParseIntL(aLine) - 1;		// -1 to translate between wsini & CWsScreenDevice mode numbers
	TAknPrivSoftkeyLocation location = ParseSoftkeyLocationL(aLine);
	ScreenModeL(modeNumber).iSoftkeyLocation = location;
	}

void CAknLayoutConfigWsiniParser::ScreenModeStyleNameL(TPtrC& aLine)
	{
	//S60_SCR_STYLE_NAMEn <ScreenStyleName>
	TInt modeNumber = ParseIntL(aLine) - 1;		// -1 to translate between wsini & CWsScreenDevice mode numbers
	TInt hash = ScreenStyleHash(aLine);
	ScreenModeL(modeNumber).iScreenStyleHash = hash;
	}

HBufC* CAknLayoutConfigWsiniParser::GetWsiniLC()
	{
	RFs& fs = CEikonEnv::Static()->FsSession();
	_LIT(KWsini, "z:\\system\\data\\wsini.ini");
	TEntry wsiniEntry;
	User::LeaveIfError(fs.Entry(KWsini, wsiniEntry));
	
	HBufC* wsiniText = HBufC::NewLC((wsiniEntry.iSize+1)/2);	// +1 /2 to round up and convert file size to UTF-16 character size
	TPtr wsiniPtr = wsiniText->Des();
	TPtr8 wsiniPtr8((TText8*)wsiniPtr.Ptr(), 0, wsiniPtr.MaxLength()*2);

	RFile wsiniFile;
	User::LeaveIfError(wsiniFile.Open(fs, KWsini, EFileRead | EFileShareReadersOnly));
	CleanupClosePushL(wsiniFile);
	
	User::LeaveIfError(wsiniFile.Read(wsiniPtr8, wsiniEntry.iSize));
	wsiniPtr.SetLength(wsiniPtr8.Length()/2);
	
	CleanupStack::PopAndDestroy(&wsiniFile);
	
	return wsiniText;
	}

inline TBool IsDigit(TText aChar)
	{
	return ('0' <= aChar && aChar <= '9');
	}
	
inline TBool IsKeywordChar(TText aChar)
	{
	return ('A' <= aChar && aChar <= 'Z') ||
		   IsDigit(aChar) ||
		   aChar == '_';
	}

inline TBool IsEndOfLine(TText aChar)
	{
	return aChar == '\r' || aChar == '\n';
	}
	
void CAknLayoutConfigWsiniParser::ParseWsiniL(const TDesC& aWsini)
	{
	if (!aWsini.Length())
		return;
	
	const TText* pChar = aWsini.Ptr();
	const TText* end = pChar + aWsini.Length();
	if (*pChar == 0xFEFF || *pChar == 0xFFFE)
		pChar++; 	// Skip, but otherwise ignore, the UTF-16 byte ordering marker (this is how it works in wserv)

	while (pChar != end)
		{
		// mark start of line
		const TText* kwStart = pChar;
		
		// find end of keyword (including digits)
		while (pChar != end && IsKeywordChar(*pChar))
			++pChar;

		// mark end of keyword (including digits)
		const TText* kwEnd = pChar;
		
		// count back to remove digits
		while (kwEnd != kwStart && IsDigit(*(kwEnd-1)))
			--kwEnd;
		
		// find end of line
		while (pChar != end && !IsEndOfLine(*pChar))
			++pChar;
		
		// parse the line
		ParseLineL(kwStart, kwEnd, pChar);

		// find start of next line
		while (pChar != end && IsEndOfLine(*pChar))
			++pChar;
		}
	}

void CAknLayoutConfigWsiniParser::ParseLineL(const TText* aKwStart, const TText* aKwEnd, const TText* aLineEnd)
	{
	if (aKwEnd == aKwStart)
		return;
	
	TPtrC kw(aKwStart, aKwEnd-aKwStart);
	TPtrC rest(aKwEnd, aLineEnd-aKwEnd);
	
	TInt targetCount = sizeof(iParseTable)/sizeof(SParseEntry);
	for (TInt ii=0; ii<targetCount; ii++)
		{
		const SParseEntry& parseEntry = iParseTable[ii];
		TPtrC header(parseEntry.iKeyword, parseEntry.iKeywordLen);
		if (kw == header)
			{
			(*parseEntry.iFunc)(this, rest);
			break;
			}
		}
	}

SHardwareStateInfo& CAknLayoutConfigWsiniParser::HardwareStateL(TInt aStateNumber)
	{
	TInt count = iHardwareStateArray.Count();
	for (TInt ii=0; ii<count; ii++)
		{
		if (iHardwareStateArray[ii].iStateNum == aStateNumber)
			return iHardwareStateArray[ii];
		}
		
	// not found, create a new one
	SHardwareStateInfo newInfo = { aStateNumber, 0, 0, 0 };
	iHardwareStateArray.AppendL(newInfo);
	return iHardwareStateArray[count];
	}

SAknScreenModeInfo& CAknLayoutConfigWsiniParser::ScreenModeL(TInt aModeNumber)
	{
	TInt count = iScreenInfoArray.Count();
	for (TInt ii=0; ii<count; ii++)
		{
		if (iScreenInfoArray[ii].iModeNumber == aModeNumber)
			return iScreenInfoArray[ii];
		}
	
	// we failed to find the screen mode.
	User::Leave(KErrNotFound);
	return iScreenInfoArray[0];	// dummy return, will never get here.
	}

TInt CAknLayoutConfigWsiniParser::ParseIntL(TPtrC& aLine)
	{
	TLex lex(aLine);
	lex.SkipSpace();
	TInt num;
	User::LeaveIfError(lex.Val(num));
	aLine.Set(lex.Remainder());
	return num;
	}

struct SKeyTranslation
    {
    const TDesC* iName;
    TInt iBase;
    TInt iRangeStart;
    TInt iRangeEnd;
    };

_LIT(KKeyNameApp, "EKeyApplication");
_LIT(KKeyNameDev, "EKeyDevice");

const SKeyTranslation KKeyTranslationTable[] =
    {
        {
        LIT_AS_DESC_PTR(KKeyNameApp),
        EKeyApplication0,
        0x0,
        0xf
        },
        {
        LIT_AS_DESC_PTR(KKeyNameDev),
        EKeyDevice0,
        0x0,
        0xf
        },
        {
        LIT_AS_DESC_PTR(KKeyNameApp),
        EKeyApplication10,
        0x10,
        0x1f
        },
        {
        LIT_AS_DESC_PTR(KKeyNameDev),
        EKeyDevice10,
        0x10,
        0x1f
        }
    };

TInt CAknLayoutConfigWsiniParser::ParseKeycodeL(TPtrC& aLine)
	{
	TLex lex(aLine);
	lex.SkipSpace();
	aLine.Set(lex.Remainder());
	
	TUint key;
    // look in the translation table for a KeyNameXX match
	TInt count = sizeof(KKeyTranslationTable)/sizeof(SKeyTranslation);
	for (TInt ii = 0; ii < count; ii++)
	    {
	    const SKeyTranslation& trans = KKeyTranslationTable[ii];
	    const TDesC& name = *trans.iName;
	    TInt len = name.Length();
	    if (aLine.Length() > len && aLine.Left(len) == name)
	        {
	        lex.Assign(aLine.Mid(len));
    	    if (lex.Val(key, EHex) == KErrNone && trans.iRangeStart <= key && key <= trans.iRangeEnd)
    	        {
            	aLine.Set(lex.Remainder());
    	        return trans.iBase + key - trans.iRangeStart;
    	        }
	        }
	    }
	
	if (aLine.Length())
		{
		// use the character
		key = aLine[0];
		aLine.Set(aLine.Mid(1));
		return key;
		}

	User::Leave(KErrCorrupt);
	return 0;
	}

TAknPrivSoftkeyLocation CAknLayoutConfigWsiniParser::ParseSoftkeyLocationL(TPtrC& aLine)
	{
	TAknPrivSoftkeyLocation location = EAknPrivSoftkeyLocationBottom;
	TLex lex(aLine);
	lex.SkipSpace();
	TPtrC token = lex.NextToken();
	if (token == _L("right"))
		location = EAknPrivSoftkeyLocationRight;
	else if (token == _L("left"))
		location = EAknPrivSoftkeyLocationLeft;
	aLine.Set(lex.Remainder());
	return location;
	}

TInt CAknLayoutConfigWsiniParser::ScreenStyleHash(TPtrC& aLine)
	{
	TInt hash = 0;
	TLex lex(aLine);
	TPtrC name = lex.NextToken();
	const TText* pChar = name.Ptr();
	const TText* end = pChar + name.Length();
	
	// calculate the hash
	for (; pChar != end; ++pChar)
		{
		hash *= KAknLayoutScreenStyleNameHashMult;
		hash += *pChar;
		}

	return hash;
	}
