# Homework 3 - Functions and Recursion

- Learn about functions, recursion and HTML elements.
- _[Live demo](http://hwdemo.prototyping.id/hw3)_

## General Description

In this assignment you are required to understand **functions and recursion**, and it allows you to practice with basic **GUI** elements (_HTML_ elements such as dropdown selections, sliders, buttons). Using a web interface the user can insert two dates, and then the system reports the number of days between the two dates (like [this website](https://www.timeanddate.com/date/durationresult.html?d1=01&m1=02&y1=2022&d2=2&m2=01&y2=2023)).

<p align="center">
<img src="assets/main.png" height="300" />
</p>

## Before Starting

Clone the repository in your computer and you will find a few files and these instructions.

You are on the `main` branch, but the code for this exercise and the instructions are inside the `develop` branch. Checkout (or switch to) the `develop`branch and you will see the main files `main.js` and `index.html` as well as the rest of the instructions. The file `main.js`contains some stub code to get you started. Do all your commits in the develop branch, then, when you are done, **merge** your changes in the `main` branch, before submitting.

## Overview

### 1. Graphical User Interface

- The user should be able to pick **any two dates between January 1st, 1900, and December 31st, 2100**.
- The **days available in the dropdown depend on the month and year** that have been selected. For example, if February 1900 is selected, the days in the range 29-31 are not selectable.
- **If the current day selected does not exist** in the subsequently selected month, the day should be **reset to 1**. For example, if the current selection is January 31, but then the user picks February, the currently selected day (31) is reset to 1.
- If the start date is after the end date, the day difference is 0.
- You can access the HTML elements using the document functions `getElementById`, `getElementsByClassName`, `getElementsByName`, `getElementsByTagName`, `getElementsByAttribute`, `querySelector`, etc. Once you have a reference to an HTML _element_, you can access its value as `element.value` and its HTML content with `element.innerHTML`. Here is a list of all the IDs used in the interface.
- This image shows a list of all the IDs for input elements (in <span style="background:red">red</span>) and for output elements (in <span style="background:green">green</span>). The **inputs** are: `day1`, `month1`, `day2`, `month2` (the dropdowns); `year1` and `year2` (the sliders); `iteration` and `recursion` (the radio buttons); and `button`. The **outputs** are displayed on the right side and they are `date1` and `date2` (they show the selected date in the format _day/month/year_); `weekday1` and `weekday2` (the days of the week for the two dates); and `days` (the computed result).

<p align="center">
<img src="assets/ids.png" height="450" />
</p>

### 2. Computing the days between two dates

In this assignment you need to implement the code for different functions. You can create more functions, but the one listed below should also be included.

#### `isLeapYear (year)`

- _Input_: year as number (an integer)
- _Returns_: boolean

One solar year has the length of 365 days, 5 hours, 48 minutes and 47 seconds. Because this is rather dysfunctional, **a normal year has been given 365 days and a leap year 366 days**. At leap years February 29th is added, which doesn't exist in a normal year. **A leap year is every 4 years, but not every 100 years, then again every 400 years**.

So, notice that 1900 is not a leap year, and so 2100, but 2000 is leap divisible by 400.

The function `isLeapYear` returns true if the supplied year is a leap year (366 days long), otherwise it is a normal year and the function should return false.

**Example**:

```js
isLeapYear(1980); //-> returns true
isLeapYear(2014); //-> returns false
```

---

#### `computeDaysInMonth (month, year)`

- _Input_: month and year as numbers
- _Returns_: number

Returns the number of days in the selected month. The year is supplied so that in case of leap year, February should return 29 days.

**Example**:

```js
computeDaysInMonth(2, 1980); //-> returns 29
computeDaysInMonth(2, 1981); //-> returns 28
computeDaysInMonth(12, 2018); //-> returns 31
```

---

#### `computeDaysInYear (year)`

#### `computeDaysSinceBeginningYear (day, month, year)`

#### `computeDaysLeftYear ( day, month, year)`

- _Input_: day, month, year are all number
- _Returns_: number

`computeDaysInYear` computes the number of days in the year (365 or 366, depending if it is a normal year or a leap year) **that day included**.
`computeDaysSinceBeginningYear` returns the number of days since the beginning of the year that day **included**.
`computeDaysLeftYear` returns the number of days left until the end of the year that day **included**.

**Example**:

```js
computeDaysInYear(2014); //-> returns 365
computeDaysSinceBeginningYear(31, 1, 2014); //->  returns 31
computeDaysLeftYear(31, 1, 2014); //-> returns 335
```

Therefore, **Note that** 31 + 335 **-1** is = 365. The **-1** is needed because we considered the starting date twice (both computeDays functions are until the end day _included_!)

#### `computeDaysBetweenDatesIter (fromDay, fromMonth, fromYear, toDay, toMonth, toYear)`

#### `computeDaysBetweenDatesRec (fromDay, fromMonth, fromYear, toDay, toMonth, toYear)`

- _Input_: fromDay, fromMonth, fromYear, toDay, toMonth, toYear are all Numbers
- _Returns_: Number

These functions return the number of days between two dates **excluding** the end date. They account for leap years. The first function works using loops to iterate through the years between fromYear and toYear. The second function is recursive and **cannot use** loops, though it might call other functions you developed (see the one above in this list) which contain loops.

**Example**:

```js
// Iterative
computeDaysBetweenDatesIter(12, 7, 1910, 23, 4, 2014); //-> returns 37906
computeDaysBetweenDatesIter(12, 7, 1910, 12, 7, 1910); //-> returns 0 // same date
computeDaysBetweenDatesIter(15, 6, 2000, 12, 7, 1900); //-> returns 0 // start date > end date

// Recursive
computeDaysBetweenDatesRec(12, 7, 1910, 23, 4, 2014); //-> returns 37906
computeDaysBetweenDatesRec(12, 7, 1910, 12, 7, 1910); //-> returns  // same date
computeDaysBetweenDatesRec(15, 6, 2000, 12, 7, 1900); //-> returns 0 // start date > end date
```

---

#### `getDayOfWeek (day, month, year)`

- _Input_: day, month, year
- _Returns_: String

There are 7 days of the week, each indicated using a string: “Mon”, “Tue”, “Wed”, “Thu”, “Fri”, “Sat”, and “Sun”. This function takes the reference date (1 January 1900) and its corresponding day of the week ‘Mon’ (Monday) and uses this information to find the day of the week of the input date (day, month, year). Underneath, you can use either `computeDaysBetweenDatesRec` or `computeDaysBetweenDatesIter`.

**Example**:

```js
getDayOfWeek(12, 7, 1910); //-> returns as result ‘Tue’ for Tuesday
getDayOfWeek(29, 2, 1980); //-> returns 'Fri' for Friday
getDayOfWeek(1, 1, 1900); //-> returns ‘Mon’ for MOnday
```

---

## Tips

1. It will be easier if you develop the functions in the order they are explained in these instructions. The best practice is to develop pieces of functionalities that you can re-use in other parts of the program. For example, the function `getDayOfWeek` will require you to compute first `computeDaysBetweenDates` (recursive or iterative). So you can call the function `computeDaysBetweenDates` inside the body of the function `getDayOfWeek`. **Avoid copying and pasting**; instead, call functions that you have defined before!

2. `computeDaysBetweenDatesRec` is the hardest of the functions of this assignment. It is a recursive function. Try to identify the base case first. What about the recursive case?

## About grading

The maximum score of this assignment is 100 points, divide in this way:

1. The graphical user interface (input controllers and output text) is working (15%).
2. All functions **except** `computeDaysBetweenDatesRec` are working (50%).
3. The function `computeDaysBetweenDatesRec` is working (20%).
4. Submit your local repository with your code (the hidden .git folder). There should be at least 10 commits in a branch called `develop`, which is finally merged back to `main` (10%).
5. The [SubmissionNotes](./SubmissionNotes.md) file (5%).

If the program does not compile (e.g., not a valid JavaScript file), the score is 0. If it runs, the score is inversely proportional to the number of errors. If the code has runtime errors (crash), there is a 20-point penalty, plus a penalty for any additional part that cannot be checked.

## How to submit

<p align="center">
<img src="assets/submission.png" width="600" />
</p>

1. After completing your code, make sure to fill out the [Submission Notes](./SubmissionNotes.md) with your basic info and indicate whether you received any help. Feel free to add any relevant information.
2. Zip the folder of this repository containing your solution.
3. Submit the homework using the class [submission system](https://homework.designware.xyz). Choose `HW3`.
4. For any problems, feel free to contact the professor or TA via Discord.

**NOTES**

- Only submissions made through the system will be considered (e.g., no direct emails to the TA or Prof).
- You can resubmit as many times as you want; only the last submission will be considered.
- Submissions after the deadline (even a few minutes) will receive a penalty of 20%. Submissions made after 24 hours from the deadline will be ignored (score will be 0).
- Keep a screenshot that proves your completed submission.
- Coding style may be considered in grading.
