// EIKTELED.CPP
//
// Copyright (c) 1997-1999 Symbian Ltd.  All rights reserved.
//

#include <barsread.h>
#include <baclipb.h>
#include <eikenv.h>
#include <eikteled.h>
#include <eikon.rsg>

EXPORT_C CEikTelephoneNumberEditor::CEikTelephoneNumberEditor()
	{
	__DECLARE_NAME(_S("CEikTelephoneNumberEditor"));
	}

EXPORT_C CEikTelephoneNumberEditor::~CEikTelephoneNumberEditor()
	{
	iRws.Close();
	}

EXPORT_C void CEikTelephoneNumberEditor::ConstructL(TTelephoneEditorMode aMode, TInt aFlags, TPtrC* aPromptArray, TInt aWidth)
//
// Manual construct
//
	{
	User::LeaveIfError(iRws.Connect());
	iFlags = aFlags;
	iPrompts[0] = aPromptArray[0];
	iPrompts[1] = aPromptArray[1];
	iPrompts[2] = aPromptArray[2];
	CEikEdwin::ConstructL(EWidthInPixels,aWidth,32,1);
	// Set a blank telephone number
	BlankNumberL();
	SetModeL(aMode);

#if defined(_DEBUG) // Test code
#define TESTSET(S, T) SetNumberL(_L(S)); GetNumber(res); if (res != _L(T)) User::Invariant();
	TBuf<32> res;
	TWorldId old;
	iRws.DefaultCountry(old);
	TWorldId acntry;
	iRws.FindCountry(acntry,_L("United Kingdom"));
	iRws.SetDefaultCountry(acntry);
	TESTSET("123","123");
	TESTSET("1231234","1231234");
	TESTSET("123 1234","1231234");
	TESTSET("0171 1231234","+44 171 1231234");
	TESTSET("(0171) 1231234","+44 171 1231234");
	TESTSET("0171 123-1234","+44 171 1231234");
	TESTSET("44 171 1231234","+44 171 1231234");
	TESTSET("0044 171 1231234","+44 171 1231234");
	TESTSET("0044 171 123 1234","+44 171 1231234");
	TESTSET("49 71 12341234","+49 71 12341234");
	TESTSET("0049 71 12341234","+49 71 12341234");
	TESTSET("0049 71 1234 1234","+49 71 12341234");
	TESTSET("0049 (0) 71 1234 1234","+49 71 12341234");
	TESTSET("00 49 (0) 71 1234 1234","+49 71 12341234");
	TESTSET("Some text 44 171 1231234","+44 171 1231234");
	TESTSET("My number: +44 (0)171 123-1234","+44 171 1231234");
	TESTSET("[USA] 800 12800800 ","+1 800 12800800");
	TESTSET("+1 800 12800800 ","+1 800 12800800");
	TESTSET("Mobile tel. +358-50-553 4732 ","+358 50 5534732");
	TESTSET("Mobile tel. +358-(0)10-505 6800","+358 10 5056800");
	TESTSET("Tel: +81(0)3-3378-5933","+81 3 33785933");
	TESTSET("Tel: +81(0)3-3378-5933","+81 3 33785933");
	TESTSET("[Japan] 0427 96 5721 ","+81 427 965721");
	TESTSET("[Singapore] 1231234 ","+65 1231234");
	iRws.FindCountry(acntry,_L("USA"));
	iRws.SetDefaultCountry(acntry);
	TESTSET("123","123");
	TESTSET("1231234","1231234");
	TESTSET("123 1234","1231234");
	TESTSET("0171 1231234","+1 0171 1231234");
	TESTSET("(0171) 1231234","+1 0171 1231234");
	TESTSET("0171 123-1234","+1 0171 1231234");
	TESTSET("44 171 1231234","+44 171 1231234");
	TESTSET("01144 171 1231234","+44 171 1231234");
	TESTSET("01144 171 123 1234","+44 171 1231234");
	TESTSET("011 44 171 123 1234","+44 171 1231234");
	TESTSET("49 71 12341234","+49 71 12341234");
	TESTSET("01149 71 12341234","+49 71 12341234");
	TESTSET("01149 71 1234 1234","+49 71 12341234");
	TESTSET("01149 71 1234 1234","+49 71 12341234");
	TESTSET("011 49 71 1234 1234","+49 71 12341234");
	TESTSET("Some text 44 171 1231234","+44 171 1231234");
	TESTSET("My number: +44 (0)171 123-1234","+44 171 1231234");
	TESTSET("[USA] 800 12800800 ","+1 800 12800800");
	TESTSET("+1 800 12800800 ","+1 800 12800800");
	TESTSET("Mobile tel. +358-50-553 4732 ","+358 50 5534732");
	TESTSET("Mobile tel. +358-(0)10-505 6800","+358 10 5056800");
	TESTSET("Tel: +81(0)3-3378-5933","+81 3 33785933");
	TESTSET("Tel: +81(0)3-3378-5933","+81 3 33785933");
	TESTSET("[Japan] 0427 96 5721 ","+81 427 965721");
	TESTSET("[Singapore] 1231234 ","+65 1231234");
	iRws.SetDefaultCountry(old);
//	SetModeL(EFreeFormat);
	BlankNumberL();
#endif
	}

