package paketFeiertage;

import java.util.Date;
import java.text.DateFormat;
import java.text.DecimalFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.ArrayList;
import java.util.TimeZone;

public class Feiertage
{
	private Calendar meinDatum = new GregorianCalendar();
	private String meinDatumString;
	private Date meinDatumDate;
	private int wochentagszahl;
	private int jahreszahl, monatszahl, tageszahl;
	private ArrayList<String> datum;
	private ArrayList<String> feiertage;
	private SimpleDateFormat sDFddMMMyyyy;
	private SimpleDateFormat sDFddMMyyyy;
	private String feiertagsName;
	private String osterDatumString; 
	private int osterDifferenz;
	private DecimalFormat dfZweistellig = new DecimalFormat("##00");

	public Feiertage()
	{

		sDFddMMMyyyy = new SimpleDateFormat("dd. MMM yyyy");
		sDFddMMMyyyy.setTimeZone(TimeZone.getTimeZone("Europe/Berlin"));
		sDFddMMyyyy = new SimpleDateFormat("dd.MM.yyyy");
		feiertage = new ArrayList<String>();
		datum = new ArrayList<String>();
		datum.add("01.01. Neujahr");
		datum.add("06.01. Heilige 3 Könige");
		datum.add("-48 Rosenmontag");
		datum.add("-47 Faschingsdienstag");
		datum.add("-02 Karfreitag");
		datum.add("-00 Ostersonntag");
		datum.add("001 Ostermontag");
		datum.add("01.05. Tag der Arbeit");
		datum.add("039 Christi Himmelfahrt");
		datum.add("049 Pfingstsonntag");
		datum.add("050 Pfingstmontag");
		datum.add("060 Fronleichnam");
		datum.add("15.08. Maria Himmelfahrt");
		datum.add("03.10. Tag der deutschen Einheit");
		datum.add("31.10. Reformationstag");
		datum.add("01.11. Allerheiligen");
		datum.add("BB Buß und Bettag");
		datum.add("06.12. Nikolaustag");
		datum.add("24.12. Heiligabend");
		datum.add("25.12. Christtag");
		datum.add("26.12. Stefanitag");
		datum.add("31.12. Silvester");

		feiertage = new ArrayList<String>();
	}

	public void setJahreszahl(String pJahreszahl)
	{
		jahreszahl = Integer.parseInt(pJahreszahl);
	}

	public String getFeiertag(int pPosition)
	{
		return feiertage.get(pPosition);

	}

