/* minibar.js
needs: minibar_support.js, minibar_input.js, minibar_translations.js, support.js
*/

/*
// This is essentially what happens when you call start_minibar:
if(server.grammar_list) grammars=server.grammar_list;
else grammars=server.get_grammarlist();
show_grammarlist(grammars)
select_grammar(grammars[0])
grammar_info=server.get_languages()
show_languages(grammar_info)
new_language()
complete_output=get_completions()
show_completions(complete_output)
*/

// For backward compatibility:
function start_minibar(server,opts,target) {
    if(target) opts.target=target;
    return new Minibar(server,opts);
}

/* --- Main Minibar object -------------------------------------------------- */
function Minibar(server,opts) {
    // Contructor, typically called when the HTML document is loaded

    /* --- Configuration ---------------------------------------------------- */

    // default values for options:
    this.options={
	target: "minibar",
	try_google: true,
	feedback_url: null,
	help_url: null,
	initial_grammar: null
    }

    // Apply supplied options
    this.server=server;
    if(opts) for(var o in opts) this.options[o]=opts[o];

    // LocalStorage
    this.local=appLocalStorage("gf.minibar.")

    /* --- Syntax editor integration ---------------------------------------- */
    if(!this.options.abstract_action) this.integrate_syntax_editor()

    /* --- Creating the components of the minibar --------------------------- */
    this.translations=new Translations(server,this.options)
    this.input=new Input(server,this.translations,this.options)

    /* --- Creating user interface elements --------------------------------- */

    this.menubar=div_class("menubar");
    this.infobar=div_class("infobar");
    this.extra=div_id("extra");

    this.minibar=element(this.options.target);
    this.minibar.innerHTML="";
    with(this) {
	appendChildren(menubar,[input.menus,translations.menus,input.buttons])
	appendChildren(minibar,[menubar,infobar,input.main,translations.main,extra]);
	if(options.help_url)
	    menubar.appendChild(button("Help",bind(open_help,this)));
	append_extra_buttons(extra,options);
    }
    this.set_hidden = function(b) {
	this.hidden=b
	this.minibar.style.display= b ? "none" : ""
    }
    this.hide = function() { this.set_hidden(true); }
    this.show = function() { this.set_hidden(false); }

    /* --- Minibar client state initialisation ------------------------------ */
    this.grammar=null;

    /* --- Main program, this gets things going ----------------------------- */
    with(this) {
	server.get_grammarlists(bind(show_grammarlist,this));
    }
}

Minibar.prototype.integrate_syntax_editor=function() {
    var minibar=this
    var editor_target="syntax_editor"
    var e=element(editor_target)
    if(!e || !window.Editor) return

    e.style.display="none"
    minibar.options.abstract_action=function(tree) {
	function not_all(s) { return s!="All" }
	var languages=filter(not_all,minibar.translations.toLangs)
	var editor_options = {
	    target: editor_target,
            show_grammar_menu: minibar.grammars.length>1,
	    show_startcat_menu: minibar.input.options.startcat_menu,
	    initial: { grammar: minibar.grammar_menu.value, // hmm
		       startcat: minibar.input.startcat_menu.value, // hmm
		       languages: languages,
		       abstr: tree
		     },
	    lin_action: function(new_input,langFrom) {
		console.log(editor.menu.ui.grammar_menu.value)
		var grammar_url=editor.menu.ui.grammar_menu.value // hmm
		                || minibar.server.current_grammar_url // hmm
		var startcat=editor.get_startcat()
		             || minibar.input.startcat_menu.value // hmm
		var toLangs=gm.languages // hmm
		minibar.input.set_input_for(grammar_url,
					    {from:langFrom,
					     startcat:startcat,
					     input:gf_lex(new_input)})
		minibar.translations.set_toLangs_for(grammar_url,toLangs)

		//Better: keep editor around and reactivate it next time:
		editor.hide()
		// ...

		//Easier: delete the editor and create a new one next time:
		clear(editor.container)
		editor=minibar.editor=null;

		// Even if the grammar is the same as before, this call is
		// what eventually triggers the new_input to be loaded:
		minibar.select_grammar(grammar_url)

		// Make the minibar visible again
		minibar.show()
	    }
	}
	minibar.hide()
        var gm = new GrammarManager(minibar.server,editor_options);
	var editor=minibar.editor=new Editor(gm,editor_options)
	editor.show()
    }
}

