1/*
2ADOBE SYSTEMS INCORPORATED
3 Copyright 2008 Adobe Systems Incorporated
4 All Rights Reserved.
5
6NOTICE:  Adobe permits you to use, modify, and distribute this file in accordance with the
7terms of the Adobe license agreement accompanying it.  If you have received this file from a
8source other than Adobe, then your use, modification, or distribution of it requires the prior
9written permission of Adobe.
10*/
11
12
13package com.adobe.utils
14{
15	import flash.utils.Dictionary;
16
17	internal final class LocaleId
18	{
19
20		private var lang:String = '';
21		private var script:String = '';
22		private var region:String = '';
23		private var extended_langs:Array = [];
24		private var variants:Array = [];
25		private var extensions:Object = {};
26		private var privates:Array = [];
27		private var privateLangs:Boolean = false;
28
29		public function LocaleId()
30		{
31		}
32
33
34		public static function fromString(str:String):LocaleId{
35			var localeId:LocaleId = new LocaleId();
36
37			var state:int = LocaleParserState.PRIMARY_LANGUAGE;
38			var subtags:Array = str.replace(/-/g, '_').split('_');
39
40			var last_extension:Array;
41
42			for(var i:int=0, l:int=subtags.length; i<l ;i++){
43				var subtag:String = subtags[i].toLowerCase();
44
45				if(state==LocaleParserState.PRIMARY_LANGUAGE){
46					if(subtag=='x'){
47						localeId.privateLangs = true; //not used in our implementation, but makes the tag private
48					}else if(subtag=='i'){
49						localeId.lang += 'i-';	//and wait the next subtag to complete the language name
50					}else{
51						localeId.lang += subtag;
52						state ++;
53					}
54				}else{
55					//looging for an extended language 	- 3 chars
56					//			   a script 			- 4 chars
57					//			   a region				- 2-3 chars
58					//			   a variant			- alpha with at least 5 chars or numeric with at least 4 chars
59					//			  an extension/private singleton - 1 char
60
61					var subtag_length:int = subtag.length; //store it for faster use later
62					if(subtag_length==0) continue; //skip zero-lengthed subtags
63					var firstChar:String = subtag.charAt(0).toLowerCase();
64
65					if(state<=LocaleParserState.EXTENDED_LANGUAGES && subtag_length==3){
66					    localeId.extended_langs.push(subtag);
67						if(localeId.extended_langs.length==3){ //allow a maximum of 3 extended langs
68							state = LocaleParserState.SCRIPT;
69						}
70					}else if ( state <= LocaleParserState.SCRIPT && subtag_length==4 ){
71						localeId.script = subtag;
72						state = LocaleParserState.REGION;
73					}else if( state <= LocaleParserState.REGION && (subtag_length==2 || subtag_length==3) ){
74						localeId.region = subtag;
75						state = LocaleParserState.VARIANTS;
76					}else if ( state <= LocaleParserState.VARIANTS &&
77							(
78								( firstChar>='a' && firstChar<='z' && subtag_length>=5 )
79														||
80								( firstChar>='0' && firstChar<='9' && subtag_length>=4 )
81							)
82					  ){
83						//variant
84						localeId.variants.push(subtag);
85						state = LocaleParserState.VARIANTS;
86					}else if ( state < LocaleParserState.PRIVATES && subtag_length==1 ){ //singleton
87						if(subtag == 'x'){
88							state = LocaleParserState.PRIVATES;
89							last_extension = localeId.privates;
90						} else {
91							state = LocaleParserState.EXTENSIONS;
92							last_extension = localeId.extensions[subtag] || [];
93							localeId.extensions[subtag] = last_extension;
94						}
95					}else if(state >= LocaleParserState.EXTENSIONS){
96						last_extension.push(subtag);
97					}
98				}
99			}
100			localeId.canonicalize();
101			return localeId;
102		}
103
104		public function canonicalize():void{
105			for(var i:String in this.extensions){
106				if(this.extensions.hasOwnProperty(i)){
107					//also clear zero length extensions
108					if(this.extensions[i].length==0) delete this.extensions[i];
109					else this.extensions[i] = this.extensions[i].sort();
110				}
111			}
112			this.extended_langs = this.extended_langs.sort();
113			this.variants = this.variants.sort();
114			this.privates = this.privates.sort();
115			if(this.script == ''){
116				this.script = LocaleRegistry.getScriptByLang(this.lang);
117			}
118			//still no script, check the region
119			if(this.script == '' && this.region!=''){
120				this.script = LocaleRegistry.getScriptByLangAndRegion(this.lang, this.region);
121			}
122
123			if(this.region=='' && this.script!=''){
124				this.region = LocaleRegistry.getDefaultRegionForLangAndScript(this.lang, this.script);
125			}
126		}
127
128		public function toString():String{
129			var stack:Array = [ this.lang ];
130			appendElements(stack, this.extended_langs);
131			if(this.script!='') stack.push(this.script);
132			if(this.region!='') stack.push(this.region);
133			appendElements(stack, this.variants);
134			for(var i:String in this.extensions){
135				if(this.extensions.hasOwnProperty(i)){
136					stack.push(i);
137					appendElements(stack, this.extensions[i]);
138				}
139			}
140			if(this.privates.length>0){
141				stack.push('x');
142				appendElements(stack, this.privates);
143			}
144			return stack.join('_');
145		}
146
147		public function equals(locale:LocaleId):Boolean{
148			return this.toString() == locale.toString();
149		}
150
151		public function isSiblingOf(other:LocaleId):Boolean{
152			return (this.lang==other.lang&&this.script==other.script);
153		}
154
155		public function transformToParent():Boolean{
156			if(this.privates.length>0){
157				this.privates.splice(this.privates.length-1, 1);
158				return true;
159			}
160
161			var lastExtensionName:String = null;
162			for(var i:String in this.extensions){
163				if(this.extensions.hasOwnProperty(i)){
164					lastExtensionName = i;
165				}
166			}
167			if(lastExtensionName){
168				var lastExtension:Array = this.extensions[lastExtensionName];
169				if(lastExtension.length==1){
170					delete this.extensions[ lastExtensionName ];
171					return true;
172				}
173				lastExtension.splice(lastExtension.length-1, 1);
174				return true;
175			}
176
177			if(this.variants.length>0){
178				this.variants.splice(this.variants.length-1, 1);
179				return true;
180			}
181
182			if(this.script!=''){
183				//check if we can surpress the script
184			    if(LocaleRegistry.getScriptByLang(this.lang)!=''){
185					this.script='';
186					return true;
187			    }else if(this.region==''){
188					//maybe the default region can surpress the script
189					var region:String = LocaleRegistry.getDefaultRegionForLangAndScript(this.lang, this.script);
190					if(region!=''){
191						this.region = region;
192						this.script = '';
193						return true;
194					}
195				}
196			}
197
198			if(this.region!=''){
199				if(!(this.script=='' && LocaleRegistry.getScriptByLang(this.lang) == '')){
200					this.region='';
201					return true;
202				}
203			}
204
205
206			if(this.extended_langs.length>0){
207				this.extended_langs.splice(this.extended_langs.length-1, 1);
208				return true;
209			}
210
211			return false;
212		}
213
214		/**
215		 *  @private
216		*/
217		private static function appendElements(dest:Array, src:Array):void
218		{
219			for (var i:uint=0, argc:uint=src.length; i < argc; i++)
220				dest.push(src[i]);
221		}
222
223
224	}
225}