EXPORT_C void CEikTelephoneNumberEditor::ClipboardL(TClipboardFunc aClipboardFunc)
	{
	switch (aClipboardFunc)
		{	
	case ECut:
	case ECopy:
		if (iMode == ECoerceFormat)
			{
			if ((iNumlen[ECountry]==0)&&(iNumlen[EArea]==0)&&(iNumlen[ENumber]==0))
				{
				iEikonEnv->InfoMsg(R_EIK_TBUF_NOTHING_TO_COPY);
				return;
				}
			}
		else if (TextLength() == 0)
			{
			iEikonEnv->InfoMsg(R_EIK_TBUF_NOTHING_TO_COPY);
			return;
			}
		{
		CClipboard* cb=CClipboard::NewForWritingLC(iCoeEnv->FsSession());
		TBuf<32> origContents, dialNumber;
		CEikEdwin::GetText(origContents);
		GetNumber(dialNumber);
		SetTextL(&dialNumber);
		iText->CopyToStoreL(cb->Store(), cb->StreamDictionary(),0,TextLength());
		cb->CommitL();
		SetTextL(&origContents);
		CleanupStack::PopAndDestroy();
		}
		if (aClipboardFunc == ECut)
			BlankNumberL();
		else
			iEikonEnv->InfoMsg(R_EIK_TBUF_COPIED);
		return;
	case EPaste:
		CheckNotReadOnlyL();
		SetSelectionL(TextLength(),0);
		{
		CClipboard* cb=NULL;
		TRAPD(err,cb=CClipboard::NewForReadingL(iCoeEnv->FsSession()));
		CleanupStack::PushL(cb);
		if (err==KErrPathNotFound || err==KErrNotFound)
			iEikonEnv->LeaveWithInfoMsg(R_EIK_TBUF_NOTHING_TO_PASTE);
		User::LeaveIfError(err);
		PasteFromStoreL(cb->Store(), cb->StreamDictionary());
		CleanupStack::PopAndDestroy();	// cb
		}
		{
		TBuf<32> tmpbuf;
		CEikEdwin::GetText(tmpbuf);
		SetNumberL(tmpbuf);
		}
		ReportEventL(MCoeControlObserver::EEventStateChanged);
		return;
	default:
		return;
		}
	}

EXPORT_C void CEikTelephoneNumberEditor::FocusChanged(TDrawNow aDrawNow)
	{
	if (iMode == ECoerceFormat)
		{
		if (iNumlen[0]==0)
			SelectPartL(ECountry,EEnd);
		else if (iNumlen[1]==0)
			SelectPartL(EArea,EEnd);
		else
			SelectPartL(ENumber,EEnd);
		}
	CEikEdwin::FocusChanged(aDrawNow);
	}