Minibar.prototype.get_current_input=function(cont) {
    var t=this
    if(!t.hidden) cont(gf_unlex(t.input.current.input))
    else {
	var tree=t.editor.get_ast()
	function pick(lins) { cont(lins[0].text) }
	t.server.linearize({tree:tree,to:t.input.current.from},pick)
    }
}

Minibar.prototype.show_grammarlist=function(dir,grammar_names,dir_count) {
    var t=this;
    var first_time= !t.grammar_menu
    if(first_time) {
	t.grammar_menu=empty_id("select","grammar_menu");
	t.grammars=[];
	t.grammar_dirs=[];
    }

    t.grammar_dirs.push(dir);
    t.grammars=t.grammars.concat(grammar_names.map(function(g){return dir+g}))
    function glabel(g) {
	return hasPrefix(dir,"/tmp/gfse.") ? "gfse: "+g : g
    }
    function opt(g) { return option(glabel(g),dir+g); }
    appendChildren(t.grammar_menu,map(opt,grammar_names));
    function pick() {
	var grammar_url=t.grammar_menu.value
	t.local.put("last_grammar",grammar_url)
	t.select_grammar(grammar_url);
    }
    function pick_first_grammar() {
	if(t.timeout) clearTimeout(t.timeout),t.timeout=null;
	if(t.grammar_menu.length>1 && !t.grammar_menu.parentElement) {
	    t.grammar_menu.onchange=pick;
	    insertFirst(t.menubar,title("Show grammar info",button("i",bind(t.show_grammarinfo,t))))
	    insertFirst(t.menubar,t.grammar_menu);
	    insertFirst(t.menubar,text("Grammar: "));
	}
	var grammar0=t.options.initial_grammar
	if(!grammar0) {
	    var last_grammar=t.local.get("last_grammar");
	    if(last_grammar && elem(last_grammar,t.grammars))
		grammar0=last_grammar;
	}
	var pgs=t.options.preferred_grammars
	if(!grammar0 && pgs)
	    for(var i in pgs)
		if(elem(pgs[i],t.grammars)) {
		    grammar0=pgs[i]
		    break
		}
	if(!grammar0) grammar0=t.grammars[0];
	//console.log("grammar0=",grammar0)
	t.grammar_menu.value=grammar0;
	t.select_grammar(grammar0);
    }
    // Wait at most 1.5s before showing the grammar menu.
    if(first_time) t.timeout=setTimeout(pick_first_grammar,1500);
    if(t.grammar_dirs.length>=dir_count) pick_first_grammar();

}

Minibar.prototype.select_grammar=function(grammar_url) {
    var t=this;
    //debug("select_grammar ");
    function change_grammar() {
	t.server.grammar_info(bind(t.change_grammar,t));
    }
    t.server.switch_to_other_grammar(grammar_url,change_grammar);
}

Minibar.prototype.change_grammar=function(grammar_info) {
    var t=this;
    //debug("show_languages ");
    t.grammar=grammar_info;
    t.input.change_grammar(grammar_info)
    t.translations.change_grammar(grammar_info)
    t.get_pgf_info()
}

Minibar.prototype.get_pgf_info=function() {
    var t=this;
    var info_url=t.server.current_grammar_url+"_info";
    clear(t.infobar)
    t.pgf_info=null;
    ajax_http_get(info_url,bind(t.show_pgf_info,t),function(){})
}

Minibar.prototype.show_pgf_info=function(info) {
    var t=this;
    var cnt=0;
    //console.log(info)
    info=info.split("\n");
    for(var i=0;i<info.length;i++) {
	if(info[i]=="") info[i]="<p>"
	else cnt++
    }
    t.pgf_info=info.join("\n")
    t.infobar.innerHTML=info[0]+" "
    if(cnt>1)
	t.infobar.appendChild(button("More info",bind(t.show_grammarinfo,t)))
}

