import java.util.Scanner;

public class PrintCalendar {
  /** Metoda main */
  public static void main(String[] args) {
    Scanner input = new Scanner(System.in);

    // Wyświetlanie prośby o wpisanie roku
    System.out.print("Wpisz rok w formacie czterocyfrowym (na przykład 2012): ");
    int year = input.nextInt();

    // Wyświetlanie prośby o podanie miesiąca
    System.out.print("Wpisz miesiąc (od 1 do 12): ");
    int month = input.nextInt();

    // Wyświetlanie kalendarza podanego miesiąca z danego roku
    printMonth(year, month);
  }

  /** Wyświetlanie kalendarza podanego miesiąca z danego roku */
  public static void printMonth(int year, int month) {
    // Wyświetlanie nagłówka kalendarza
    printMonthTitle(year, month);

    // Wyświetlanie numerów dni miesiąca
    printMonthBody(year, month);
  }

  /** Wyświetlanie nagłówka, na przykład Marzec 2012 */
  public static void printMonthTitle(int year, int month) {
    System.out.println("         " + getMonthName(month)
      + " " + year);
    System.out.println("-----------------------------");
    System.out.println("    N  Pn  Wt  Śr  Cz  Pt  So");
  }

  /** Zwraca nazwę miesiąca */
  public static String getMonthName(int month) {
    String monthName = "";
    switch (month) {
      case 1: monthName = "Styczeń"; break;
      case 2: monthName = "Luty"; break;
      case 3: monthName = "Marzec"; break;
      case 4: monthName = "Kwiecień"; break;
      case 5: monthName = "Maj"; break;
      case 6: monthName = "Czerwiec"; break;
      case 7: monthName = "Lipiec"; break;
      case 8: monthName = "Sierpień"; break;
      case 9: monthName = "Wrzesień"; break;
      case 10: monthName = "Październik"; break;
      case 11: monthName = "Listopad"; break;
      case 12: monthName = "Grudzień";
    }

    return monthName;
  }

  /** Wyświetla numery dni miesiąca */
  public static void printMonthBody(int year, int month) {
    // Pobieranie dnia tygodnia wypadającego w pierwszym dniu danego miesiąca
    int startDay = getStartDay(year, month);

    // Pobieranie liczby dni w podanym miesiącu
    int numberOfDaysInMonth = getNumberOfDaysInMonth(year, month);

    // Dodawanie spacji przed pierwszym dniem miesiąca
    int i = 0;
    for (i = 0; i < startDay; i++)
      System.out.print("    ");

    for (i = 1; i <= numberOfDaysInMonth; i++) {
      System.out.printf("%4d", i);

      if ((i + startDay) % 7 == 0)
        System.out.println();
    }

    System.out.println();
  }

  /** Pobieranie dnia tygodnia wypadającego w pierwszym dniu danego miesiąca danego roku */
  public static int getStartDay(int year, int month) {
    final int START_DAY_FOR_JAN_1_1800 = 3;
    // Pobieranie liczby dni od 1/1/1800 do 1/month/year
    int totalNumberOfDays = getTotalNumberOfDays(year, month);

    // Zwracanie dnia wypadającego w pierwszym dniu danego miesiąca danego roku
    return (totalNumberOfDays + START_DAY_FOR_JAN_1_1800) % 7;
  }

  /** Zwraca łączną liczbę dni od 1 stycznia 1800 roku */
  public static int getTotalNumberOfDays(int year, int month) {
    int total = 0;

    // Pobieranie liczby dni od 1800 roku do 1/1/year
    for (int i = 1800; i < year; i++)
      if (isLeapYear(i))
        total = total + 366;
      else
        total = total + 365;

    // Dodawanie dni od stycznia do końca miesiąca przed wyświetlanym miesiącem
    for (int i = 1; i < month; i++)
      total = total + getNumberOfDaysInMonth(year, i);

    return total;
  }

  /** Zwracanie liczby dni w miesiącu */
  public static int getNumberOfDaysInMonth(int year, int month) {
    if (month == 1 || month == 3 || month == 5 || month == 7 ||
      month == 8 || month == 10 || month == 12)
      return 31;

    if (month == 4 || month == 6 || month == 9 || month == 11)
      return 30;

    if (month == 2) return isLeapYear(year) ? 29 : 28;

    return 0; // Jeśli podano nieprawidłowy miesiąc
  }

  /** Sprawdzanie, czy dany rok jest przestępny */
  public static boolean isLeapYear(int year) {
    return year % 400 == 0 || (year % 4 == 0 && year % 100 != 0);
  }
}
