require 'set'

class Filter < NSObject
  
  attr_accessor :name, :category, :selected, :categoryObject, :tcount, :dcount, :acount
  
  def init
    super_init
    @category="Misc."
    @name="no filter name!"
    self
  end
  
  def selected=(value)
     setSelected(value)
  end
  
  def rawName
    return @name
  end

	def name
	  return "#{@name} (#{@acount}/#{@tcount}/#{@dcount})" if @tcount
	  return @name
  end
  def setSelected(value)
    willChangeValueForKey "selected"
    @selected=value
    didChangeValueForKey "selected"
    @categoryObject.updateSelected
  end
  
  def toggleSelected
#    if !@selected || @selected==0
#      selected=1
#    else
#      selected=0
#    end
#    @categoryObject.updateSelected
  end
    

  def showAction?(action)
    false
  end
  
  def filterActions(actions)
    actions.find_all { |x| showAction?(x)}
  end
  
  def showDeepAction?(action)
    action.deepEach do |x|
      if showAction?(x)
        return true
      end
    end
  end
  
  def filters
    nil
  end
  
  def filterDeepActions(actions)
    actions.find_all { |x| showDeepAction?(x)}
  end
  
  def filterTasks(actions)
    result=[]
    actions.each do |x|
      x.eachTask do |y|
        if showAction?(y)
          result << y
        end
      end
    end
    result
  end
  
  def filterRootActions(actions)
    result=Set.new(filterTasks(actions).collect { |task| task.rootAction})
    result.to_a
  end
  
  def tasks
    result=filterTasks($managedObjectContext.objectsForEntityNamed('Action'))
    #result=$managedObjectContext.objectsForEntityNamed('Action')
    result
    Set.new(result).to_a
  end
  def rootActions
    result=filterRootActions($managedObjectContext.objectsForEntityNamed('Action'))
    result
  end
  
  def predicate
	return @predicate if @predicate
	@predicate= NSPredicate.predicateWithValue(true)
  end
  
end

class NullFilter < Filter
  
  def showAction?
    true
  end
end


class TimeFilter < Filter
  
  def init(low,high)
    super_init
    @low=low
    @high=high
    @category="Time"
    self
  end
  
  def showAction?(action)
    d=action.finishOrDoDate
    if d
      d=d.dayNumber
      (d>=@low) && (d<=@high)
    end
  end
  
  def predicate
	return @predicate if @predicate
	@predicate= NSPredicate.predicateWithFormat("finishOrDoDate.dayNumber >= %@ AND finishOrDoDate.dayNumber <= %@", low, high)
  end

  
  def TimeFilter.buildFilters
    result=[]
    result << TodayFilter.alloc.init()
    result << ThisWeekFilter.alloc.init()
    result << ThisMonthFilter.alloc.init()
    result << LastWeekFilter.alloc.init()
    result << LastMonthFilter.alloc.init()
    result << PastDueFilter.alloc.init()
    result << BeforeStartFilter.alloc.init()
    result << NoStartFilter.alloc.init
    result << NoDueFilter.alloc.init
    result << NoDoFilter.alloc.init
    result
  end

end

class TimeRelatedFilter < Filter
  def init
    super_init
    @category="Time"
    self
  end
end

class PastDueFilter < TimeRelatedFilter
  def init
    super
    @name="Past Due"
    self
  end
  
  def showAction?(action)
    return action.isDue?
  end
  
  def predicate
	return @predicate if @predicate
	@predicate= NSPredicate.predicateWithFormat("isDue == true")
  end

end

class BeforeStartFilter < TimeRelatedFilter
  def init
    super
    @name="Before Start"
    self
  end
  
  def showAction?(action)
    return action.beforeStart?
  end
  
  def predicate
	return @predicate if @predicate
	@predicate= NSPredicate.predicateWithFormat("beforeStart == true")
  end
end

class NoStartFilter < TimeRelatedFilter
  def init
    super
    @name="No Start Date"
    self
  end
  
  def showAction?(action)
    return !action.startDate?
  end
  
  def predicate
	return @predicate if @predicate
	@predicate= NSPredicate.predicateWithFormat("startDate == nil")
  end

end

class NoDueFilter < TimeRelatedFilter
  def init
    super
    @name="No Due Date"
    self
  end
  
  def showAction?(action)
    return !action.dueDate?
  end

  def predicate
	return @predicate if @predicate
	@predicate= NSPredicate.predicateWithFormat("dueDate == nil")
  end

end

class NoDoFilter < TimeRelatedFilter
  def init
    super
    @name="No Do On Date"
    self
  end
  
  def showAction?(action)
    return !action.doDate?
  end

  def predicate
	return @predicate if @predicate
	@predicate= NSPredicate.predicateWithFormat("doDate == nil")
  end

