// Aufgabe 1106 Maskdate: Datum formatieren
// Teil der ersten Übungsrunde
// "AU Einführung in das Programmieren" an der TU-Wien
// Dokumentation siehe 'maskdate.txt'
// Autor: Starzinger Michael, <e0306126@student.tuwien.ac.at>
// Datum: Dienstag, 21. Oktober 2003


import eprog.EprogException;
import eprog.EprogIO;
import java.lang.Math;
import java.text.NumberFormat;


class DateFormatExt
{
	static boolean checkDateStr(String date, String pattern)
	{
		boolean bValid = false;

	//nur überprüfen wenn datum und pattern gleich lang
	//ansonsten ist das datum ungültig
		if (date.length() == pattern.length())
		{
			bValid = true;
	//zeichenweises vergleichen der beiden strings
			for (int i=0; i<date.length(); i++)
			{
				char chD = date.charAt(i);
				char chP = pattern.charAt(i);
	//entweder zeichen sind gleich oder im pattern ist ein 'x' als escape verzeichnet
				bValid &= (chP == 'x' || chP == chD);
			}
		}
		return bValid;
	}

	static boolean checkDate(int dateD, int dateM, int dateY)
	{
		boolean bValid;

	//grobe beschränkung aller werte
		bValid = (dateD <= 31 && dateD > 0) && (dateM <= 12 && dateM > 0) && (dateY >= 0);
	//genau berücksichtigung des schaltjahres beim februar vornehmen
	//entweder es ist nicht februar oder <28 oder schaltjahr und <29
		bValid &= (dateM != 2) || (dateD <= 28) || (dateD <= 29 && isLeap(dateY));
	//genaue beschränkung des tages in den einzelnen monaten mit nur 30 tagen
		switch (dateM)
		{
		case 4:
		case 6:
		case 9:
		case 11:
			bValid &= (dateD <= 30);
		}
		return bValid;
	}

	static boolean isLeap(int dateY)
	{
	//schaltjahre sind jedes vierte jahr, alle hundert jahre nicht und alle 400 dann wieder schon
	//das heisst das jahr muss auf jeden fall durch vier teilbar sein und nicht durch hundert teilbar
	//ausser es ist dann wieder durch 400 teilbar
		return ((dateY % 4 == 0) && ((dateY % 100 != 0) || (dateY % 400 == 0)));
	}

	static String getDayName(int dateDOW)
	{
	//array mit allen namen beginnen bei 0
	//dateDOW darf den rahmen des arrays unter keinen umständen sprengen, deshalb mod 7
		String DayNames[] = {"SUNDAY", "MONDAY", "TUESDAY", "WEDNESDAY", "THURSDAY", "FRIDAY", "SATURDAY"};
		return DayNames[dateDOW % 7];
	}

	static String getMonthName(int dateM)
	//detto!
	{
		String MonthNames[] = {"JANUARY", "FEBRUARY", "MARCH", "APRIL", "MAY", "JUNE", "JULY", "AUGUST", "SEPTEMBER", "OCTOBER", "NOVEMBER", "DECEMBER"};
		return MonthNames[dateM % 12];
	}

	static String getMonthNameShort(int dateM)
	//um nicht alle monatsnamen noch einmal eintippen zu müssen werden hier einfach
	//die ersten drei buchstaben des langen namens extrahiert
	{
		return getMonthName(dateM).substring(0,3);
	}

	static byte getDayOfWeek(int d, int m, int y)
	{
	//berechnung des wochentages!
		int days = 0;

	//zunächst werden die tage gezählt die im eingegebenen jahr bereits vergangen sind
	//dazu werden rückwärts für jedes volendete monat die tage addiert
		switch (m)
		{
		case 12: days+=30;
		case 11: days+=31;
		case 10: days+=30;
		case 9: days+=31;
		case 8: days+=31;
		case 7: days+=30;
		case 6: days+=31;
		case 5: days+=30;
		case 4: days+=31;
		case 3: days+=isLeap(y)?29:28;
		case 2: days+=31;
	//...zum schluss werden noch die tage des gerade laufenden monats addiert
	//wobei zu beachten ist, dass hier auch von null zu zählen begonnen werden muss
		default: days+=d-1;
		}
	//...wir haben nun die anzahl der tage die in diesem jahr vergangen sind.
	//wenn wir nun noch die verschiebung des ersten wochentages addieren, so ist es
	//möglich danach auf den gewünschten wochentag zu schließen indem wir durch 7 modulieren
		days += (y + Math.floor((y-1)/4) - Math.floor((y-1)/100) + Math.floor((y-1)/400));
		return (byte)(days % 7);
	//...voila!
	}

	static String getFormattedNumeric(int numeric, int count)
	{
	//zum formatieren der einzelnen zahlen benutzen wir hier java.text.NumberFormat
		NumberFormat nf = NumberFormat.getNumberInstance();
	//sowohl ober- als auch untergrenze der ziffernanzahl werden auf den gewünschten wert gesetzt
		nf.setMinimumIntegerDigits(count);
		nf.setMaximumIntegerDigits(count);
	//nun muss noch verhindert werden, dass nach der dritten stelle ein punkt folgt,
	//dies wäre bei der vierstelligen ausgabe des jahres fatal!
		nf.setGroupingUsed(false);
		return nf.format(numeric);
	}