	public void feiertageberechnen()
	{
		feiertage.clear();
		berechnenOstern(jahreszahl);

		int position = 0;
		while (position < getAnzahlFeiertage())
		{

			meinDatumString = datum.get(position);

			if (meinDatumString.substring(3, 4).equals(" "))
			{
				osterDifferenz = Integer.parseInt(meinDatumString.substring(0,
						3));

				feiertagsName = meinDatumString.substring(4,
						meinDatumString.length());

				jahreszahl = Integer
						.parseInt(osterDatumString.substring(6, 10));
				monatszahl = Integer.parseInt(osterDatumString.substring(3, 5));
				tageszahl = Integer.parseInt(osterDatumString.substring(0, 2));
				meinDatum.set(jahreszahl, monatszahl - 1, tageszahl);
				meinDatum = (GregorianCalendar) plusminusTage(meinDatum,
						osterDifferenz);

				jahreszahl = meinDatum.get(Calendar.YEAR);
				monatszahl = meinDatum.get(Calendar.MONTH) + 1;
				tageszahl = meinDatum.get(Calendar.DAY_OF_MONTH);
				meinDatumString = dfZweistellig.format(tageszahl) + "."
						+ dfZweistellig.format(monatszahl) + "." + jahreszahl;
				try
				{
					meinDatumDate = sDFddMMyyyy.parse(meinDatumString);
				} catch (ParseException mFehler)
				{

				}

				// set(int year, int month, int date) Jan=0,Feb=1,Mar=2...

				meinDatum.set(jahreszahl, monatszahl - 1, tageszahl);

				wochentagszahl = meinDatum.get(Calendar.DAY_OF_WEEK);

				feiertage.add(getWochentag(wochentagszahl) + " "
						+ sDFddMMMyyyy.format(meinDatumDate) + " : "
						+ feiertagsName);

			} else
			{
				if (meinDatumString.substring(0, 2).equals("BB"))
				{
					feiertagsName = meinDatumString.substring(3,
							meinDatumString.length());
					meinDatumString = meinDatumString.substring(0, 6)
							+ jahreszahl;

					berechneBussundBettag(jahreszahl);

					try
					{
						meinDatumDate = (Date) sDFddMMyyyy
								.parse(meinDatumString);
					} catch (ParseException mFehler)
					{
					}

					jahreszahl = Integer.parseInt(meinDatumString.substring(6,
							10));
					monatszahl = Integer.parseInt(meinDatumString.substring(3,
							5));
					tageszahl = Integer.parseInt(meinDatumString
							.substring(0, 2));
					meinDatum.set(jahreszahl, monatszahl - 1, tageszahl);

					wochentagszahl = meinDatum.get(Calendar.DAY_OF_WEEK);

					feiertage.add(getWochentag(wochentagszahl) + " "
							+ sDFddMMMyyyy.format(meinDatumDate) + " : "
							+ feiertagsName);

				} else
				{

					feiertagsName = meinDatumString.substring(7,
							meinDatumString.length());
					meinDatumString = meinDatumString.substring(0, 6)
							+ jahreszahl;

					try
					{
						meinDatumDate = (Date) sDFddMMyyyy
								.parse(meinDatumString);
					} catch (ParseException mFehler)
					{
					}

					jahreszahl = Integer.parseInt(meinDatumString.substring(6,
							10));
					monatszahl = Integer.parseInt(meinDatumString.substring(3,
							5));
					tageszahl = Integer.parseInt(meinDatumString
							.substring(0, 2));
					meinDatum.set(jahreszahl, monatszahl - 1, tageszahl);

					wochentagszahl = meinDatum.get(Calendar.DAY_OF_WEEK);

					feiertage.add(getWochentag(wochentagszahl) + " "
							+ sDFddMMMyyyy.format(meinDatumDate) + " : "
							+ feiertagsName);
				}
			}
			position = position + 1;

		}
		sommerzeitbeginn();
		sommerzeitende();

	}

	public int getAnzahlFeiertage()
	{
		return datum.size();
	}

	private void sommerzeitbeginn()
	{
		// letzter Sonntag im März
		meinDatum.set(jahreszahl, 3 - 1, 31);

		wochentagszahl = meinDatum.get(Calendar.DAY_OF_WEEK);

		meinDatumString = 31 - wochentagszahl + 1 + ".03." + jahreszahl;
		jahreszahl = Integer.parseInt(meinDatumString.substring(6, 10));
		monatszahl = Integer.parseInt(meinDatumString.substring(3, 5));
		tageszahl = Integer.parseInt(meinDatumString.substring(0, 2));
		meinDatum.set(jahreszahl, monatszahl - 1, tageszahl);

		wochentagszahl = meinDatum.get(Calendar.DAY_OF_WEEK);
		feiertagsName = "Beginn der Sommerzeit";
		try
		{
			meinDatumDate = (Date) sDFddMMyyyy.parse(meinDatumString);
		} catch (ParseException mFehler)
		{
		}

		feiertage.add(getWochentag(wochentagszahl) + " "
				+ sDFddMMMyyyy.format(meinDatumDate) + " : " + feiertagsName);
	}