EXPORT_C TKeyResponse CEikTelephoneNumberEditor::OfferKeyEventL(const TKeyEvent& aKeyEvent,TEventCode aType)
	{ 
	TKeyResponse ret = EKeyWasConsumed;

	if (aType!=EEventKey)
		return EKeyWasNotConsumed;
	TInt code=aKeyEvent.iCode;
	TInt cursorPos=CursorPos();

	// Update current part pointer
	TPositionInPart pos;
	TInt beg,end,len;
	TPart part = ECountry;
	
	if (iMode == ECoerceFormat)
		part = CheckPart(pos,beg,end,len);

	const TInt modifiers=aKeyEvent.iModifiers;
	TBool select=modifiers&EModifierShift;
	TBool magnify=modifiers&EModifierCtrl;
	if (magnify && code<100 && code!=' ')//!!! magic number
		{
		TBuf<24> buf;
		if (select)
			iCoeEnv->ReadResource(buf,R_EIK_EDWIN_SHIFT_CTRL_HOTKEYS);
		else
			iCoeEnv->ReadResource(buf,R_EIK_EDWIN_CTRL_HOTKEYS);
		const TInt loc=buf.Locate(TChar(code+'a'-1));
		switch (loc)
			{
		case EHotKeyCut:
			ClipboardL(ECut);
			break;
		case EHotKeyCopy:
			ClipboardL(ECopy);
			break;
		case EHotKeyPaste:
			ClipboardL(EPaste);
			break;
		default:
			break;
			}
		return ret;
		}

	switch (code)
		{
	case EKeyDelete:
	case EKeyBackspace:
		// FIXES SW1-495 BUT presumes that Shift-Backspace = Delete 
		if (select)
			code = EKeyDelete;

		if (iMode == ECoerceFormat)
			{
			// Shift back if at start of field
			if ((code==EKeyBackspace)&&((pos==EStart)||(len==0)))
				{
				if (part != ECountry)
					SelectPartL(TPart(part-1),EEnd);
				return ret;
				}
			// Shift forward if at end of field
			if ((code==EKeyDelete)&&(pos==EEnd))
				{
				if (part != ENumber)
					SelectPartL(TPart(part+1),EStart);
				return ret;
				}
			}
		else if ( ((code == EKeyBackspace)&&(cursorPos == 0)) ||
			      ((code == EKeyDelete   )&&(cursorPos == TextLength())) )
			return ret;
		// Else do a delete as normal
		DeleteCharL(cursorPos,code);
		break;
	case EKeyLeftArrow:
		if (iMode == ECoerceFormat)
			{
			if ((part==ECountry)&&((pos==EStart)||(len==0))) // Can't move cursor onto + sign
				;
			else if ((len==0)||(pos==EStart))
				SelectPartL(TPart(part-1),EEnd);
			else
				MoveCursorL(TCursorPosition::EFLeft,EFalse);
			}
		else
			MoveCursorL(TCursorPosition::EFLeft,EFalse);
		return ret;
	case EKeyRightArrow:
		if (iMode == ECoerceFormat)
			{
			if ((part==ENumber)&&((pos==EEnd)||(len==0)))
				;
			else if ((len==0)||(pos==EEnd))
				SelectPartL(TPart(part+1),EStart);
			else
				MoveCursorL(TCursorPosition::EFRight,EFalse);
			}
		else
			MoveCursorL(TCursorPosition::EFRight,EFalse);			
		return ret;
	case '-': 
	case EKeySpace:
		// Skip onto next field if not last field
		if (iMode == ECoerceFormat)
			{
			if (part != ENumber)
				SelectPartL(TPart(part+1),EStart);
			else if ((part == ENumber)&&(code == EKeySpace))
				goto insert;		
			}
		else if (code == EKeySpace)
			goto insert;
		return ret;
	case EKeyEscape:
	case EKeyPageUp:
	case EKeyPageDown:
	case EKeyUpArrow:
	case EKeyDownArrow:
		return EKeyWasNotConsumed;
	case EKeyHome:
		if (iMode == ECoerceFormat)
			SelectPartL(ECountry,EStart);
		else
			SetCursorPosL(0,EFalse);
		return ret;
	case EKeyEnd:
		if (iMode == ECoerceFormat)
			SelectPartL(ENumber,EEnd);
		else
			SetCursorPosL(TextLength(),EFalse);
		return ret;
	case ',':
	case '#':
	case '*':
	case 'p':
	case 'P':
	case 'w':
	case 'W':
	case 't':
	case 'T':
		if (iMode == ECoerceFormat)
			return ret;
	case '0':
	case '1':
	case '2':
	case '3':
	case '4':
	case '5':
	case '6':
	case '7':
	case '8':
	case '9':
		{
insert:
		if (iMode == ECoerceFormat)
			{
			if (((part == ECountry)&&(len >= 4))||((part == EArea)&&(len >= 8)))
				{ // Country or area part is full
				if (pos == EEnd)
					SelectPartL(TPart(part+1),EStart);
				else // Overwrite next char
					DeleteCharL(cursorPos,EKeyDelete);
				}
			else if ((part == ENumber)&&(len >= 12))
				{
				if (pos == EEnd)
					{
					CEikonEnv::Beep();
					iEikonEnv->InfoMsg(R_EIK_TBUF_MAX_CHARACTERS_REACHED);
					return ret;
					}
				else // Overwrite next char
					DeleteCharL(cursorPos,EKeyDelete);
				}
			}
		else if (TextLength() >= 32)
			{
			CEikonEnv::Beep();
			iEikonEnv->InfoMsg(R_EIK_TBUF_MAX_CHARACTERS_REACHED);
			return ret;
			}
		TInt cursorPos=CursorPos();
		TChar ch(code);
		InsertCharL(cursorPos,ch);
		}
		break;
	default: // Do nothing - default
		return ret;
		}
	ReportEventL(MCoeControlObserver::EEventStateChanged);
	return ret;
	}

