#!/usr/bin/env python3
# -*- coding: utf-8 -*-


# Query the openmensa.org API for the menu of a weekday of the current week.
#
# Copyright © 2018 Wolfgang Popp
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the "Software"),
# to deal in the Software without restriction, including without limitation
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
# and/or sell copies of the Software, and to permit persons to whom the
# Software is furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
# DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
# OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.


"""Query the openmensa.org API for the menu of a weekday of the current week.

# Usage

```bash
mensa <Weekday; optional; Monday: 1, ... , Sunday: 7>
```

# Use with rofi
## Show plan for today

```bash
rofi -modi "Mensa:mensa" -show Mensa
```

## Load plan for the entire week
Every day in a separate mode. The default keybinding to switch modes is
`Shift+Arrow`

```bash
rofi -modi "Mensa Monday:mensa 1#Mensa Tuesday:mensa 2#Mensa Wednesday:mensa 3#Mensa Thursday:mensa 4#Mensa Friday:mensa 5" -show "$(date +'Mensa %A')"
```

# Use with dmenu
```bash
mensa | dmenu
```
"""

import sys
import calendar
import json
import os
import datetime

from urllib.request import urlopen
from urllib.error import HTTPError
from typing import TextIO

PRICE_CATEGORY = "student"
CANTEEN_ID = 196

CACHE_DIR = os.path.expanduser("~/.cache/mensa.woefe.github.com/")
CACHE_TEMPLATE = os.path.join(CACHE_DIR, "{}_{}_{}.txt")
URL_TEMPLATE = "http://openmensa.org/api/v2/canteens/{}/days/{}/meals"


def convert_date(weekday: int) -> str:
    """Convert given weekday (of the current week) to YYYY-MM-DD date string.

    Weekday is specified as 1: Monday, ... , 7: Sunday.
    """
    if weekday not in range(0, 7):
        raise ValueError("Invalid weekday")

    today = datetime.date.today()
    today_weekday = today.isoweekday()
    converted = today

    if weekday < today_weekday:
        day = today.day - (today_weekday - weekday)
        month = today.month
        year = today.year
        if day < 1:
            month = today.month - 1
            if month < 1:
                year = today.year - 1
                month = 12

            day = calendar.monthrange(year, month)[1] + day

        converted = datetime.date(year, month, day)

    if weekday > today_weekday:
        day = today.day + (weekday - today_weekday)
        month = today.month
        year = today.year
        last_day_of_month = calendar.monthrange(year, month)[1]
        if day > last_day_of_month:
            month = today.month + 1
            day = day - last_day_of_month
            if month > 12:
                year = today.year + 1
                month = 1

        converted = datetime.date(year, month, day)

    return converted.strftime("%Y-%m-%d")


def download(target_file: TextIO, date: str) -> None:
    """Download the menu of the given date and save it to the given file."""
    url = URL_TEMPLATE.format(CANTEEN_ID, date)

    try:
        with urlopen(url) as response:
            meals = json.load(response)
            template = "{{:>{}}}   {{:.2f}}€   {{}}\n"
            width = max(map(lambda m: len(m.get("category", "")), meals))
            render = template.format(width)

            for meal in meals:
                name = meal.get("name", "")
                price = meal.get("prices", {}).get("students")
                category = meal.get("category", "")
                target_file.write(render.format(category, price, name))
    except HTTPError:
        pass


def main(weekday: int) -> None:
    """Print the menu of the given weekday to stdout.

    Downloads the menu only if it is not already cached locally on disk.
    """
    os.makedirs(CACHE_DIR, exist_ok=True)

    date = convert_date(weekday)
    cache_file = CACHE_TEMPLATE.format(CANTEEN_ID, PRICE_CATEGORY, date)

    if not os.path.isfile(cache_file):
        with open(cache_file, "w") as destination:
            download(destination, date)

    with open(cache_file) as cached:
        for line in cached.readlines():
            print(line, end="")


if __name__ == "__main__":
    try:
        WEEKDAY = int(sys.argv[1])
    except (IndexError, ValueError):
        WEEKDAY = datetime.date.today().isoweekday()
    main(WEEKDAY)