end


class TodayFilter < TimeRelatedFilter

  def init
    super
    @name="Today"
    self
  end
  
  def showAction?(action)
    return action.isToday?
  end

  def predicate
	return @predicate if @predicate
	@predicate= NSPredicate.predicateWithFormat("isToday == true")
  end



end

class ThisWeekFilter < TimeFilter
  def init
    dn=NSDate.date.dayNumber
    super(dn,dn+6)
    @name="This Week"
    self
  end

end

class LastWeekFilter < TimeFilter
  def init
    dn=NSDate.date.dayNumber
    super(dn-7,dn)
    @name="Last Week"
    self
  end
end

class ThisMonthFilter < TimeFilter
  
  def init
    dn=NSDate.date.dayNumber
    super(dn,dn+30)
    @name="This Month"
    self
  end
  
end
class LastMonthFilter < TimeFilter
  
  def init
    dn=NSDate.date.dayNumber
    super(dn-30,dn)
    @name="Last Month"
    self
  end
  
end
      
      

class AreaFilter < Filter
  
	def init(area)
		super_init()
		@area = area
		@name=area.name
		@category="Area/Role"
		self
	end
  def showAction?(action)
    action.hasAncestor?(@area)
  end


  def predicate
	return @predicate if @predicate
	@predicate= NSPredicate.predicateWithFormat("%@ in ancestors")
  end

   
  def AreaFilter.buildFilters(actions)
    result=[]
    actions.each do |y| 
        if y.isArea?
          result << AreaFilter.alloc.init(y)
        end
    end
    result=result.sort_by{|f| f.name.to_s}
  end
end

class ContextFilter < Filter

	attr_accessor :context
	
	def init(context)
		super_init()
		@context = context
		@category="Context"
		@name=@context.name unless context==nil
		self
	end
	
	def showAction?(action)
	  (action.context == @context)
	end
	
	def to_s
	  @context.name+"Filter"
	end
	
	def name
	  return "#{@name} (#{@acount}/#{@tcount}/#{@dcount})" if @tcount
	  return "#{@name} (#{@context.actions.count})"
	end
		
	def ContextFilter.buildFilters(contexts)
	  result=[]
	  result <<  NoContextFilter.alloc.init
	  contexts=contexts.sort_by {|c| c.name.to_s }
	  contexts.each {|x| result << ContextFilter.alloc.init(x)}
	  result
	end
	
  def predicate
	return @predicate if @predicate
	@predicate= NSPredicate.predicateWithFormat("context == %@", @context)
  end

   


end

class NoContextFilter < ContextFilter

  def init
    super(nil)
    @name="-INBOX-"
    self
  end

  def showAction?(action)
    (action.context == nil && !action.done?)
  end
  
	def to_s
	  "No Context Filter"
	end
	
  def predicate
	return @predicate if @predicate
	@predicate= NSPredicate.predicateWithFormat("context == nil")
  end

	
end

class ActionableFilter < Filter

  def init
    super()
    @name="Actionable"
    @category="Completion"
    self
  end
  def showAction?(action)
    action.isActionable?
  end
  
  def predicate
	return @predicate if @predicate
	@predicate= NSPredicate.predicateWithFormat("isActionable == true")
  end

  
end
class TaskFilter < Filter

  def init
    super()
    @name="Tasks"
    self
  end
  def showAction?(action)
    action.isTask?
  end

 def predicate
	return @predicate if @predicate
	@predicate= NSPredicate.predicateWithFormat("isTask == true")
  end
  
end

class NextFilter < Filter

  def init
    super()
    @name="Next"
    self
  end
  def showAction?(action)
    action.isNext?
  end
  
   def predicate
	return @predicate if @predicate
	@predicate= NSPredicate.predicateWithFormat("isNext == true")
  end

  
end


class TemplateFilter < Filter

  def init
    super()
    @name="Templates"
    self
  end
  def showAction?(action)
    action.isTemplateUp?
  end
  
   def predicate
	return @predicate if @predicate
	@predicate= NSPredicate.predicateWithFormat("isTemplateUp == true")
  end

  
end

class CameFromEmailFilter < Filter

  def init
    super()
    @name="Came From Email"
    self
  end
  def showAction?(action)
    action.inMailMessageID?
  end
  
   def predicate
	return @predicate if @predicate
	@predicate= NSPredicate.predicateWithFormat("inMailMessageID != null")
  end

  
end