EXPORT_C void CEikTelephoneNumberEditor::HandlePointerEventL(const TPointerEvent& aPointerEvent)
	{
	const TPoint pointerPos=aPointerEvent.iPosition;
	TPoint origPos=pointerPos;
	TInt newCursorPos=iTextView->XyPosToDocPosL(origPos);
	if (iMode == ECoerceFormat)
		{
		if (newCursorPos == 0)
			newCursorPos = 1; // Disallow cursor before '+'
		SetCursorPosL(newCursorPos,EFalse);
		TPart part;
		TPositionInPart pos;
		TInt beg,end,len;
		part = CheckPart(pos,beg,end,len);
		SelectPartL(part,pos);
		}
	else
		SetCursorPosL(newCursorPos,EFalse);
	}

EXPORT_C void CEikTelephoneNumberEditor::ConstructFromResourceL(TResourceReader& aReader)
//
// Automatic construct from a resource
//
	{
	TTelephoneEditorMode mode = (TTelephoneEditorMode)aReader.ReadUint16();
	TInt flags = aReader.ReadUint16();
	TBuf<20> prompts[3];
	TPtrC pptrs[3];
	pptrs[0].Set(prompts[0] = aReader.ReadTPtrC());
	pptrs[1].Set(prompts[1] = aReader.ReadTPtrC());
	pptrs[2].Set(prompts[2] = aReader.ReadTPtrC());
	TInt wid = aReader.ReadInt16();
	ConstructL(mode,flags,pptrs,wid);
	}

EXPORT_C void CEikTelephoneNumberEditor::SetModeL(TTelephoneEditorMode aMode)
// Actual set mode function
	{
	TBuf<128> num;
	num.Zero();
	GetNumber(num);
	iMode = aMode;
	SetNumberL(num);
	}

enum TNumParseState
	{
	EStateSpace=0,
	EStatePart=1,
	EStateCountry=2
	};

EXPORT_C void CEikTelephoneNumberEditor::SetNumberL(const TDesC& aNumber)
//
// Parse the provided number, filling in any blanks and removing
// obselete bits, and set the control
//
	{
	if (iMode == ECoerceFormat)
		{
		TBuf<32> country, area, number;
		ParseToParts(aNumber, country, area, number);
		SetNumberL(country, area, number);
		SelectPartL(ECountry,EEnd);
		}	
	else
		{
		TBuf<64> num; // Should be enough for whole number
		TInt pos,len;
		pos =0;
		TChar ch;
		num.Zero();
		len = aNumber.Length();
		while (pos < len)
			{
			TInt ich = aNumber[pos];
			ch = ich;
			ch.Fold();
			TInt fch = ch;
			if (ch.IsDigit() || ch.IsSpace() || 
				fch == ',' || fch == '*' || fch == '#'
				|| fch == 'P' || fch == 'W' || fch == 'T')	
				{
				num.Append(aNumber[pos]);
				}
			pos++;
			if (pos>32)
				break;
			}
		SetTextL(&num);
		SetCursorPosL(0,EFalse);
		DrawNow();
		}
	}

