/*
 * 创建日期 2004-4-23
 *
 * 更改所生成文件模板为
 * 窗口 > 首选项 > Java > 代码生成 > 代码和注释
 */
package com.poweroa.generation;

import java.io.IOException;
import java.util.Calendar;
import java.util.Locale;
import java.util.Map;
import java.util.TimeZone;

import org.apache.avalon.framework.parameters.Parameters;
import org.apache.cocoon.ProcessingException;
import org.apache.cocoon.environment.SourceResolver;
import org.xml.sax.SAXException;

/**
 * @author roy
 *
 * 更改所生成类型注释的模板为
 * 窗口 > 首选项 > Java > 代码生成 > 代码和注释
 */
public class CalendarGenerator
	extends org.apache.cocoon.generation.CalendarGenerator {
	protected static final String TODAY_ATTR_NAME = "today";
	protected static final String TYPE_ATTR_NAME = "type";

	protected static final String MONTH_NODE_NAME = "month";

	protected static final String PREV_DAY_ATTR_NAME = "prevDay";
	protected static final String NEXT_DAY_ATTR_NAME = "nextDay";

	protected static final String TYPE_YEAR_NAME = "year";
	protected static final String TYPE_MONTH_NAME = "month";
	protected static final String TYPE_TWO_WEEKS_NAME = "two_weeks";
	protected static final String TYPE_WEEK_NAME = "week";
	protected static final String TYPE_WORK_DAY_NAME = "work_day";
	protected static final String TYPE_TWO_DAYS_NAME = "two_days";
	protected static final String TYPE_DAY_NAME = "day";

	/** The day to generate the calendar for */
	protected int day;

	protected String calendar_type;
	protected String today;
	/* （非 Javadoc）
	 * @see org.apache.cocoon.generation.Generator#generate()
	 */
	public void generate() throws SAXException, ProcessingException {
		Calendar tmp =
			Calendar.getInstance(TimeZone.getTimeZone("UTC"), locale);
		this.today = dateFormatter.format(tmp.getTime());
		tmp = null;
		if (calendar_type.equals(TYPE_YEAR_NAME)) {
			generate_year();
		} else if (calendar_type.equals(TYPE_TWO_WEEKS_NAME)) {
			generate_two_weeks();
		} else if (calendar_type.equals(TYPE_WEEK_NAME)) {
			generate_week();
		} else if (calendar_type.equals(TYPE_WORK_DAY_NAME)) {
			generate_work_day();
		} else if (calendar_type.equals(TYPE_TWO_DAYS_NAME)) {
			generate_two_days();
		} else if (calendar_type.equals(TYPE_DAY_NAME)) {
			generate_day();
		} else {
			//缺省都是month
			calendar_type = TYPE_MONTH_NAME;
			generate_month();
		}
		today = "";
	}

	/* （非 Javadoc）
	 * @see org.apache.cocoon.sitemap.SitemapModelComponent#setup(org.apache.cocoon.environment.SourceResolver, java.util.Map, java.lang.String, org.apache.avalon.framework.parameters.Parameters)
	 */
	public void setup(
		SourceResolver resolver,
		Map objectModel,
		String src,
		Parameters par)
		throws ProcessingException, SAXException, IOException {
		super.setup(resolver, objectModel, src, par);
		this.calendar_type = par.getParameter("type", TYPE_MONTH_NAME);
		Calendar now = Calendar.getInstance(locale);
		this.day = par.getParameterAsInteger("day", now.get(Calendar.DATE));
	}

	/* （非 Javadoc）
	 * @see org.apache.cocoon.generation.CalendarGenerator#addContent(java.util.Calendar, java.util.Locale)
	 */

	public void generate_month() throws SAXException, ProcessingException {
		Calendar start =
			Calendar.getInstance(TimeZone.getTimeZone("UTC"), locale);
		start.clear();
		start.set(Calendar.YEAR, this.year);
		start.set(Calendar.MONTH, this.month);
		start.set(Calendar.DAY_OF_MONTH, 1);
		Calendar end = (Calendar) start.clone();
		end.add(Calendar.MONTH, 1);

		// Determine previous and next months
		Calendar prevMonth = (Calendar) start.clone();
		prevMonth.add(Calendar.MONTH, -1);

		this.contentHandler.startDocument();
		this.contentHandler.startPrefixMapping(PREFIX, URI);
		attributes.clear();

		// add type by roy
		attributes.addAttribute(
			"",
			TYPE_ATTR_NAME,
			TYPE_ATTR_NAME,
			"CDATA",
			this.calendar_type);

		attributes.addAttribute(
			"",
			YEAR_ATTR_NAME,
			YEAR_ATTR_NAME,
			"CDATA",
			String.valueOf(year));
		attributes.addAttribute(
			"",
			MONTH_ATTR_NAME,
			MONTH_ATTR_NAME,
			"CDATA",
			monthFormatter.format(start.getTime()));

		// Add previous and next month
		attributes.addAttribute(
			"",
			PREV_YEAR_ATTR_NAME,
			PREV_YEAR_ATTR_NAME,
			"CDATA",
			String.valueOf(prevMonth.get(Calendar.YEAR)));
		attributes.addAttribute(
			"",
			PREV_MONTH_ATTR_NAME,
			PREV_MONTH_ATTR_NAME,
			"CDATA",
			monthNumberFormatter.format(prevMonth.get(Calendar.MONTH) + 1));
		attributes.addAttribute(
			"",
			NEXT_YEAR_ATTR_NAME,
			NEXT_YEAR_ATTR_NAME,
			"CDATA",
			String.valueOf(end.get(Calendar.YEAR)));
		attributes.addAttribute(
			"",
			NEXT_MONTH_ATTR_NAME,
			NEXT_MONTH_ATTR_NAME,
			"CDATA",
			monthNumberFormatter.format(end.get(Calendar.MONTH) + 1));
		//add today by roy
		attributes.addAttribute(
			"",
			TODAY_ATTR_NAME,
			TODAY_ATTR_NAME,
			"CDATA",
			today);
		this.contentHandler.startElement(
			URI,
			CALENDAR_NODE_NAME,
			PREFIX + ':' + CALENDAR_NODE_NAME,
			attributes);
		int weekNo = start.get(Calendar.WEEK_OF_MONTH);
		if (start.get(Calendar.DAY_OF_WEEK) != start.getFirstDayOfWeek()) {
			attributes.clear();
			attributes.addAttribute(
				"",
				NUMBER_ATTR_NAME,
				NUMBER_ATTR_NAME,
				"CDATA",
				String.valueOf(weekNo));
			this.contentHandler.startElement(
				URI,
				WEEK_NODE_NAME,
				PREFIX + ':' + WEEK_NODE_NAME,
				attributes);
		}
		while (start.before(end)) {
			if (start.get(Calendar.DAY_OF_WEEK) == start.getFirstDayOfWeek()) {
				weekNo = start.get(Calendar.WEEK_OF_MONTH);
				attributes.clear();
				attributes.addAttribute(
					"",
					NUMBER_ATTR_NAME,
					NUMBER_ATTR_NAME,
					"CDATA",
					String.valueOf(weekNo));
				this.contentHandler.startElement(
					URI,
					WEEK_NODE_NAME,
					PREFIX + ':' + WEEK_NODE_NAME,
					attributes);
			}
			attributes.clear();
			attributes.addAttribute(
				"",
				NUMBER_ATTR_NAME,
				NUMBER_ATTR_NAME,
				"CDATA",
				String.valueOf(start.get(Calendar.DAY_OF_MONTH)));
			attributes.addAttribute(
				"",
				DATE_ATTR_NAME,
				DATE_ATTR_NAME,
				"CDATA",
				dateFormatter.format(start.getTime()));
			this.contentHandler.startElement(
				URI,
				DAY_NODE_NAME,
				PREFIX + ':' + DAY_NODE_NAME,
				attributes);
			addContent(start, locale);
			this.contentHandler.endElement(
				URI,
				DAY_NODE_NAME,
				PREFIX + ':' + DAY_NODE_NAME);
			start.add(Calendar.DAY_OF_MONTH, 1);
			if (start.get(Calendar.DAY_OF_WEEK) == start.getFirstDayOfWeek()
				|| !start.before(end)) {
				this.contentHandler.endElement(
					URI,
					WEEK_NODE_NAME,
					PREFIX + ':' + WEEK_NODE_NAME);
			}
		}

		this.contentHandler.endElement(
			URI,
			CALENDAR_NODE_NAME,
			PREFIX + ':' + CALENDAR_NODE_NAME);
		this.contentHandler.endPrefixMapping(PREFIX);
		this.contentHandler.endDocument();
	}

	/* （非 Javadoc）
	 * @see org.apache.cocoon.generation.CalendarGenerator#addContent(java.util.Calendar, java.util.Locale)
	 */

	public void generate_year() throws SAXException, ProcessingException {
		Calendar start =
			Calendar.getInstance(TimeZone.getTimeZone("UTC"), locale);
		start.clear();
		start.set(Calendar.YEAR, this.year);
		start.set(Calendar.MONTH, Calendar.JANUARY);
		start.set(Calendar.DAY_OF_MONTH, 1);

		Calendar end = (Calendar) start.clone();
		end.add(Calendar.YEAR, 1);

		Calendar prev = (Calendar) start.clone();
		prev.add(Calendar.YEAR, -1);

		this.contentHandler.startDocument();
		this.contentHandler.startPrefixMapping(PREFIX, URI);
		attributes.clear();

		attributes.addAttribute(
			"",
			TYPE_ATTR_NAME,
			TYPE_ATTR_NAME,
			"CDATA",
			this.calendar_type);

		attributes.addAttribute(
			"",
			YEAR_ATTR_NAME,
			YEAR_ATTR_NAME,
			"CDATA",
			String.valueOf(year));

		// Add previous and next year
		attributes.addAttribute(
			"",
			PREV_YEAR_ATTR_NAME,
			PREV_YEAR_ATTR_NAME,
			"CDATA",
			String.valueOf(prev.get(Calendar.YEAR)));
		attributes.addAttribute(
			"",
			NEXT_YEAR_ATTR_NAME,
			NEXT_YEAR_ATTR_NAME,
			"CDATA",
			String.valueOf(end.get(Calendar.YEAR)));

		//add today by roy
		attributes.addAttribute(
			"",
			TODAY_ATTR_NAME,
			TODAY_ATTR_NAME,
			"CDATA",
			today);

		this.contentHandler.startElement(
			URI,
			CALENDAR_NODE_NAME,
			PREFIX + ':' + CALENDAR_NODE_NAME,
			attributes);
		int month = -1;

		while (start.before(end)) {

			int currentMonth = start.get(Calendar.MONTH);
			if (month != currentMonth) {
				attributes.clear();
				attributes.addAttribute(
					"",
					NUMBER_ATTR_NAME,
					NUMBER_ATTR_NAME,
					"CDATA",
					String.valueOf(currentMonth + 1));
				attributes.addAttribute(
					"",
					MONTH_ATTR_NAME,
					MONTH_ATTR_NAME,
					"CDATA",
					monthFormatter.format(start.getTime()));
				this.contentHandler.startElement(
					URI,
					MONTH_NODE_NAME,
					PREFIX + ':' + MONTH_NODE_NAME,
					attributes);
				month = currentMonth;
			}

			if (start.get(Calendar.DAY_OF_WEEK) == start.getFirstDayOfWeek()
				|| start.get(Calendar.DAY_OF_YEAR) == 1
				|| start.get(Calendar.DAY_OF_MONTH) == 1) {
				int weekNo = start.get(Calendar.WEEK_OF_YEAR);
				attributes.clear();
				attributes.addAttribute(
					"",
					NUMBER_ATTR_NAME,
					NUMBER_ATTR_NAME,
					"CDATA",
					String.valueOf(weekNo));
				this.contentHandler.startElement(
					URI,
					WEEK_NODE_NAME,
					PREFIX + ':' + WEEK_NODE_NAME,
					attributes);
			}

			attributes.addAttribute(
				"",
				NUMBER_ATTR_NAME,
				NUMBER_ATTR_NAME,
				"CDATA",
				String.valueOf(start.get(Calendar.DAY_OF_MONTH)));
			attributes.addAttribute(
				"",
				DATE_ATTR_NAME,
				DATE_ATTR_NAME,
				"CDATA",
				dateFormatter.format(start.getTime()));
			this.contentHandler.startElement(
				URI,
				DAY_NODE_NAME,
				PREFIX + ':' + DAY_NODE_NAME,
				attributes);
			addContent(start, locale);
			this.contentHandler.endElement(
				URI,
				DAY_NODE_NAME,
				PREFIX + ':' + DAY_NODE_NAME);

			start.add(Calendar.DATE, 1); //加一天
			if (start.get(Calendar.DAY_OF_WEEK) == start.getFirstDayOfWeek()
				|| !start.before(end)
				|| start.get(Calendar.DAY_OF_MONTH) == 1) {
				this.contentHandler.endElement(
					URI,
					WEEK_NODE_NAME,
					PREFIX + ':' + WEEK_NODE_NAME);
			}
			currentMonth = start.get(Calendar.MONTH);
			if (month != currentMonth) {
				this.contentHandler.endElement(
					URI,
					MONTH_NODE_NAME,
					PREFIX + ':' + MONTH_NODE_NAME);
			}

		}

		this.contentHandler.endElement(
			URI,
			CALENDAR_NODE_NAME,
			PREFIX + ':' + CALENDAR_NODE_NAME);
		this.contentHandler.endPrefixMapping(PREFIX);
		this.contentHandler.endDocument();
	}

	/* （非 Javadoc）
	 * @see org.apache.cocoon.generation.CalendarGenerator#addContent(java.util.Calendar, java.util.Locale)
	 */

	public void generate_two_weeks() throws SAXException, ProcessingException {
		Calendar start =
			Calendar.getInstance(TimeZone.getTimeZone("UTC"), locale);
		start.clear();
		start.set(Calendar.YEAR, this.year);
		start.set(Calendar.MONTH, this.month);
		start.set(Calendar.DAY_OF_MONTH, day);
		if (start.get(Calendar.DAY_OF_WEEK) != start.getFirstDayOfWeek()) {
			int days =
				start.get(Calendar.DAY_OF_WEEK) - start.getFirstDayOfWeek();
			if (days > 0) {
				start.add(Calendar.DAY_OF_MONTH, -days);
			} else {
				start.add(Calendar.DAY_OF_MONTH, -days - 7);
			}
		}
		Calendar end = (Calendar) start.clone();
		end.add(Calendar.DAY_OF_MONTH, 14);

		Calendar next = (Calendar) start.clone();
		next.add(Calendar.DAY_OF_MONTH, 7);

		// Determine previous and next months
		Calendar prev = (Calendar) start.clone();
		prev.add(Calendar.DAY_OF_MONTH, -7);

		this.contentHandler.startDocument();
		this.contentHandler.startPrefixMapping(PREFIX, URI);
		attributes.clear();
		attributes.addAttribute(
			"",
			YEAR_ATTR_NAME,
			YEAR_ATTR_NAME,
			"CDATA",
			String.valueOf(year));
		attributes.addAttribute(
			"",
			MONTH_ATTR_NAME,
			MONTH_ATTR_NAME,
			"CDATA",
			monthFormatter.format(start.getTime()));

		// Add previous and next month
		attributes.addAttribute(
			"",
			PREV_YEAR_ATTR_NAME,
			PREV_YEAR_ATTR_NAME,
			"CDATA",
			String.valueOf(prev.get(Calendar.YEAR)));
		attributes.addAttribute(
			"",
			PREV_MONTH_ATTR_NAME,
			PREV_MONTH_ATTR_NAME,
			"CDATA",
			monthNumberFormatter.format(prev.get(Calendar.MONTH) + 1));
		attributes.addAttribute(
			"",
			PREV_DAY_ATTR_NAME,
			PREV_DAY_ATTR_NAME,
			"CDATA",
			String.valueOf(prev.get(Calendar.DAY_OF_MONTH)));
		attributes.addAttribute(
			"",
			NEXT_YEAR_ATTR_NAME,
			NEXT_YEAR_ATTR_NAME,
			"CDATA",
			String.valueOf(next.get(Calendar.YEAR)));
		attributes.addAttribute(
			"",
			NEXT_MONTH_ATTR_NAME,
			NEXT_MONTH_ATTR_NAME,
			"CDATA",
			monthNumberFormatter.format(next.get(Calendar.MONTH) + 1));
		attributes.addAttribute(
			"",
			NEXT_DAY_ATTR_NAME,
			NEXT_DAY_ATTR_NAME,
			"CDATA",
			String.valueOf(next.get(Calendar.DAY_OF_MONTH)));
		//add today by roy
		attributes.addAttribute(
			"",
			TODAY_ATTR_NAME,
			TODAY_ATTR_NAME,
			"CDATA",
			today);
		this.contentHandler.startElement(
			URI,
			CALENDAR_NODE_NAME,
			PREFIX + ':' + CALENDAR_NODE_NAME,
			attributes);

		while (start.before(end)) {
			if (start.get(Calendar.DAY_OF_WEEK) == start.getFirstDayOfWeek()) {
				attributes.clear();
				attributes.addAttribute(
					"",
					NUMBER_ATTR_NAME,
					NUMBER_ATTR_NAME,
					"CDATA",
					String.valueOf(start.get(Calendar.WEEK_OF_YEAR)));
				this.contentHandler.startElement(
					URI,
					WEEK_NODE_NAME,
					PREFIX + ':' + WEEK_NODE_NAME,
					attributes);
			}
			attributes.clear();
			attributes.addAttribute(
				"",
				YEAR_ATTR_NAME,
				YEAR_ATTR_NAME,
				"CDATA",
				String.valueOf(start.get(Calendar.YEAR)));
			attributes.addAttribute(
				"",
				MONTH_ATTR_NAME,
				MONTH_ATTR_NAME,
				"CDATA",
				String.valueOf(start.get(Calendar.MONTH) + 1));

			attributes.addAttribute(
				"",
				NUMBER_ATTR_NAME,
				NUMBER_ATTR_NAME,
				"CDATA",
				String.valueOf(start.get(Calendar.DAY_OF_MONTH)));
			attributes.addAttribute(
				"",
				DATE_ATTR_NAME,
				DATE_ATTR_NAME,
				"CDATA",
				dateFormatter.format(start.getTime()));
			this.contentHandler.startElement(
				URI,
				DAY_NODE_NAME,
				PREFIX + ':' + DAY_NODE_NAME,
				attributes);
			addContent(start, locale);
			this.contentHandler.endElement(
				URI,
				DAY_NODE_NAME,
				PREFIX + ':' + DAY_NODE_NAME);
			start.add(Calendar.DAY_OF_MONTH, 1);
			if (start.get(Calendar.DAY_OF_WEEK) == start.getFirstDayOfWeek()
				|| !start.before(end)) {
				this.contentHandler.endElement(
					URI,
					WEEK_NODE_NAME,
					PREFIX + ':' + WEEK_NODE_NAME);
			}
		}

		this.contentHandler.endElement(
			URI,
			CALENDAR_NODE_NAME,
			PREFIX + ':' + CALENDAR_NODE_NAME);
		this.contentHandler.endPrefixMapping(PREFIX);
		this.contentHandler.endDocument();
	}

	/* （非 Javadoc）
	 * @see org.apache.cocoon.generation.CalendarGenerator#addContent(java.util.Calendar, java.util.Locale)
	 */

	public void generate_week() throws SAXException, ProcessingException {
		Calendar start =
			Calendar.getInstance(TimeZone.getTimeZone("UTC"), locale);
		start.clear();
		start.set(Calendar.YEAR, this.year);
		start.set(Calendar.MONTH, this.month);
		start.set(Calendar.DAY_OF_MONTH, day);
		if (start.get(Calendar.DAY_OF_WEEK) != start.getFirstDayOfWeek()) {
			int days =
				start.get(Calendar.DAY_OF_WEEK) - start.getFirstDayOfWeek();
			if (days > 0) {
				start.add(Calendar.DAY_OF_MONTH, -days);
			} else {
				start.add(Calendar.DAY_OF_MONTH, -days - 7);
			}
		}
		Calendar end = (Calendar) start.clone();
		end.add(Calendar.DAY_OF_MONTH, 7);

		// Determine previous and next months
		Calendar prev = (Calendar) start.clone();
		prev.add(Calendar.DAY_OF_MONTH, -7);

		this.contentHandler.startDocument();
		this.contentHandler.startPrefixMapping(PREFIX, URI);
		attributes.clear();
		attributes.addAttribute(
			"",
			YEAR_ATTR_NAME,
			YEAR_ATTR_NAME,
			"CDATA",
			String.valueOf(year));
		attributes.addAttribute(
			"",
			MONTH_ATTR_NAME,
			MONTH_ATTR_NAME,
			"CDATA",
			monthFormatter.format(start.getTime()));

		// Add previous and next month
		attributes.addAttribute(
			"",
			PREV_YEAR_ATTR_NAME,
			PREV_YEAR_ATTR_NAME,
			"CDATA",
			String.valueOf(prev.get(Calendar.YEAR)));
		attributes.addAttribute(
			"",
			PREV_MONTH_ATTR_NAME,
			PREV_MONTH_ATTR_NAME,
			"CDATA",
			monthNumberFormatter.format(prev.get(Calendar.MONTH) + 1));
		attributes.addAttribute(
			"",
			PREV_DAY_ATTR_NAME,
			PREV_DAY_ATTR_NAME,
			"CDATA",
			String.valueOf(prev.get(Calendar.DAY_OF_MONTH)));
		attributes.addAttribute(
			"",
			NEXT_YEAR_ATTR_NAME,
			NEXT_YEAR_ATTR_NAME,
			"CDATA",
			String.valueOf(end.get(Calendar.YEAR)));
		attributes.addAttribute(
			"",
			NEXT_MONTH_ATTR_NAME,
			NEXT_MONTH_ATTR_NAME,
			"CDATA",
			monthNumberFormatter.format(end.get(Calendar.MONTH) + 1));
		attributes.addAttribute(
			"",
			NEXT_DAY_ATTR_NAME,
			NEXT_DAY_ATTR_NAME,
			"CDATA",
			String.valueOf(end.get(Calendar.DAY_OF_MONTH)));
		//add today by roy
		attributes.addAttribute(
			"",
			TODAY_ATTR_NAME,
			TODAY_ATTR_NAME,
			"CDATA",
			today);
		this.contentHandler.startElement(
			URI,
			CALENDAR_NODE_NAME,
			PREFIX + ':' + CALENDAR_NODE_NAME,
			attributes);

		while (start.before(end)) {
			if (start.get(Calendar.DAY_OF_WEEK) == start.getFirstDayOfWeek()) {
				attributes.clear();
				attributes.addAttribute(
					"",
					NUMBER_ATTR_NAME,
					NUMBER_ATTR_NAME,
					"CDATA",
					String.valueOf(start.get(Calendar.WEEK_OF_YEAR)));
				this.contentHandler.startElement(
					URI,
					WEEK_NODE_NAME,
					PREFIX + ':' + WEEK_NODE_NAME,
					attributes);
			}
			attributes.clear();
			attributes.addAttribute(
				"",
				YEAR_ATTR_NAME,
				YEAR_ATTR_NAME,
				"CDATA",
				String.valueOf(start.get(Calendar.YEAR)));
			attributes.addAttribute(
				"",
				MONTH_ATTR_NAME,
				MONTH_ATTR_NAME,
				"CDATA",
				String.valueOf(start.get(Calendar.MONTH) + 1));
			attributes.addAttribute(
				"",
				NUMBER_ATTR_NAME,
				NUMBER_ATTR_NAME,
				"CDATA",
				String.valueOf(start.get(Calendar.DAY_OF_MONTH)));
			attributes.addAttribute(
				"",
				DATE_ATTR_NAME,
				DATE_ATTR_NAME,
				"CDATA",
				dateFormatter.format(start.getTime()));
			this.contentHandler.startElement(
				URI,
				DAY_NODE_NAME,
				PREFIX + ':' + DAY_NODE_NAME,
				attributes);
			addContent(start, locale);
			this.contentHandler.endElement(
				URI,
				DAY_NODE_NAME,
				PREFIX + ':' + DAY_NODE_NAME);
			start.add(Calendar.DAY_OF_MONTH, 1);
			if (start.get(Calendar.DAY_OF_WEEK) == start.getFirstDayOfWeek()
				|| !start.before(end)) {
				this.contentHandler.endElement(
					URI,
					WEEK_NODE_NAME,
					PREFIX + ':' + WEEK_NODE_NAME);
			}
		}

		this.contentHandler.endElement(
			URI,
			CALENDAR_NODE_NAME,
			PREFIX + ':' + CALENDAR_NODE_NAME);
		this.contentHandler.endPrefixMapping(PREFIX);
		this.contentHandler.endDocument();
	}

	/* （非 Javadoc）
	 * @see org.apache.cocoon.generation.CalendarGenerator#addContent(java.util.Calendar, java.util.Locale)
	 */

	public void generate_two_days() throws SAXException, ProcessingException {
		Calendar start =
			Calendar.getInstance(TimeZone.getTimeZone("UTC"), locale);
		start.clear();
		start.set(Calendar.YEAR, this.year);
		start.set(Calendar.MONTH, this.month);
		start.set(Calendar.DAY_OF_MONTH, day);

		Calendar end = (Calendar) start.clone();
		end.add(Calendar.DAY_OF_MONTH, 2);

		Calendar next = (Calendar) start.clone();
		next.add(Calendar.DAY_OF_MONTH, 1);
		// Determine previous and next months
		Calendar prev = (Calendar) start.clone();
		prev.add(Calendar.DAY_OF_MONTH, -1);

		this.contentHandler.startDocument();
		this.contentHandler.startPrefixMapping(PREFIX, URI);
		attributes.clear();
		attributes.addAttribute(
			"",
			YEAR_ATTR_NAME,
			YEAR_ATTR_NAME,
			"CDATA",
			String.valueOf(year));
		attributes.addAttribute(
			"",
			MONTH_ATTR_NAME,
			MONTH_ATTR_NAME,
			"CDATA",
			monthFormatter.format(start.getTime()));

		// Add previous and next month
		attributes.addAttribute(
			"",
			PREV_YEAR_ATTR_NAME,
			PREV_YEAR_ATTR_NAME,
			"CDATA",
			String.valueOf(prev.get(Calendar.YEAR)));
		attributes.addAttribute(
			"",
			PREV_MONTH_ATTR_NAME,
			PREV_MONTH_ATTR_NAME,
			"CDATA",
			monthNumberFormatter.format(prev.get(Calendar.MONTH) + 1));
		attributes.addAttribute(
			"",
			PREV_DAY_ATTR_NAME,
			PREV_DAY_ATTR_NAME,
			"CDATA",
			String.valueOf(prev.get(Calendar.DAY_OF_MONTH)));
		attributes.addAttribute(
			"",
			NEXT_YEAR_ATTR_NAME,
			NEXT_YEAR_ATTR_NAME,
			"CDATA",
			String.valueOf(next.get(Calendar.YEAR)));
		attributes.addAttribute(
			"",
			NEXT_MONTH_ATTR_NAME,
			NEXT_MONTH_ATTR_NAME,
			"CDATA",
			monthNumberFormatter.format(next.get(Calendar.MONTH) + 1));
		attributes.addAttribute(
			"",
			NEXT_DAY_ATTR_NAME,
			NEXT_DAY_ATTR_NAME,
			"CDATA",
			String.valueOf(next.get(Calendar.DAY_OF_MONTH)));
		//add today by roy
		attributes.addAttribute(
			"",
			TODAY_ATTR_NAME,
			TODAY_ATTR_NAME,
			"CDATA",
			today);
		this.contentHandler.startElement(
			URI,
			CALENDAR_NODE_NAME,
			PREFIX + ':' + CALENDAR_NODE_NAME,
			attributes);
		while (start.before(end)) {
			attributes.clear();
			attributes.addAttribute(
				"",
				YEAR_ATTR_NAME,
				YEAR_ATTR_NAME,
				"CDATA",
				String.valueOf(start.get(Calendar.YEAR)));
			attributes.addAttribute(
				"",
				MONTH_ATTR_NAME,
				MONTH_ATTR_NAME,
				"CDATA",
				String.valueOf(start.get(Calendar.MONTH) + 1));
			attributes.addAttribute(
				"",
				NUMBER_ATTR_NAME,
				NUMBER_ATTR_NAME,
				"CDATA",
				String.valueOf(start.get(Calendar.DAY_OF_MONTH)));
			attributes.addAttribute(
				"",
				DATE_ATTR_NAME,
				DATE_ATTR_NAME,
				"CDATA",
				dateFormatter.format(start.getTime()));
			this.contentHandler.startElement(
				URI,
				DAY_NODE_NAME,
				PREFIX + ':' + DAY_NODE_NAME,
				attributes);
			addContent(start, locale);
			this.contentHandler.endElement(
				URI,
				DAY_NODE_NAME,
				PREFIX + ':' + DAY_NODE_NAME);
			start.add(Calendar.DAY_OF_MONTH, 1);
		}
		this.contentHandler.endElement(
			URI,
			CALENDAR_NODE_NAME,
			PREFIX + ':' + CALENDAR_NODE_NAME);
		this.contentHandler.endPrefixMapping(PREFIX);
		this.contentHandler.endDocument();
	}

	/* （非 Javadoc）
	 * @see org.apache.cocoon.generation.CalendarGenerator#addContent(java.util.Calendar, java.util.Locale)
	 */

	public void generate_work_day() throws SAXException, ProcessingException {
		Calendar start =
			Calendar.getInstance(TimeZone.getTimeZone("UTC"), locale);
		start.clear();
		start.set(Calendar.YEAR, this.year);
		start.set(Calendar.MONTH, this.month);
		start.set(Calendar.DAY_OF_MONTH, day);
		if (start.get(Calendar.DAY_OF_WEEK) != start.getFirstDayOfWeek()) {
			int days =
				start.get(Calendar.DAY_OF_WEEK) - start.getFirstDayOfWeek();
			if (days > 0) {
				start.add(Calendar.DAY_OF_MONTH, -days);
			} else {
				start.add(Calendar.DAY_OF_MONTH, -days - 7);
			}
		}
		Calendar end = (Calendar) start.clone();
		end.add(Calendar.DAY_OF_MONTH, 7);

		// Determine previous and next months
		Calendar prev = (Calendar) start.clone();
		prev.add(Calendar.DAY_OF_MONTH, -7);

		this.contentHandler.startDocument();
		this.contentHandler.startPrefixMapping(PREFIX, URI);
		attributes.clear();
		attributes.addAttribute(
			"",
			YEAR_ATTR_NAME,
			YEAR_ATTR_NAME,
			"CDATA",
			String.valueOf(year));
		attributes.addAttribute(
			"",
			MONTH_ATTR_NAME,
			MONTH_ATTR_NAME,
			"CDATA",
			monthFormatter.format(start.getTime()));

		// Add previous and next month
		attributes.addAttribute(
			"",
			PREV_YEAR_ATTR_NAME,
			PREV_YEAR_ATTR_NAME,
			"CDATA",
			String.valueOf(prev.get(Calendar.YEAR)));
		attributes.addAttribute(
			"",
			PREV_MONTH_ATTR_NAME,
			PREV_MONTH_ATTR_NAME,
			"CDATA",
			monthNumberFormatter.format(prev.get(Calendar.MONTH) + 1));
		attributes.addAttribute(
			"",
			PREV_DAY_ATTR_NAME,
			PREV_DAY_ATTR_NAME,
			"CDATA",
			String.valueOf(prev.get(Calendar.DAY_OF_MONTH)));
		attributes.addAttribute(
			"",
			NEXT_YEAR_ATTR_NAME,
			NEXT_YEAR_ATTR_NAME,
			"CDATA",
			String.valueOf(end.get(Calendar.YEAR)));
		attributes.addAttribute(
			"",
			NEXT_MONTH_ATTR_NAME,
			NEXT_MONTH_ATTR_NAME,
			"CDATA",
			monthNumberFormatter.format(end.get(Calendar.MONTH) + 1));
		attributes.addAttribute(
			"",
			NEXT_DAY_ATTR_NAME,
			NEXT_DAY_ATTR_NAME,
			"CDATA",
			String.valueOf(end.get(Calendar.DAY_OF_MONTH)));
		//add today by roy
		attributes.addAttribute(
			"",
			TODAY_ATTR_NAME,
			TODAY_ATTR_NAME,
			"CDATA",
			today);
		this.contentHandler.startElement(
			URI,
			CALENDAR_NODE_NAME,
			PREFIX + ':' + CALENDAR_NODE_NAME,
			attributes);

		while (start.before(end)) {
			if (start.get(Calendar.DAY_OF_WEEK) == start.getFirstDayOfWeek()) {
				attributes.clear();
				attributes.addAttribute(
					"",
					NUMBER_ATTR_NAME,
					NUMBER_ATTR_NAME,
					"CDATA",
					String.valueOf(start.get(Calendar.WEEK_OF_YEAR)));
				this.contentHandler.startElement(
					URI,
					WEEK_NODE_NAME,
					PREFIX + ':' + WEEK_NODE_NAME,
					attributes);
			}
			if (start.get(Calendar.DAY_OF_WEEK) != Calendar.SUNDAY
				&& start.get(Calendar.DAY_OF_WEEK) != Calendar.SATURDAY) {

				attributes.clear();
				attributes.addAttribute(
					"",
					YEAR_ATTR_NAME,
					YEAR_ATTR_NAME,
					"CDATA",
					String.valueOf(start.get(Calendar.YEAR)));
				attributes.addAttribute(
					"",
					MONTH_ATTR_NAME,
					MONTH_ATTR_NAME,
					"CDATA",
					String.valueOf(start.get(Calendar.MONTH) + 1));
				attributes.addAttribute(
					"",
					NUMBER_ATTR_NAME,
					NUMBER_ATTR_NAME,
					"CDATA",
					String.valueOf(start.get(Calendar.DAY_OF_MONTH)));
				attributes.addAttribute(
					"",
					DATE_ATTR_NAME,
					DATE_ATTR_NAME,
					"CDATA",
					dateFormatter.format(start.getTime()));
				this.contentHandler.startElement(
					URI,
					DAY_NODE_NAME,
					PREFIX + ':' + DAY_NODE_NAME,
					attributes);
				addContent(start, locale);
				this.contentHandler.endElement(
					URI,
					DAY_NODE_NAME,
					PREFIX + ':' + DAY_NODE_NAME);
			}
			start.add(Calendar.DAY_OF_MONTH, 1);
			if (start.get(Calendar.DAY_OF_WEEK) == start.getFirstDayOfWeek()
				|| !start.before(end)) {
				this.contentHandler.endElement(
					URI,
					WEEK_NODE_NAME,
					PREFIX + ':' + WEEK_NODE_NAME);
			}
		}

		this.contentHandler.endElement(
			URI,
			CALENDAR_NODE_NAME,
			PREFIX + ':' + CALENDAR_NODE_NAME);
		this.contentHandler.endPrefixMapping(PREFIX);
		this.contentHandler.endDocument();

	}

	/* （非 Javadoc）
	 * @see org.apache.cocoon.generation.CalendarGenerator#addContent(java.util.Calendar, java.util.Locale)
	 */

	public void generate_day() throws SAXException, ProcessingException {
		Calendar start =
			Calendar.getInstance(TimeZone.getTimeZone("UTC"), locale);
		start.clear();
		start.set(Calendar.YEAR, this.year);
		start.set(Calendar.MONTH, this.month);
		start.set(Calendar.DAY_OF_MONTH, day);

		Calendar end = (Calendar) start.clone();
		end.add(Calendar.DAY_OF_MONTH, 1);

		// Determine previous and next months
		Calendar prev = (Calendar) start.clone();
		prev.add(Calendar.DAY_OF_MONTH, -1);

		this.contentHandler.startDocument();
		this.contentHandler.startPrefixMapping(PREFIX, URI);
		attributes.clear();
		attributes.addAttribute(
			"",
			YEAR_ATTR_NAME,
			YEAR_ATTR_NAME,
			"CDATA",
			String.valueOf(year));
		attributes.addAttribute(
			"",
			MONTH_ATTR_NAME,
			MONTH_ATTR_NAME,
			"CDATA",
			monthFormatter.format(start.getTime()));

		// Add previous and next month
		attributes.addAttribute(
			"",
			PREV_YEAR_ATTR_NAME,
			PREV_YEAR_ATTR_NAME,
			"CDATA",
			String.valueOf(prev.get(Calendar.YEAR)));
		attributes.addAttribute(
			"",
			PREV_MONTH_ATTR_NAME,
			PREV_MONTH_ATTR_NAME,
			"CDATA",
			monthNumberFormatter.format(prev.get(Calendar.MONTH) + 1));
		attributes.addAttribute(
			"",
			PREV_DAY_ATTR_NAME,
			PREV_DAY_ATTR_NAME,
			"CDATA",
			String.valueOf(prev.get(Calendar.DAY_OF_MONTH)));
		attributes.addAttribute(
			"",
			NEXT_YEAR_ATTR_NAME,
			NEXT_YEAR_ATTR_NAME,
			"CDATA",
			String.valueOf(end.get(Calendar.YEAR)));
		attributes.addAttribute(
			"",
			NEXT_MONTH_ATTR_NAME,
			NEXT_MONTH_ATTR_NAME,
			"CDATA",
			monthNumberFormatter.format(end.get(Calendar.MONTH) + 1));
		attributes.addAttribute(
			"",
			NEXT_DAY_ATTR_NAME,
			NEXT_DAY_ATTR_NAME,
			"CDATA",
			String.valueOf(end.get(Calendar.DAY_OF_MONTH)));
		//add today by roy
		attributes.addAttribute(
			"",
			TODAY_ATTR_NAME,
			TODAY_ATTR_NAME,
			"CDATA",
			today);
		this.contentHandler.startElement(
			URI,
			CALENDAR_NODE_NAME,
			PREFIX + ':' + CALENDAR_NODE_NAME,
			attributes);

		attributes.clear();
		attributes.addAttribute(
			"",
			NUMBER_ATTR_NAME,
			NUMBER_ATTR_NAME,
			"CDATA",
			String.valueOf(start.get(Calendar.DAY_OF_MONTH)));
		attributes.addAttribute(
			"",
			DATE_ATTR_NAME,
			DATE_ATTR_NAME,
			"CDATA",
			dateFormatter.format(start.getTime()));
		this.contentHandler.startElement(
			URI,
			DAY_NODE_NAME,
			PREFIX + ':' + DAY_NODE_NAME,
			attributes);
		addContent(start, locale);
		this.contentHandler.endElement(
			URI,
			DAY_NODE_NAME,
			PREFIX + ':' + DAY_NODE_NAME);

		this.contentHandler.endElement(
			URI,
			CALENDAR_NODE_NAME,
			PREFIX + ':' + CALENDAR_NODE_NAME);
		this.contentHandler.endPrefixMapping(PREFIX);
		this.contentHandler.endDocument();
	}
}
