Shoes.setup do
  gem 'pdf-writer'
end

require 'pdf/writer'
require 'date'

class Exercise
  attr_accessor :date, :time, :activity, :location, :description, :calories

   def initialize(*args)
     raise "Wrong number of args for Event" unless args.size == 6
    @date, @time, @activity, @location, @description, @calories=args
   end
  
  def to_s

     <<-EOM
   Activity: #{activity}
   Location: #{location}
   Description: #{description}
 
   Doing this exercise you burned: #{calories} calories

   EOM
   end
end

class Item
  attr_accessor :name,:calories,:fat, :quantity

   def initialize(*args)
     raise "Wrong number of args for Event" unless args.size == 4
    @name, @calories, @fat, @quantity = args
   end

   def to_s
   "#{quantity} of #{name} for #{calories} calories and #{fat} grams of fat"
   end
end

class Meal
  attr_accessor :menu, :name, :date, :time, :location, :guests, :mood, :activity

   def initialize(*args)
    raise "Wrong number of args for Event" unless args.size == 7 
    @menu = []
    @name, @date, @time, @location, @guests, @mood, @activity = args
   end

   def get_date
     Time.parse(@date)
   end

   def nq(x)
    @menu << x
   end

   def dq
    @menu.shift
   end

   def length
    @menu.length
   end

   def delete_item(index)
     @menu.delete_at(index)
   end

   def to_s

     <<-EOM
  Where you ate: #{location}
  You ate with: #{guests}
  Your mood was: #{mood}
  While you ate you were: #{activity}
  You Ate:
 
    EOM
  end
end