EXPORT_C void CEikTelephoneNumberEditor::SetNumberL(const TDesC& aCountry, const TDesC& aArea, const TDesC& aNumber)
//
// Build number up from three components
// 
	{
	TBuf<128> num; // Should be enough for whole number
	__ASSERT_DEBUG(aCountry.Length()+aArea.Length()+aNumber.Length()+3 < 128, User::Invariant());

	num = _S("+");
	num.Append(NumberOrBlank(ECountry,aCountry));
	num.Append(_L(" "));
	num.Append(NumberOrBlank(EArea,aArea));
	num.Append(_L(" "));
	num.Append(NumberOrBlank(ENumber,aNumber));
	iNumlen[0] = aCountry.Length();
	iNumlen[1] = aArea.Length();
	iNumlen[2] = aNumber.Length();
	iNumPos[0] = 1; // Always
	iNumPos[1] = 2 + (iNumlen[0] ? iNumlen[0] : iBlnkResLen[0]);
	iNumPos[2] = iNumPos[1] + 1 + (iNumlen[1] ? iNumlen[1] : iBlnkResLen[1]);
	// Set the edwin
	SetTextL(&num);
	// Set focus
	if (iNumlen[0] == 0)
		SelectPartL(ECountry,EEnd);
	else if (iNumlen[1] == 0)
		SelectPartL(EArea,EEnd);
	else 
		SelectPartL(ENumber,EEnd);
	DrawNow();
	}

EXPORT_C void CEikTelephoneNumberEditor::GetNumber(TDes& aNumber) const
// Actual get number function
	{
	if (iMode!=ECoerceFormat)
		CEikEdwin::GetText(aNumber);
	else
		{
		TBuf<64> number;
		TBuf<32> country, area, local;
		GetText(number);
		ParseToParts(number, country, area, local);	
		aNumber.Zero(); // Blank it for starters
		if (country.Length())
			{
			aNumber.Append(_L("+"));
			aNumber.Append(country);
			aNumber.Append(_L(" "));
			}
		if (area.Length())
			{
			aNumber.Append(area);
			aNumber.Append(_L(" "));
			}
		if (local.Length())
			aNumber.Append(local);
		}
	}

EXPORT_C void CEikTelephoneNumberEditor::BlankNumberL()
// Blank the number
	{
	TPtrC blank;
	if (iMode == ECoerceFormat)
		{
		SetNumberL(blank,blank,blank);
		SelectPartL(ECountry,EEnd);
		}
	else
		SetNumberL(blank);
	}

// Helper functions

TPtrC CEikTelephoneNumberEditor::NumberOrBlank(TPart aPart, const TDesC& aNumber)
// 
// 
//
	{
	TPtrC ret(aNumber);
	if (ret.Length() == 0)
		{ // Append resource (hardcoded for now)
		switch (aPart)
			{
		case ECountry:
			ret.Set(iPrompts[ECountry]);
			break;
		case EArea:
			ret.Set(iPrompts[EArea]);
			break;
		case ENumber:
			ret.Set(iPrompts[ENumber]);
			break;
			}
		}
	iBlnkResLen[aPart] = ret.Length();
	return ret;
	}

void CEikTelephoneNumberEditor::SelectPartL(TPart aPart, TPositionInPart aPos)
	{
	TInt len = iNumlen[aPart];
	TInt beg = iNumPos[aPart];
	SetCursorVisibilityL(len&&IsFocused()); // Hidden if blank
	if (len)
		{ // Position cursor - no selection
		if (aPos == EEnd)
			SetCursorPosL(beg+len,EFalse);
		else if (aPos == EStart)
			SetCursorPosL(beg,EFalse);
		// Middle - don't do anything
		}
	else
		{
		SetCursorPosL(beg,EFalse);
		SetSelectionL(beg+iBlnkResLen[aPart],beg);
		}
	}

CEikTelephoneNumberEditor::TPart CEikTelephoneNumberEditor::CheckPart(TPositionInPart& aPos, TInt& aBeg, TInt& aEnd, TInt& aLen) const
//
// Work out current part
//
	{
	TInt cp=CursorPos();
	TInt part=0;
	aPos = EStart;
	TInt beg,end,len;
	
	__ASSERT_DEBUG(cp != 0,User::Invariant()); // Bug - this not allowed

	for (part=0;part<=2;part++)
		{
		len = iNumlen[part];
		beg = iNumPos[part];
		end = beg+(len?len:iBlnkResLen[part]);
		
		if (cp == beg)
			{
			break;
			}
		else if (cp == end)			
			{
			aPos = EEnd;
			break;
			}
		else if ((cp > beg)&&(cp <end))
			{
			aPos = EMiddle;
			break;
			}
		}
	aLen = len;
	aBeg = beg;
	aEnd = end;
	return (TPart)part;
	}