	private void sommerzeitende()
	{
		// letzter Sonntag im Oktober
		meinDatum.set(jahreszahl, 10 - 1, 31);

		wochentagszahl = meinDatum.get(Calendar.DAY_OF_WEEK);

		meinDatumString = 31 - wochentagszahl + 1 + ".10." + jahreszahl;
		jahreszahl = Integer.parseInt(meinDatumString.substring(6, 10));
		monatszahl = Integer.parseInt(meinDatumString.substring(3, 5));
		tageszahl = Integer.parseInt(meinDatumString.substring(0, 2));
		meinDatum.set(jahreszahl, monatszahl - 1, tageszahl);

		wochentagszahl = meinDatum.get(Calendar.DAY_OF_WEEK);
		feiertagsName = "Ende der Sommerzeit";
		try
		{
			meinDatumDate = (Date) sDFddMMyyyy.parse(meinDatumString);
		} catch (ParseException mFehler)
		{
		}

		feiertage.add(getWochentag(wochentagszahl) + " "
				+ sDFddMMMyyyy.format(meinDatumDate) + " : " + feiertagsName);
	}

	private String getWochentag(int pWochentagszahl)
	{
		String wochentag = "";
		switch (pWochentagszahl)
		{
		case Calendar.MONDAY:
			wochentag = "Mo";
			break;
		case Calendar.TUESDAY:
			wochentag = "Di";
			break;
		case Calendar.WEDNESDAY:
			wochentag = "Mi";
			break;
		case Calendar.THURSDAY:
			wochentag = "Do";
			break;
		case Calendar.FRIDAY:
			wochentag = "Fr";
			break;
		case Calendar.SATURDAY:
			wochentag = "Sa";
			break;
		case Calendar.SUNDAY:
			wochentag = "So";
			break;
		}
		return wochentag;
	}

	private void berechneBussundBettag(int pJahreszahl)
	{
		// BußundBettag ist der 3. Mittwoch im November
		Calendar einBBTag = new GregorianCalendar(pJahreszahl, 11 - 1, 1);

		meinDatum = (GregorianCalendar) plusminusTage(einBBTag,
				((11 - einBBTag.get(Calendar.DAY_OF_WEEK)) % 7) + 14);
		meinDatumString = DateFormat.getDateInstance(DateFormat.MEDIUM).format(
				meinDatum.getTime());

	}

	private void berechnenOstern(int pJahreszahl)
	{
		int a, b, c, d, e, p, q, r, x, y, tag, monat;

		// Es geht um die Berechnung der Größen d und e
		// Dazu braucht man die 9 Hilfsgrößen a, b, c, p, n, q, r, x, y !!

		p = pJahreszahl / 100;

		q = p / 3;
		r = p / 4;

		x = (15 + p - q - r) % 30;
		y = (4 + p - r) % 7;

		a = pJahreszahl % 19;
		b = pJahreszahl % 4;
		c = pJahreszahl % 7;

		d = (19 * a + x) % 30;
		e = (2 * b + 4 * c + 6 * d + y) % 7;

		if (d == 29 && e == 6)
		{
			// => Ostern am 19.April
			tag = 19;
			monat = 4;
		} else
		{
			if (d == 28 && e == 6)
			{
				// => Ostern am 18.April
				tag = 18;
				monat = 4;
			} else
			{
				if (22 + d + e < 32)
				{
					// => Ostern am (22+d+e).März
					tag = 22 + d + e;
					monat = 3;
				} else
				{
					// => Ostern am (d+e-9).April
					tag = d + e - 9;
					monat = 4;
				}
			}
		}

		if (tag < 10)
		{
			meinDatumString = "0" + tag + "." + "0" + monat + "." + pJahreszahl;
		} else
		{
			meinDatumString = tag + "." + "0" + monat + "." + pJahreszahl;
		}
		osterDatumString = meinDatumString;
	}

	private Calendar plusminusTage(Calendar pDatum, int pTageDiffernz)
	{

		Calendar neuesDatum = (Calendar) pDatum.clone();
		neuesDatum.add(Calendar.DAY_OF_YEAR, pTageDiffernz);
		return neuesDatum;
	}
}