	static String getFormattedDate(String date, String format) throws EprogException
	{
	//das kernstück der vorliegenden klasse
		short dateD, dateM, dateY;
		String strResult = "";

	//als erstes muss überprüft werden ob das eingegebenen datum einem der gewünschten
	//formate entspricht. wenn nicht, haben wir einen grund uns beim benutzer zu beschweren.
	//die methode terminiert in diesem fall mit einer exception welche im hauptprogramm
	//wieder abgefangen wird.
		if (!(checkDateStr(date, "xx-xx-xxxx") || checkDateStr(date, "xx/xx/xxxx")))
		{
			throw new EprogException("incorrect date string");
		}

		try
		{
	//nun werden die zahlen an den erwarteten positionen eingelesen und in numerische
	//werte konvertiert.
			dateD = Short.parseShort(date.substring(0,2));
			dateM = Short.parseShort(date.substring(3,5));
			dateY = Short.parseShort(date.substring(6,10));
	//zur sicherheit fangen wir hier alle ausnahmen auf, die mir einem fehler in der
	//formatierung zu tun haben (zb: zeichen die keine ziffern darstellen!)
		} catch(java.lang.NumberFormatException e) {
	//und lösen gegebenenfalls unsere eigene exception aus
			throw new EprogException("incorrect number format");
		}

	//sind die eingegebenen werte plausibel??? -> nein -> beschweren!
		if (!checkDate(dateD, dateM, dateY))
		{
			throw new EprogException("incorrect date");
		}

	//zeichenweises abarbeiten des format-strings!
		for (int i=0; i<format.length(); i++)
		{
			char ch;
			switch (ch = format.charAt(i))
			{
	//sollte eines der gültigen trennzeichen gefunden werden, so übernehmen wir es an
	//dieser stelle direkt in unser ergebnis. ein '_' wird auch gleich zu einem ' '
			case '_': ch = ' ';
			case '/':
			case '.':
			case '-':
				strResult += ch;
				break;
	//ansonsten muss es sich wohl um eines der definierten schlüsselwörter handeln
			default:
	//...das schlüsselwort wird extrahiert...
				String strToken = format.substring(i, format.length());
	//...und der reihe nach verglichen. hierbei ist zu beachten dass vergleiche mit längeren
	//schlüssel wörter (zB. YYYY) vor deren küzeren versionen (zB YY) gemacht werden müssen.
	//würde dies nicht geschehen dann würde anstatt einmal dem vierstelligen jahr, zweimal das
	//zweistellige jahr im ergebniss erscheinen.
	//ausserdem wir bei einem gefunden schlüssel mit dem vergeichen abgebrochen und der index
	//an das letzte zeichen im schlüsselwort verschoben!
				if (strToken.startsWith("DD")) {strResult += getFormattedNumeric(dateD,2); i+=1;}
				else if (strToken.startsWith("MM")) {strResult += getFormattedNumeric(dateM,2); i+=1;}
				else if (strToken.startsWith("YYYY")) {strResult += getFormattedNumeric(dateY,4); i+=3;}
				else if (strToken.startsWith("YY")) {strResult += getFormattedNumeric(dateY,2); i+=1;}
				else if (strToken.startsWith("MONTH")) {strResult += getMonthName(dateM-1); i+=4;}
				else if (strToken.startsWith("MON")) {strResult += getMonthNameShort(dateM-1); i+=2;}
				else if (strToken.startsWith("DAY")) {strResult += getDayName(getDayOfWeek(dateD,dateM,dateY)); i+=2;}
	//ist der schlüssel nicht definiert, liegt ein fehler in der eingabe vor
	//wir haben wieder einen grund uns zu beschweren!
				else {throw new EprogException("incorrect format string");}
			}
		}
		return strResult;
	}
};


class Maskdate 
{
	//in dieser klasse liegt unser hauptprogramm, sonst nichts interessantes.
	public static void main(String[] args) 
	{
		EprogIO IO = new EprogIO();
		DateFormatExt df = new DateFormatExt();
		String strDate, strFormat;
		String strResult = "";

		//als erstes müssen zwei strings eingelesen werden
		strDate = IO.readWord();
		strFormat = IO.readWord();

		try
		{
		//...danach wird versucht das datum mit hilfe einer instanz der DateFormatExt klasse zu formatieren
			strResult = df.getFormattedDate(strDate, strFormat);
		} catch (EprogException e) {
		//...tritt innerhalb dieser instanz ein fehler auf werden wir mittels EprogException
		//darüber in kenntnis gesetzt und ändern die ausgabe definitionsgemäß ab!
			strResult = "FALSCHE EINGABE";
		//eine ausgabe der fehlerbeschreibung kann zu debug-zweichen nützlich sein
			//IO.println("---> Error-Message: " + e.getMessage());
		}

		//in jedem fall erfolgt eine ausgabe!
		IO.println(strResult);
	}
}