/* Copyright (c) 1993 by Sanjay Ghemawat */
#ifndef _DATESET_H
#define _DATESET_H

#include <stdio.h>
#include "Array.h"
#include "Date.h"
#include "smallintset.h"

declareArray(DateList,Date)

class DateSetRep;
class Lexer;

/*
 * A date set is a mutable set of dates.
 */

class DateSet {
  public:
    /*
     * effects	post(*this) = empty
     */
    DateSet();

    /*
     * effects	post(*this) = d
     */
    DateSet(DateSet const& d);

    ~DateSet();

    /*
     * modifies	*this
     * effects	post(*this) = d
     */
    void operator = (DateSet const& d);

    /*
     * effects	Returns true iff d is in *this.
     */
    int contains(Date d) const;

    /*
     * effects	Returns true iff *this has more than one element.
     */
    int repeats() const;

    /*
     * effects	Returns true iff *this has zero elements
     */
    int empty() const;

    /*
     * modifies	result
     * effects	If *this is not empty, sets result to the smallest element in
     *		*this and returns true.  Else returns false.
     */
    int  first(Date& result) const;

    /*
     * modifies result
     * effects	If *this contains a date greater than d, then sets
     *		result to the smallest such date and returns true.
     *		Else returns false.
     */
    int next(Date d, Date& result) const;

    /*
     * effects	Returns true iff first occurrence of s1 occurs strictly
     *		before the first occurrence of s2.  If a set is empty,
     *		its first occurrence is assumed to occur after all legal
     *		dates.
     */
    static int occurs_before(DateSet const& s1, DateSet const& s2);

    /*
     * effects	Returns -1, 0, +1 depending on whether the first
     *		occurrence of s1 occurs strictly before, on the same date
     *		as, or strictly after, the first occurrence of s2.
     *		Empty sets are treated as in occurs_before.
     */
    static int occurs_compare(DateSet const& s1, DateSet const& s2);

    /*
     * Repetition type.
     */
    enum RepeatType {
	None,
	Daily,
	Weekly,
	BiWeekly,
	ThreeWeekly,
	FourWeekly,
	Monthly,
	TwoMonthly,
	ThreeMonthly,
	FourMonthly,
	SixMonthly,
	Annual,
	Other
	};

    /*
     * effects	Returns description of set contents.
     */
    RepeatType type() const;

    /*
     * modifies	*this
     * effects	post(*this) = the empty set
     */
    void set_empty();

    /*
     * modifies	*this
     * effects	post(*this) = { d }
     */
    void set_date(Date d);

    /*
     * requires	interval > 0
     * modifies	*this
     * effects	post(*this) = { d | d = (anchor + k*interval) }
     *					where k is an integer.
     */
    void set_day_based_repeat(int interval, Date anchor);

    /*
     * requires	interval > 0
     * modifies	*this
     * effects	post(*this) = { d | d is an integral multiple of <interval>
     *				    months away from <anchor> }
     */
    void set_month_based_repeat(int interval, Date anchor);

    /*
     * modifies	*this
     * effects	post(*this) = { d | weekday(d) in days and month(d) in months }
     */
    void set_week_set(SmallIntSet days, SmallIntSet months);
    
    /*
     * modifies	*this
     * effects	post(*this) = { d | monthday(d) in days and
     *				    month(d) in months }
     */
    void set_month_set(SmallIntSet days, SmallIntSet months);

    /*
     * modifies	*this
     * effects	post(*this) = pre(*this) - { d | d < start }
     */
    void set_start(Date start);

    /*
     * modifies	*this
     * effects	post(*this) = pre(*this) - { d | d > finish }
     */
    void set_finish(Date finish);

    /*
     * modifies	*this
     * effects	post(*this) = pre(*this) - { d }
     */
    void delete_occurrence(Date d);

    /*
     * modifies	*this
     * effects	post(*this) = string representation of dateset read from lexer.
     *		Returns true iff successful.  If not successful, *this may
     *		have arbitrary contents.
     */
    int read(Lexer* lexer);

    /*
     * effects	Writes a string representation of *this to file.
     */
    void write(FILE* file) const;
  private:
    DateSetRep*	rep;		/* Type specific representation */
    int		normalized;	/* Rep has been normalized? */
    DateList	deleted;	/* List of deleted dates */

    /* Range limit on dates */
    Date	start;
    Date	finish;

    /*
     * Abstraction Function
     *
     * A(this) = { d | d is in A(rep) and d is not in deleted and
     *		       d >= start and d <= finish }.
     */

    /*
     * Normalize representation.
     */
    void normalize() const;
};

#endif /* _DATESET_H */
