require 'pathname'
require 'forwardable'
require 'config'
require 'rexml/document'

LANGS_DIRECTORY=BIBLICONC_BASE_DIRECTORY.to_s+"/langues/"

def change_menus_lang
    $quit_button.label=$lang.menu("1000")
    $selectconc_button.label=$lang.menu("2000")
    $find_button.label=$lang.menu("3000")
    $read_button.label=$lang.menu("4000")
end

def cb_select_bible
    # crash if bible loading problem
    return unless wait_for_loading&&$main_bible.valid?

    dialog=SelectBibleDialog::new($bibles_directory)
    if (dialog.run==Gtk::Dialog::RESPONSE_OK) 
	dialog.load_config
	change_menus_lang
    end
    dialog.destroy
    Request::casual.show if wait_for_loading&&Request::casual
end

def compare_strings(str1,str2)
    return -1 if !str1
    return 1 if !str2
    (0..str1.length-1).each do |i|
	if i>=str2.length then return 1 end
	if str1[i]>str2[i] then return 1 end
	if str1[i]<str2[i] then return -1 end
    end
    if str2.length==str1.length then return 0 end
    return -1
end

class Lang
    extend Forwardable
    attr_reader :lang_name, :xml_name
    def_delegators :lang_name, :length, :[]

    def initialize(xml_name)
	@xml_name=xml_name#.gsub(".xml","")
	@menu=Hash::new
	@message=Hash::new
	@tip=Hash::new
	@help=Hash::new
	begin
	    file=File::new(LANGS_DIRECTORY.to_s+"/"+xml_name,"r")
	    doc=REXML::Document::new(file)
	    root=doc.root
	    @lang_name=root.attributes["lang"]
	    root.each_element do |el|
		next unless el.attributes["code"]
		case el.name
		when "menu": @menu[el.attributes["code"]]=el.text
		when "message": @message[el.attributes["code"]]=el.text
		when "tip": @tip[el.attributes["code"]]=el.text
		when "help": @help[el.attributes["code"]]=el.text
		end
	    end
	rescue 
	    return nil
	end
    end
    def <=>(other)
	return 1 if !other
	return compare_strings(@lang_name,other.lang_name)
    end
    def menu(str)
	@menu[str]
    end
    def message(str)
	@message[str]
    end
    def tip(str)
	@tip[str]
    end
    def help(str)
	@help[str]
    end
end

