=begin rdoc
Blender: iCookWare core module, chooses recipes matching query

Author:: Nicola Kaiser (kaiser@cl.uni-heidelberg.de)
Project:: iCookWare
Copyright:: iCookWare Team 2005 (Nicola Kaiser, Ana Kovatcheva, Olga Mordvinova, Stephanie Schuldes)
Embedded Documentation Tool:: rdoc
=end

module ICW
  class Blender
    # +query+:: hash with parameters of query, keys:'fridge'->array, 'pers'-->int 
    #def initialize query, rec_fn="./recipes_hash_marshalled", cl_fn="./test_cluster_marshalled"
    def initialize query, rec_fn, cl_fn 
	  @cl_fn=cl_fn
      @query_ingreds=query['fridge']
      @servings=query['pers']
      # datastructure [{title => "", category => [], yields => "", ingreds => [[ing, amount, unit]], data => "rezepttext", keywords=> []},...]
      @av_recs=getMarshalledData rec_fn      
      #puts @av_recs.inspect
      #@av_recs.each do |rec|
      #  puts rec["ingreds"].inspect
      #end
      @matched_recs=Array.new
    end

    def getMarshalledData fn
      fp=open(fn, 'r')
      data=Marshal.load(fp)
      fp.close
      return data
    end

    def removeDefaults l
      #ingredients which are asumed to be available in every kitchen
      #removed only from unmatched, not from the recipe!
      ignore=["Salz", "Pfeffer", "Zucker", "Zwiebel", "Butter"]
      l2=Array.new
      l.each do |i|
        if not ignore.include?(i)
          l2.push(i)
        end
      end
      return l2
    end

    def match ingreds 
      # tries to match queried ingreds in a given recipe 
      # takes: ingreds of a recipe
      # returns: ingreds not matches
      not_matched=Array.new
      matched=Array.new
      unused=Array.new
      ingreds.each do |i, a, u|
        if not @query_ingreds.include?(i)
          not_matched.push i
        else
          matched.push i
        end
      end
      @query_ingreds.each do |i|
        if not matched.include?(i)
          unused.push(i)
        end
      end
      not_matched=removeDefaults not_matched
      return not_matched, unused
    end    

    def matchQuery num_replacements=3, leftOut=0.4
      # search for a recipe with the corresponding ingredients and searches for replacements if none is found
      replaceables=Array.new # here all recipes which may be suitable for replacements (not more than num_replacements must be found) are stored
      @av_recs.each do |rec|
        num_ing=rec["ingreds"].length
        #puts "*******************"+rec["title"]+"********************"
        not_matched, unused=match(rec["ingreds"])
        stuff=rec["ingreds"].length*leftOut
        if not_matched.length<=stuff #0 #<=rec["ingreds"].length*(1-foundIngreds) 
          @matched_recs.push rec
        else
          if not_matched.length<=num_replacements+stuff
            replaceables.push([not_matched,unused,rec, stuff])
          end
        end
      end
      # this would work if we had clean recipe data ...
      if @matched_recs.length>5
        return @matched_recs # list of recipes
      else
        substitute(replaceables)
        return @matched_recs
      end 
    end
    
    def substitute recipes
      # datastructure [[i1,i2,...],[ix,ix+1,...]...]
      cluster=getMarshalledData @cl_fn
      puts "trying to substitute"
      recipes.each do |to_r, un_u, rec, leftOut|
        to_r.each do |ing|
          cluster.each do |cl|
            if cl.include?(ing)
              #flag=0
              #while flag==0
                un_u.each do |ing2|
                  if cl.include?(ing2)
                    flag=1
                    puts "ersetze " + ing +" mit "+ing2
                    rec["ingreds"].each do |i| 
                      if i[0]==ing 
                        i[0]=ing2 
                      end 
                    end
                    to_r.delete(ing)
                    un_u.delete(ing2)
                  end
                end
              #end
            end   
          end 
        end
        if to_r.length<=leftOut #==0
          @matched_recs.push rec  
        end
      end             
     end
  end
end


def test
	#f="Karotten, Sardellen, Eier, Morzrella, Baguette"
	f="Rinderhackfleisch,Paprika,Majoran,Schweinelende,Baguette,Petersilie"

	fl=Array.new
	f.split(',').each do |ingr|
 		fl.push ingr.strip
		end
	q={}
	q['fridge']=fl
	q['pers']=4
	myBlender=ICW::Blender.new(q, "./muster_rezepte")
	my_recs=myBlender.matchQuery
	puts "********** Empfehlung ***********" #my_recs.inspect 
	my_recs.each do |i| puts i["title"], i["ingreds"].inspect end
end

test
######### TO DO #########
# * Zutaten normalisieren
# * "defaults" erweitern, evtl in ne datei schreiben
# * encoding - how???