void CEikTelephoneNumberEditor::SetCursorVisibilityL(TBool aEmphasis)
	{
	const TCursor::TVisibility textCursor=(aEmphasis? TCursor::EFCursorFlashing : TCursor::EFCursorInvisible);
	const TCursor::TVisibility lineCursor=TCursor::EFCursorInvisible;
	if (iTextView)
		iTextView->SetCursorVisibilityL(lineCursor,textCursor);
	}


void CEikTelephoneNumberEditor::InsertTextL(TInt aPos, const TDesC& aText)
	{
	TRAPD(err,iText->InsertL(aPos,aText));
	TCursorSelection sel(aPos,aPos+aText.Length());
	iTextView->HandleInsertDeleteL(sel,0);
	}

void CEikTelephoneNumberEditor::DeleteCharL(TInt aPos, TInt aCode)
	{
	// Do the delete
	TInt charEditType=CTextLayout::EFRightDelete;
	if	(aCode==EKeyBackspace)
		{
		charEditType = CTextLayout::EFLeftDelete;
		aPos--;
		}
	TCursorSelection sel(aPos,aPos);
	TBool change=EFalse;
	DeleteL(change,sel,aCode==EKeyBackspace,EFalse);
	iTextView->HandleCharEditL(charEditType,EFalse);
	// Update the lengths of the current part
	if (iMode == ECoerceFormat)
		{
		TPositionInPart pos;
		TInt beg,end,len;
		TPart part = CheckPart(pos,beg,end,len);
		TInt delta,off;
		if ((--len) == 0)
			{ // The delete has blanked this field
			TPtrC text(NumberOrBlank(part,_L("")));
			InsertTextL(aPos,text);
			delta = -1;
			off = iBlnkResLen[part] + delta;
			}
		else
			{ // Simple delete
			off = delta = -1;
			}
		ChangePartLenL(part, delta, off);
		SelectPartL(part,pos);
		}
	}

void CEikTelephoneNumberEditor::ChangePartLenL(TPart aPart, TInt aDelta, TInt aOff)
//
// Change length of this part (shuffles subsequent)
//
	{
	iNumlen[aPart]+=aDelta;
	for (TInt p=aPart+1;p<=ENumber;p++)
		iNumPos[p]+=aOff;
	}

void CEikTelephoneNumberEditor::InsertCharL(TInt aPos, TChar aChar)
	{
	TPositionInPart pos;
	TInt beg,end,len;
	TPart part=ECountry;
	TInt delta(0),off(0);
	if (iMode == ECoerceFormat)
		{
		// Update the lengths of the current part
		part = CheckPart(pos,beg,end,len);
		if ((len) == 0)
			{ // The delete will unblank this field - delete the blank text
			TCursorSelection sel(beg,end);
			TBool change=EFalse;
			DeleteL(change,sel,EFalse,EFalse);
			iTextView->HandleInsertDeleteL(sel,end-beg,EFalse);
			delta = +1;
			off = -iBlnkResLen[part] + delta;
			aPos = beg;
			CancelSelectionL(TEnd(EStart));
			SetCursorVisibilityL(ETrue);
			}
		else
			{ // Simple insert
			off = delta = 1;
			}
		}
	// Do the insert
	iText->InsertL(aPos,aChar);
	iTextView->HandleCharEditL(CTextLayout::EFCharacterInsert);
	if (iMode == ECoerceFormat)
		ChangePartLenL(part, delta, off);
	}

