public  class HTML5InputRange extends InputRangeWidget implements IInputRange{

	
	
	


	private ElementInputRange range;

	public HTML5InputRange(){
		range = new ElementInputRange();
		
		add((Widget) range);
	}
	
	
	
	
	@Override
	public void setSize(String width, String height) {
		setWidth(width);
		setHeight(height);
	}
	
	@Override
	public void setWidth(String width){
		
		super.setWidth(width);
		if(width.endsWith("px")){
			try{
				int w=Integer.parseInt(width.substring(0,width.length()-2));
				range.setWidth(w);
			}catch(Exception e){}
		}
	}
	
	@Override
	public void setHeight(String height){
		super.setHeight(height);
		if(height.endsWith("px")){
			try{
				int h=Integer.parseInt(height.substring(0,height.length()-2));
				range.setHeight(h);
			}catch(Exception e){}
		}
	}



	
	


	 public void setMax(int max){
		 range.setMax(max);
	 }
	
	 
	
	
	 public synchronized void addInputRangeListener(InputRangeListener listener){
		 range.addInputRangeListener(listener);
	 }
	 public synchronized void removeInputRangeListener(InputRangeListener listener){
		 range.removeInputRangeListener(listener);
	 }
	 
	


	@Override
	public void setMin(int min) {
		 range.setMin(min);
	}

	@Override
	public void setEnabled(boolean bool) {
		range.setEnabled(bool);
	}

	@Override
	public void setWidth(int width) {
		range.setWidth(width);
	}

	@Override
	public int getMin() {
		return range.getMin();
	}

	@Override
	public int getMax() {
		return range.getMax();
	}




	@Override
	public void setHeight(int height) {
		range.setHeight(height);
	}



