require 'forwardable'
require 'strscan'

def update_forrew_buttons
    fbad=$request.empty?||$casual_request==$request.length-1
    rbad=$request.empty?||$casual_request==0
    $rewind_button.sensitive=!rbad
    $forward_button.sensitive=!fbad
end
def cb_rewind
    $casual_request-=1 if $casual_request>0
    Request::casual.show
    update_forrew_buttons
end
def cb_forward
    $casual_request+=1 if $casual_request<$request.length-1
    Request::casual.show
    update_forrew_buttons
end

class Reference 
    extend Forwardable
    ALL=-2

    attr_reader :book,:chapter,:verse
    def_delegators :target_verse,:match_expression

    def initialize(book,chapter,verse)
	@book=book
	@chapter=chapter
	@verse=verse
    end

    def show(text_buffer,iter,search)
	v=$main_bible.get_verse(self)
	v.write(text_buffer,iter,search) if v
	$optional_bible.each do |b|
	    v=b.get_verse(self)
	    v.write(text_buffer,iter,search,false) if v
	end
    end
    def write_to_file(file)
	v=$main_bible.get_verse(self)
        v.write_to_file(file) if v
# to be continued
    end
    def target_verse
	$main_bible.get_verse(self)
    end
    
    WHOLE=Reference::new(-1,ALL,ALL)
end

class Request
    NONE=0
    READ=1
    SEARCH=2

    class SearchExp
	attr_reader :regexp,:negative
	def initialize(escape,guill,str,negative=false)
	    @guillemets=guill
	    @str=str
	    #if escape then @str.gsub!(/\./u,"\\.") end
	    @negative=negative
	    update_regexp
	end
	def update_regexp
	    if SearchDialog::options["no_case"]&&!SearchDialog::options["is_regexp"]
		@regexp=Regexp::new(@str,Regexp::IGNORECASE,"u")
	    else
		@regexp=Regexp::new(@str,nil,"u")
	    end
	end
	def str=(new_str)
	    @str=new_str
	    update_regexp
	end
	def map_options
	    if @guillemets&&@str.match(/^£/u)
		@negative=true
		@str.gsub!(/^£/u,"")
	    end
	    if !@guillemets&&@str.match(/^-/u)
		@negative=true
		@str.gsub!(/^-/u,"")
	    end
	    @str.gsub!(/\W+/u,"\\W+") if SearchDialog.options["no_punct"]
	    @str="\\b#{@str}" if SearchDialog.options["position"]==SearchDialog::BEGIN_OF_WORDS||SearchDialog.options["position"]==SearchDialog::WHOLE_WORDS
	    @str="#{@str}\\b" if SearchDialog.options["position"]==SearchDialog::END_OF_WORDS||SearchDialog.options["position"]==SearchDialog::WHOLE_WORDS
	    if SearchDialog::options["no_accents"]||SearchDialog::options["no_case"]
		list=Array::new
		if SearchDialog::options["no_accents"]&&SearchDialog::options["no_case"] then $main_bible.equiv_class.each {|ec| list.push(ec)}
		elsif SearchDialog::options["no_accents"] then eci=0;$main_bible.equiv_class.each{|ec| st=ec.clone;list[eci*2]="";list[eci*2+1]="";while (st.length>0) do list[eci*2].<<st.slice!(/^./u);list[eci*2+1].<<st.slice!(/^./u);end;eci+=1;}
		elsif SearchDialog::options["no_case"] then $main_bible.equiv_class.each{|ec| st=ec.clone;while (st.length>0) do list.push(st.slice!(/^../u)) end}
		end
		list.each do |ec|
		    class_motif=ec.split(//u)*"|"
		    @str.gsub!(/(#{class_motif})/u,"§")
		    @str.gsub!(/§/u,"(#{class_motif})")
		end
	    end
	    update_regexp
	end
    end
    ######################

    attr_reader :valid
    def initialize(method,textview)
	@textview=textview
	@reference=Array::new
	@matches=0
	@valid=true
	case method
	when READ
	    if !wait_for_loading 
		print_error $lang.message("101")
		return
	    end
	    read_dialog=ReadDialog::new()
	    if read_dialog.run==Gtk::Dialog::RESPONSE_OK
		ref=read_dialog.reference
		@reference=$main_bible.expand_ref(ref)
		read_dialog.destroy
	    else
		read_dialog.destroy
		@valid=false
		return
	    end
	when SEARCH
	    search_dialog=SearchDialog::new($main_bible,$expr)
	    if search_dialog.run==Gtk::Dialog::RESPONSE_OK
		$expr=search_dialog.expression
		$list=search_dialog.list.select{|br| br.active}
		if !wait_for_loading 
		    print_error $lang.message("101")
		    return
		end
		@search=scan_research($expr)
		quick_search=nil
		@matches=0
		@reference=Array::new
		$list.each do |b|
		    rep=b.search_expression(@search,quick_search)
		    @reference.concat rep[0]
		    @matches+=rep[1]
		end
		search_dialog.destroy
	    else
		search_dialog.destroy
		#raise $lang.menu("9001")
		@valid=false
		return 
	    end
	end
    end
    def scan_research(expr)
	if SearchDialog::options["is_regexp"]
	    tab=Array::new
	    tab[0]=SearchExp::new(false,false,expr)
	    tab
	else
	    expr2=expr.gsub(/(\s-)\s+/u,'\1').gsub(/-"/u,'"£')
	    if SearchDialog.options["no_punct"]
	        expr2.gsub!(/[*#\[\]]/u,"")
	    else
		expr2.gsub!(/([*#\[\]])/u,'0000\1').gsub!(/0000/u,"\\")
	    end
	    tab_one=expr2.split('"')
	    i=0
	    tab_two=tab_one.map{|e| 
		i+=1;
		if i%2==1 then 
		    e.split(' ').map{|s| SearchExp::new(true,false,s)}
		else
		    SearchExp::new(true,true,e) 
		end
	    }.flatten
	    tab_two.map{|se| se.map_options} 
	    tab_two
	end
    end

    def show
	text_buffer=@textview.buffer
	text_buffer.text=""
	iter=text_buffer.get_iter_at_offset(0)
	@reference.each do |r|
	    r.show(text_buffer,iter,@search)
	end
	if !@search
	    $status_bar.push($status_bar.get_context_id("Read"),"")
	else
	    if @search.length==1
		$status_bar.push($status_bar.get_context_id("Search"),"Recherche de '#{$expr}': #{@matches} ocurence#{(@matches>1)?"s":""} trouvée#{(@matches>1)?"s":""} dans #{@reference.length} verset#{(@reference.length>1)?"s":""}.")
	    else
		$status_bar.push($status_bar.get_context_id("Search"),"Recherche de '#{$expr}': #{@reference.length} verset#{(@reference.length>1)?"s":""} trouvé#{(@reference.length>1)?"s":""}.")
	    end
	end
    end

    def save_to_file(chemin)
	begin
	    file=open(chemin,"w")
	    @reference.each do |r|
		r.write_to_file(file)
	    end
	    file.close
	rescue
	    print_error $lang.message("10101")
	end
    end


    def Request::casual
	$request[$casual_request]
    end
end