class SelectBibleDialog < Gtk::Dialog
    # Classe MiniBible
    class MiniBible
	attr_reader :bible_name,:lang,:xml_name
	def initialize(xml_name)
	    @xml_name=xml_name#.gsub(".xml","")
	    @bible_name="Sans nom"
	    @lang="Français"
	    @inputenc="ascii"
	    begin
		file=open($bibles_directory.to_s+xml_name,"r")
		file.each_line do |l|
		    if l.match(/^<bibliquest_concordance_bible/) then
			l.gsub!(/^<bibliquest_concordance_bible/,"")
			l.gsub!(/>\s*$/,"")
			tab=l.scan(/\s*(\w+)="(.*?)"/){|par,val| 
			    case par.to_s
			    when "name": @bible_name=val.to_s
			    when "lang": @lang=val.to_s
			    when "inputenc": @inputenc=val.to_s
			    end
			}
			break
		    end
		end
		file.close
	    rescue 
		puts "Erreur dans la lecture du fichier #{xml_name}"
		return nil
	    end
	end
	def <=>(other)
	    return 1 if !other
	    return compare_strings(@bible_name,other.bible_name)
	end
	def description
	    "#{@bible_name} (#{@lang})"
	end
    end


    # Classe SaveConfigDialog
    class SaveConfigDialog < Gtk::Dialog
	def initialize(parent)
	    super("Nom de la configuration",
		  parent,
		  Gtk::Dialog::MODAL|Gtk::Dialog::DESTROY_WITH_PARENT
		 )
	    cancel_button=add_button(Gtk::Stock::CANCEL,Gtk::Dialog::RESPONSE_CANCEL)
	    ok_button=add_button(Gtk::Stock::OK,Gtk::Dialog::RESPONSE_OK)
	    accel_group=Gtk::AccelGroup::new
	    add_accel_group(accel_group)
	    cancel_button.add_accelerator('clicked',accel_group,Gdk::Keyval::GDK_Escape,0,0)
	    ok_button.add_accelerator('clicked',accel_group,Gdk::Keyval::GDK_Return,0,0)
	    @list=Gtk::ListStore::new(String,Configg)
	    @list.clear
	    $config.each {|cf| iter=@list.append;iter.set_value(0,cf.name);iter.set_value(1,cf)}
	    @entry=Gtk::ComboBoxEntry::new
	    # Pourquoi ça émet une erreur?
	    #@entry.text_column=0
	    @entry.model=@list
	    vbox.pack_start(@entry,true,true,0)

	    vbox.show_all
	end
	def save_name
	    @entry.active_text
	end
    end
    

    def scan_for_langs
	rep=Pathname::new(LANGS_DIRECTORY)
	@langs=Array::new
	rep.entries.select{|f| (rep+f).file?&&f.extname==".xml"}.each do |f|
	    @langs.push Lang::new(f.basename.to_s)
	end
	@langs.sort!
    end
    def scan_for_bibles
	rep=Pathname::new($bibles_directory)
	@mini_bibles=Array::new
	rep.entries.select{|f| (rep+f).file?&&f.extname==".xml"}.each do |f|
	    @mini_bibles.push MiniBible::new(f.basename.to_s)
	end
	@mini_bibles.sort!
    end

    def configs_store_update
	@configs_store.clear
	@config_open_combo_box.model=nil
	$config.each {|cf| @configs_store.append.set_value(0,cf)}
	@config_open_combo_box.model=@configs_store
    end
    def initialize(bibles_directory)
	super("Sélection de la langue",
	      $main_window,
              Gtk::Dialog::MODAL|Gtk::Dialog::DESTROY_WITH_PARENT
             )
	accel_group=Gtk::AccelGroup::new
	add_accel_group(accel_group)
	button_help=create_button(Gtk::Stock::HELP,$lang.menu("9002"),Gtk::IconSize::MENU)
	action_area.pack_start(button_help,false,false,0)
	accel_group=Gtk::AccelGroup::new
	add_accel_group(accel_group)
	# otherwise the help button will not appear!
	action_area.show_all
	action_area.layout_style=Gtk::ButtonBox::EDGE
	button_help.add_accelerator('clicked',accel_group,Gdk::Keyval::GDK_F1,0,0)
	button_help.signal_connect('clicked'){cb_help("2000")}
	button_help.image=Gtk::Image::new(Gtk::Stock::HELP,Gtk::IconSize::LARGE_TOOLBAR)
        button_cancel=add_button(Gtk::Stock::CANCEL,Gtk::Dialog::RESPONSE_CANCEL)
	button_cancel.label=$lang.menu("9001")
	button_cancel.image=Gtk::Image::new(Gtk::Stock::CANCEL,Gtk::IconSize::LARGE_TOOLBAR)
        button_ok=add_button(Gtk::Stock::OK,Gtk::Dialog::RESPONSE_OK)
	button_ok.label=$lang.menu("9000")
	button_ok.image=Gtk::Image::new(Gtk::Stock::OK,Gtk::IconSize::LARGE_TOOLBAR)

	hbox=Gtk::HBox::new(false,0)
	vbox.pack_start(hbox)
	# left panel
	vboxl=Gtk::VBox::new(false,10)
	######hbox.pack_start(vboxl,true,true,0)

	hbox.pack_start(Gtk::VSeparator::new,false,true,0)
	hbox.pack_start(Gtk::VSeparator::new,false,true,0)

	img=Gtk::Image::new(Gtk::Stock::DIALOG_QUESTION,Gtk::IconSize::DIALOG)
	vboxl.pack_start(img,true,true,0)

	vboxl.pack_start(Gtk::HSeparator::new,true,false,0)
	vboxl.pack_start(Gtk::Label::new($lang.menu("2400")),true,false,0)
	@configs_store=Gtk::ListStore::new(Configg)
	@config_open_combo_box=Gtk::ComboBox::new(true)
	@config_open_combo_box.clear
	cr=Gtk::CellRendererText::new
	@config_open_combo_box.pack_start(cr,true)
	@config_open_combo_box.set_cell_data_func(cr){|cell_layout, cell, treemodel, iter| cell.text=iter.get_value(0).name}
	configs_store_update
	@config_open_combo_box.model=@configs_store
	@config_open_combo_box.active=-1
	vboxl.pack_start(@config_open_combo_box,true,false,0)

	save_button=create_button(Gtk::Stock::SAVE,$lang.menu("2410"))
	vboxl.pack_start(save_button,true,false,0)
	# right panel
	vboxr=Gtk::VBox::new(false,10)
	hbox.pack_start(vboxr,true,true,0)

	vboxr.pack_start(Gtk::HSeparator::new,true,false,0)
	scan_for_langs
	vboxr.pack_start(Gtk::Label::new($lang.menu("2100")),true,false,0)
	@langs_store=Gtk::ListStore::new(Lang)
	@langs_combo_box=Gtk::ComboBox::new(true)
	c=Gtk::CellRendererText::new
	@langs_combo_box.clear
	@langs_combo_box.pack_start(c,true)
	@langs_combo_box.set_cell_data_func(c) {|cell_layout, cell, treemodel, iter| cell.text=treemodel.get_value(iter,0).lang_name}
	langs_number=-1
	@langs.each{|l| @langs_store.append.set_value(0,l); if $lang.xml_name==l.xml_name then langs_number=@langs.index(l) end}
	@langs_combo_box.model=@langs_store
	@langs_combo_box.active=langs_number
	vboxr.pack_start(@langs_combo_box,true,false,0)

	vboxr.pack_start Gtk::HSeparator::new
	vboxr.pack_start(Gtk::HSeparator::new,true,false,0)

	scan_for_bibles
	@main_bible_number=0
	@main_bible=nil
	@main_bible_store=Gtk::ListStore::new(MiniBible)
	@mini_bibles.each {|mb| @main_bible_store.append.set_value(0,mb); if mb.xml_name==$main_bible.xml_name then @main_bible_number=@mini_bibles.index(mb);@main_bible=mb end}
	vboxr.pack_start(Gtk::Label::new($lang.menu("2200")),true,false,0)
	@main_bible_combo_box=Gtk::ComboBox::new(true)
	crt=Gtk::CellRendererText::new
	@main_bible_combo_box.clear
	@main_bible_combo_box.pack_start(crt,true)
	@main_bible_combo_box.set_cell_data_func(crt) {|cell_layout, cell, treemodel, iter| cell.text=treemodel.get_value(iter,0).description}
	@main_bible_combo_box.model=@main_bible_store
	@main_bible_combo_box.active=@main_bible_number
	#@mini_bibles.each{|mb| @main_bible_combo_box.append_text("#{mb.description}"); if $main_bible.xml_name==mb.xml_name then @main_bible_combo_box.active=@mini_bibles.index(mb) end}
	vboxr.pack_start(@main_bible_combo_box,true,false,0)

	vboxr.pack_start(Gtk::HSeparator::new,true,false,0)
	vboxr.pack_start(Gtk::Label::new($lang.menu("2300")),true,false,0)
	rmaddbox=Gtk::HBox::new
	add_button=create_button(Gtk::Stock::GO_FORWARD,$lang.menu("2310"))
	rmaddbox.pack_start(add_button,false,false,0)
	rm_button=create_button(Gtk::Stock::GO_BACK,$lang.menu("2320"))
	rmaddbox.pack_start(rm_button,false,false,0)
	vboxr.pack_start(rmaddbox,true,false,0)

	@sec_bibles_store_l=Gtk::ListStore::new(MiniBible)
	@sec_bibles_view_l=Gtk::TreeView::new
	@sec_bibles_view_l.model=@sec_bibles_store_l
	@sec_bibles_view_l.insert_column(0,'Non sélectionnées',Gtk::CellRendererText::new){|tvc,cell,model,iter| cell.text=iter.get_value(0).description}
	@sec_bibles_view_l.selection.mode=Gtk::SELECTION_MULTIPLE
	#@sec_bibles_view_l.headers_visible=false
	scroll_win_l=Gtk::ScrolledWindow::new
	scroll_win_l.set_policy(Gtk::POLICY_NEVER,Gtk::POLICY_AUTOMATIC)
	scroll_win_l.add(@sec_bibles_view_l)

	@sec_bibles_store_r=Gtk::ListStore::new(MiniBible)
	@sec_bibles_view_r=Gtk::TreeView::new
	@sec_bibles_view_r.model=@sec_bibles_store_r
	@sec_bibles_view_r.insert_column(0,'Sélectionnées',Gtk::CellRendererText::new){|tvc,cell,model,iter| cell.text=model.get_value(iter,0).description}
	@sec_bibles_view_r.selection.mode=Gtk::SELECTION_MULTIPLE
	#@sec_bibles_view_r.headers_visible=false
	scroll_win_r=Gtk::ScrolledWindow::new
	scroll_win_r.set_policy(Gtk::POLICY_NEVER,Gtk::POLICY_AUTOMATIC)
	scroll_win_r.add(@sec_bibles_view_r)

	@mini_bibles.each do |mb|
	    if mb.xml_name==$main_bible.xml_name then next; end
	    sel=false
	    $optional_bible.each {|b| if b.xml_name==mb.xml_name then sel=true end}
	    if sel then @sec_bibles_store_r.append.set_value(0,mb)
	    else @sec_bibles_store_l.append.set_value(0,mb) end
	end
	
	hpaned=Gtk::HPaned::new
	hpaned.height_request=200
	hpaned.add1(scroll_win_l)
	hpaned.add2(scroll_win_r)
	vboxr.pack_start(hpaned,true,true,0)

	add_button.signal_connect('clicked'){|widget| 
	    select=Array::new
	    @sec_bibles_view_l.selection.selected_each {|model,path,iter| select.push iter}
	    select.each do |iter|
		target=@sec_bibles_store_l.get_value(iter,0)
		@sec_bibles_store_r.append.set_value(0,target)
		@sec_bibles_store_l.remove(iter)
	    end
	    @sec_bibles_view_r.focus=true
	    @config_open_combo_box.active=-1
	}
	rm_button.signal_connect('clicked'){|widget| 
	    select=Array::new
	    @sec_bibles_view_r.selection.selected_each {|model,path,iter| select.push iter}
	    select.each do |iter|
		target=@sec_bibles_store_r.get_value(iter,0)
		@sec_bibles_store_l.append.set_value(0,target)
		@sec_bibles_store_r.remove(iter)
	    end
	    @sec_bibles_view_l.focus=true
	    @config_open_combo_box.active=-1
	}
	@main_bible_combo_box.signal_connect('changed'){|widget|
	    @sec_bibles_store_l.append.set_value(0,@main_bible)
	    @main_bible=@main_bible_store.get_value(@main_bible_combo_box.active_iter,0)
	    @sec_bibles_store_l.each {|model,path,iter| if model.get_value(iter,0)==@main_bible then model.remove(iter) end}
	    @sec_bibles_store_r.each {|model,path,iter| if model.get_value(iter,0)==@main_bible then model.remove(iter) end}
	    @config_open_combo_box.active=-1
	}
	@config_open_combo_box.signal_connect('changed'){|widget|
	    next if @config_open_combo_box.active==-1
	    new_conf=@configs_store.get_value(@config_open_combo_box.active_iter,0)
	    @sec_bibles_store_l.clear
	    @sec_bibles_store_r.clear
	    @mini_bibles.each do |mb|
		case new_conf.selection_of(mb.xml_name)
		when Configg::MAIN: @main_bible=mb;@main_bible_store.each {|model,path,iter| if model.get_value(iter,0)==@main_bible then @main_bible_combo_box.active_iter=iter end}
		when Configg::SELECTION: @sec_bibles_store_r.append.set_value(0,mb)
		when Configg::NO_SELECTION: @sec_bibles_store_l.append.set_value(0,mb)
		end
	    end
	}
	save_button.signal_connect('clicked') {|widget|
	    dialog=SaveConfigDialog::new(self)
	    if dialog.run==Gtk::Dialog::RESPONSE_OK
		conf=REXML::Element::new("config")
		conf.attributes["name"]=dialog.save_name 
		conf.add_element("lang").text=@langs_store.get_value(@langs_combo_box.active_iter,0).xml_name
		conf.add_element("main_bible").text=@main_bible.xml_name
		@sec_bibles_store_r.each {|model,path,iter| conf.add_element("optional_bible").text=model.get_value(iter,0).xml_name}
		$config.push Configg::new(conf)
	    end
	    dialog.destroy
	    configs_store_update
	}

	hbox.show_all
    end

    def lang_selected
	@langs[@langs_combo_box.active]
    end
    def load_config
	$lang=Lang::new(@langs_store.get_value(@langs_combo_box.active_iter,0).xml_name)
	optionals=Array::new
	@sec_bibles_store_r.each {|model,path,iter| optionals.push model.get_value(iter,0).xml_name}
	Configg::default(@main_bible.xml_name,optionals).load
    end
end