Minibar.prototype.show_grammarinfo=function() {
    var t=this
    var g=this.grammar;
    function draw_cats(cats) {
	function draw_cat(cat) {
	    var i=cats[cat]
	    return tr([td(text(i.def)),
		       td(text(i.producers.join(", "))),
		       td(text(i.consumers.join(", ")))])
	}
	var table=wrap_class("table","browse",g.categories.map(draw_cat))
	var hdr=tr([th(text("Category")),
		    th(text("Producers")),
		    th(text("Consumers"))])
	insertFirst(table,hdr)
	return table
    }
    function draw_funs(funs) {
	function draw_fun(fun) {
	    var def=funs[fun].def.split(":")
	    return tr([td(text(def[0])),td(text(":")),td(text(def[1]||""))])
	}
	return div_class("browse",wrap("table",g.functions.map(draw_fun)))
    }
    function draw_more(info) {
	replaceChildren(cats,draw_cats(info.cats))
	replaceChildren(funs,draw_funs(info.funs))
	btn.disabled=true;
    }

    function more() { t.server.browse({},draw_more) }

    var cats=wrap("div",text(g.categories.join(", ")))
    var funs=wrap("div",text(g.functions.join(", ")))
    var btn=button("Show more details",more)
    
    var info=empty("div")
    if(t.pgf_info) info.innerHTML=t.pgf_info
    if(true || /^\/(tmp|grammars)\//.test(server.grammars_url)) {
	var q="?"+server.grammars_url+" "+server.current_grammar_url
	var link=node("a",{href:q})
	link.appendChild(text(link.href));
	info.appendChild(wrap("p",[text("Link directly to this grammar: "),link]))
    }

    clear(t.translations.main)
    var hdr=[text(g.name)]
    if(g.lastmodified) {
	hdr.push(text(" "))
	hdr.push(wrap("small",text("("+g.lastmodified+")")))
    }
    
    appendChildren(this.translations.main,
		   [wrap("h3",hdr),
		    info,
		    text("The categories and functions in the grammar are listed below."),
		    btn,
		    wrap("h4",text("Start category")), text(g.startcat || ""),
		    wrap("h4",text("Categories")), cats,
		    wrap("h4",text("Functions")), funs])
}

Minibar.prototype.append_extra_buttons=function(extra,options) {
    with(this) {
	if(options.try_google)
	    extra.appendChild(button("Try Google Translate",bind(try_google,this)));
	if(options.feedback_url) {
	    var b=button("Feedback",bind(open_feedback,this));
	    b.title="Click to suggest improvements. Select a language in the To: menu first to suggest a better translation to that language."
	    appendChildren(extra,[text(" "),b]);
	}
    }
}

Minibar.prototype.try_google=function() {
    with(this) {
	var to=translations.target_lang();
	var s=gf_unlex(input.current.input);
	if(input.surface.typed) s+=" "+input.surface.typed.value;
	var url="http://translate.google.com/?sl="
	        +langpart(input.current.from,grammar.name);
	if(to!="All") url+="&tl="+to;
	url+="&q="+encodeURIComponent(s);
	window.open(url);
    }
}

Minibar.prototype.open_help=function() {
    open_popup(this.options.help_url,"help");
}

Minibar.prototype.open_feedback=function() {
    with(this) {
	// make the minibar state easily accessible from the feedback page:
	minibar.state={grammar:grammar,current:input.current,
		       to:translations.to_menu.value,
		       translations:translations.main};
	open_popup(options.feedback_url,'feedback');
    }
}

// This function is called from feedback.html
function prefill_feedback_form() {
    var state=opener_element("minibar").state;
    var trans=state.translations;
    var gn=state.grammar.name
    var to=langpart(state.to,gn);

    var form=document.forms.namedItem("feedback");
    setField(form,"grammar",gn);
    setField(form,"from",langpart(state.current.from,gn));
    setField(form,"input",gf_unlex(state.current.input));
    setField(form,"to",to);
    if(to=="All") element("translation_box").innerHTML=" To suggest a better translation to a particular language, select that language in the To: menu before pressing the Feedback button."
    else setField(form,"translation",trans.single_translation.join(" / "));
    
    // Browser info:
    form["inner_size"].value=window.innerWidth+"×"+window.innerHeight;
    form["outer_size"].value=window.outerWidth+"×"+window.outerHeight;
    form["screen_size"].value=screen.width+"×"+screen.height;
    form["available_screen_size"].value=screen.availWidth+"×"+screen.availHeight;
    form["color_depth"].value=screen.colorDepth;
    form["pixel_depth"].value=screen.pixelDepth;

    window.focus();
}
    

/*
se.chalmers.cs.gf.gwt.TranslateApp/align-btn.png

GET /grammars/Foods.pgf?&command=abstrtree&tree=Pred+(This+Fish)+(Very+Fresh)
GET /grammars/Foods.pgf?&command=parsetree&tree=Pred+(This+Fish)+Expensive&from=FoodsAfr
GET /grammars/Foods.pgf?&command=alignment&tree=Pred+(This+Fish)+Expensive
*/