	private LeafValueEditor<Integer> editor;
	@Override
	public LeafValueEditor<Integer> asEditor() {
		if (editor == null) {
		      editor = TakesValueEditor.of(this);
		    }
		    return editor;
	}
	public Integer getValue(){
		return range.getValue();
	 }
	@Override
	public void setValue(Integer value) {
		 range.setValue(value);
	}

} public class HTML5Builder {
	public static Label createRangeLabel(final String text,final IInputRange range){
		final Label label=new Label();
		label.setText(text+""+range.getValue());
		label.setStylePrimaryName("title");
		range.addInputRangeListener(new InputRangeListener() {
			@Override
			public void changed(int newValue) {
				label.setText(text+""+newValue);
			}
		});
		
		/*
		range.addChangeHandler(new ChangeHandler() {
			
			@Override
			public void onChange(ChangeEvent event) {
				label.setText(text+":"+range.getValue());
				
			}
		});*/
		/*
		range.addMouseUpHandler(new MouseUpHandler() {
			
			@Override
			public void onMouseUp(MouseUpEvent event) {
				label.setText(text+":"+range.getValue());
			}
		});
		*/
		
		return label;
	}
	//TODO add point
	public static Label createRangeLabel(final String text,final IInputRange range,final int divided){
		final Label label=new Label();
		label.setText(text+""+((double)range.getValue()/divided));
		label.setStylePrimaryName("title");
		range.addInputRangeListener(new InputRangeListener() {
			@Override
			public void changed(int newValue) {
				label.setText(text+""+((double)newValue/divided));
			}
		});
		return label;
	}
	
	public static Label createRangeLabel(final String text,final IInputRange range,final int divided,final int point){
		final Label label=new Label();
		label.setText(text+""+((double)range.getValue()/divided));
		label.setStylePrimaryName("title");
		range.addInputRangeListener(new InputRangeListener() {
			@Override
			public void changed(int newValue) {
				String v=""+((double)newValue/divided);
				int index=v.indexOf(".");
				if(index!=-1){
					v=v.substring(0,Math.min(v.length(), index+1+point));//this is easy than numberformat.
				}
				label.setText(text+""+v);
			}
		});
		return label;
	}
	
	
}
 public class SpeechSynthesis extends JavaScriptObject{
protected SpeechSynthesis(){}
	public final native static SpeechSynthesis get()/*-{
		if($wnd.speechSynthesis){
			
    	return $wnd.speechSynthesis;
		}
		if($wnd.SpeechSynthesis){
    	return $wnd.SpeechSynthesis;
		}
		
		return null;
  	}-*/; 
	
	public final native static boolean supported()/*-{
   		if($wnd.speechSynthesis || $wnd.SpeechSynthesis){
   		return true;
   		}else{
   		return false;
   		}
  	}-*/; 
	
	
	public  final native boolean isPaused()/*-{
    return this.paused;
  	}-*/; 
	
	public  final native boolean isPending()/*-{
    return this.pending;
  	}-*/; 
	
	public   final native boolean isSpeaking()/*-{
    return this.speaking;
  	}-*/; 
	
	
	/**
	 * possible 0 onload
	 * @return
	 */
	public  final  List<Voice> getVoicesAsList(){
		List<Voice> voices=new ArrayList<Voice>();
		JsArray<Voice> array=getVoices();
		for(int i=0;i<array.length();i++){
			voices.add(array.get(i));
		}
		return voices;
	}
	/**
	 * possible 0 onload
	 * @return
	 */
	public  final native JsArray<Voice> getVoices()/*-{
    return this.getVoices();
  	}-*/;
	
	public   final native void cancel()/*-{
    this.cancel();
  	}-*/;
	
	public  final native void pause()/*-{
    this.pause();
  	}-*/;
	
	public  final native void resume()/*-{
    this.resume();
  	}-*/;
	
	public  final native void speak(SpeechSynthesisUtterance utterance)/*-{
    this.speak(utterance);
  	}-*/;
	
}
 public class SpeechSynthesisUtterance  extends JavaScriptObject{
	protected SpeechSynthesisUtterance(){}
	
	public  static final native SpeechSynthesisUtterance create()/*-{
    return new $wnd.SpeechSynthesisUtterance();
  	}-*/;
	
	public  static final native SpeechSynthesisUtterance create(String text)/*-{
    return new $wnd.SpeechSynthesisUtterance(text);
  	}-*/;
	
	public   final native void setText(String text)/*-{
    this.text=text;
  	}-*/;
	
	public   final native void setLang(String lang)/*-{
    this.lang=lang;
  	}-*/;
	
	public   final native void setVoiceURI(String voiceURI)/*-{
    this.voiceURI=voiceURI;
  	}-*/;
	
	public   final native void setVolume(double volume)/*-{
    this.volume=volume;
  	}-*/;
	
	public   final native void setRate(double rate)/*-{
	
    this.rate=rate;
  	}-*/;
	
	public   final native void setPitch(double pitch)/*-{
	
    this.pitch=pitch;
  	}-*/;
	
	public   final native void setVoice(Voice voice)/*-{
    this.voice=voice;
  	}-*/;
	
	public final native void setOnEnd(SpeechSynthesisEndListener listener)/*-{
    this.onend=function (event) {
	listener.@com.akjava.gwt.html5.client.speechsynthesis.listeners.SpeechSynthesisEndListener::onEnd(Lcom/akjava/gwt/html5/client/speechsynthesis/SpeechSynthesisEvent;)(event);
	};
  	}-*/;
	
	public final native void setOnStart(SpeechSynthesisStartListener listener)/*-{
    this.onstart=function (event) {
	listener.@com.akjava.gwt.html5.client.speechsynthesis.listeners.SpeechSynthesisStartListener::onStart(Lcom/akjava/gwt/html5/client/speechsynthesis/SpeechSynthesisEvent;)(event);
	};
  	}-*/;
	
	public final native void setOnBoundary(SpeechSynthesisBoundaryListener listener)/*-{
    this.onboundary=function (event) {
	listener.@com.akjava.gwt.html5.client.speechsynthesis.listeners.SpeechSynthesisBoundaryListener::onBoundary(Lcom/akjava/gwt/html5/client/speechsynthesis/SpeechSynthesisEvent;)(event);
	};
  	}-*/;
	
	public final native void setOnError(SpeechSynthesisErrorListener listener)/*-{
    this.onerror=function (event) {
	listener.@com.akjava.gwt.html5.client.speechsynthesis.listeners.SpeechSynthesisErrorListener::onError(Lcom/akjava/gwt/html5/client/speechsynthesis/SpeechSynthesisEvent;)(event);
	};
  	}-*/;
	
	public final native void setOnMark(SpeechSynthesisMarkListener listener)/*-{
    this.onmark=function (event) {
	listener.@com.akjava.gwt.html5.client.speechsynthesis.listeners.SpeechSynthesisMarkListener::onMark(Lcom/akjava/gwt/html5/client/speechsynthesis/SpeechSynthesisEvent;)(event);
	};
  	}-*/;
	
	public final native void setOnPause(SpeechSynthesisPauseListener listener)/*-{
    this.onpause=function (event) {
	listener.@com.akjava.gwt.html5.client.speechsynthesis.listeners.SpeechSynthesisPauseListener::onPause(Lcom/akjava/gwt/html5/client/speechsynthesis/SpeechSynthesisEvent;)(event);
	};
  	}-*/;
	
	public final native void setOnResume(SpeechSynthesisResumeListener listener)/*-{
    this.onresume=function (event) {
	listener.@com.akjava.gwt.html5.client.speechsynthesis.listeners.SpeechSynthesisResumeListener::onResume(Lcom/akjava/gwt/html5/client/speechsynthesis/SpeechSynthesisEvent;)(event);
	};
  	}-*/;
	
	
}
 public class SpeechUtils {
private SpeechUtils(){}
//came from chrome33 voice list
public static final String DE_DE="de_De";
public static final String EN_GB="en_GB";
public static final String EN_US="en_US";
public static final String ES_ES="es_ES";
public static final String ES_MX="eS_MX";
public static final String FR_BE="fr_BE";
public static final String FR_FR="fr_FR";
public static final String IT_IT="it_IT";
public static final String JA_JP="ja_JP";
public static final String KO_KR="ko_KR";
public static final String PT_BR="pt_BR";
public static final String PT_PT="pt_PT";
//TODO multiple case?

	public static Voice getVoiceAtLang(String lang){
		JsArray<Voice> voices=SpeechSynthesis.get().getVoices();
		for(int i=0;i<voices.length();i++){
			if(voices.get(i).getLang().equals(lang)){
				return voices.get(i);
			}
		}
		return null;
	}
	public static Voice getVoiceAtLang(List<Voice> voices,String lang){
		String hifun=lang.replace('_', '-');
		for(int i=0;i<voices.size();i++){
			//System.out.println(voices.get(i).getLang()+","+lang);
			if(voices.get(i).getLang().equals(lang)||voices.get(i).getLang().equals(hifun)){
				return voices.get(i);
			}
		}
		return null;
	}
}
 public class Voice extends JavaScriptObject{
	protected Voice(){}

	public  final native boolean isDefault()/*-{
    return this['default'];
  	}-*/;
	
	public  final native boolean isLocalService()/*-{
    return this['localService'];
  	}-*/;
	public  final native String getName()/*-{
    return this['name'];
  	}-*/;
	
	public  final native String getLang()/*-{
    return this['lang'];
  	}-*/;
	
	public  final native String getVoiceURI()/*-{
    return this['voiceURI'];
  	}-*/;
	
}
 public interface SpeechSynthesisBoundaryListener {
public void onBoundary(SpeechSynthesisEvent event);
}
 public interface SpeechSynthesisEndListener {
public void onEnd(SpeechSynthesisEvent event);
}
 public interface SpeechSynthesisErrorListener {
public void onError(SpeechSynthesisEvent event);
}
 public interface SpeechSynthesisMarkListener {
public void onMark(SpeechSynthesisEvent event);
}
 public interface SpeechSynthesisResumeListener {
public void onResume(SpeechSynthesisEvent event);
}
 public interface SpeechSynthesisStartListener {
public void onStart(SpeechSynthesisEvent event);
}

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import com.akjava.gwt.html5.client.HTML5InputRange;
import com.akjava.gwt.html5.client.InputRangeWidget;
import com.akjava.gwt.html5.client.extra.HTML5Builder;
import com.akjava.gwt.html5.client.speechsynthesis.SpeechSynthesis;
import com.akjava.gwt.html5.client.speechsynthesis.SpeechSynthesisEvent;
import com.akjava.gwt.html5.client.speechsynthesis.SpeechSynthesisUtterance;
import com.akjava.gwt.html5.client.speechsynthesis.SpeechUtils;
import com.akjava.gwt.html5.client.speechsynthesis.Voice;
import com.akjava.gwt.html5.client.speechsynthesis.listeners.SpeechSynthesisBoundaryListener;
import com.akjava.gwt.html5.client.speechsynthesis.listeners.SpeechSynthesisEndListener;
import com.akjava.gwt.html5.client.speechsynthesis.listeners.SpeechSynthesisErrorListener;
import com.akjava.gwt.html5.client.speechsynthesis.listeners.SpeechSynthesisMarkListener;
import com.akjava.gwt.html5.client.speechsynthesis.listeners.SpeechSynthesisPauseListener;
import com.akjava.gwt.html5.client.speechsynthesis.listeners.SpeechSynthesisResumeListener;
import com.akjava.gwt.html5.client.speechsynthesis.listeners.SpeechSynthesisStartListener;
import com.google.common.base.Function;
import com.google.common.base.Joiner;
import com.google.common.base.Objects;
import com.google.common.base.Strings;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.gwt.core.client.Scheduler;
import com.google.gwt.core.client.Scheduler.ScheduledCommand;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.text.shared.Renderer;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.TextArea;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.ValueListBox;
import com.google.gwt.user.client.ui.VerticalPanel;

	private TextBox defaultLangBox;
	private ValueListBox<Voice> voiceListBox;
	
	public void createWidget(){
		Timer timer=new Timer(){

			
		
			@Override
			public void run() {
				long s=System.currentTimeMillis();
				speechSynthesis = SpeechSynthesis.get();
				List<Voice> voices=speechSynthesis.getVoicesAsList();
				
				
				
				if(voices.size()>0){

					Voice voice=Objects.firstNonNull(SpeechUtils.getVoiceAtLang(voices, SpeechUtils.JA_JP), voices.get(0));
					
					voiceListBox = new ValueListBox<Voice>(new Renderer<Voice>() {
						@Override
						public String render(Voice voice) {
							return voice.getName()+"("+voice.getLang()+")";
						}

						@Override
						public void render(Voice object, Appendable appendable) throws IOException {
							
						}
					});
					voiceListBox.setValue(voice);
					voiceListBox.setAcceptableValues(voices);
					add(voiceListBox);
					
					HorizontalPanel h1=new HorizontalPanel();
					add(h1);
					
					ValueListBox<String> speakTests=new ValueListBox<String>(new Renderer<String>() {
						@Override
						public String render(String object) {
							return object;
						}

						@Override
						public void render(String object, Appendable appendable) throws IOException {
							// TODO Auto-generated method stub
							
						}
					});
					speakTests.addValueChangeHandler(new ValueChangeHandler<String>() {
						
						@Override
						public void onValueChange(ValueChangeEvent<String> event) {
							textBox.setText(event.getValue());
						}
					});
					List<String> tests=Lists.newArrayList("hello world","こんにちは",
							"<speak version=\"1.1\">Speak it</speak>",
							"<speak version=\"1.1\"> That is a <emphasis> big </emphasis> car!</speak>",
							"<speak version=\"1.0\" xmlns=\"http://www.w3.org/2001/10/synthesis\"> That is a <emphasis> big </emphasis> car!</speak>"
							);
					speakTests.setValue(tests.get(0));
					speakTests.setAcceptableValues(tests);
					add(speakTests);
					
					textBox = new TextBox();
					//<speak version=\"1.0\" xmlns=\"http://www.w3.org/2001/10/synthesis\" xml:lang=\"en-US\">Hello world<voice xml:lang=\"fr-FR\" gender=\"female\">do you know me?</voice></speak>
					textBox.setText(tests.get(0));
					h1.add(textBox);
					Button speakBt=new Button("speak",new ClickHandler() {
					

						@Override
						public void onClick(ClickEvent event) {
							execSpeak();
						}

						
					});
					h1.add(speakBt);
					
					Button cancelBt=new Button("cancel",new ClickHandler() {
						@Override
						public void onClick(ClickEvent event) {
							if(speechSynthesis!=null){
								speechSynthesis.cancel();
								updateStatus();
							}
						}

						
						
					});
					h1.add(cancelBt);
					Button pauseBt=new Button("pause",new ClickHandler() {
						@Override
						public void onClick(ClickEvent event) {
							if(speechSynthesis!=null){
								speechSynthesis.pause();
								updateStatus();
							}
						}
						
					});
					h1.add(pauseBt);
					Button resumeBt=new Button("resume",new ClickHandler() {
						@Override
						public void onClick(ClickEvent event) {
							if(speechSynthesis!=null){
								speechSynthesis.resume();
								updateStatus();
							}
						}
						
					});
					h1.add(resumeBt);
					
					HorizontalPanel h2=new HorizontalPanel();
					add(h2);

					rateRange = HTML5InputRange.createInputRange(1, 100, 10);