class SentEmailFilter < Filter

  def init
    super()
    @name="Sent Email"
    self
  end
  def showAction?(action)
    action.outMailMessageID?
  end
  
  def predicate
	return @predicate if @predicate
	@predicate= NSPredicate.predicateWithFormat("outMailMessageID != null")
  end

  
end

class DelegatedFromFilter < Filter

  def init
    super()
    @name="Delegated From"
    self
  end
  def showAction?(action)
    action.delegatedFromEmail? || action.delegatedFromID
  end
  
  def predicate
	return @predicate if @predicate
	@predicate= NSPredicate.predicateWithFormat("delegatedFromEmail? != null OR delegatedFromID != null")
  end

  
end
class DelegatedToFilter < Filter

  def init
    super()
    @name="Delegated To"
    self
  end
  def showAction?(action)
    action.delegatedToEmail? || action.delegatedToID
  end

  def predicate
	return @predicate if @predicate
	@predicate= NSPredicate.predicateWithFormat("delegatedToEmail? != null OR delegatedToID != null")
  end

  
end

class RecurringFilter < Filter

  def init
    super()
    @name="Recurring"
    self
  end
  def showAction?(action)
    action.isRecurring?
  end
  
  def predicate
	return @predicate if @predicate
	@predicate= NSPredicate.predicateWithFormat("isRecurring==true")
  end

end

class SomedayFilter < Filter

  def init
    super()
    @name="Someday"
    self
  end
  def showAction?(action)
    action.isSomedayUp?
  end
  
  def predicate
	return @predicate if @predicate
	@predicate= NSPredicate.predicateWithFormat("isSomedayUp==true")
  end


end

class PriorityFilter < Filter
  def init(u,i,name)
    super_init()
    @u=u
    @i=i
    @name=name
    @category="Priority"
    self
  end
  def showAction?(action)
    action.isUrgent? == @u && action.isImportant? == @i
  end
  
  def predicate
	return @predicate if @predicate
	@predicate= NSPredicate.predicateWithFormat("isUrgent==%@ && isImportant==%@",@u,@i)
  end


  def PriorityFilter.buildFilters
    result = []
    result << PriorityFilter.alloc.init(true,true,"Important-Urgent")
    result << PriorityFilter.alloc.init(false,true,"Important")
    result << PriorityFilter.alloc.init(true,false,"Urgent")
    result << PriorityFilter.alloc.init(false,false,"N W D")
  end
end

class CompletionFilter < Filter
  def init(d,name)
    super_init()
    @done = d
    @name = name
    @category="Completion"
    self
  end
  def showAction?(action)
    if (@done != 0)
      return action.done?
    else
      return !action.done?
    end
  end

  def CompletionFilter.buildFilters
    result=[]
    result << CompletionFilter.alloc.init(1,"Done")
    result << CompletionFilter.alloc.init(0,"To-Do")
  end
  
  
  def predicate
	return @predicate if @predicate
	@predicate= NSPredicate.predicateWithFormat("done==%@",@done)
  end

end

class FilterCategory < NSObject
  attr_accessor :filters,:name, :selected
  
  def init(name)
    ##super_init
    @filters=[]
    @name=name
    self
  end
  
  def rootActions
    result=Set.new
    @filters.each {|f|
      result += f.rootActions
    }
    return result.to_a
  end
  
  def tasks
    result=Set.new
    @filters.each {|f|
      result += f.tasks
    }
    return result.to_a
  end
  
  def filterTasks(actions)
    return actions.filteredArrayUsingPredicate(self.predicate)
    result=Set.new
    @filters.each {|f|
      result += f.filterTasks(actions)
    }
    return result.to_a
  end
  
  def showAction?(action)
    @filters.each {|f| return true if f.showAction?(action) }
    return false
  end
  
  def predicate
	return @predicate if @predicate
	cpreds=[]
	@filters.each {|f| cpreds << f}
	@predicate= NSCompoundPredicate.orPredicateWithSubpredicates(cpreds)
  end

  
  def addFilter(filter)
    @filters<< filter
    filter.categoryObject= self
  end

  def category
    self.name
  end
  
  def selected
    return 1 if @filters.any?{|f| f.selected==1}
    return 0
  end
  
  def toggleSelected
  end
  
  def selected=(value)
    setSelected(value)
  end
  
  def setSelected(value)
    willChangeValueForKey "selected"
    if @filters.all?{|f| f.selected.to_i==1 }
      @filters.each{|f| f.selected= 0 }
    else
      @filters.each{|f| f.selected= 1 }
    end
    didChangeValueForKey "selected"
  end
  
  def updateSelected
    willChangeValueForKey "selected"
    didChangeValueForKey "selected"
  end
  
  
end