void CEikTelephoneNumberEditor::ParseToParts(const TDesC& aNumber, TDes& aCountry, TDes& aArea, TDes& aLocal) const
	{
	TPtrC parts[6];
	TPtrC givencountry(_L(""));
	TInt numparts=0;
	TInt len(aNumber.Length()), index(0), mark(0);	
	TNumParseState state = EStateSpace;
	TBool hasplus = EFalse;
	TBool hasbrackets = EFalse;

	// Parse into seperate numerical parts
	while (index<len)
		{
		switch (aNumber[index])
			{
		case '(': // Has brackets
			hasbrackets = ETrue;
			goto space;
		case '[': // Special case - might be a country name until next ']'
			{
			TInt pos = aNumber.Mid(index).Locate(TChar(']'));
			if (pos != KErrNotFound)
				{
				givencountry.Set(aNumber.Mid(index+1,pos-1));
				index += pos + 1;
				}
			// else ignore - can't parse
			}
			break;
			goto space;
		case '+':
			hasplus = ETrue;
			goto space;
		case '0': // Either, it's a a number...
		case '1': 
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9':
			switch (state)
				{
			case EStateSpace:
				state = EStatePart;
				mark = index;
				break;
			case EStatePart:
			case EStateCountry:
				break;
				}
			break;
		default: // or it isn't...
space:
			switch (state)
				{
			case EStateSpace:
				break;
			case EStatePart:
				state = EStateSpace;
				parts[numparts++].Set(aNumber.Mid(mark,index-mark));
				break;
			case EStateCountry:
				break;
				}
			break;
			}
		index++;
		if (numparts == 6)
			break; // Break out of while loop - we can't cope with any more parts
		}
	if (state == EStatePart)
		{ // Terminate last part if necessary
		parts[numparts++].Set(aNumber.Mid(mark,index-mark));
		}

	TWorldId id;
	if (givencountry.Length() != 0)
		{
		if (iRws.FindCountry(id,givencountry) != KErrNone)
			{ // Couldn't find that country - use the default
			iRws.DefaultCountry(id);
			}
		}
	else
		iRws.DefaultCountry(id);
	TCountryData cd;
	iRws.CountryData(cd,id);
	aLocal = _L(""); // Blank
	aArea = aLocal;
	aCountry = aArea;
	TBuf<12> numbuf;
	TInt proc = numparts-1;
	TBool stripc(EFalse),stripa(EFalse);

	// e.g. +44 171 1231234
	if (proc >= 0)
		{
		// Find number part
		if ((proc > 0) && (parts[proc].Length() <= 4) && (parts[proc-1].Length() <= 4))
			{ // Last part is a number - concatenate e.g. 123 1234
			numbuf = parts[proc-1];
			numbuf += parts[proc];
			aLocal = numbuf;
			proc -= 2;
			}
		else
			{ // Normal number e.g. 1231234
			aLocal = parts[proc--];
			}
		// Find area part
		if (proc >= 0)
			{
			aArea = parts[proc];
			if ((proc > 1)&&(parts[proc-1].Length()<=2)&&(hasbrackets))
				{ // Split area part e.g. (0)171 1231234
				proc -= 2;
				}
			else
				{ // Single area part - does area code need stripping? 
				proc--;
				stripa = ETrue;
				}
			// Find country code
			if (proc >= 0)
				{
				aCountry = parts[proc];
				if ((proc > 0)&&(parts[proc-1] == cd.iIntlPref))
					{ // Split country part e.g. 00 44 171 1231234
					proc -= 2;

					}
				else
					{ // Single country part 
					proc--;
					stripc = ETrue;
					}
				if (aCountry.Length()!=0)
					stripa = EFalse;
				}
			else
				{
				// else aLocal and area only - append country
				if (hasplus)
					{ // Interesting case - no country was specified but there was a plus
					  // assume this means no area code - bump area code into country code
					aCountry = aArea;
					aArea.Zero();
					}
				else
					{
					aCountry = cd.iNatCode;
					}
				}
			}
		// else number only
		if (givencountry.Length() != 0)
			{ // Possible if country with no area code
			aCountry = cd.iNatCode;
			}
		}
	// else no parts...leave blank

	// Do stripping
	if (stripc)
		{
		if (aCountry.Length() >= cd.iIntlPref.Length())
			{
			if ((aCountry.Left(cd.iIntlPref.Length()))==cd.iIntlPref)
				{ // Yes
				aCountry = aCountry.Right(aCountry.Length()-cd.iIntlPref.Length());
				stripa = EFalse; // Don't strip area code if country stripped
				}
			}
		}
	if (stripa)
		{
		if (aArea.Length() >= cd.iNatPref.Length())
			{
			if ((aArea.Left(cd.iNatPref.Length()))==cd.iNatPref)
				{
				aArea = aArea.Right(aArea.Length()-cd.iNatPref.Length());
				}
			}
		}
	}

void CEikTelephoneNumberEditor::GetText(TDes& aDes) const
	{
	CEikEdwin::GetText(aDes);
	
	// Now modify the returned text to remove any blank strings
	for (TInt part=2; part>=0; part--)
		{
		if (iNumlen[part]==0)
			aDes.Delete(iNumPos[part],iBlnkResLen[part]+(part<2?1:0));
		}
	if (iNumlen[0]==0) // no country - remove plus
		aDes.Delete(0,1);
	}