class MealDiary < Shoes
  url '/',      :index
  url '/home', :home
  url '/general', :collect
  url '/exercise', :exercise
  url '/meal_entry', :meal_entry
  url '/journal', :journal
  url '/edit_gen/(\d+)', :edit_gen
  url '/add_food/(\d+)', :add_food
  url '/edit_fooditem/(\d+)', :edit_fooditem
  url '/journal', :journal

  def index
     load(data_path())
  end

  def home
    header 'Keep a Record of Your Meals'
    stack do
      inscription link("About"){show_about}, :margin_top=>5, :margin_left=>300
    end
    stack do
      para  "",
      link("New Meal Entry\n", :click=>"/general"),
      link("New Exercise Entry\n", :click=>"/exercise"),
      link("View My Journal\n", :click=>"/journal"), :margin_top => 40
    end
    stack :margin_top =>10 do
      button ("Exit"){close}
    end
  
  end

  def show_about
    window :width=>400, :height=>400 do
      background white
      background tan, :height => 40
      flow :margin_left=>5, :margin_right=>15 do
        caption "About My Food Diary", {:margin => 8, :stroke => white}
      end
      
      inscription "a free and open source program (c) 2008 by Howard Roberts\n\nUse this program or the code any way you see fit\n\n"
      stack do
        para "Dedicated to my wife Penny"
      end
      stack do
        inscription "Data path and storage routines borrowed en masse from the ", link("Reminder Application", :click=>"http://www.the- shoebox.org/"), " by Oliver Smith <osmith@gmail.com>\n"
        inscription "Special thanks to Botp Pena, David A. Black and Erik Veenstra for guidance and suggestions for the object sorting routines used in the journal."
        inscription "Finally, great thanks to _Why for such a fine gui toolkit for Ruby!"
      end
      stack :margin_left =>270 do
        button("Close") do
          close()
        end
      end
    end
  end

  def collect
       header 'Record Information About My Meal'
       stack do
          stack :margin_left=>220 do
            button("Cancel", :margin_top=>5){visit "/home"}
          end
         caption "This Meal Was For"
         @mealname= list_box :margin_left => 10, :width => 180,:items=> ["Breakfast","Lunch","Dinner","Snack"]
         inscription "Date", link("?"){|x| help("date")}
         @date=edit_line(Time.now.strftime('%m/%d/%y'),:margin_left=>10 )
         inscription "Where I Ate:", link("?"){|x| help("where")}
         @location = edit_line :margin_left => 10
         inscription "The Time That I Ate:"
         @time = edit_line :margin_left => 10
         inscription "Who I Ate With:", link("?"){ help("with")}
         @guests= edit_line :margin_left => 10
         inscription "What I Was Doing While I Ate:", link("?"){ help("activity")}
         @activity= edit_line :margin_left => 10
         inscription "My Mood When I Ate:", link("?"){ help("mood")}
         @mood = list_box(:margin_left => 10, :width => 180,:items=> ["Angry","Anxious/Nervous","Bored","Depressed","Happy","Hungry", "Lonely","Relaxed","Sad","Sociable"])
       end
       stack do
         button("Done", :margin_left =>200) do
           if @mealname.text.nil? || @date.text=='' || @time.text !~ /(\d*):(\d\d) (AM|PM)/
             alert("Each meal must have, at least, a Name, Date, and Time\n The Time must be entered in the format: 9;00 AM")
           else
             @@meal=Meal.new(@mealname.text, Date.parse(@date.text), @time.text, @location.text, @guests.text, @mood.text, @activity.text)
             visit ("/meal_entry")
           end
         end
       end
  end

  def meal_entry
    header 'Add The Items That You Ate:'
    stack :margin_top =>20, :margin=>20 do
       para "Please enter an item that you ate for this meal,\n then press Add.\nWhen you've Added the last item\npress Save to continue."
    end
    stack do
      para "For this meal, you ate the following:\n"
      inscription  "Food ", link("?"){help("type")}
      @food=edit_line :margin_left=>10, :width=>140
    end
    stack do
      inscription "How Much ", link("?"){ help("quantity")}
      @quantity=edit_line :margin_left=>10 , :width=>90
    end
    stack do
      flow :margin_top=>4 do
         inscription "Calories ", link("?", :click=>"http://www.google.com/search?q=calories+in+food")
         @calories=edit_line :margin_left=>10, :width=>40
       end
       flow :margin_top=>4 do
         inscription "Fat Grams"
         @fat=edit_line :margin_left=>10 ,:width=>40
       end
       end
       stack do
         button("Add", :margin_left =>60, :margin_top=>10) do
           if @food.text=='' 
             alert("You must, at least, enter a name for the food you ate.")
           else
             item= Item.new(@food.text, @calories.text,@fat.text, @quantity.text)
             @food.text=''
             @quantity.text=''
             @calories.text=''
             @fat.text=''
             @meal_panel.append do
               inscription item.to_s
             end
             @@meal.nq(item)
          end  
      end
    end
    stack do 
      button("Save", :margin_left =>240, :margin_top=>10) do
        if @@meal.menu.empty?
          alert("Please add at least one food item before saving your meal.")
        else
          @@data << @@meal if @editing.nil?
          save(data_path())
          @@meal = nil
        end
      end
    end
    @meal_panel= stack do
     para ''
    end 
  end

  def exercise
    header 'Record Information About Your Exercise'
    stack do
      stack :margin_left=>220 do
        button("Cancel", :margin_top=>5){visit "/home"}
      end
      inscription "Date", link("?"){|x| help("time")}
      @date=edit_line(Time.now.strftime('%m/%d/%y'),:margin_left=>10 )
      inscription "Time:"
      @time = edit_line :margin_left => 10, :width=>100
      inscription "Where I exercised:"
      @location = edit_line :margin_left => 10
      inscription "What exercise I performed:"
      @activity= edit_line :margin_left => 10
      inscription "A brief description of my exercise:"
      @description = edit_box(:margin_left => 10)
      inscription "How many calories I burned exercising:"
      @calories= edit_line :margin_left => 10, :width=>40
    end
    stack do
      button("Done", :margin_left =>200) do
        if @date.text=='' || @activity==''|| @time.text !~ /(\d*):(\d\d) (AM|PM)/
          alert("Each exercise must have, at least, an Activity and Date, and Time\n The Time must be entered in the format: 9;00 AM")
        else
          ex=Exercise.new(Date.parse(@date.text), @time.text, @activity.text,@location.text,@description.text,@calories.text)
          @@data << ex
          save(data_path())
        end
      end
    end
  end

 def journal
   header 'A Record of Your Daily Meals & Exercise'
   prev_date=nil
   @@data.sort_by do |item|
     t,ampm = item.time.split
     hr,min = t.split ":"
     hr = "0"+hr if hr.size==1
     timenew = ampm+hr+min
     [item.date, timenew, item.class.to_s]
     end.each_with_index do |item,index|
       inscription strong( "#{item.date.strftime('%m/%d/%y')}\n\n")  if prev_date != item.date
       if item.class.to_s == "Shoes::Meal"
         inscription strong("#{item.name}")," - #{item.time} ", link("edit", :click=>"/edit_gen/#{@@data.index(item)}")," " ,link("delete\n"){delete_data(@@data.index(item))}
         para item, "   ", link("add",:click=>"/add_food/#{@@data.index(item)}")
         stack :margin_left =>10 do 
           item.menu.each_with_index do |food,idx|
             key=@@data.index(item).to_s + "_" + idx.to_s
             inscription food.to_s," ", link("edit"){edit(key)}, " ",  link("delete"){delete_item(@@data.index(item),idx)}
           end
         end
         para "\n"
       else
          inscription strong("Exercise") , " - #{item.time}"," " ,link("delete\n"){delete_data(@@data.index(item))}
	  inscription item.to_s
       end
      prev_date = item.date
    end
    stack do
      button("Copy") do
        copy(0)
      end
    end
    stack do
      button("save to pdf") do
        copy(1)
      end
    end
    stack :margin_left =>270 do
      button("Done"){visit "/home"}
    end
  end  
  def copy(type)
    puts "in copy. type is #{type}"
    prev_date=nil
    txt="A Record of your Daily Meals & Exercise\n"
    @@data.sort_by do |item|
      t,ampm = item.time.split
      hr,min = t.split ":"
      hr = "0"+hr if hr.size==1
      timenew = ampm+hr+min
      [item.date, timenew, item.class.to_s]
    end.each do |item|
      txt+= "\n#{item.date.strftime('%m/%d/%y')}\n" if prev_date != item.date
      if item.class.to_s == "Shoes::Meal"
        txt+=item.name+"\n"
        txt+=item.to_s
        item.menu.each_with_index do |food,idx|
          txt+="\n#{food.quantity} of #{food.name} for #{food.calories} calories and #{food.fat} grams of fat \n"
        end
        txt+="\n"
     else
       txt+="Exercise\n"
       txt+=item.to_s+"\n"
     end
     prev_date = item.date
   end
     txt+="\n"
     puts "text is compiled. it read:\n#{txt}"
     case type
       when 0
         self.clipboard= txt
       when 1
         make_pdf(txt)
    end
  end

  def make_pdf(menu)
    file= ask_save_file
    pdf = PDF::Writer.new
    pdf.text menu, :justification => :full, :font_size => 14, :left => 50,
  :right => 50
   pdf.save_as(file)
  end

 def add_food(key)
   @@meal=@@data[key.to_i]
   @editing="Yup, I'm editing"
   meal_entry
   button("cancel"){visit "/home"}
     @meal_panel = stack do
   end
 end

 def edit_general
   header 'Change Details About Your Meals'

   stack do
     inscription "Where I Ate:", link("?"){|x| help("where")}
     @location = edit_line(@item.location, :margin_left => 10)
   end
   stack do
     inscription "The Time That I Ate:"
     @time = edit_line(@item.time, :margin_left => 10)
   end
   stack do
     inscription "Who I Ate With:", link("?"){ help("with")}
     @guests= edit_line(@item.guests, :margin_left => 10)
   end
   stack do
     inscription "What I Was Doing While I Ate:", link("?"){ help("activity")}
     @activity= edit_line(@item.activity, :margin_left => 10)
   end
   stack do
     inscription "My Mood When I Ate:", link("?"){ help("mood")}
      @mood = list_box(:margin_left => 10, :width => 180,:items=> ["Happy","Relaxed","Sociable","Bored", "Lonely","Sad","Depressed","Angry","Hungry"])
   end
   stack do
     button("Done") do
       @item.location=@location.text
       @item.time=@time.text
       @item.guests=@guests.text
       @item.activity=@activity.text
       @item.mood=@mood.text
       save(data_path())
     end
   end

 end
  def edit(keyinfo)
    key =keyinfo.split("_")
    @@meal=@@data[key[0].to_i]
    visit "/edit_fooditem/#{key[1]}"
  end

  def edit_fooditem(index)

    header 'Edit Your Meal Item'

    stack do
      button("cancel", :margin_left=>140,:margin_top=>10){visit "/home"}
    end
    item=@@meal.menu[index.to_i]
    stack do
      inscription  "Food ", link("?"){help("type")}
      @food=edit_line item.name, :left=>80, :width=>140
    end
    stack do
      inscription "How Much ", link("?"){ help("quantity")}
      @quantity=edit_line item.quantity, :left=>80, :width=>90
    end
    stack do
      inscription "Calories ", link("?", :click=>"http://www.google.com/search?q=calories+in+food")
      @calories=edit_line item.calories, :left=>80,:width=>30
    end
    stack do
      inscription "Fat Grams"
      @fat=edit_line item.fat, :left=>80,:width=>30
    end 
    stack do
      button("Done") do
        item.name=@food.text
        item.quantity=@quantity.text
        item.calories=@calories.text
        item.fat=@fat.text
        save(data_path())
      end
    end
  end

  def edit_gen(key)
    @item=@@data[key.to_i]
    edit_general
    button("cancel"){visit "/home"}
  end

  def delete_item(index,idx)
    meal=@@data[index.to_i]
    if meal.menu.length > 1
      if confirm("Are you sure you want to delete #{meal.menu[idx.to_i].name} from your meal?")
        meal.delete_item(idx.to_i)
        save(data_path())
      else
        visit "/home"
      end
    else
      alert("Your meal only has one item. Please edit this.")
    end
  end

  def header(title='My Meal Diary')
    background white
    background tan, :height => 40
    stack do
      caption "#{title}", {:margin => 8, :stroke => white}
    end
  end
  
  def help(topic)
    txt=''
    case topic
      when "date"
        txt="Enter the date of your meal. Use any common date format, such as:\n 01/01/08\n01/01/2008\nor\nJanuary 1, 2008\nJan 1st 2008\nJan 1, 2008\nNOTE: Do NOT use 01-01-08"
      when "type"
        txt="Enter of the foods you ate. Remember details like beverages, gravies and sauces, and condiments,such as soda, salad dressing, mayonnaise, butter, sour cream, sugar and ketchup."
      when "quantity"
        txt="Enter the amount of the particular food item you ate. Use any meaningful measurement that you can think of, such as size-- 4\"x3\"x3/4\" piece of meat, volume-- 3/4 cups of oats, a handful of raisens, weight- 4oz. of corn, or numbers such as 2 strips of turkey bacon, or 1 plate of cassarole."
      when "where"
        txt="Enter the room or area of the house that you were in when you ate. If you ate out, put in the location, such as work, your car, or the name of the restaurant."
      when "with"
        txt="If you ate by yourself, write \"alone.\" If you were with other people, list their names."
      when "activity"
        txt="List any activities you were doing while you were eating (for example, working, watching TV or ironing)."
      when "mood"
        txt="How were you feeling while you were eating (for example, sad, happy or depressed)?"
      when "calories"
        txt="You can find out the calories in most foods by using Internet search engines, such as Google, search for the keyword 'calories in food'"
    end
    window :width=>370, :height=>200 do
      background white
      background tan, :height => 40
      flow :margin_left=>5, :margin_right=>15 do
        caption "Help -#{topic}", {:margin => 8, :stroke => white}
      end
      para txt,"\n"
      button("Close") do
        close()
      end
    end
  end

  def delete_data(k)
    
    item = @@data[k].class.to_s == "Shoes::Meal" ? "meal" : "exercise"

    if confirm("Are you sure you want to delete this #{item}?")
      @@data.delete_at(k)
      save(data_path())
    end
  end

 def data_path
    if RUBY_PLATFORM =~ /win32/
      if ENV['USERPROFILE']
        if File.exist?(File.join(File.expand_path(ENV['USERPROFILE']), "Application Data"))
          user_data_directory = File.join File.expand_path(ENV['USERPROFILE']), "Application Data", "MyFoodDiary"
        else
          user_data_directory = File.join File.expand_path(ENV['USERPROFILE']), "MyFoodDiary"
        end
      else
        user_data_directory = File.join File.expand_path(Dir.getwd), "data"
      end
    else
      user_data_directory = File.expand_path(File.join("~", ".myFoodDiary"))
    end
    unless File.exist?(user_data_directory)
      Dir.mkdir(user_data_directory)
    end
    return File.join(user_data_directory, "data.dat")
  end
   def load(data_path)
     if File.exist?(data_path)
       f=File.open(data_path, 'r'){|f|
       @@data = Marshal.load(f)}
     else
       @@data=[]
     end
     visit '/home'
  end
  def save(data_path)
    File.open(data_path, 'wb') { |f|
      f.write Marshal.dump(@@data)
    }
    visit '/home'
  end 
end

Shoes.app :title => "My Meal Diary", 
  :width => 370, :height => 570, :resizable => true
